mirror of
https://github.com/YunoHost-Apps/rocketchat_ynh.git
synced 2024-09-03 20:16:25 +02:00
816 lines
88 KiB
JavaScript
816 lines
88 KiB
JavaScript
(function () {
|
|
|
|
/* Imports */
|
|
var Meteor = Package.meteor.Meteor;
|
|
var MongoInternals = Package.mongo.MongoInternals;
|
|
var Mongo = Package.mongo.Mongo;
|
|
var Tracker = Package.tracker.Tracker;
|
|
var Deps = Package.tracker.Deps;
|
|
var _ = Package.underscore._;
|
|
var EJSON = Package.ejson.EJSON;
|
|
var LocalCollection = Package.minimongo.LocalCollection;
|
|
var Minimongo = Package.minimongo.Minimongo;
|
|
|
|
/* Package-scope variables */
|
|
var CollectionHooks;
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/collection-hooks.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Relevant AOP terminology: // 1
|
|
// Aspect: User code that runs before/after (hook) // 2
|
|
// Advice: Wrapper code that knows when to call user code (aspects) // 3
|
|
// Pointcut: before/after // 4
|
|
// 5
|
|
var advices = {}; // 6
|
|
var Tracker = Package.tracker && Package.tracker.Tracker || Package.deps.Deps; // 7
|
|
var publishUserId = Meteor.isServer && new Meteor.EnvironmentVariable(); // 8
|
|
// 9
|
|
CollectionHooks = { // 10
|
|
defaults: { // 11
|
|
before: { insert: {}, update: {}, remove: {}, upsert: {}, find: {}, findOne: {}, all: {}}, // 12
|
|
after: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {}}, // 13
|
|
all: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {}} // 14
|
|
}, // 15
|
|
directEnv: new Meteor.EnvironmentVariable(), // 16
|
|
directOp: function directOp(func) { // 17
|
|
return this.directEnv.withValue(true, func); // 18
|
|
}, // 19
|
|
hookedOp: function hookedOp(func) { // 20
|
|
return this.directEnv.withValue(false, func); // 21
|
|
} // 22
|
|
}; // 23
|
|
// 24
|
|
CollectionHooks.getUserId = function getUserId() { // 25
|
|
var userId; // 26
|
|
// 27
|
|
if (Meteor.isClient) { // 28
|
|
Tracker.nonreactive(function () { // 29
|
|
userId = Meteor.userId && Meteor.userId(); // 30
|
|
}); // 31
|
|
} // 32
|
|
// 33
|
|
if (Meteor.isServer) { // 34
|
|
try { // 35
|
|
// Will throw an error unless within method call. // 36
|
|
// Attempt to recover gracefully by catching: // 37
|
|
userId = Meteor.userId && Meteor.userId(); // 38
|
|
} catch (e) {} // 39
|
|
// 40
|
|
if (!userId) { // 41
|
|
// Get the userId if we are in a publish function. // 42
|
|
userId = publishUserId.get(); // 43
|
|
} // 44
|
|
} // 45
|
|
// 46
|
|
return userId; // 47
|
|
}; // 48
|
|
// 49
|
|
CollectionHooks.extendCollectionInstance = function extendCollectionInstance(self, constructor) { // 50
|
|
// Offer a public API to allow the user to define aspects // 51
|
|
// Example: collection.before.insert(func); // 52
|
|
_.each(["before", "after"], function (pointcut) { // 53
|
|
_.each(advices, function (advice, method) { // 54
|
|
if (advice === "upsert" && pointcut === "after") return; // 55
|
|
// 56
|
|
Meteor._ensure(self, pointcut, method); // 57
|
|
Meteor._ensure(self, "_hookAspects", method); // 58
|
|
// 59
|
|
self._hookAspects[method][pointcut] = []; // 60
|
|
self[pointcut][method] = function (aspect, options) { // 61
|
|
var len = self._hookAspects[method][pointcut].push({ // 62
|
|
aspect: aspect, // 63
|
|
options: CollectionHooks.initOptions(options, pointcut, method) // 64
|
|
}); // 65
|
|
// 66
|
|
return { // 67
|
|
replace: function (aspect, options) { // 68
|
|
self._hookAspects[method][pointcut].splice(len - 1, 1, { // 69
|
|
aspect: aspect, // 70
|
|
options: CollectionHooks.initOptions(options, pointcut, method) // 71
|
|
}); // 72
|
|
}, // 73
|
|
remove: function () { // 74
|
|
self._hookAspects[method][pointcut].splice(len - 1, 1); // 75
|
|
} // 76
|
|
}; // 77
|
|
}; // 78
|
|
}); // 79
|
|
}); // 80
|
|
// 81
|
|
// Offer a publicly accessible object to allow the user to define // 82
|
|
// collection-wide hook options. // 83
|
|
// Example: collection.hookOptions.after.update = {fetchPrevious: false}; // 84
|
|
self.hookOptions = EJSON.clone(CollectionHooks.defaults); // 85
|
|
// 86
|
|
// Wrap mutator methods, letting the defined advice do the work // 87
|
|
_.each(advices, function (advice, method) { // 88
|
|
var collection = Meteor.isClient || method === "upsert" ? self : self._collection; // 89
|
|
// 90
|
|
// Store a reference to the original mutator method // 91
|
|
var _super = collection[method]; // 92
|
|
// 93
|
|
Meteor._ensure(self, "direct", method); // 94
|
|
self.direct[method] = function () { // 95
|
|
var args = arguments; // 96
|
|
return CollectionHooks.directOp(function () { // 97
|
|
return constructor.prototype[method].apply(self, args); // 98
|
|
}); // 99
|
|
}; // 100
|
|
// 101
|
|
collection[method] = function () { // 102
|
|
if (CollectionHooks.directEnv.get() === true) { // 103
|
|
return _super.apply(collection, arguments); // 104
|
|
} // 105
|
|
// 106
|
|
// NOTE: should we decide to force `update` with `{upsert:true}` to use // 107
|
|
// the `upsert` hooks, this is what will accomplish it. It's important to // 108
|
|
// realize that Meteor won't distinguish between an `update` and an // 109
|
|
// `insert` though, so we'll end up with `after.update` getting called // 110
|
|
// even on an `insert`. That's why we've chosen to disable this for now. // 111
|
|
// if (method === "update" && _.isObject(arguments[2]) && arguments[2].upsert) { // 112
|
|
// method = "upsert"; // 113
|
|
// advice = CollectionHooks.getAdvice(method); // 114
|
|
// } // 115
|
|
// 116
|
|
return advice.call(this, // 117
|
|
CollectionHooks.getUserId(), // 118
|
|
_super, // 119
|
|
self, // 120
|
|
method === "upsert" ? { // 121
|
|
insert: self._hookAspects.insert || {}, // 122
|
|
update: self._hookAspects.update || {}, // 123
|
|
upsert: self._hookAspects.upsert || {} // 124
|
|
} : self._hookAspects[method] || {}, // 125
|
|
function (doc) { // 126
|
|
return _.isFunction(self._transform) // 127
|
|
? function (d) { return self._transform(d || doc); } // 128
|
|
: function (d) { return d || doc; }; // 129
|
|
}, // 130
|
|
_.toArray(arguments), // 131
|
|
false // 132
|
|
); // 133
|
|
}; // 134
|
|
}); // 135
|
|
}; // 136
|
|
// 137
|
|
CollectionHooks.defineAdvice = function defineAdvice(method, advice) { // 138
|
|
advices[method] = advice; // 139
|
|
}; // 140
|
|
// 141
|
|
CollectionHooks.getAdvice = function getAdvice(method) { // 142
|
|
return advices[method]; // 143
|
|
}; // 144
|
|
// 145
|
|
CollectionHooks.initOptions = function initOptions(options, pointcut, method) { // 146
|
|
return CollectionHooks.extendOptions(CollectionHooks.defaults, options, pointcut, method); // 147
|
|
}; // 148
|
|
// 149
|
|
CollectionHooks.extendOptions = function extendOptions(source, options, pointcut, method) { // 150
|
|
options = _.extend(options || {}, source.all.all); // 151
|
|
options = _.extend(options, source[pointcut].all); // 152
|
|
options = _.extend(options, source.all[method]); // 153
|
|
options = _.extend(options, source[pointcut][method]); // 154
|
|
return options; // 155
|
|
}; // 156
|
|
// 157
|
|
CollectionHooks.getDocs = function getDocs(collection, selector, options) { // 158
|
|
var self = this; // 159
|
|
// 160
|
|
var findOptions = {transform: null, reactive: false}; // added reactive: false // 161
|
|
// 162
|
|
/* // 163
|
|
// No "fetch" support at this time. // 164
|
|
if (!self._validators.fetchAllFields) { // 165
|
|
findOptions.fields = {}; // 166
|
|
_.each(self._validators.fetch, function(fieldName) { // 167
|
|
findOptions.fields[fieldName] = 1; // 168
|
|
}); // 169
|
|
} // 170
|
|
*/ // 171
|
|
// 172
|
|
// Bit of a magic condition here... only "update" passes options, so this is // 173
|
|
// only relevant to when update calls getDocs: // 174
|
|
if (options) { // 175
|
|
// This was added because in our case, we are potentially iterating over // 176
|
|
// multiple docs. If multi isn't enabled, force a limit (almost like // 177
|
|
// findOne), as the default for update without multi enabled is to affect // 178
|
|
// only the first matched document: // 179
|
|
if (!options.multi) { // 180
|
|
findOptions.limit = 1; // 181
|
|
} // 182
|
|
} // 183
|
|
// 184
|
|
// Unlike validators, we iterate over multiple docs, so use // 185
|
|
// find instead of findOne: // 186
|
|
return collection.find(selector, findOptions); // 187
|
|
}; // 188
|
|
// 189
|
|
// This function contains a snippet of code pulled and modified from: // 190
|
|
// ~/.meteor/packages/mongo-livedata/collection.js // 191
|
|
// It's contained in these utility functions to make updates easier for us in // 192
|
|
// case this code changes. // 193
|
|
CollectionHooks.getFields = function getFields(mutator) { // 194
|
|
// compute modified fields // 195
|
|
var fields = []; // 196
|
|
// 197
|
|
_.each(mutator, function (params, op) { // 198
|
|
//====ADDED START======================= // 199
|
|
if (_.contains(["$set", "$unset", "$inc", "$push", "$pull", "$pop", "$rename", "$pullAll", "$addToSet", "$bit"], op)) {
|
|
//====ADDED END========================= // 201
|
|
_.each(_.keys(params), function (field) { // 202
|
|
// treat dotted fields as if they are replacing their // 203
|
|
// top-level part // 204
|
|
if (field.indexOf('.') !== -1) // 205
|
|
field = field.substring(0, field.indexOf('.')); // 206
|
|
// 207
|
|
// record the field we are trying to change // 208
|
|
if (!_.contains(fields, field)) // 209
|
|
fields.push(field); // 210
|
|
}); // 211
|
|
//====ADDED START======================= // 212
|
|
} else { // 213
|
|
fields.push(op); // 214
|
|
} // 215
|
|
//====ADDED END========================= // 216
|
|
}); // 217
|
|
// 218
|
|
return fields; // 219
|
|
}; // 220
|
|
// 221
|
|
CollectionHooks.reassignPrototype = function reassignPrototype(instance, constr) { // 222
|
|
var hasSetPrototypeOf = typeof Object.setPrototypeOf === "function"; // 223
|
|
// 224
|
|
if (!constr) constr = typeof Mongo !== "undefined" ? Mongo.Collection : Meteor.Collection; // 225
|
|
// 226
|
|
// __proto__ is not available in < IE11 // 227
|
|
// Note: Assigning a prototype dynamically has performance implications // 228
|
|
if (hasSetPrototypeOf) { // 229
|
|
Object.setPrototypeOf(instance, constr.prototype); // 230
|
|
} else if (instance.__proto__) { // 231
|
|
instance.__proto__ = constr.prototype; // 232
|
|
} // 233
|
|
}; // 234
|
|
// 235
|
|
CollectionHooks.wrapCollection = function wrapCollection(ns, as) { // 236
|
|
if (!as._CollectionConstructor) as._CollectionConstructor = as.Collection; // 237
|
|
if (!as._CollectionPrototype) as._CollectionPrototype = new as.Collection(null); // 238
|
|
// 239
|
|
var constructor = as._CollectionConstructor; // 240
|
|
var proto = as._CollectionPrototype; // 241
|
|
// 242
|
|
ns.Collection = function () { // 243
|
|
var ret = constructor.apply(this, arguments); // 244
|
|
CollectionHooks.extendCollectionInstance(this, constructor); // 245
|
|
return ret; // 246
|
|
}; // 247
|
|
// 248
|
|
ns.Collection.prototype = proto; // 249
|
|
ns.Collection.prototype.constructor = ns.Collection; // 250
|
|
// 251
|
|
for (var prop in constructor) { // 252
|
|
if (constructor.hasOwnProperty(prop)) { // 253
|
|
ns.Collection[prop] = constructor[prop]; // 254
|
|
} // 255
|
|
} // 256
|
|
}; // 257
|
|
// 258
|
|
CollectionHooks.modify = LocalCollection._modify; // 259
|
|
// 260
|
|
if (typeof Mongo !== "undefined") { // 261
|
|
CollectionHooks.wrapCollection(Meteor, Mongo); // 262
|
|
CollectionHooks.wrapCollection(Mongo, Mongo); // 263
|
|
} else { // 264
|
|
CollectionHooks.wrapCollection(Meteor, Meteor); // 265
|
|
} // 266
|
|
// 267
|
|
if (Meteor.isServer) { // 268
|
|
var _publish = Meteor.publish; // 269
|
|
Meteor.publish = function (name, func) { // 270
|
|
return _publish.call(this, name, function () { // 271
|
|
// This function is called repeatedly in publications // 272
|
|
var ctx = this, args = arguments; // 273
|
|
return publishUserId.withValue(ctx && ctx.userId, function () { // 274
|
|
return func.apply(ctx, args); // 275
|
|
}); // 276
|
|
}); // 277
|
|
}; // 278
|
|
// 279
|
|
// Make the above available for packages with hooks that want to determine // 280
|
|
// whether they are running inside a publish function or not. // 281
|
|
CollectionHooks.isWithinPublish = function isWithinPublish() { // 282
|
|
return publishUserId.get() !== undefined; // 283
|
|
}; // 284
|
|
} // 285
|
|
// 286
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/insert.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CollectionHooks.defineAdvice("insert", function (userId, _super, instance, aspects, getTransform, args, suppressAspects) {
|
|
var self = this; // 2
|
|
var ctx = {context: self, _super: _super, args: args}; // 3
|
|
var callback = _.last(args); // 4
|
|
var async = _.isFunction(callback); // 5
|
|
var abort, ret; // 6
|
|
// 7
|
|
// args[0] : doc // 8
|
|
// args[1] : callback // 9
|
|
// 10
|
|
// before // 11
|
|
if (!suppressAspects) { // 12
|
|
try { // 13
|
|
_.each(aspects.before, function (o) { // 14
|
|
var r = o.aspect.call(_.extend({transform: getTransform(args[0])}, ctx), userId, args[0]); // 15
|
|
if (r === false) abort = true; // 16
|
|
}); // 17
|
|
// 18
|
|
if (abort) return false; // 19
|
|
} catch (e) { // 20
|
|
if (async) return callback.call(self, e); // 21
|
|
throw e; // 22
|
|
} // 23
|
|
} // 24
|
|
// 25
|
|
function after(id, err) { // 26
|
|
var doc = args[0]; // 27
|
|
if (id) { // 28
|
|
doc = EJSON.clone(args[0]); // 29
|
|
doc._id = id; // 30
|
|
} // 31
|
|
if (!suppressAspects) { // 32
|
|
var lctx = _.extend({transform: getTransform(doc), _id: id, err: err}, ctx); // 33
|
|
_.each(aspects.after, function (o) { // 34
|
|
o.aspect.call(lctx, userId, doc); // 35
|
|
}); // 36
|
|
} // 37
|
|
return id; // 38
|
|
} // 39
|
|
// 40
|
|
if (async) { // 41
|
|
args[args.length - 1] = function (err, obj) { // 42
|
|
after(obj && obj[0] && obj[0]._id || obj, err); // 43
|
|
return callback.apply(this, arguments); // 44
|
|
}; // 45
|
|
return _super.apply(self, args); // 46
|
|
} else { // 47
|
|
ret = _super.apply(self, args); // 48
|
|
return after(ret && ret[0] && ret[0]._id || ret); // 49
|
|
} // 50
|
|
}); // 51
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/update.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CollectionHooks.defineAdvice("update", function (userId, _super, instance, aspects, getTransform, args, suppressAspects) {
|
|
var self = this; // 2
|
|
var ctx = {context: self, _super: _super, args: args}; // 3
|
|
var callback = _.last(args); // 4
|
|
var async = _.isFunction(callback); // 5
|
|
var docs, docIds, fields, abort, prev = {}; // 6
|
|
var collection = _.has(self, "_collection") ? self._collection : self; // 7
|
|
// 8
|
|
// args[0] : selector // 9
|
|
// args[1] : mutator // 10
|
|
// args[2] : options (optional) // 11
|
|
// args[3] : callback // 12
|
|
// 13
|
|
if (_.isFunction(args[2])) { // 14
|
|
callback = args[2]; // 15
|
|
args[2] = {}; // 16
|
|
} // 17
|
|
// 18
|
|
if (!suppressAspects) { // 19
|
|
try { // 20
|
|
if (aspects.before || aspects.after) { // 21
|
|
fields = CollectionHooks.getFields(args[1]); // 22
|
|
docs = CollectionHooks.getDocs.call(self, collection, args[0], args[2]).fetch(); // 23
|
|
docIds = _.map(docs, function (doc) { return doc._id; }); // 24
|
|
} // 25
|
|
// 26
|
|
// copy originals for convenience for the "after" pointcut // 27
|
|
if (aspects.after) { // 28
|
|
prev.mutator = EJSON.clone(args[1]); // 29
|
|
prev.options = EJSON.clone(args[2]); // 30
|
|
if (_.some(aspects.after, function (o) { return o.options.fetchPrevious !== false; }) && // 31
|
|
CollectionHooks.extendOptions(instance.hookOptions, {}, "after", "update").fetchPrevious !== false) { // 32
|
|
prev.docs = {}; // 33
|
|
_.each(docs, function (doc) { // 34
|
|
prev.docs[doc._id] = EJSON.clone(doc); // 35
|
|
}); // 36
|
|
} // 37
|
|
} // 38
|
|
// 39
|
|
// before // 40
|
|
_.each(aspects.before, function (o) { // 41
|
|
_.each(docs, function (doc) { // 42
|
|
var r = o.aspect.call(_.extend({transform: getTransform(doc)}, ctx), userId, doc, fields, args[1], args[2]);
|
|
if (r === false) abort = true; // 44
|
|
}); // 45
|
|
}); // 46
|
|
// 47
|
|
if (abort) return false; // 48
|
|
} catch (e) { // 49
|
|
if (async) return callback.call(self, e); // 50
|
|
throw e; // 51
|
|
} // 52
|
|
} // 53
|
|
// 54
|
|
function after(affected, err) { // 55
|
|
if (!suppressAspects) { // 56
|
|
var fields = CollectionHooks.getFields(args[1]); // 57
|
|
var docs = CollectionHooks.getDocs.call(self, collection, {_id: {$in: docIds}}, args[2]).fetch(); // 58
|
|
// 59
|
|
_.each(aspects.after, function (o) { // 60
|
|
_.each(docs, function (doc) { // 61
|
|
o.aspect.call(_.extend({ // 62
|
|
transform: getTransform(doc), // 63
|
|
previous: prev.docs && prev.docs[doc._id], // 64
|
|
affected: affected, // 65
|
|
err: err // 66
|
|
}, ctx), userId, doc, fields, prev.mutator, prev.options); // 67
|
|
}); // 68
|
|
}); // 69
|
|
} // 70
|
|
} // 71
|
|
// 72
|
|
if (async) { // 73
|
|
args[args.length - 1] = function (err, affected) { // 74
|
|
after(affected, err); // 75
|
|
return callback.apply(this, arguments); // 76
|
|
}; // 77
|
|
return _super.apply(this, args); // 78
|
|
} else { // 79
|
|
var affected = _super.apply(self, args); // 80
|
|
after(affected); // 81
|
|
return affected; // 82
|
|
} // 83
|
|
}); // 84
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/remove.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CollectionHooks.defineAdvice("remove", function (userId, _super, instance, aspects, getTransform, args, suppressAspects) {
|
|
var self = this; // 2
|
|
var ctx = {context: self, _super: _super, args: args}; // 3
|
|
var callback = _.last(args); // 4
|
|
var async = _.isFunction(callback); // 5
|
|
var docs, abort, prev = []; // 6
|
|
var collection = _.has(self, "_collection") ? self._collection : self; // 7
|
|
// 8
|
|
// args[0] : selector // 9
|
|
// args[1] : callback // 10
|
|
// 11
|
|
if (!suppressAspects) { // 12
|
|
try { // 13
|
|
if (aspects.before || aspects.after) { // 14
|
|
docs = CollectionHooks.getDocs.call(self, collection, args[0]).fetch(); // 15
|
|
} // 16
|
|
// 17
|
|
// copy originals for convenience for the "after" pointcut // 18
|
|
if (aspects.after) { // 19
|
|
_.each(docs, function (doc) { // 20
|
|
prev.push(EJSON.clone(doc)); // 21
|
|
}); // 22
|
|
} // 23
|
|
// 24
|
|
// before // 25
|
|
_.each(aspects.before, function (o) { // 26
|
|
_.each(docs, function (doc) { // 27
|
|
var r = o.aspect.call(_.extend({transform: getTransform(doc)}, ctx), userId, doc); // 28
|
|
if (r === false) abort = true; // 29
|
|
}); // 30
|
|
}); // 31
|
|
// 32
|
|
if (abort) return false; // 33
|
|
} catch (e) { // 34
|
|
if (async) return callback.call(self, e); // 35
|
|
throw e; // 36
|
|
} // 37
|
|
} // 38
|
|
// 39
|
|
function after(err) { // 40
|
|
if (!suppressAspects) { // 41
|
|
_.each(aspects.after, function (o) { // 42
|
|
_.each(prev, function (doc) { // 43
|
|
o.aspect.call(_.extend({transform: getTransform(doc), err: err}, ctx), userId, doc); // 44
|
|
}); // 45
|
|
}); // 46
|
|
} // 47
|
|
} // 48
|
|
// 49
|
|
if (async) { // 50
|
|
args[args.length - 1] = function (err) { // 51
|
|
after(err); // 52
|
|
return callback.apply(this, arguments); // 53
|
|
}; // 54
|
|
return _super.apply(self, args); // 55
|
|
} else { // 56
|
|
var result = _super.apply(self, args); // 57
|
|
after(); // 58
|
|
return result; // 59
|
|
} // 60
|
|
}); // 61
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/upsert.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CollectionHooks.defineAdvice("upsert", function (userId, _super, instance, aspectGroup, getTransform, args, suppressAspects) {
|
|
var self = this; // 2
|
|
var ctx = {context: self, _super: _super, args: args}; // 3
|
|
var callback = _.last(args); // 4
|
|
var async = _.isFunction(callback); // 5
|
|
var docs, docIds, fields, abort, prev = {}; // 6
|
|
var collection = _.has(self, "_collection") ? self._collection : self; // 7
|
|
// 8
|
|
// args[0] : selector // 9
|
|
// args[1] : mutator // 10
|
|
// args[2] : options (optional) // 11
|
|
// args[3] : callback // 12
|
|
// 13
|
|
if (_.isFunction(args[2])) { // 14
|
|
callback = args[2]; // 15
|
|
args[2] = {}; // 16
|
|
} // 17
|
|
// 18
|
|
if (!suppressAspects) { // 19
|
|
if (aspectGroup.upsert.before) { // 20
|
|
fields = CollectionHooks.getFields(args[1]); // 21
|
|
docs = CollectionHooks.getDocs.call(self, collection, args[0], args[2]).fetch(); // 22
|
|
docIds = _.map(docs, function (doc) { return doc._id; }); // 23
|
|
} // 24
|
|
// 25
|
|
// copy originals for convenience for the "after" pointcut // 26
|
|
if (aspectGroup.update.after) { // 27
|
|
if (_.some(aspectGroup.update.after, function (o) { return o.options.fetchPrevious !== false; }) && // 28
|
|
CollectionHooks.extendOptions(instance.hookOptions, {}, "after", "update").fetchPrevious !== false) { // 29
|
|
prev.mutator = EJSON.clone(args[1]); // 30
|
|
prev.options = EJSON.clone(args[2]); // 31
|
|
prev.docs = {}; // 32
|
|
_.each(docs, function (doc) { // 33
|
|
prev.docs[doc._id] = EJSON.clone(doc); // 34
|
|
}); // 35
|
|
} // 36
|
|
} // 37
|
|
// 38
|
|
// before // 39
|
|
if (!suppressAspects) { // 40
|
|
_.each(aspectGroup.upsert.before, function (o) { // 41
|
|
var r = o.aspect.call(ctx, userId, args[0], args[1], args[2]); // 42
|
|
if (r === false) abort = true; // 43
|
|
}); // 44
|
|
// 45
|
|
if (abort) return false; // 46
|
|
} // 47
|
|
} // 48
|
|
// 49
|
|
function afterUpdate(affected, err) { // 50
|
|
if (!suppressAspects) { // 51
|
|
var fields = CollectionHooks.getFields(args[1]); // 52
|
|
var docs = CollectionHooks.getDocs.call(self, collection, {_id: {$in: docIds}}, args[2]).fetch(); // 53
|
|
// 54
|
|
_.each(aspectGroup.update.after, function (o) { // 55
|
|
_.each(docs, function (doc) { // 56
|
|
o.aspect.call(_.extend({ // 57
|
|
transform: getTransform(doc), // 58
|
|
previous: prev.docs && prev.docs[doc._id], // 59
|
|
affected: affected, // 60
|
|
err: err // 61
|
|
}, ctx), userId, doc, fields, prev.mutator, prev.options); // 62
|
|
}); // 63
|
|
}); // 64
|
|
} // 65
|
|
} // 66
|
|
// 67
|
|
function afterInsert(id, err) { // 68
|
|
if (!suppressAspects) { // 69
|
|
var doc = CollectionHooks.getDocs.call(self, collection, {_id: id}, args[0], {}).fetch()[0]; // 3rd argument passes empty object which causes magic logic to imply limit:1
|
|
var lctx = _.extend({transform: getTransform(doc), _id: id, err: err}, ctx); // 71
|
|
_.each(aspectGroup.insert.after, function (o) { // 72
|
|
o.aspect.call(lctx, userId, doc); // 73
|
|
}); // 74
|
|
} // 75
|
|
} // 76
|
|
// 77
|
|
if (async) { // 78
|
|
args[args.length - 1] = function (err, ret) { // 79
|
|
if (ret.insertedId) { // 80
|
|
afterInsert(ret.insertedId, err); // 81
|
|
} else { // 82
|
|
afterUpdate(ret.numberAffected, err); // 83
|
|
} // 84
|
|
// 85
|
|
return CollectionHooks.hookedOp(function () { // 86
|
|
return callback.call(this, err, ret); // 87
|
|
}); // 88
|
|
}; // 89
|
|
// 90
|
|
return CollectionHooks.directOp(function () { // 91
|
|
return _super.apply(self, args); // 92
|
|
}); // 93
|
|
} else { // 94
|
|
var ret = CollectionHooks.directOp(function () { // 95
|
|
return _super.apply(self, args); // 96
|
|
}); // 97
|
|
// 98
|
|
if (ret.insertedId) { // 99
|
|
afterInsert(ret.insertedId); // 100
|
|
} else { // 101
|
|
afterUpdate(ret.numberAffected); // 102
|
|
} // 103
|
|
// 104
|
|
return ret; // 105
|
|
} // 106
|
|
}); // 107
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/find.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CollectionHooks.defineAdvice("find", function (userId, _super, instance, aspects, getTransform, args, suppressAspects) {
|
|
var self = this; // 2
|
|
var ctx = {context: self, _super: _super, args: args}; // 3
|
|
var ret, abort; // 4
|
|
// 5
|
|
// args[0] : selector // 6
|
|
// args[1] : options // 7
|
|
// 8
|
|
// before // 9
|
|
if (!suppressAspects) { // 10
|
|
_.each(aspects.before, function (o) { // 11
|
|
var r = o.aspect.call(ctx, userId, args[0], args[1]); // 12
|
|
if (r === false) abort = true; // 13
|
|
}); // 14
|
|
// 15
|
|
if (abort) return false; // 16
|
|
} // 17
|
|
// 18
|
|
function after(cursor) { // 19
|
|
if (!suppressAspects) { // 20
|
|
_.each(aspects.after, function (o) { // 21
|
|
o.aspect.call(ctx, userId, args[0], args[1], cursor); // 22
|
|
}); // 23
|
|
} // 24
|
|
} // 25
|
|
// 26
|
|
ret = _super.apply(self, args); // 27
|
|
after(ret); // 28
|
|
// 29
|
|
return ret; // 30
|
|
}); // 31
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/findone.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CollectionHooks.defineAdvice("findOne", function (userId, _super, instance, aspects, getTransform, args, suppressAspects) {
|
|
var self = this; // 2
|
|
var ctx = {context: self, _super: _super, args: args}; // 3
|
|
var ret, abort; // 4
|
|
// 5
|
|
// args[0] : selector // 6
|
|
// args[1] : options // 7
|
|
// 8
|
|
// before // 9
|
|
if (!suppressAspects) { // 10
|
|
_.each(aspects.before, function (o) { // 11
|
|
var r = o.aspect.call(ctx, userId, args[0], args[1]); // 12
|
|
if (r === false) abort = true; // 13
|
|
}); // 14
|
|
// 15
|
|
if (abort) return false; // 16
|
|
} // 17
|
|
// 18
|
|
function after(doc) { // 19
|
|
if (!suppressAspects) { // 20
|
|
_.each(aspects.after, function (o) { // 21
|
|
o.aspect.call(ctx, userId, args[0], args[1], doc); // 22
|
|
}); // 23
|
|
} // 24
|
|
} // 25
|
|
// 26
|
|
ret = _super.apply(self, args); // 27
|
|
after(ret); // 28
|
|
// 29
|
|
return ret; // 30
|
|
}); // 31
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/matb33_collection-hooks/users-compat.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
if (Meteor.users) { // 1
|
|
// If Meteor.users has been instantiated, attempt to re-assign its prototype: // 2
|
|
CollectionHooks.reassignPrototype(Meteor.users); // 3
|
|
// 4
|
|
// Next, give it the hook aspects: // 5
|
|
var Collection = typeof Mongo !== "undefined" && typeof Mongo.Collection !== "undefined" ? Mongo.Collection : Meteor.Collection;
|
|
CollectionHooks.extendCollectionInstance(Meteor.users, Collection); // 7
|
|
} // 8
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
/* Exports */
|
|
if (typeof Package === 'undefined') Package = {};
|
|
Package['matb33:collection-hooks'] = {
|
|
CollectionHooks: CollectionHooks
|
|
};
|
|
|
|
})();
|
|
|
|
//# sourceMappingURL=matb33_collection-hooks.js.map
|