UNPKG

16.1 kBJavaScriptView Raw
1/*!
2 * Mongoose Admin
3 * Copyright (c) 2011 Marc Campbell (marc.e.campbell@gmail.com)
4 * MIT Licensed
5 */
6
7
8 /**
9 * Module dependencies
10 */
11var MongooseAdminUser = require('./mongoose_admin_user.js').MongooseAdminUser,
12 MongooseAdminAudit = require('./mongoose_admin_audit.js').MongooseAdminAudit,
13 _ = require('underscore'),
14 async = require('async'),
15 permissions = require('./permissions'),
16 paths = require('./http/register_paths'),
17 forms = require('j-forms').forms;
18
19
20exports = module.exports = MongooseAdmin;
21exports.version = '0.0.1';
22
23var app;
24
25/**
26 * Create the admin singleton object
27 *
28 * @param {String} dbUri
29 * @param {Number} port
30 *
31 * @api public
32 */
33exports.createAdmin = function(app,options) {
34// if (options.port) {
35// var app = app || (app = require('http'));
36//
37// app.listen(options.port);
38// require('http/paths').registerPaths(app, '/');
39//
40// console.log('\x1b[36mMongooseAdmin is listening on port: \x1b[0m %d', options.port);
41// console.log('\x1b[36mMongooseAdmin is connected using db: \x1b[0m %s', dbUri);
42//
43// MongooseAdmin.singleton = new MongooseAdmin(app, '');
44// return MongooseAdmin.singleton;
45// } else if (options.app && options.root) {
46 options = options || {};
47 var root = options.root || '';
48 console.log('\x1b[36mMongooseAdmin is listening at path: \x1b[0m %s', root);
49// console.log('\x1b[36mMongooseAdmin is connected using db: \x1b[0m %s', dbUri);
50
51
52 paths.registerPaths(MongooseAdmin, app, '/' + root);
53
54 app.use(require('express').static(__dirname + '/public'));
55
56 MongooseAdmin.singleton = new MongooseAdmin(app, '/' + root);
57
58 return MongooseAdmin.singleton;
59// }
60};
61
62/**
63 * MongooseAdmin Constructor
64 *
65 * @api private
66 */
67function MongooseAdmin(app, root) {
68 //mongoose.connect(dbUri);
69 this.app = app;
70 this.root = root;
71 this.models = {};
72 this.title = "Backoffice";
73};
74
75/**
76 * Build a full path that can be used in a URL
77 *
78 * @param {String} path
79 */
80MongooseAdmin.prototype.buildPath = function(path) {
81 return this.root + path;
82};
83
84MongooseAdmin.prototype.getAdminTitle = function(){
85 return this.title;
86};
87
88MongooseAdmin.prototype.setAdminTitle = function(title)
89{
90 this.title = title;
91};
92
93/**
94 * Push the mongoose-admin express config to the current config
95 *
96 */
97MongooseAdmin.prototype.pushExpressConfig = function() {
98 var currentViewsPath = MongooseAdmin.singleton.app.set('views');
99 this.app.set('views', __dirname + '/views');
100 return {'views': currentViewsPath};
101};
102
103/**
104 * Replace the mongoose-admin express config with the original
105 */
106MongooseAdmin.prototype.popExpressConfig = function(config) {
107 this.app.set('views', config.views);
108};
109
110/**
111 * Stop listening and end the admin process
112 *
113 * @api public
114 */
115MongooseAdmin.prototype.close = function() {
116 this.app.close();
117};
118
119
120MongooseAdmin.prototype.registerMongooseModel = function(modelName, model,fields, options) {
121 options = options || {};
122 options.actions = options.actions || [];
123 options.actions.push({value:'delete', label:'Delete',func:function(user,ids,callback)
124 {
125 async.parallel(_.map(ids,function(id)
126 {
127 return function(cbk)
128 {
129 forms.checkDependecies(modelName,id,cbk);
130 }
131 }),function(err,results)
132 {
133 if(err)
134 callback(err);
135 else
136 {
137 var no_dependecies = _.filter(ids,function(result,index)
138 {
139 return results[index].length == 0;
140 });
141 model.remove({_id:{$in:no_dependecies}},callback);
142 }
143 });
144 }});
145 this.models[modelName] = {model: model,
146 modelName:modelName,
147 options: options,
148 fields: fields};
149
150 console.log('\x1b[36mMongooseAdmin registered model: \x1b[0m %s', modelName);
151
152 permissions.registerModel(modelName);
153};
154
155MongooseAdmin.prototype.registerSingleRowModel = function(model,name,options)
156{
157 model.is_single = true;
158 this.models[name] = {model:model,options:options||{},fields:{},is_single:true,modelName:name}
159 permissions.registerModel(name);
160};
161
162
163/**
164* Register a new mongoose model/schema with admin
165*
166* @param {String} modelName
167* @param {Object} fields
168* @param {Object} options
169*
170* @api public
171*/
172MongooseAdmin.prototype.registerModel = function(model, name, options) {
173 this.models[name] = {model: model,
174 modelName:name,
175 options: options
176 };
177 console.log('\x1b[36mMongooseAdmin registered model: \x1b[0m %s', name);
178
179};
180
181/**
182 * Retrieve a list of all registered models
183 *
184 * @param {Function} onReady
185 *
186 * @api public
187 */
188MongooseAdmin.prototype.getRegisteredModels = function(user,onReady) {
189 var models = [];
190 for (var collectionName in this.models) {
191 this.models[collectionName].model.is_single = this.models[collectionName].is_single;
192 models.push(this.models[collectionName]);
193 };
194 models = _.filter(models,function(model)
195 {
196 return permissions.hasPermissions(user,model.modelName,'view');
197 });
198 onReady(null, models);
199};
200
201/**
202 * Get a single model from the registered list with admin
203 *
204 * @param {String} collectionName
205 * @param {Function} onReady
206 *
207 * @api public
208 */
209MongooseAdmin.prototype.getModel = function(collectionName, onReady) {
210 onReady(null, this.models[collectionName].model, this.models[collectionName].fields, this.models[collectionName].options);
211};
212
213/**
214 * Get the counts of a model
215 *
216 * @param {String} collectionName
217 *
218 * @api public
219 */
220MongooseAdmin.prototype.modelCounts = function(collectionName, onReady) {
221 if(this.models[collectionName].is_single)
222 {
223 onReady(null,1);
224 return;
225 }
226 this.models[collectionName].model.count({}, function(err, count) {
227 if (err) {
228 console.log('Unable to get counts for model because: ' + err);
229 } else {
230 onReady(null, count);
231 }
232 });
233};
234
235/**
236 * List a page of documents from a model
237 *
238 * @param {String} collectionName
239 * @param {Number} start
240 * @param {Number} count
241 * @param {Function} onReady
242 *
243 * @api public
244 */
245MongooseAdmin.prototype.listModelDocuments = function(collectionName, start, count, onReady) {
246 var listFields = this.models[collectionName].options.list;
247 if(listFields)
248 {
249
250 var query = this.models[collectionName].model.find({});
251 var sorts = this.models[collectionName].options.order_by;
252 var populates = this.models[collectionName].options.list_populate;
253 if(sorts)
254 {
255 for(var i=0; i<sorts.length; i++)
256 {
257 if(sorts[i].indexOf('-') == 0)
258 query.sort(sorts[i].substring(1),'descending');
259 else
260 query.sort(sorts[i],'ascending');
261 }
262 }
263 if(populates)
264 {
265 _.each(populates,function(populate)
266 {
267 query.populate(populate);
268 });
269 }
270 query.skip(start).limit(count).execFind(function(err, documents) {
271 if (err) {
272 console.log('Unable to get documents for model because: ' + err);
273 onReady('Unable to get documents for model', null);
274 } else {
275 var filteredDocuments = [];
276 documents.forEach(function(document) {
277 var d = {};
278 d['_id'] = document['_id'];
279 listFields.forEach(function(listField) {
280 d[listField] = document.get(listField);
281 });
282 filteredDocuments.push(d);
283 });
284
285 onReady(null, filteredDocuments);
286 }
287 });
288 }
289 else
290 {
291 onReady(null,[]);
292 }
293};
294
295/**
296 * Retrieve a single document
297 *
298 * @param {String} collectionName
299 * @param {String} documentId
300 * @param {Function} onReady
301 *
302 * @api public
303 */
304MongooseAdmin.prototype.getDocument = function(collectionName, documentId, onReady) {
305 this.models[collectionName].model.findById(documentId, function(err, document) {
306 if (err) {
307 console.log('Unable to get document because: ' + err);
308 onReady('Unable to get document', null);
309 } else {
310 onReady(null, document);
311 }
312 });
313};
314
315/**
316 * Create a new document
317 *
318 * @param {String} collectionName
319 * @param {Object} params
320 * @param {Function} onReady
321 *
322 * @api public
323 */
324MongooseAdmin.prototype.createDocument = function(req,user, collectionName, params, onReady) {
325 var self = this;
326 var model = this.models[collectionName].model;
327 var form_type = this.models[collectionName].options.form || forms.AdminForm;
328 if(permissions.hasPermissions(user,collectionName,'create'))
329 {
330
331 var form = new form_type(req,{data:params},model);
332 form.is_valid(function(err,valid)
333 {
334 if(err)
335 {
336 onReady(err);
337 return;
338 }
339 if(valid)
340 {
341 form.save(function(err,document)
342 {
343 if (err) {
344 //console.log('Error saving document: ' + err);
345 onReady(form);
346 } else {
347
348 if (self.models[collectionName].options && self.models[collectionName].options.post) {
349 document = self.models[collectionName].options.post(document);
350 }
351 MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, document._id, 'add', null, function(err, auditLog) {
352 onReady(null, document);
353 });
354 }
355 });
356 }
357 else
358 {
359 onReady(form,null);
360 }
361 });
362 }
363 else
364 {
365 onReady('unauthorizaed');
366 }
367};
368
369/**
370 * Update a document
371 *
372 * @param {String} collectionName
373 * @param {String} documentId
374 * @param {Object} params
375 * @param {Function} onReady
376 *
377 * @api public
378 */
379MongooseAdmin.prototype.updateDocument = function(req,user, collectionName, documentId, params, onReady) {
380 var self = this;
381 var fields = this.models[collectionName].fields;
382 var model = this.models[collectionName].model;
383 if(permissions.hasPermissions(user,collectionName,'update'))
384 {
385
386 var form_type = this.models[collectionName].options.form || forms.AdminForm;
387 model.findById(documentId, function(err, document) {
388 if (err) {
389 console.log('Error retrieving document to update: ' + err);
390 onReady('Unable to update', null);
391 } else {
392
393 var form = new form_type(req,{instance:document,data:params},model);
394 form.is_valid(function(err,valid)
395 {
396 if(err)
397 {
398 onReady(err, null);
399 return;
400 }
401 if(valid)
402 {
403 form.save(function(err,document)
404 {
405 if (err) {
406// console.log('Unable to update document: ' + err);
407 onReady(form, null);
408 } else {
409
410 if (self.models[collectionName].options && self.models[collectionName].options.post) {
411 document = self.models[collectionName].options.post(document);
412 }
413 MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, document._id, 'edit', null, function(err, auditLog) {
414 onReady(null, document);
415 });
416 }
417
418 });
419 }
420 else
421 {
422 onReady(form,null);
423 }
424 });
425 }
426 });
427 }
428 else
429 {
430 onReady('unauthorized');
431 }
432};
433
434/**
435 * Delete, remove a document
436 *
437 * @param {String} collectionName
438 * @param {String} documentId
439 * @param {Function} onReady
440 *
441 * @api public
442 */
443MongooseAdmin.prototype.deleteDocument = function(user, collectionName, documentId, onReady) {
444 var self = this;
445 var model = this.models[collectionName].model;
446 if(permissions.hasPermissions(user,collectionName,'delete'))
447 {
448 model.findById(documentId, function(err, document) {
449 if (err) {
450 console.log('Error retrieving document to delete: ' + err);
451 onReady('Unable to delete');
452 } else {
453 if (!document) {
454 onReady('Document not found');
455 } else {
456 forms.unlinkDependencies(self.models[collectionName].modelName,documentId,function(err) {
457 if(err)
458 onReady('unlink dependencies failed');
459 else {
460 document.remove();
461 MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, documentId, 'del', null, function(err, auditLog) {
462 onReady(null);
463 });
464 }
465 });
466 }
467 }
468 });
469 }
470 else
471 {
472 onReady('unauthorized')
473 }
474};
475
476MongooseAdmin.prototype.orderDocuments =function(user,collectionName,data,onReady)
477{
478 //console.log(data);
479 if(permissions.hasPermissions(user,collectionName,'order'))
480 {
481 var sorting_attr = this.models[collectionName].options.sortable;
482 if(sorting_attr)
483 {
484 for(var id in data)
485 {
486 var set_dict = {};
487 set_dict[sorting_attr] = data[id];
488 this.models[collectionName].model.update({_id:id},{$set:set_dict},function(err,r)
489 {
490 });
491 }
492 }
493
494 onReady(null);
495 }
496 else
497 onReady('unauthorized');
498};
499
500MongooseAdmin.prototype.actionDocuments =function(user,collectionName,actionId,data,onReady)
501{
502 //console.log(data);
503 if(permissions.hasPermissions(user,collectionName,'action'))
504 {
505 var action = _.find(this.models[collectionName].options.actions, function(action){ return action.value == actionId; });
506 if(action)
507 {
508 action.func(user,data.ids,onReady);
509 }
510 else
511 onReady('no action');
512 }
513 else
514 onReady('unauthorized');
515};
516
517
518
519/**
520 * Deserialize a user from a session store object
521 *
522 * @param {Object} sessionStore
523 *
524 * @api private
525 */
526MongooseAdmin.userFromSessionStore = function(sessionStore) {
527 return MongooseAdminUser.fromSessionStore(sessionStore);
528};
529
530/**
531 * Create an admin user account
532 *
533 * @param {String} username
534 * @param {Stirng} password
535 *
536 * @api public
537 */
538MongooseAdmin.prototype.ensureUserExists = function(username, password) {
539 MongooseAdminUser.ensureExists(username, password, function(err, adminUser) {
540 if (!err) {
541 console.log('Created admin user: ' + adminUser.fields.username);
542 }
543 });
544};
545
546/**
547 * Log in as a user
548 *
549 * @param {String} username
550 * @param {String} password
551 * @param {Function} onReady
552 *
553 * @api public
554 */
555MongooseAdmin.prototype.login = function(username, password, onReady) {
556 MongooseAdminUser.getByUsernamePassword(username, password, function(err, adminUser) {
557 onReady(err, adminUser);
558 });
559};
560
561