all files / keystone/lib/schemaPlugins/ track.js

96% Statements 48/50
90.2% Branches 46/51
100% Functions 3/3
96% Lines 48/50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137                   10× 10× 10× 10×           10×     10×                                               31×     31×           31×     30×         29×   21× 21× 21×   21×     11× 11×       10× 10×                             12×     12×           12× 12× 12×   12× 12×       12×          
var _ = require('lodash');
var keystone = require('../../');
var Types = require('../fieldTypes');
 
/**
 * List track option
 *
 * When enabled, it tracks when a document are created/updated,
 * as well as the user who created/updated it.
 */
 
module.exports = function track () {
 
	var list = this;
	var options = list.get('track');
	var userModel = keystone.get('user model');
	var defaultOptions = {
		createdAt: false,
		createdBy: false,
		updatedAt: false,
		updatedBy: false,
	};
	var fields = {};
 
	// ensure track is a boolean or an object
	if (!_.isBoolean(options) && !_.isObject(options)) {
		throw new Error('Invalid List "track" option for ' + list.key + '\n'
			+ '"track" must be a boolean or an object.\n\n'
			+ 'See http://keystonejs.com/docs/database/#lists-options for more information.');
	}
 
	if (_.isBoolean(options)) {
		// shorthand: { track: true } sets all tracked fields to true
		Eif (options) {
			options = {
				createdAt: true,
				createdBy: true,
				updatedAt: true,
				updatedBy: true,
			};
		} else {
			// otherwise user doesn't want tracking
			return;
		}
	}
 
	// if all track fields are set to false, then user doesn't want to track anything
	if (!options.createdAt && !options.createdBy && !options.updatedAt && !options.updatedBy) {
		return;
	}
 
	// merge user options with default options
	options = _.extend({}, defaultOptions, options);
 
	// validate option fields
	_.forEach(options, function (value, key) {
 
		var fieldName;
 
		// make sure the key isn't already defined as a field
		Iif (_.has(list.fields, key)) {
			throw new Error('Invalid List "track" option for ' + list.key + '\n'
				+ '"' + key + '" is already defined in the Schema.');
		}
 
		// make sure it's a valid track option field
		if (_.has(defaultOptions, key)) {
 
			// make sure the option field value is either a boolean or a string
			if (!_.isBoolean(value) && !_.isString(value)) {
				throw new Error('Invalid List "track" option for ' + list.key + '\n'
					+ '"' + key + '" must be a boolean or a string.\n\n'
					+ 'See http://keystonejs.com/docs/database/#lists-options for more information.');
			}
 
			if (value) {
				// determine
				fieldName = value === true ? key : value;
				options[key] = fieldName;
				list.map(key, fieldName);
 
				switch (key) {
					case 'createdAt':
					case 'updatedAt':
						fields[fieldName] = { type: Date, hidden: true, index: true };
						break;
 
					case 'createdBy':
					case 'updatedBy':
						fields[fieldName] = { type: Types.Relationship, ref: userModel, hidden: true, index: true };
						break;
				}
			}
		} else {
			throw new Error('Invalid List "track" option for ' + list.key + '\n'
				+ 'valid field options are "createdAt", "createdBy", "updatedAt", an "updatedBy".\n\n'
				+ 'See http://keystonejs.com/docs/database/#lists-options for more information.');
		}
 
	});
 
	// add track fields to schema
	list.add(fields);
 
	list.tracking = options;
 
	// add the pre-save schema plugin
	list.schema.pre('save', function (next) {
 
		var now = new Date();
 
		// set createdAt/createdBy on new docs
		if (this.isNew) {
			if (options.createdAt && !this.get(options.createdAt)) {
				this.set(options.createdAt, now);
			}
			if (options.createdBy && this._req_user && !this.get(options.createdBy)) {
				this.set(options.createdBy, this._req_user._id);
			}
		}
 
		// set updatedAt/updatedBy when doc is modified
		Eif (this.isNew || this.isModified()) {
			Eif (options.updatedAt) {
				this.set(options.updatedAt, now);
			}
			Eif (options.updatedBy && this._req_user) {
				this.set(options.updatedBy, this._req_user._id);
			}
		}
 
		next();
 
	});
 
};