Started work on migrating model to lazy evaluation
This commit is contained in:
@@ -1,219 +0,0 @@
|
||||
var childSchema = new SimpleSchema({
|
||||
parent: {type: Object},
|
||||
"parent.collection": {type: String},
|
||||
"parent.id": {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
"parent.group": {type: String, optional: true},
|
||||
"removedWith": {
|
||||
optional: true,
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
},
|
||||
});
|
||||
|
||||
var joinWithDefaultKeys = function(keys){
|
||||
var defaultKeys = [
|
||||
"charId",
|
||||
];
|
||||
return _.union(keys, defaultKeys);
|
||||
};
|
||||
|
||||
var limitModifierToKeys = function(modifier, keys){
|
||||
if (!modifier) return;
|
||||
modifier = _.pick(modifier, ["$set", "$unset"]);
|
||||
if (modifier.$set) modifier.$set = _.pick(modifier.$set, keys);
|
||||
if (modifier.$unset) modifier.$unset = _.pick(modifier.$unset, keys);
|
||||
if (_.isEmpty(modifier.$set)) delete modifier.$set;
|
||||
if (_.isEmpty(modifier.$unset)) delete modifier.$unset;
|
||||
return modifier;
|
||||
};
|
||||
|
||||
var getParent = function(doc){
|
||||
if (!doc || !doc.parent) return;
|
||||
var parentCol = Meteor.isClient ?
|
||||
window[doc.parent.collection] : global[doc.parent.collection];
|
||||
if (parentCol)
|
||||
return parentCol.findOne(doc.parent.id, {removed: true});
|
||||
};
|
||||
|
||||
var inheritParentProperties = function(doc, collection){
|
||||
var parent = getParent(doc);
|
||||
if (!parent) throw new Meteor.Error(
|
||||
"Parenting Error",
|
||||
"Document's parent does not exist"
|
||||
);
|
||||
var handMeDowns = _.pick(parent, collection.inheritedKeys);
|
||||
if (
|
||||
_.contains(collection.inheritedKeys, "charId") &&
|
||||
doc.parent.collection === "Characters"
|
||||
){
|
||||
handMeDowns.charId = doc.parent.id;
|
||||
}
|
||||
if (_.isEmpty(handMeDowns)) return;
|
||||
collection.update(doc._id, {$set: handMeDowns});
|
||||
};
|
||||
|
||||
var childCollections = [];
|
||||
|
||||
makeChild = function(collection, inheritedKeys){
|
||||
inheritedKeys = inheritedKeys || [];
|
||||
if (inheritedKeys) {
|
||||
collection.inheritedKeys = joinWithDefaultKeys(inheritedKeys);
|
||||
}
|
||||
collection.helpers({
|
||||
//returns the parent even if it's removed
|
||||
getParent: function(){
|
||||
return getParent(this);
|
||||
},
|
||||
getParentCollection: function(){
|
||||
return Meteor.isClient ?
|
||||
window[this.parent.collection] : global[this.parent.collection];
|
||||
},
|
||||
});
|
||||
|
||||
//when created, inherit parent properties
|
||||
collection.after.insert(function(userId, doc){
|
||||
inheritParentProperties(doc, collection);
|
||||
});
|
||||
|
||||
collection.before.update(function(userId, doc, fieldNames, modifier, options){
|
||||
//if we are restoring this asset, unmark that it was removed with its parent, we no longer care
|
||||
if (modifier && modifier.$unset && modifier.$unset.removed) {
|
||||
modifier.$unset.removedWith = "";
|
||||
}
|
||||
});
|
||||
|
||||
collection.after.update(function(userId, doc, fieldNames, modifier, options) {
|
||||
if (modifier && modifier.$set && modifier.$set["parent.id"]){
|
||||
//when we change parents, inherit its properties
|
||||
inheritParentProperties(doc, collection);
|
||||
}
|
||||
});
|
||||
|
||||
collection.softRemoveNode = collection.softRemoveNode || function(id){
|
||||
collection.softRemove(id);
|
||||
};
|
||||
|
||||
collection.restoreNode = collection.restoreNode || function(id){
|
||||
collection.restore(id);
|
||||
};
|
||||
|
||||
collection.attachSchema(childSchema);
|
||||
|
||||
childCollections.push(collection);
|
||||
};
|
||||
|
||||
makeParent = function(collection, donatedKeys){
|
||||
donatedKeys = joinWithDefaultKeys(donatedKeys);
|
||||
var collectionName = collection._collection.name;
|
||||
//after changing, push the changes to all children
|
||||
collection.after.update(function(userId, doc, fieldNames, modifier, options) {
|
||||
modifier = limitModifierToKeys(modifier, donatedKeys);
|
||||
doc = _.pick(doc, ["_id", "charId"]);
|
||||
if (!modifier) return;
|
||||
Meteor.call("updateChildren", doc, modifier, true);
|
||||
});
|
||||
collection.softRemoveNode = function(id){
|
||||
Meteor.call("softRemoveNode", collectionName, id);
|
||||
};
|
||||
|
||||
collection.restoreNode = function(id){
|
||||
Meteor.call("restoreNode", collectionName, id);
|
||||
};
|
||||
|
||||
if (Meteor.isServer) collection.after.remove(function(userId, doc) {
|
||||
_.each(childCollections, function(collection){
|
||||
collection.remove(
|
||||
{"parent.id": doc._id}
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var checkPermission = function(userId, charId){
|
||||
var char = Characters.findOne(charId, {fields: {owner: 1, writers: 1}});
|
||||
if (!char)
|
||||
throw new Meteor.Error("Access Denied, no charId",
|
||||
"Character " + charId + " does not exist");
|
||||
if (!userId)
|
||||
throw new Meteor.Error("Access Denied, no userId",
|
||||
"No UserId set when trying to update character asset.");
|
||||
if (char.owner !== userId && !_.contains(char.writers, userId))
|
||||
throw new Meteor.Error("Access Denied, not permitted",
|
||||
"Not permitted to update assets of this character.");
|
||||
return true;
|
||||
};
|
||||
|
||||
var cascadeSoftRemove = function(id, removedWithId){
|
||||
_.each(childCollections, function(treeCollection){
|
||||
treeCollection.update(
|
||||
{"parent.id": id},
|
||||
{$set: {
|
||||
removed: true,
|
||||
removedWith: removedWithId,
|
||||
}},
|
||||
{multi: true}
|
||||
);
|
||||
treeCollection.find({"parent.id": id}).forEach(function(doc){
|
||||
cascadeSoftRemove(doc._id, removedWithId);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var checkRemovePermission = function(collectionName, id, self){
|
||||
check(collectionName, String);
|
||||
check(id, String);
|
||||
var collection = Mongo.Collection.get(collectionName);
|
||||
var node = collection.findOne(id);
|
||||
var charId = node && node.charId;
|
||||
checkPermission(self.userId, charId);
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
softRemoveNode: function(collectionName, id){
|
||||
checkRemovePermission(collectionName, id, this);
|
||||
var collection = Mongo.Collection.get(collectionName);
|
||||
collection.softRemove(id);
|
||||
cascadeSoftRemove(id, id);
|
||||
},
|
||||
restoreNode: function(collectionName, id){
|
||||
checkRemovePermission(collectionName, id, this);
|
||||
var collection = Mongo.Collection.get(collectionName);
|
||||
collection.restore(id);
|
||||
_.each(childCollections, function(treeCollection){
|
||||
treeCollection.update(
|
||||
{removedWith: id, removed: true},
|
||||
{$unset: {removed: true, removedWith: ""}},
|
||||
{multi: true}
|
||||
);
|
||||
});
|
||||
},
|
||||
updateChildren: function(parent, modifier, limitToInheritance) {
|
||||
check(parent, {_id: String, charId: String});
|
||||
check(modifier, Object);
|
||||
checkPermission(this.userId, parent.charId);
|
||||
var selector = {"parent.id": parent._id};
|
||||
_.each(childCollections, function(collection){
|
||||
var thisModifier;
|
||||
if (limitToInheritance){
|
||||
thisModifier = limitModifierToKeys(modifier, collection.inheritedKeys);
|
||||
} else {
|
||||
thisModifier = _.clone(modifier);
|
||||
}
|
||||
if (_.isEmpty(thisModifier)) return;
|
||||
collection.update(selector, thisModifier, {multi: true, removed: true});
|
||||
});
|
||||
},
|
||||
cloneChildren: function(objectId, newParent){
|
||||
check(objectId, String);
|
||||
check(newParent, {id: String, collection: String});
|
||||
|
||||
_.each(childCollections, function(collection){
|
||||
var keys = collection.simpleSchema().objectKeys();
|
||||
collection.find({"parent.id": objectId}).forEach(function(doc){
|
||||
var newDoc = _.pick(doc, keys);
|
||||
newDoc.parent = newParent;
|
||||
collection.insert(newDoc);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user