<commit_before>

var p = require('deployk-utils').path;
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var async = require('async');
var extend = require('config-extend');

var DeployEmitter = require('./Emitter');
var DeployContext = require('./Context');

var WatchWrapper = require('./../Rule/WatchWrapper');

var MirrorTree = require('../Mirror/MirrorTree');
var MirrorSync = require('../Mirror/MirrorSync');

var diffMirrorTree = require('../Mirror-Diff/diffMirrorTree');
var diffMirrorSync = require('../Mirror-Diff/diffMirrorSync');
var DeferEmitter = require('../Mirror-Diff/DeferEmitter');
var PathEmitter = require('../Mirror-Diff/PathEmitter');
var UntreeEmitter = require('../Mirror-Diff/UntreeEmitter');
var SharedEmitter = require('../Mirror-Diff/SharedEmitter');
var SharedTree = require('../Mirror-Diff/SharedTree');

module.exports = DeployProcess;

/**
 * @param {Config}
 * @param {LocalWrapper}
 * @param {RemoteWrapper}
 * @constructor
 */
function DeployProcess(config, local, remote)
{
	var self = this;
	EventEmitter.call(this);

	/** @var {Config} */
	this.config = config;

	/** @var {LocalWrapper} */
	this.local = local;

	/** @var {RemoteWrapper} */
	this.remote = remote;

	this.remote.on('command', function(client, message) {
		self.emit('command', client, message);
	});

	/** @var {boolean} */
	this.aborted = false;

	/** @var {SharedTree} */
	this.sharedTree = new SharedTree();

	/** @var {MirrorTree} */
	this.mirrorTree;

	/** @var {Array.<Object>} */
	this.mirrorSyncList = [];

	/** @var {DeployContext} */
	this.context = new DeployContext(this);

	this.context.on('start', function(message, done, total) {
		self.emit('step', 'async: ' + done + '/' + total + (message ? '; Start: ' + message : ''));
	});

	this.context.on('end', function(message, done, total) {
		self.emit('step', 'async: ' + done + '/' + total + (message ? '; Done: ' + message : ''));
	});

	/** @var {WatchWrapper} */
	this.watchWrapper = new WatchWrapper(config.watchList, this.context.createContext());

	/** @var {WatchWrapper} */
	this.globWrapper = new WatchWrapper(config.globList, this.context.createContext());
};
util.inherits(DeployProcess, EventEmitter);

DeployProcess.prototype.abort = function(message)
{
	this.aborted = message ? message : true;
};

DeployProcess.prototype.should = function(run)
{
	var self = this;
	return function(cb) {
		if (self.aborted) {
			cb(true);

		} else {
			run(cb);
		}
	};
};

DeployProcess.prototype.run = function(opts)
{
	opts = extend({
		dry: false,
		setup: false
	}, opts);

	var self = this;
	async.series([
		this.should(function(cb) {
			self.emit('step', '1/9:\tConnect to remote server.');
			self.remote.connect(function(err) {
				if (err) self.abort('Could not connect to remote server.');
				cb();
			})
		}),
		this.should(function(cb) {
			self.mirrorTree = new MirrorTree(self.remote.walk('/'));
			self.createMirrorTree();
			self.createMirrorSyncList();
			cb();
		}),
		this.should(function(cb) {
			self.emit('step', '2/9:\tMirror project tree.');
			self.runMirrorTree(function() {
				cb();
			});
		}),
		this.should(function(cb) {
			self.emit('step', '3/9:\tbefore events.')
			self.config.eventList['before'].forEach(function(event) {
				event.apply(self.context.createContext());
			});

			self.context.whenDone(function() {
				cb();
			});
		}),
		this.should(function(cb) {
			self.emit('step', '4/9:\tGlob events');
			self.local.glob(self.globWrapper.buildPatterns(), function(files) {

				self.emit('step', '5/9:\tSynchronization loop.');
				Object.keys(files).forEach(function(file) {
					self.globWrapper.track(file);
				});

				cb();
			});
		}),
		this.should(function(cb) {
			self.runLoop(cb);
		}),
		this.should(function(cb) {
			if (opts.dry) {
				self.emit('step', '6/9:\tSkip setup.');
				cb();

			} else {
				if (opts.setup) {
					self.emit('step', '6/9:\tSetup project and deploy dirs.');

				} else {
					self.emit('step', '6/9:\tSetup deploy dirs.');
				}

				self.remote.setup(opts.setup, function(err) {
					if (err && opts.setup) {
						self.abort('Could not setup project and deploy dir.');

					} else if (err) {
						self.abort('Could not setup deploy dir. Project dir is probably missing, call setup to create ' + self.remote.basedir);
					}

					cb();
				});
			}
		}),
		this.should(function(cb) {
			var emitter, defer = new DeferEmitter();
			self.emit('step', '7/9:\tCalculate diffs between local and remote.');

			emitter = defer;
			emitter = new DeployEmitter(emitter, self.local, self.config.dirRights, self.config.fileRights);
			diffMirrorTree(self.mirrorTree, emitter);

			self.mirrorSyncList.forEach(function(sync) {
				emitter = defer;
				emitter = new DeployEmitter(emitter, self.local, self.config.dirRights, self.config.fileRights);
				emitter = new SharedEmitter(emitter, self.sharedTree);
				emitter = new PathEmitter(emitter, sync.remoteDir, sync.localDir);

				diffMirrorSync(sync.from, sync.to, emitter);
			});

			self.emit('step', ' - \t\tPending: ' + defer.getLength() + ' commands.');

			if (opts.dry) {
				self.abort('Dry mode. Commands not executed.');
				cb();

			} else {
				defer.emit(self.remote);
				self.remote.whenDone(function() {
					cb();
				});
			}
		}),
		this.should(function(cb) {
			self.emit('step', '8/9:\tCommit changes into production.');
			self.emit('step', ' - \t\tPending: ' + self.remote.getDelayedLength() + ' commands.');
			self.remote.commit(function() {
				cb();
			});
		}),
		this.should(function(cb) {
			self.emit('step', '9/9:\tbeforeend events.');
			self.config.eventList['beforeend'].forEach(function(event) {
				event.apply(self.context.createWaitContext());
			});

			self.context.whenDone(function() {
				cb();
			});
		}),
	], function(err) {
		if (err===undefined) {
			self.emit('success');

		} else {
			self.emit('abort', self.aborted);
		}

		self.emit('end');
	})
};

/**
 * @param {function}
 */
DeployProcess.prototype.runLoop = function(cb)
{
	var self = this;
	async.doWhilst(
		function(cb) {
			self.context.whenDone(function() {
				var defer = new DeferEmitter();
				var changes = self.context.purgeChanges();
				var syncList = [].concat(self.mirrorSyncList);

				async.whilst(
					function() { return self.aborted===false && syncList.length>0; },
					function(cb) {
						var sync = syncList.shift();
						if (changes===true) {
							sync.from.prepare('', true);
							sync.to.prepare('');

						} else {
							changes.local.forEach(function(local) {
								if (local = sync.sync.localMonitored(local)) {
									sync.from.prepare(local, true);
									sync.to.prepare(local);
								}
							});

							changes.remote.forEach(function(remote) {
								if (remote = sync.sync.remoteMonitored(remote)) {
									sync.from.prepare(remote, true);
									sync.to.prepare(remote);
								}
							});
						}

						self.emit('step', ' - \t\tSync ' + sync.localDir + ' -> ' + sync.remoteDir);

						async.parallel([
							sync.from.run.bind(sync.from),
							sync.to.run.bind(sync.to)
						], function(err) {
					 		var emitter = defer;
					 		emitter = new DeployEmitter(emitter, self.local, self.config.dirRights, self.config.fileRights);
					 		emitter = new PathEmitter(emitter, sync.remoteDir, sync.localDir);
					 		emitter = new UntreeEmitter(emitter);
					 		diffMirrorSync(sync.from, sync.to, emitter);

							cb();
						});

					},
					function() {
						self.emit('step', ' - \t\tPending: ' + defer.getLength() + ' commands');

						defer.emit({
							emitOp: function(op, dest, source) {
								if (op==='putFile' || op==='putContent') {
									self.watchWrapper.track(source.getRelativePath());
								}
							}
				 		});

						cb();
					}
				);
			});
		},
		function() { return self.aborted===false && !self.context.isFinished(); },
		cb
	);
};

/**
 * @param {string}
 * @param {function}
 */
DeployProcess.prototype.purge = function(path, cb)
{
	var self = this;

	async.parallel([
		function(cb) {
			self.mirrorTree.purge(path);
			var syncList = [].concat(self.mirrorSyncList);
			async.whilst(
				function() { return syncList.length>0; },
				function(cb) {

					var sync = syncList.shift();
					var remote;
					if (remote = sync.sync.remoteMonitored(path)) {
						sync.to.prepare(remote);

						sync.to.run(function() {
							sync.to.purgeTree(remote);
							cb();
						})

					} else {
						cb();
					}
				},
				cb
			);
		},
		function(cb) {
			self.remote.walk('').stat(path, function(err, stat) {
				if (!err) {
					if (stat.isDirectory()) {
						self.remote.deleteDir(path);

					} else if (stat.isFile()) {
						self.remote.deleteFile(path);
					}
				}

				cb();
			});
		}
	], cb);
}

/**
 * @param {string}
 */
DeployProcess.prototype.touch = function(path)
{
	this.local.touch(path);
};

/**
 * @param {string}
 * @param {string|Buffer}
 * @param {function}
 */
DeployProcess.prototype.touchContent = function(path, content, cb)
{
	var self = this;
	this.local.walk('').stat(p.dirname(path), function(err, stat) {
		if (stat && stat.isDirectory()) {
			self.mirrorSyncList.forEach(function(sync) {
				var local;
				if (local = sync.sync.localMonitored(path)) {
					sync.from.prepare(local, true);
					sync.to.prepare(local);
				}
			});

		} else {
			self.mirrorSyncList.forEach(function(sync) {
				if (sync.sync.localMonitored(path)) {
					sync.from.prepare('', true);
					sync.to.prepare('');
				}
			});
		}

		self.local.touchContent(path, content);
		cb();
	});
};

/**
 * @param {function}
 */
DeployProcess.prototype.createMirrorTree = function()
{
	this.config.ruleList.syncList.forEach(function(sync) {
		this.mirrorTree.prepare(sync.remoteDir);
		this.sharedTree.add(sync.remoteDir);
	}, this);

	this.config.ruleList.keepDir.forEach(function(dir) {
		this.mirrorTree.prepare(dir, MirrorTree.TYPE_DIR);
		this.sharedTree.add(dir);
	}, this);

	this.config.ruleList.keepSymlink.forEach(function(symlink) {
		this.mirrorTree.prepare(symlink[0], MirrorTree.TYPE_SYMLINK, symlink[1]);
		this.sharedTree.add(symlink[0]);
	}, this);
};

DeployProcess.prototype.createMirrorSyncList = function()
{
	this.config.ruleList.syncList.forEach(function(sync) {
		this.mirrorSyncList.push({
			sync: sync,
			remoteDir: sync.remoteDir,
			localDir: sync.localDir,
			from: new MirrorSync(this.local.walk(sync.localDir), sync, this.config.ruleList),
			to: new MirrorSync(this.remote.walk(sync.remoteDir), sync, this.config.ruleList)
		});
	}, this);
};

/**
 * @param {function}
 */
DeployProcess.prototype.runMirrorTree = function(cb)
{
	this.mirrorTree.run(cb);
}
<commit_msg>Refactor DeployProcess<commit_after>

var p = require('deployk-utils').path;
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var async = require('async');
var extend = require('config-extend');

var DeployEmitter = require('./Emitter');
var DeployContext = require('./Context');

var WatchWrapper = require('./../Rule/WatchWrapper');

var MirrorTree = require('../Mirror/MirrorTree');
var MirrorSync = require('../Mirror/MirrorSync');

var diffMirrorTree = require('../Mirror-Diff/diffMirrorTree');
var diffMirrorSync = require('../Mirror-Diff/diffMirrorSync');
var DeferEmitter = require('../Mirror-Diff/DeferEmitter');
var PathEmitter = require('../Mirror-Diff/PathEmitter');
var UntreeEmitter = require('../Mirror-Diff/UntreeEmitter');
var SharedEmitter = require('../Mirror-Diff/SharedEmitter');
var SharedTree = require('../Mirror-Diff/SharedTree');

module.exports = DeployProcess;

/**
 * @param {Config}
 * @param {LocalWrapper}
 * @param {RemoteWrapper}
 * @constructor
 */
function DeployProcess(config, local, remote)
{
	var self = this;
	EventEmitter.call(this);

	/** @var {Config} */
	this.config = config;

	/** @var {LocalWrapper} */
	this.local = local;

	/** @var {RemoteWrapper} */
	this.remote = remote;

	this.remote.on('command', function(client, message) {
		self.emit('command', client, message);
	});

	/** @var {boolean} */
	this.aborted = false;

	/** @var {SharedTree} */
	this.sharedTree = new SharedTree();

	/** @var {MirrorTree} */
	this.mirrorTree;

	/** @var {Array.<Object>} */
	this.mirrorSyncList = [];

	/** @var {DeployContext} */
	this.context = new DeployContext(this);

	this.context.on('start', function(message, done, total) {
		self.emit('step', 'async: ' + done + '/' + total + (message ? '; Start: ' + message : ''));
	});

	this.context.on('end', function(message, done, total) {
		self.emit('step', 'async: ' + done + '/' + total + (message ? '; Done: ' + message : ''));
	});

	/** @var {WatchWrapper} */
	this.watchWrapper = new WatchWrapper(config.watchList, this.context.createContext());

	/** @var {WatchWrapper} */
	this.globWrapper = new WatchWrapper(config.globList, this.context.createContext());
};
util.inherits(DeployProcess, EventEmitter);

DeployProcess.prototype.abort = function(message)
{
	this.aborted = message ? message : true;
};

DeployProcess.prototype.should = function(run)
{
	var self = this;
	return function(cb) {
		if (self.aborted) {
			cb(true);

		} else {
			run(cb);
		}
	};
};

DeployProcess.prototype.run = function(opts)
{
	opts = extend({
		dry: false,
		setup: false
	}, opts);

	var self = this;
	async.series([
		this.should(function(cb) {
			self.emit('step', '1/9:\tConnect to remote server.');
			self.remote.connect(function(err) {
				if (err) self.abort('Could not connect to remote server.');
				cb();
			})
		}),
		this.should(function(cb) {
			self.mirrorTree = new MirrorTree(self.remote.walk('/'));
			self.createMirrorTree();
			self.createMirrorSyncList();
			cb();
		}),
		this.should(function(cb) {
			self.emit('step', '2/9:\tMirror project tree.');
			self.mirrorTree.run(cb);
		}),
		this.should(function(cb) {
			self.emit('step', '3/9:\tbefore events.')
			self.config.eventList['before'].forEach(function(event) {
				event.apply(self.context.createContext());
			});

			self.context.whenDone(function() {
				cb();
			});
		}),
		this.should(function(cb) {
			self.emit('step', '4/9:\tGlob events');
			self.local.glob(self.globWrapper.buildPatterns(), function(files) {

				self.emit('step', '5/9:\tSynchronization loop.');
				Object.keys(files).forEach(function(file) {
					self.globWrapper.track(file);
				});

				cb();
			});
		}),
		this.should(function(cb) {
			self.runLoop(cb);
		}),
		this.should(function(cb) {
			if (opts.dry) {
				self.emit('step', '6/9:\tSkip setup.');
				cb();

			} else {
				if (opts.setup) {
					self.emit('step', '6/9:\tSetup project and deploy dirs.');

				} else {
					self.emit('step', '6/9:\tSetup deploy dirs.');
				}

				self.remote.setup(opts.setup, function(err) {
					if (err && opts.setup) {
						self.abort('Could not setup project and deploy dir.');

					} else if (err) {
						self.abort('Could not setup deploy dir. Project dir is probably missing, call setup to create ' + self.remote.basedir);
					}

					cb();
				});
			}
		}),
		this.should(function(cb) {
			var emitter, defer = new DeferEmitter();
			self.emit('step', '7/9:\tCalculate diffs between local and remote.');

			emitter = defer;
			emitter = new DeployEmitter(emitter, self.local, self.config.dirRights, self.config.fileRights);
			diffMirrorTree(self.mirrorTree, emitter);

			self.mirrorSyncList.forEach(function(sync) {
				emitter = defer;
				emitter = new DeployEmitter(emitter, self.local, self.config.dirRights, self.config.fileRights);
				emitter = new SharedEmitter(emitter, self.sharedTree);
				emitter = new PathEmitter(emitter, sync.remoteDir, sync.localDir);

				diffMirrorSync(sync.from, sync.to, emitter);
			});

			self.emit('step', ' - \t\tPending: ' + defer.getLength() + ' commands.');

			if (opts.dry) {
				self.abort('Dry mode. Commands not executed.');
				cb();

			} else {
				defer.emit(self.remote);
				self.remote.whenDone(function() {
					cb();
				});
			}
		}),
		this.should(function(cb) {
			self.emit('step', '8/9:\tCommit changes into production.');
			self.emit('step', ' - \t\tPending: ' + self.remote.getDelayedLength() + ' commands.');
			self.remote.commit(function() {
				cb();
			});
		}),
		this.should(function(cb) {
			self.emit('step', '9/9:\tbeforeend events.');
			self.config.eventList['beforeend'].forEach(function(event) {
				event.apply(self.context.createWaitContext());
			});

			self.context.whenDone(function() {
				cb();
			});
		}),
	], function(err) {
		if (err===undefined) {
			self.emit('success');

		} else {
			self.emit('abort', self.aborted);
		}

		self.emit('end');
	})
};

/**
 * @param {function}
 */
DeployProcess.prototype.runLoop = function(cb)
{
	var self = this;
	async.doWhilst(
		function(cb) {
			self.context.whenDone(function() {
				var defer = new DeferEmitter();
				var changes = self.context.purgeChanges();
				var syncList = [].concat(self.mirrorSyncList);

				async.whilst(
					function() { return self.aborted===false && syncList.length>0; },
					function(cb) {
						var sync = syncList.shift();
						if (changes===true) {
							sync.from.prepare('', true);
							sync.to.prepare('');

						} else {
							changes.local.forEach(function(local) {
								if (local = sync.sync.localMonitored(local)) {
									sync.from.prepare(local, true);
									sync.to.prepare(local);
								}
							});

							changes.remote.forEach(function(remote) {
								if (remote = sync.sync.remoteMonitored(remote)) {
									sync.from.prepare(remote, true);
									sync.to.prepare(remote);
								}
							});
						}

						self.emit('step', ' - \t\tSync ' + sync.localDir + ' -> ' + sync.remoteDir);

						async.parallel([
							sync.from.run.bind(sync.from),
							sync.to.run.bind(sync.to)
						], function(err) {
					 		var emitter = defer;
					 		emitter = new DeployEmitter(emitter, self.local, self.config.dirRights, self.config.fileRights);
					 		emitter = new PathEmitter(emitter, sync.remoteDir, sync.localDir);
					 		emitter = new UntreeEmitter(emitter);
					 		diffMirrorSync(sync.from, sync.to, emitter);

							cb();
						});

					},
					function() {
						self.emit('step', ' - \t\tPending: ' + defer.getLength() + ' commands');

						defer.emit({
							emitOp: function(op, dest, source) {
								if (op==='putFile' || op==='putContent') {
									self.watchWrapper.track(source.getRelativePath());
								}
							}
				 		});

						cb();
					}
				);
			});
		},
		function() { return self.aborted===false && !self.context.isFinished(); },
		cb
	);
};

/**
 * @param {string}
 * @param {function}
 */
DeployProcess.prototype.purge = function(path, cb)
{
	var self = this;

	async.parallel([
		function(cb) {
			self.mirrorTree.purge(path);
			var syncList = [].concat(self.mirrorSyncList);
			async.whilst(
				function() { return syncList.length>0; },
				function(cb) {

					var sync = syncList.shift();
					var remote;
					if (remote = sync.sync.remoteMonitored(path)) {
						sync.to.prepare(remote);

						sync.to.run(function() {
							sync.to.purgeTree(remote);
							cb();
						})

					} else {
						cb();
					}
				},
				cb
			);
		},
		function(cb) {
			self.remote.walk('').stat(path, function(err, stat) {
				if (!err) {
					if (stat.isDirectory()) {
						self.remote.deleteDir(path);

					} else if (stat.isFile()) {
						self.remote.deleteFile(path);
					}
				}

				cb();
			});
		}
	], cb);
}

/**
 * @param {string}
 */
DeployProcess.prototype.touch = function(path)
{
	this.local.touch(path);
};

/**
 * @param {string}
 * @param {string|Buffer}
 * @param {function}
 */
DeployProcess.prototype.touchContent = function(path, content, cb)
{
	var self = this;
	this.local.walk('').stat(p.dirname(path), function(err, stat) {
		if (stat && stat.isDirectory()) {
			self.mirrorSyncList.forEach(function(sync) {
				var local;
				if (local = sync.sync.localMonitored(path)) {
					sync.from.prepare(local, true);
					sync.to.prepare(local);
				}
			});

		} else {
			self.mirrorSyncList.forEach(function(sync) {
				if (sync.sync.localMonitored(path)) {
					sync.from.prepare('', true);
					sync.to.prepare('');
				}
			});
		}

		self.local.touchContent(path, content);
		cb();
	});
};

/**
 * @param {function}
 */
DeployProcess.prototype.createMirrorTree = function()
{
	this.config.ruleList.syncList.forEach(function(sync) {
		this.mirrorTree.prepare(sync.remoteDir);
		this.sharedTree.add(sync.remoteDir);
	}, this);

	this.config.ruleList.keepDir.forEach(function(dir) {
		this.mirrorTree.prepare(dir, MirrorTree.TYPE_DIR);
		this.sharedTree.add(dir);
	}, this);

	this.config.ruleList.keepSymlink.forEach(function(symlink) {
		this.mirrorTree.prepare(symlink[0], MirrorTree.TYPE_SYMLINK, symlink[1]);
		this.sharedTree.add(symlink[0]);
	}, this);
};

DeployProcess.prototype.createMirrorSyncList = function()
{
	this.config.ruleList.syncList.forEach(function(sync) {
		this.mirrorSyncList.push({
			sync: sync,
			remoteDir: sync.remoteDir,
			localDir: sync.localDir,
			from: new MirrorSync(this.local.walk(sync.localDir), sync, this.config.ruleList),
			to: new MirrorSync(this.remote.walk(sync.remoteDir), sync, this.config.ruleList)
		});
	}, this);
};
<|endoftext|>


<commit_before>/**
 * 高级模型
 * @return {[type]} [description]
 */
module.exports = Model(function(){
	//关联类型
	const HAS_ONE = 1;
	const BELONGS_TO = 2;
	const HAS_MANY = 3;
	const MANY_TO_MANY = 4;
	//解析page参数
	var parsePage = function(options){
		if ("page" in options) {
			var page = options.page + "";
			var num = 0;
			if (page.indexOf(",") > -1) {
				page = page.split(",");
				num = parseInt(page[1], 10);
				page = page[0];
			}
			num = num || C('db_nums_per_page')
			page = parseInt(page, 10) || 1;
			return {
				page: page,
				num: num
			}
		};
		return {
			page: 1,
			num: C('db_nums_per_page')
		}
	}

	return {
		/**
		 * 关联定义
		 * 数据格式：
		 * "Profile": {
		 * 		type: 1,
		 * 		model: "Profile",
		 * 		name: "Profile",
		 * 		key: "id",
		 * 		fKey: "user_id",
		 * 		field: "id,name",
		 * 		where: "name=xx",
		 * 		order: "",
		 * 		limit: ""
		 * }
		 * @type {Object}
		 */
		relation: {},
		/**
		 * 本次使用的关联名称，默认是全部使用
		 * @type {Boolean}
		 */
		_relationName: true,
		/**
		 * 返回数据里含有count信息的查询
		 * @param  options  查询选项
		 * @param  pageFlag 当页面不合法时的处理方式，true为获取第一页，false为获取最后一页，undefined获取为空
		 * @return promise
		 */
		countSelect: function(options, pageFlag){
			if (isBoolean(options)) {
				pageFlag = options;
				options = {};
			};
			var self = this;
			//解析后的options
			var parsedOptions = {};
			var result = {};
			return this.parseOptions(options).then(function(options){
				delete options.table;
				parsedOptions = options;
				return self.options({
					where: options.where,
					cache: options.cache
				}).count(self.getPk());
			}).then(function(count){
				var pageOptions = parsePage(parsedOptions);
				var totalPage = Math.ceil(count / pageOptions.num);
				if (isBoolean(pageFlag)) {
					if (pageOptions.page > totalPage) {
						pageOptions.page = pageFlag === true ? 1 : totalPage;
					};
					parsedOptions.page = pageOptions.page + ',' + pageOptions.num;
				};
				result = extend({count: count, totalPage: totalPage}, pageOptions);
				return self.select(parsedOptions);
			}).then(function(data){
				result.data = data;
				return result;
			})
		},
		/**
		 * 设置本次使用的relation
		 * @param {[type]} name [description]
		 */
		setRelation: function(name){
			if (isString(name)) {
				name = name.split(",");
			};
			this._relationName = name;
			return this;
		},
		/**
		 * find后置操作
		 * @param  {[type]} data [description]
		 * @return {[type]}      [description]
		 */
		_afterFind: function(data, parsedOptions){
			return this.getRelation(data, parsedOptions);
		},
		/**
		 * select后置操作
		 * @param  {[type]} data [description]
		 * @return {[type]}      [description]
		 */
		_afterSelect: function(data, parsedOptions){
			return this.getRelation(data, parsedOptions);
		},
		/**
		 * 获取关联的数据
		 * @param  {[type]}  data       [description]
		 * @param  Boolean isDataList 是否是数据列表
		 * @return {[type]}
		 */
		getRelation: function(data, parsedOptions){
			if (isEmpty(data) || isEmpty(this.relation) || isEmpty(this._relationName)) {
				return data;
			};
			var self = this;
			var promises = [];
			var db = thinkRequire("Db")();
			Object.keys(this.relation).forEach(function(key){
				var promise, mapName, mapType, model, mapWhere, mapKey, mapfKey;
				var value = self.relation[key];
				if (!isObject(value)) {
					value = {type: value};
				};
				mapName = value.name || key;
				if (self._relationName !== true && self._relationName.indexOf(mapName) === -1) {
					return;
				};
				mapType = value.type || HAS_ONE;
				mapKey = value.key || self.getPk();
				mapfKey = value.fKey || (self.name.toLowerCase() + "_id");
				model = D(value.model || key);
				model.where(value.where).cache(parsedOptions.cache).field(value.field).order(value.order).limit(value.limit);
				switch(mapType){
					case HAS_ONE:
						model.where(self.parseRelationWhere(data, mapKey, mapfKey));
						promise = model.select().then(function(mapData){
							self.parseRelationData(data, mapData, mapName);
						})
						break;
					case BELONGS_TO:
						promise = model.promise.then(function(){
							mapKey = model.getModelName().toLowerCase() + "_id";
							mapfKey = model.getPk();
							model.where(self.parseRelationWhere(data, mapKey, mapfKey));
							return model.select();
						}).then(function(mapData){
							self.parseRelationData(data, mapData, mapName);
						})
						break;
					case HAS_MANY:
						model.where(self.parseRelationWhere(data, mapKey, mapfKey));
						promise = model.select().then(function(mapData){
							self.parseRelationData(data, mapData, mapName, mapKey, mapfKey, true);
						})
						break;
					case MANY_TO_MANY:
						promise = model.promise.then(function(){
							var whereStr = db.parseWhere(self.parseRelationWhere(data, mapKey, mapfKey));
							var sql = "SELECT b.%s,a.%s FROM %s as a, %s as b %s AND a.%s=b.%s %s %s";
							var queryData = [
								value.field || "*",
								mapfKey,
								self.getRelationTableName(model),
								model.getTableName(),
								whereStr || "WHERE ",
								(model.getModelName() + "_id").toLowerCase(),
								model.getPk(),
								db.parseOrder(value.order),
								db.parseLimit(value.limit)
							];
							return self.parseSql(sql, queryData).then(function(sql){
								return self.db.select(sql, parsedOptions.cache);
							}).then(function(mapData){
								self.parseRelationData(data, mapData, mapName, mapKey, mapfKey, true);
							});
						})
						break;
					default:
						break;
				}
				promises.push(promise);
			})
			return Promise.all(promises).then(function(){
				return data;
			});
		},
		/**
		 * 多对多关系下，获取对应的关联表
		 * @return {[type]} [description]
		 */
		getRelationTableName: function(relationModel){
			var table = [
				this.tablePrefix,
				this.tableName || this.name,
				"_",
				relationModel.getModelName()
			].join("");
			return table.toLowerCase();
		},
		/**
		 * 解析relation的where条件
		 * @param  {[type]} data    [description]
		 * @param  {[type]} mapKey  [description]
		 * @param  {[type]} mapfKey [description]
		 * @return {[type]}         [description]
		 */
		parseRelationWhere: function(data, mapKey, mapfKey){
			if (isArray(data)) {
				var value = data.map(function(item){
					return item[mapKey];
				});
				return getObject(mapfKey, ["IN", value]);
			};
			return getObject(mapfKey, data[mapKey]);
		},
		/**
		 * 解析查询后的数据
		 * @param  {[type]}  data     [description]
		 * @param  {[type]}  mapData  [description]
		 * @param  {[type]}  mapName  [description]
		 * @param  {[type]}  mapKey   [description]
		 * @param  {[type]}  mapfKey  [description]
		 * @param  {Boolean} isArrMap [description]
		 * @return {[type]}           [description]
		 */
		parseRelationData: function(data, mapData, mapName, mapKey, mapfKey, isArrMap){
			if (isArray(data)) {
				//提前初始化，防止mapData为空导致data里的数据没有初始化的情况
				data.forEach(function(item, i){
					data[i][mapName] = isArrMap ? [] : {};
				})
				mapData.forEach(function(mapItem){
					data.forEach(function(item, i){
						if (mapItem[mapfKey] !== item[mapKey]) {
							return;
						};
						if (isArrMap) {
							data[i][mapName].push(mapItem);
						}else{
							data[i][mapName] = mapItem;
						}
					});
				})
			}else{
				data[mapName] = isArrMap ? (mapData || []) : (mapData[0] || {});
			}
			return data;
		},
		postRelation: function(data){

		}
	}
})<commit_msg>update<commit_after>/**
 * 高级模型
 * @return {[type]} [description]
 */
module.exports = Model(function(){
	//关联类型
	const HAS_ONE = 1;
	const BELONGS_TO = 2;
	const HAS_MANY = 3;
	const MANY_TO_MANY = 4;
	//解析page参数
	var parsePage = function(options){
		if ("page" in options) {
			var page = options.page + "";
			var num = 0;
			if (page.indexOf(",") > -1) {
				page = page.split(",");
				num = parseInt(page[1], 10);
				page = page[0];
			}
			num = num || C('db_nums_per_page')
			page = parseInt(page, 10) || 1;
			return {
				page: page,
				num: num
			}
		};
		return {
			page: 1,
			num: C('db_nums_per_page')
		}
	}

	return {
		/**
		 * 关联定义
		 * 数据格式：
		 * "Profile": {
		 * 		type: 1,
		 * 		model: "Profile",
		 * 		name: "Profile",
		 * 		key: "id",
		 * 		fKey: "user_id",
		 * 		field: "id,name",
		 * 		where: "name=xx",
		 * 		order: "",
		 * 		limit: ""
		 * }
		 * @type {Object}
		 */
		relation: {},
		/**
		 * 本次使用的关联名称，默认是全部使用
		 * @type {Boolean}
		 */
		_relationName: true,
		/**
		 * 返回数据里含有count信息的查询
		 * @param  options  查询选项
		 * @param  pageFlag 当页面不合法时的处理方式，true为获取第一页，false为获取最后一页，undefined获取为空
		 * @return promise
		 */
		countSelect: function(options, pageFlag){
			if (isBoolean(options)) {
				pageFlag = options;
				options = {};
			};
			var self = this;
			//解析后的options
			var parsedOptions = {};
			var result = {};
			return this.parseOptions(options).then(function(options){
				delete options.table;
				parsedOptions = options;
				return self.options({
					where: options.where,
					cache: options.cache
				}).count(self.getPk());
			}).then(function(count){
				var pageOptions = parsePage(parsedOptions);
				var totalPage = Math.ceil(count / pageOptions.num);
				if (isBoolean(pageFlag)) {
					if (pageOptions.page > totalPage) {
						pageOptions.page = pageFlag === true ? 1 : totalPage;
					};
					parsedOptions.page = pageOptions.page + ',' + pageOptions.num;
				};
				result = extend({count: count, totalPage: totalPage}, pageOptions);
				return self.select(parsedOptions);
			}).then(function(data){
				result.data = data;
				return result;
			})
		},
		/**
		 * 设置本次使用的relation
		 * @param {[type]} name [description]
		 */
		setRelation: function(name){
			if (isString(name)) {
				name = name.split(",");
			};
			this._relationName = name;
			return this;
		},
		/**
		 * find后置操作
		 * @param  {[type]} data [description]
		 * @return {[type]}      [description]
		 */
		_afterFind: function(data, parsedOptions){
			return this.getRelation(data, parsedOptions);
		},
		/**
		 * select后置操作
		 * @param  {[type]} data [description]
		 * @return {[type]}      [description]
		 */
		_afterSelect: function(data, parsedOptions){
			return this.getRelation(data, parsedOptions);
		},
		/**
		 * 获取关联的数据
		 * @param  {[type]}  data       [description]
		 * @param  Boolean isDataList 是否是数据列表
		 * @return {[type]}
		 */
		getRelation: function(data, parsedOptions){
			if (isEmpty(data) || isEmpty(this.relation) || isEmpty(this._relationName)) {
				return data;
			};
			var self = this;
			var promises = [];
			Object.keys(this.relation).forEach(function(key){
				var promise, mapName, mapType, model, mapWhere, mapKey, mapfKey;
				var value = self.relation[key];
				if (!isObject(value)) {
					value = {type: value};
				};
				mapName = value.name || key;
				if (self._relationName !== true && self._relationName.indexOf(mapName) === -1) {
					return;
				};
				mapType = value.type || HAS_ONE;
				mapKey = value.key || self.getPk();
				mapfKey = value.fKey || (self.name.toLowerCase() + "_id");
				model = D(value.model || key);
				model.where(value.where).cache(parsedOptions.cache).field(value.field).order(value.order).limit(value.limit);
				switch(mapType){
					case HAS_ONE:
						model.where(self.parseRelationWhere(data, mapKey, mapfKey));
						promise = model.select().then(function(mapData){
							self.parseRelationData(data, mapData, mapName);
						})
						break;
					case BELONGS_TO:
						promise = model.promise.then(function(){
							mapKey = model.getModelName().toLowerCase() + "_id";
							mapfKey = model.getPk();
							model.where(self.parseRelationWhere(data, mapKey, mapfKey));
							return model.select();
						}).then(function(mapData){
							self.parseRelationData(data, mapData, mapName);
						})
						break;
					case HAS_MANY:
						model.where(self.parseRelationWhere(data, mapKey, mapfKey));
						promise = model.select().then(function(mapData){
							self.parseRelationData(data, mapData, mapName, mapKey, mapfKey, true);
						})
						break;
					case MANY_TO_MANY:
						promise = model.promise.then(function(){
							var whereStr = self.db.parseWhere(self.parseRelationWhere(data, mapKey, mapfKey));
							var sql = "SELECT b.%s,a.%s FROM %s as a, %s as b %s AND a.%s=b.%s %s %s %s";
							var queryData = [
								value.field || "*",
								mapfKey,
								self.getRelationTableName(model),
								model.getTableName(),
								whereStr || "WHERE ",
								(model.getModelName() + "_id").toLowerCase(),
								model.getPk(),
								value.where ? (" AND " + value.where) : "",
								self.db.parseOrder(value.order),
								self.db.parseLimit(value.limit)
							];
							return self.parseSql(sql, queryData).then(function(sql){
								return self.db.select(sql, parsedOptions.cache);
							}).then(function(mapData){
								self.parseRelationData(data, mapData, mapName, mapKey, mapfKey, true);
							});
						})
						break;
					default:
						break;
				}
				promises.push(promise);
			})
			return Promise.all(promises).then(function(){
				return data;
			});
		},
		/**
		 * 多对多关系下，获取对应的关联表
		 * @return {[type]} [description]
		 */
		getRelationTableName: function(relationModel){
			var table = [
				this.tablePrefix,
				this.tableName || this.name,
				"_",
				relationModel.getModelName()
			].join("");
			return table.toLowerCase();
		},
		/**
		 * 解析relation的where条件
		 * @param  {[type]} data    [description]
		 * @param  {[type]} mapKey  [description]
		 * @param  {[type]} mapfKey [description]
		 * @return {[type]}         [description]
		 */
		parseRelationWhere: function(data, mapKey, mapfKey){
			if (isArray(data)) {
				var value = data.map(function(item){
					return item[mapKey];
				});
				return getObject(mapfKey, ["IN", value]);
			};
			return getObject(mapfKey, data[mapKey]);
		},
		/**
		 * 解析查询后的数据
		 * @param  {[type]}  data     [description]
		 * @param  {[type]}  mapData  [description]
		 * @param  {[type]}  mapName  [description]
		 * @param  {[type]}  mapKey   [description]
		 * @param  {[type]}  mapfKey  [description]
		 * @param  {Boolean} isArrMap [description]
		 * @return {[type]}           [description]
		 */
		parseRelationData: function(data, mapData, mapName, mapKey, mapfKey, isArrMap){
			if (isArray(data)) {
				//提前初始化，防止mapData为空导致data里的数据没有初始化的情况
				data.forEach(function(item, i){
					data[i][mapName] = isArrMap ? [] : {};
				})
				mapData.forEach(function(mapItem){
					data.forEach(function(item, i){
						if (mapItem[mapfKey] !== item[mapKey]) {
							return;
						};
						if (isArrMap) {
							data[i][mapName].push(mapItem);
						}else{
							data[i][mapName] = mapItem;
						}
					});
				})
			}else{
				data[mapName] = isArrMap ? (mapData || []) : (mapData[0] || {});
			}
			return data;
		},
		postRelation: function(data){

		}
	}
})<|endoftext|>


<commit_before>export default class AceEditorWidget {
  constructor(initialValue) {
    this.type = 'Widget'
    this.initialValue = initialValue
  }

  init() {
    const el = document.createElement('pre')
    el.textContent = this.initialValue
    this.editor = ace.edit(el)
    return el
  }

  update(previous, domNode) {

  }

  destroy(domNode) {
    this.editor.destroy()
    this.editor.container.remove()
  }
}
<commit_msg>Preserve editor on update<commit_after>export default class AceEditorWidget {
  constructor(initialValue) {
    this.type = 'Widget'
    this.initialValue = initialValue
  }

  init() {
    const el = document.createElement('pre')
    el.textContent = this.initialValue
    this.editor = ace.edit(el)
    return el
  }

  update(previous, domNode) {
    this.editor = previous.editor
  }

  destroy(domNode) {
    this.editor.destroy()
    this.editor.container.remove()
  }
}
<|endoftext|>


<commit_before>(function(){
    var ExcerptManager = function(locationFilter, inputElementsNewBoundingBox, selectElementExistingExcerpts, formElementPartsSwitcher) {
        this.locationFilter = locationFilter;
        this.inputElementsNewBoundingBox = inputElementsNewBoundingBox;
        this.selectElementExistingExcerpts = selectElementExistingExcerpts;
        this.formElementPartsSwitcher = formElementPartsSwitcher;

        /**
         * Synchronize coordinates in input fields to excerpt on map
         */
        this.updateInputElementsBoundingBox = function() {
            var locationFilterBounds = this.locationFilter.getBounds();
            this.inputElementsNewBoundingBox.inputElementNorth.value = locationFilterBounds._northEast.lat;
            this.inputElementsNewBoundingBox.inputElementWest.value = locationFilterBounds._southWest.lng;
            this.inputElementsNewBoundingBox.inputElementEast.value = locationFilterBounds._northEast.lng;
            this.inputElementsNewBoundingBox.inputElementSouth.value = locationFilterBounds._southWest.lat;
        };

        /**
         * Synchronize excerpt on map to coordinates in input fields
         */
        this.updateMapExcerpt = function() {
            var locationFilterBounds = this.locationFilter.getBounds();
            locationFilterBounds._northEast.lat = this.inputElementsNewBoundingBox.inputElementNorth.value;
            locationFilterBounds._southWest.lng = this.inputElementsNewBoundingBox.inputElementWest.value;
            locationFilterBounds._northEast.lng = this.inputElementsNewBoundingBox.inputElementEast.value;
            locationFilterBounds._southWest.lat = this.inputElementsNewBoundingBox.inputElementSouth.value;
            this.locationFilter.setBounds(locationFilterBounds);
        };

        this.isSelectOptionSelectedAndExcerptOnMapInSyncWithInputFields = function(select, locationFilterBounds) {
            if(select.value != "") {
                var optionElement = select.querySelector('option[value="'+select.value+'"]');
            }
            return select.value != "" &&
                optionElement.getAttribute('data-north') == locationFilterBounds._northEast.lat &&
                optionElement.getAttribute('data-west') == locationFilterBounds._southWest.lng &&
                optionElement.getAttribute('data-east') == locationFilterBounds._northEast.lng &&
                optionElement.getAttribute('data-south') == locationFilterBounds._southWest.lat
        }

        /**
         * if the shown excerpt on the map changes and the change was not made by selecting an existing excerpt in the list
         * -> a user changed the excerpt, so change the form part to 'new-excerpt'
         */
        this.userChangeExcerptOnMapShowNewExcerptPart = function() {
            var locationFilterBounds = this.locationFilter.getBounds();
            var select = this.selectElementExistingExcerpts;
            if(!this.isSelectOptionSelectedAndExcerptOnMapInSyncWithInputFields(select, locationFilterBounds)) {
                this.formElementPartsSwitcher.value = 'new-excerpt';
                this.formElementPartsSwitcher.dispatchEvent(new Event('change'));
            }
        };

        // update coordinates input elements on change of excerpt on map
        this.locationFilter.on("change", function (event) {
            this.updateInputElementsBoundingBox();
            this.userChangeExcerptOnMapShowNewExcerptPart();
        }.bind(this));

        // update excerpt on map on change of coordinates input elements
        Object.keys(this.inputElementsNewBoundingBox).forEach(function(inputElementKey) {
            this.inputElementsNewBoundingBox[inputElementKey].addEventListener('change', this.updateMapExcerpt.bind(this));
        }.bind(this));

        // update excerpt on map on selection of existing excerpt in list
        this.selectElementExistingExcerpts.addEventListener('change', function(event) {
            var excerptOption = event.explicitOriginalTarget;
            if(excerptOption.getAttribute('data-geometry') == 'boundingbox') {
                var bounds = this.locationFilter.getBounds();
                bounds._northEast.lat = excerptOption.getAttribute('data-north');
                bounds._southWest.lng = excerptOption.getAttribute('data-west');
                bounds._northEast.lng = excerptOption.getAttribute('data-east');
                bounds._southWest.lat = excerptOption.getAttribute('data-south');
                this.locationFilter.setBounds(bounds);
                // enable excerpt on map for case it was disable before (e.g. by clicking on a not-boundingbox excerpt in the list)
                this.locationFilter.enable();
            } else {
                // no existing excerpt of type boundingbox -> disable excerpt because we are not able to show not-boundingbox excerpts on map
                this.locationFilter.disable();
            }
        }.bind(this));

        // enable excerpt on map on change of form mode (existing excerpt or new excerpt)
        this.formElementPartsSwitcher.addEventListener('change', function(event) {
            this.locationFilter.enable();
        }.bind(this));
    };

    var map = L.map('map').setView([0, 0], 2);
    // add an OpenStreetMap tile layer
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    var locationFilter = new L.LocationFilter({
        enable: true,
        enableButton: false
    }).addTo(map);

    var excerptManager = new ExcerptManager(
        locationFilter,
        {
            inputElementNorth: document.getElementById('new_excerpt_bounding_box_north'),
            inputElementWest: document.getElementById('new_excerpt_bounding_box_west'),
            inputElementEast: document.getElementById('new_excerpt_bounding_box_east'),
            inputElementSouth: document.getElementById('new_excerpt_bounding_box_south')
        },
        document.getElementById('existing_excerpt.id'),
        document.getElementById('form-mode')
    );

    // push initial values to text inputs
    excerptManager.updateInputElementsBoundingBox();
})();
<commit_msg>Refactoring: Simplify huge expression<commit_after>(function(){
    var ExcerptManager = function(locationFilter, inputElementsNewBoundingBox, selectElementExistingExcerpts, formElementPartsSwitcher) {
        this.locationFilter = locationFilter;
        this.inputElementsNewBoundingBox = inputElementsNewBoundingBox;
        this.selectElementExistingExcerpts = selectElementExistingExcerpts;
        this.formElementPartsSwitcher = formElementPartsSwitcher;

        /**
         * Synchronize coordinates in input fields to excerpt on map
         */
        this.updateInputElementsBoundingBox = function() {
            var locationFilterBounds = this.locationFilter.getBounds();
            this.inputElementsNewBoundingBox.inputElementNorth.value = locationFilterBounds._northEast.lat;
            this.inputElementsNewBoundingBox.inputElementWest.value = locationFilterBounds._southWest.lng;
            this.inputElementsNewBoundingBox.inputElementEast.value = locationFilterBounds._northEast.lng;
            this.inputElementsNewBoundingBox.inputElementSouth.value = locationFilterBounds._southWest.lat;
        };

        /**
         * Synchronize excerpt on map to coordinates in input fields
         */
        this.updateMapExcerpt = function() {
            var locationFilterBounds = this.locationFilter.getBounds();
            locationFilterBounds._northEast.lat = this.inputElementsNewBoundingBox.inputElementNorth.value;
            locationFilterBounds._southWest.lng = this.inputElementsNewBoundingBox.inputElementWest.value;
            locationFilterBounds._northEast.lng = this.inputElementsNewBoundingBox.inputElementEast.value;
            locationFilterBounds._southWest.lat = this.inputElementsNewBoundingBox.inputElementSouth.value;
            this.locationFilter.setBounds(locationFilterBounds);
        };

        this.isSelectOptionSelectedAndExcerptOnMapInSyncWithInputFields = function(select, locationFilterBounds) {
            if(select.value == "") {
                return false;
            }
            var optionElement = select.querySelector('option[value="'+select.value+'"]');
            return
                optionElement.getAttribute('data-north') == locationFilterBounds._northEast.lat &&
                optionElement.getAttribute('data-west') == locationFilterBounds._southWest.lng &&
                optionElement.getAttribute('data-east') == locationFilterBounds._northEast.lng &&
                optionElement.getAttribute('data-south') == locationFilterBounds._southWest.lat
        }

        /**
         * if the shown excerpt on the map changes and the change was not made by selecting an existing excerpt in the list
         * -> a user changed the excerpt, so change the form part to 'new-excerpt'
         */
        this.userChangeExcerptOnMapShowNewExcerptPart = function() {
            var locationFilterBounds = this.locationFilter.getBounds();
            var select = this.selectElementExistingExcerpts;
            if(!this.isSelectOptionSelectedAndExcerptOnMapInSyncWithInputFields(select, locationFilterBounds)) {
                this.formElementPartsSwitcher.value = 'new-excerpt';
                this.formElementPartsSwitcher.dispatchEvent(new Event('change'));
            }
        };

        // update coordinates input elements on change of excerpt on map
        this.locationFilter.on("change", function (event) {
            this.updateInputElementsBoundingBox();
            this.userChangeExcerptOnMapShowNewExcerptPart();
        }.bind(this));

        // update excerpt on map on change of coordinates input elements
        Object.keys(this.inputElementsNewBoundingBox).forEach(function(inputElementKey) {
            this.inputElementsNewBoundingBox[inputElementKey].addEventListener('change', this.updateMapExcerpt.bind(this));
        }.bind(this));

        // update excerpt on map on selection of existing excerpt in list
        this.selectElementExistingExcerpts.addEventListener('change', function(event) {
            var excerptOption = event.explicitOriginalTarget;
            if(excerptOption.getAttribute('data-geometry') == 'boundingbox') {
                var bounds = this.locationFilter.getBounds();
                bounds._northEast.lat = excerptOption.getAttribute('data-north');
                bounds._southWest.lng = excerptOption.getAttribute('data-west');
                bounds._northEast.lng = excerptOption.getAttribute('data-east');
                bounds._southWest.lat = excerptOption.getAttribute('data-south');
                this.locationFilter.setBounds(bounds);
                // enable excerpt on map for case it was disable before (e.g. by clicking on a not-boundingbox excerpt in the list)
                this.locationFilter.enable();
            } else {
                // no existing excerpt of type boundingbox -> disable excerpt because we are not able to show not-boundingbox excerpts on map
                this.locationFilter.disable();
            }
        }.bind(this));

        // enable excerpt on map on change of form mode (existing excerpt or new excerpt)
        this.formElementPartsSwitcher.addEventListener('change', function(event) {
            this.locationFilter.enable();
        }.bind(this));
    };

    var map = L.map('map').setView([0, 0], 2);
    // add an OpenStreetMap tile layer
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    var locationFilter = new L.LocationFilter({
        enable: true,
        enableButton: false
    }).addTo(map);

    var excerptManager = new ExcerptManager(
        locationFilter,
        {
            inputElementNorth: document.getElementById('new_excerpt_bounding_box_north'),
            inputElementWest: document.getElementById('new_excerpt_bounding_box_west'),
            inputElementEast: document.getElementById('new_excerpt_bounding_box_east'),
            inputElementSouth: document.getElementById('new_excerpt_bounding_box_south')
        },
        document.getElementById('existing_excerpt.id'),
        document.getElementById('form-mode')
    );

    // push initial values to text inputs
    excerptManager.updateInputElementsBoundingBox();
})();
<|endoftext|>


<commit_before>'use strict';

import Base from './base.js';

let SqliteSocket = think.adapter('socket', 'sqlite');
/**
 * sqlite db
 */
export default class extends Base {
  /**
   * get sqlite socket instance
   * @param  {Object} config []
   * @return {}        []
   */
  socket(sql){
    if(this._socket){
      return this._socket;
    }
    let config = think.extend({
      sql: sql
    }, this.config);
    this._socket = SqliteSocket.getInstance(config, thinkCache.DB, ['sql']);
    return this._socket;
  }
  /**
   * get table info
   * @param  {String} table [table name]
   * @return {Promise}       []
   */
  async getFields(table){
    let data = await this.query(`PRAGMA table_info( ${table} )`);
    let ret = {};
    data.forEach(item => {
      ret[item.name] = {
        name: item.name,
        type: item.type,
        required: !!item.notnull,
        default: item.dflt_value,
        primary: !!item.pk,
        auto_increment: false
      };
    });
    return ret;
  }
  /**
   * escape string
   * @param  {String} str []
   * @return {String}     []
   */
  escapeString(str){
    return str.replace(/\'/g, '\'\'');
  }
  /**
   * parse limit
   * @param  {Array} limit []
   * @return {String}       []
   */
  parseLimit(limit){
    if (think.isEmpty(limit)) {
      return '';
    }
    if(think.isNumber(limit)){
      return ` LIMIT ${limit}`;
    }
    if(think.isString(limit)){
      limit = limit.split(/\s*,\s*/);
    }
    if(limit[1]){
      return ' LIMIT ' + (limit[1] | 0) + ' OFFSET ' + (limit[0] | 0);
    }
    return ' LIMIT ' + (limit[0] | 0);
  }
}<commit_msg>get table indexes for sqlite<commit_after>'use strict';

import Base from './base.js';

let SqliteSocket = think.adapter('socket', 'sqlite');
/**
 * sqlite db
 */
export default class extends Base {
  /**
   * get sqlite socket instance
   * @param  {Object} config []
   * @return {}        []
   */
  socket(sql){
    if(this._socket){
      return this._socket;
    }
    let config = think.extend({
      sql: sql
    }, this.config);
    this._socket = SqliteSocket.getInstance(config, thinkCache.DB, ['sql']);
    return this._socket;
  }
  /**
   * get table info
   * @param  {String} table [table name]
   * @return {Promise}       []
   */
  async getFields(table){
    let fieldPromise = this.query(`PRAGMA table_info( ${table} )`);
    let indexPromise = this.query(`PRAGMA INDEX_LIST(${table})`).then(async list => {
      let indexes = {};
      let promises = list.map(async item => {
        if(item.unique){
          let list = await this.query(`PRAGMA index_info(${item.name})`);
          list.forEach(item => {
            indexes[item.name] = {unique: true};
          });
        }
      });
      await Promise.all(promises);
      return indexes;
    });
    let ret = {};
    let [data, indexes] = await Promise.all([fieldPromise, indexPromise]);
    data.forEach(item => {
      ret[item.name] = {
        name: item.name,
        type: item.type,
        required: !!item.notnull,
        default: item.dflt_value,
        primary: !!item.pk,
        auto_increment: false,
        unique: !item.pk && indexes[item.name] && indexes[item.name].unique
      };
    });
    return ret;
  }
  /**
   * escape string
   * @param  {String} str []
   * @return {String}     []
   */
  escapeString(str){
    return str.replace(/\'/g, '\'\'');
  }
  /**
   * parse limit
   * @param  {Array} limit []
   * @return {String}       []
   */
  parseLimit(limit){
    if (think.isEmpty(limit)) {
      return '';
    }
    if(think.isNumber(limit)){
      return ` LIMIT ${limit}`;
    }
    if(think.isString(limit)){
      limit = limit.split(/\s*,\s*/);
    }
    if(limit[1]){
      return ' LIMIT ' + (limit[1] | 0) + ' OFFSET ' + (limit[0] | 0);
    }
    return ' LIMIT ' + (limit[0] | 0);
  }
}<|endoftext|>


<commit_before>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */
/**
 *  Mixtbar.js
 *
 *  Combined component for toolbar's and header's elements
 *
 *
 *  Created by Maxim.Kadushkin on 4/11/2017.
 *  Copyright (c) 2017 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'backbone'
], function (Backbone) {
    'use strict';

    Common.UI.Mixtbar = Common.UI.BaseView.extend((function () {
        var $boxTabs;
        var $scrollL;
        var optsFold = {timeout: 2000};
        var config = {};

        var onScrollTabs = function(opts, e) {
            var sv = $boxTabs.scrollLeft();
            if ( sv || opts == 'right' ) {
                $boxTabs.animate({scrollLeft: opts == 'left' ? sv - 100 : sv + 100}, 200);
            }
        }

        function onTabDblclick(e) {
            this.fireEvent('change:compact', [$(e.target).data('tab')]);
        }

        function onShowFullviewPanel(state) {
            if ( state )
                optsFold.$bar.addClass('cover'); else
                optsFold.$bar.removeClass('cover');
        }

        function onClickDocument(e) {
            if ( this.isFolded ) {
                if ( $(e.target).parents('.toolbar').length ){
                } else {
                    this.collapseToolbar();
                }
            }
        }

        return {
            $tabs: undefined,
            $panels: undefined,
            isFolded: false,

            initialize : function(options) {
                Common.UI.BaseView.prototype.initialize.call(this, options);

                this.$layout = $(options.template({
                    tabs: options.tabs
                }));

                config.tabs = options.tabs;
                $(document.body).on('click', onClickDocument.bind(this));
            },

            afterRender: function() {
                var me = this;

                $boxTabs = me.$('.tabs > ul');
                me.$tabs = $boxTabs.find('> li');
                me.$panels = me.$('.box-panels > .panel');
                optsFold.$bar = me.$('.toolbar');
                var $scrollR = me.$('.tabs .scroll.right');
                $scrollL = me.$('.tabs .scroll.left');

                $scrollL.on('click', onScrollTabs.bind(this, 'left'));
                $scrollR.on('click', onScrollTabs.bind(this, 'right'));

                $boxTabs.on('dblclick', '> .ribtab', onTabDblclick.bind(this));
            },

            isTabActive: function(tag) {
                var t = this.$tabs.filter('.active').find('> a');
                return t.length && t.data('tab') == tag;
            },

            setFolded: function(value) {
                this.isFolded = value;

                var me = this;
                if ( this.isFolded ) {
                    if (!optsFold.$box) optsFold.$box = me.$el.find('.box-controls');

                    optsFold.$bar.addClass('folded');
                    optsFold.$box.on({
                        mouseleave: function (e) {
                            optsFold.timer = setTimeout(me.collapseToolbar, optsFold.timeout);
                        },
                        mouseenter: function (e) {
                            clearTimeout(optsFold.timer);
                        }
                    });

                    // $(document.body).on('focus', 'input, textarea', function(e) {
                    // });
                    //
                    // $(document.body).on('blur', 'input, textarea', function(e) {
                    // });
                    //
                    // Common.NotificationCenter.on({
                    //     'modal:show': function(){
                    //     },
                    //     'modal:close': function(dlg) {
                    //     },
                    //     'modal:hide': function(dlg) {
                    //     },
                    //     'dataview:focus': function(e){
                    //     },
                    //     'dataview:blur': function(e){
                    //     },
                    //     'menu:show': function(e){
                    //     },
                    //     'menu:hide': function(e){
                    //     },
                    //     'edit:complete': _.bind(me.onEditComplete, me)
                    // });

                } else {
                    clearTimeout(optsFold.timer);
                    optsFold.$bar.removeClass('folded');
                    optsFold.$box.off();
                }
            },

            collapseToolbar: function() {
                optsFold.$bar && optsFold.$bar.removeClass('expanded');
                Common.UI.Menu.Manager.hideAll();
            },

            expandToolbar: function() {
                clearTimeout(optsFold.timer);

                optsFold.$bar.addClass('expanded');
                optsFold.timer = setTimeout(this.collapseToolbar, optsFold.timeout);
            },

            onResize: function(e) {
                if ( this.hasTabInvisible() ) {
                    if ( !$boxTabs.parent().hasClass('short') )
                        $boxTabs.parent().addClass('short');
                } else
                if ( $boxTabs.parent().hasClass('short') ) {
                    $boxTabs.parent().removeClass('short');
                }
            },

            setTab: function (tab) {
                if ( !tab ) {
                    onShowFullviewPanel.call(this, false);

                    if ( this.isFolded ) { /*this.collapseToolbar();*/ }
                    else tab = this.lastPanel;
                }

                if ( tab ) {
                    this.$tabs.removeClass('active');
                    this.$panels.removeClass('active');

                    var panel = this.$panels.filter('[data-tab=' + tab + ']');
                    if ( panel.length ) {
                        this.lastPanel = tab;
                        panel.addClass('active');
                    }

                    var $tp = this.$tabs.find('> a[data-tab=' + tab + ']').parent();
                    if ( $tp.length ) {
                        $tp.addClass('active');
                    }

                    if ( panel.length ) {
                        if ( this.isFolded ) this.expandToolbar();
                    } else {
                        onShowFullviewPanel.call(this, true);
                        if ( this.isFolded ) this.collapseToolbar();
                    }
                }
            },

            addTab: function (tab, panel, after) {
                function _get_tab_action(index) {
                    if (!config.tabs[index])
                        return _get_tab_action(--index);

                    return config.tabs[index].action;
                }

                var _tabTemplate = _.template('

<a href="#" data-tab="<%= action %>" data-title="<%= caption %>"><%= caption %>
');

                config.tabs[after + 1] = tab;
                var _after_action = _get_tab_action(after);

                var _elements = this.$tabs || this.$layout.find('.tabs');
                var $target = _elements.find('a[data-tab=' + _after_action + ']');
                if ( $target.length ) {
                    $target.parent().after( _tabTemplate(tab) );

                    if (panel) {
                        _elements = this.$panels || this.$layout.find('.box-panels > .panel');
                        $target = _elements.filter('[data-tab=' + _after_action + ']');

                        if ($target.length) {
                            $target.after(panel);
                        }
                    }

                    // synchronize matched elements
                    this.$tabs && (this.$tabs = $boxTabs.find('> li'));
                    this.$panels && (this.$panels = this.$el.find('.box-panels > .panel'));
                }
            },

            isCompact: function () {
                return this.isFolded;
            },

            hasTabInvisible: function() {
                var _left_bound_ = Math.round($boxTabs.offset().left),
                    _right_bound_ = Math.round(_left_bound_ + $boxTabs.width());

                var tab = this.$tabs.first().get(0);
                var rect = tab.getBoundingClientRect();

                if ( !(Math.round(rect.left) < _left_bound_) ) {
                    tab = this.$tabs.last().get(0);
                    rect = tab.getBoundingClientRect();

                    if (!(Math.round(rect.right) > _right_bound_))
                        return false;
                }

                return true;
            },

            setExtra: function (place, el) {
                if ( !!el ) {
                    if (this.$tabs) {
                    } else {
                        if (place == 'right') {
                            this.$layout.find('.extra.right').html(el);
                        } else if (place == 'left') {
                            this.$layout.find('.extra.left').html(el);
                        }
                    }
                }
            }
        };
    }()));
});
<commit_msg>[Common] debug toolbar compact mode<commit_after>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */
/**
 *  Mixtbar.js
 *
 *  Combined component for toolbar's and header's elements
 *
 *
 *  Created by Maxim.Kadushkin on 4/11/2017.
 *  Copyright (c) 2017 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'backbone'
], function (Backbone) {
    'use strict';

    Common.UI.Mixtbar = Common.UI.BaseView.extend((function () {
        var $boxTabs;
        var $scrollL;
        var optsFold = {timeout: 2000};
        var config = {};

        var onScrollTabs = function(opts, e) {
            var sv = $boxTabs.scrollLeft();
            if ( sv || opts == 'right' ) {
                $boxTabs.animate({scrollLeft: opts == 'left' ? sv - 100 : sv + 100}, 200);
            }
        }

        function onTabDblclick(e) {
            this.fireEvent('change:compact', [$(e.target).data('tab')]);
        }

        function onShowFullviewPanel(state) {
            if ( state )
                optsFold.$bar.addClass('cover'); else
                optsFold.$bar.removeClass('cover');
        }

        function onClickDocument(e) {
            if ( this.isFolded ) {
                if ( $(e.target).parents('.toolbar').length ){
                } else {
                    this.collapseToolbar();
                }
            }
        }

        return {
            $tabs: undefined,
            $panels: undefined,
            isFolded: false,

            initialize : function(options) {
                Common.UI.BaseView.prototype.initialize.call(this, options);

                this.$layout = $(options.template({
                    tabs: options.tabs
                }));

                config.tabs = options.tabs;
                $(document.body).on('click', onClickDocument.bind(this));
            },

            afterRender: function() {
                var me = this;

                $boxTabs = me.$('.tabs > ul');
                me.$tabs = $boxTabs.find('> li');
                me.$panels = me.$('.box-panels > .panel');
                optsFold.$bar = me.$('.toolbar');
                var $scrollR = me.$('.tabs .scroll.right');
                $scrollL = me.$('.tabs .scroll.left');

                $scrollL.on('click', onScrollTabs.bind(this, 'left'));
                $scrollR.on('click', onScrollTabs.bind(this, 'right'));

                $boxTabs.on('dblclick', '> .ribtab', onTabDblclick.bind(this));
            },

            isTabActive: function(tag) {
                var t = this.$tabs.filter('.active').find('> a');
                return t.length && t.data('tab') == tag;
            },

            setFolded: function(value) {
                this.isFolded = value;

                var me = this;
                if ( this.isFolded ) {
                    if (!optsFold.$box) optsFold.$box = me.$el.find('.box-controls');

                    optsFold.$bar.addClass('folded');
                    optsFold.$box.on({
                        mouseleave: function (e) {
                            optsFold.timer = setTimeout(me.collapseToolbar, optsFold.timeout);
                        },
                        mouseenter: function (e) {
                            clearTimeout(optsFold.timer);
                        }
                    });

                    // $(document.body).on('focus', 'input, textarea', function(e) {
                    // });
                    //
                    // $(document.body).on('blur', 'input, textarea', function(e) {
                    // });
                    //
                    // Common.NotificationCenter.on({
                    //     'modal:show': function(){
                    //     },
                    //     'modal:close': function(dlg) {
                    //     },
                    //     'modal:hide': function(dlg) {
                    //     },
                    //     'dataview:focus': function(e){
                    //     },
                    //     'dataview:blur': function(e){
                    //     },
                    //     'menu:show': function(e){
                    //     },
                    //     'menu:hide': function(e){
                    //     },
                    //     'edit:complete': _.bind(me.onEditComplete, me)
                    // });

                } else {
                    clearTimeout(optsFold.timer);
                    optsFold.$bar.removeClass('folded');
                    optsFold.$box.off();
                }
            },

            collapseToolbar: function() {
                if ( optsFold.$bar ) {
                    optsFold.$bar.removeClass('expanded');
                    optsFold.$bar.find('.tabs .ribtab').removeClass('active');
                }

                Common.UI.Menu.Manager.hideAll();
            },

            expandToolbar: function() {
                clearTimeout(optsFold.timer);

                optsFold.$bar.addClass('expanded');
                optsFold.timer = setTimeout(this.collapseToolbar, optsFold.timeout);
            },

            onResize: function(e) {
                if ( this.hasTabInvisible() ) {
                    if ( !$boxTabs.parent().hasClass('short') )
                        $boxTabs.parent().addClass('short');
                } else
                if ( $boxTabs.parent().hasClass('short') ) {
                    $boxTabs.parent().removeClass('short');
                }
            },

            setTab: function (tab) {
                if ( !tab ) {
                    onShowFullviewPanel.call(this, false);

                    if ( this.isFolded ) { /*this.collapseToolbar();*/ }
                    else tab = this.lastPanel;
                }

                if ( tab ) {
                    this.$tabs.removeClass('active');
                    this.$panels.removeClass('active');

                    var panel = this.$panels.filter('[data-tab=' + tab + ']');
                    if ( panel.length ) {
                        this.lastPanel = tab;
                        panel.addClass('active');
                    }

                    var $tp = this.$tabs.find('> a[data-tab=' + tab + ']').parent();
                    if ( $tp.length ) {
                        $tp.addClass('active');
                    }

                    if ( panel.length ) {
                        if ( this.isFolded ) this.expandToolbar();
                    } else {
                        onShowFullviewPanel.call(this, true);
                        if ( this.isFolded ) this.collapseToolbar();
                    }
                }
            },

            addTab: function (tab, panel, after) {
                function _get_tab_action(index) {
                    if (!config.tabs[index])
                        return _get_tab_action(--index);

                    return config.tabs[index].action;
                }

                var _tabTemplate = _.template('

<a href="#" data-tab="<%= action %>" data-title="<%= caption %>"><%= caption %>
');

                config.tabs[after + 1] = tab;
                var _after_action = _get_tab_action(after);

                var _elements = this.$tabs || this.$layout.find('.tabs');
                var $target = _elements.find('a[data-tab=' + _after_action + ']');
                if ( $target.length ) {
                    $target.parent().after( _tabTemplate(tab) );

                    if (panel) {
                        _elements = this.$panels || this.$layout.find('.box-panels > .panel');
                        $target = _elements.filter('[data-tab=' + _after_action + ']');

                        if ($target.length) {
                            $target.after(panel);
                        }
                    }

                    // synchronize matched elements
                    this.$tabs && (this.$tabs = $boxTabs.find('> li'));
                    this.$panels && (this.$panels = this.$el.find('.box-panels > .panel'));
                }
            },

            isCompact: function () {
                return this.isFolded;
            },

            hasTabInvisible: function() {
                var _left_bound_ = Math.round($boxTabs.offset().left),
                    _right_bound_ = Math.round(_left_bound_ + $boxTabs.width());

                var tab = this.$tabs.first().get(0);
                var rect = tab.getBoundingClientRect();

                if ( !(Math.round(rect.left) < _left_bound_) ) {
                    tab = this.$tabs.last().get(0);
                    rect = tab.getBoundingClientRect();

                    if (!(Math.round(rect.right) > _right_bound_))
                        return false;
                }

                return true;
            },

            setExtra: function (place, el) {
                if ( !!el ) {
                    if (this.$tabs) {
                    } else {
                        if (place == 'right') {
                            this.$layout.find('.extra.right').html(el);
                        } else if (place == 'left') {
                            this.$layout.find('.extra.left').html(el);
                        }
                    }
                }
            }
        };
    }()));
});
<|endoftext|>


<commit_before>/*
 * @flow
 */

/**
 * PrincipalsApi gives access to OpenLattice's REST API for getting user data.
 *
 * @module PrincipalsApi
 * @memberof lattice
 *
 * @example
 * import Lattice from 'lattice';
 * // Lattice.PrincipalsApi.get...
 *
 * @example
 * import { PrincipalsApi } from 'lattice';
 * // PrincipalsApi.get...
 */

import Logger from '../utils/Logger';
import { PRINCIPALS_API } from '../constants/ApiNames';
import {
  CURRENT_PATH,
  DB_PATH,
  ROLES_PATH,
  SEARCH_PATH,
  SYNC_PATH,
  USERS_PATH,
} from '../constants/UrlConstants';
import { Principal, isValidPrincipal } from '../models/Principal';
import { isNonEmptyArray, isNonEmptyString } from '../utils/LangUtils';
import { getApiAxiosInstance } from '../utils/axios';

const LOG = new Logger('PrincipalsApi');

/**
 * `GET /principals/roles`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Map<AclKey, Role>>} - a Promise that will resolve with a map of roles
 *
 * @example
 * PrincipalsApi.getAllRoles();
 */
function getAllRoles() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${ROLES_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/users`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Map<String, Auth0UserBasic>>} - a Promise that will resolve with a map of users
 *
 * @example
 * PrincipalsApi.getAllUsers();
 */
function getAllUsers() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${USERS_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/db`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Object>} - a Promise that will resolve with an object containing the username and credential
 *
 * @example
 * PrincipalsApi.getAtlasCredentials();
 */
function getAtlasCredentials() {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${DB_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/roles`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Set<SecurablePrincipal>>} - a Promise that will resolve with a set of role SecurablePrincipals
 *
 * @example
 * PrincipalsApi.getCurrentRoles();
 */
function getCurrentRoles() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${ROLES_PATH}/${CURRENT_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `POST /principals`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {Principal} principal
 * @returns {Promise<SecurablePrincipal>} - a Promise that will resolve with the SecurablePrincipal
 *
 * @example
 * PrincipalsApi.getSecurablePrincipal({
 *   "id": "auth0|openlattice",
 *   "type": "USER"
 * });
 */
function getSecurablePrincipal(principal :Principal) :Promise<*> {

  let errorMsg = '';

  if (!isValidPrincipal(principal)) {
    errorMsg = 'invalid parameter: principal must be a valid Principal';
    LOG.error(errorMsg, principal);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .post('/', principal)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/users/{userId}`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {string} userId
 * @returns {Promise}
 *
 * @example
 * PrincipalsApi.getUser("auth0|openlattice");
 */
function getUser(userId :string) :Promise<*> {

  let errorMsg = '';

  if (!isNonEmptyString(userId)) {
    errorMsg = 'invalid parameter: userId must be a non-empty string';
    LOG.error(errorMsg, userId);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${USERS_PATH}/${userId}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `POST /principals/users`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {Array<string>} userIds
 * @returns {Promise}
 *
 * @example
 * PrincipalsApi.getUsers(["auth0|openlattice", "google-oauth2|abc123"]);
 */
function getUsers(userIds :string[]) :Promise<Object> {

  let errorMsg = '';

  if (!isNonEmptyArray(userIds)) {
    errorMsg = 'invalid parameter: "userIds" must be a non-empty array';
    LOG.error(errorMsg, userIds);
    return Promise.reject(errorMsg);
  }

  if (!userIds.every(isNonEmptyString)) {
    errorMsg = 'invalid parameter: "userIds" must be an array of strings';
    LOG.error(errorMsg, userIds);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .post(`/${USERS_PATH}`, userIds)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/users/search/{searchQuery}`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {string} searchQuery
 * @returns {Promise<Map<String, Auth0UserBasic>>} - a Promise that will resolve with a map of matching users
 *
 * @example
 * PrincipalsApi.searchAllUsers("openlattice");
 */
function searchAllUsers(searchQuery :string) :Promise<*> {

  let errorMsg = '';

  if (!isNonEmptyString(searchQuery)) {
    errorMsg = 'invalid parameter: searchQuery must be a non-empty string';
    LOG.error(errorMsg, searchQuery);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${USERS_PATH}/${SEARCH_PATH}/${searchQuery}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/sync`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise} - a Promise that resolves without a value
 *
 * @example
 * PrincipalsApi.syncUser();
 */
function syncUser() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${SYNC_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

export {
  getAllRoles,
  getAllUsers,
  getAtlasCredentials,
  getCurrentRoles,
  getSecurablePrincipal,
  getUser,
  getUsers,
  searchAllUsers,
  syncUser,
};
<commit_msg>import CREDENTIAL_PATH and add regenerateCredential to PrincipalsApi<commit_after>/*
 * @flow
 */

/**
 * PrincipalsApi gives access to OpenLattice's REST API for getting user data.
 *
 * @module PrincipalsApi
 * @memberof lattice
 *
 * @example
 * import Lattice from 'lattice';
 * // Lattice.PrincipalsApi.get...
 *
 * @example
 * import { PrincipalsApi } from 'lattice';
 * // PrincipalsApi.get...
 */

import Logger from '../utils/Logger';
import { PRINCIPALS_API } from '../constants/ApiNames';
import {
  CREDENTIAL_PATH,
  CURRENT_PATH,
  DB_PATH,
  ROLES_PATH,
  SEARCH_PATH,
  SYNC_PATH,
  USERS_PATH,
} from '../constants/UrlConstants';
import { Principal, isValidPrincipal } from '../models/Principal';
import { isNonEmptyArray, isNonEmptyString } from '../utils/LangUtils';
import { getApiAxiosInstance } from '../utils/axios';

const LOG = new Logger('PrincipalsApi');

/**
 * `GET /principals/roles`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Map<AclKey, Role>>} - a Promise that will resolve with a map of roles
 *
 * @example
 * PrincipalsApi.getAllRoles();
 */
function getAllRoles() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${ROLES_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/users`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Map<String, Auth0UserBasic>>} - a Promise that will resolve with a map of users
 *
 * @example
 * PrincipalsApi.getAllUsers();
 */
function getAllUsers() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${USERS_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/db`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Object>} - a Promise that will resolve with an object containing the username and credential
 *
 * @example
 * PrincipalsApi.getAtlasCredentials();
 */
function getAtlasCredentials() {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${DB_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/roles`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise<Set<SecurablePrincipal>>} - a Promise that will resolve with a set of role SecurablePrincipals
 *
 * @example
 * PrincipalsApi.getCurrentRoles();
 */
function getCurrentRoles() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${ROLES_PATH}/${CURRENT_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `POST /principals`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {Principal} principal
 * @returns {Promise<SecurablePrincipal>} - a Promise that will resolve with the SecurablePrincipal
 *
 * @example
 * PrincipalsApi.getSecurablePrincipal({
 *   "id": "auth0|openlattice",
 *   "type": "USER"
 * });
 */
function getSecurablePrincipal(principal :Principal) :Promise<*> {

  let errorMsg = '';

  if (!isValidPrincipal(principal)) {
    errorMsg = 'invalid parameter: principal must be a valid Principal';
    LOG.error(errorMsg, principal);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .post('/', principal)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/users/{userId}`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {string} userId
 * @returns {Promise}
 *
 * @example
 * PrincipalsApi.getUser("auth0|openlattice");
 */
function getUser(userId :string) :Promise<*> {

  let errorMsg = '';

  if (!isNonEmptyString(userId)) {
    errorMsg = 'invalid parameter: userId must be a non-empty string';
    LOG.error(errorMsg, userId);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${USERS_PATH}/${userId}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `POST /principals/users`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {Array<string>} userIds
 * @returns {Promise}
 *
 * @example
 * PrincipalsApi.getUsers(["auth0|openlattice", "google-oauth2|abc123"]);
 */
function getUsers(userIds :string[]) :Promise<Object> {

  let errorMsg = '';

  if (!isNonEmptyArray(userIds)) {
    errorMsg = 'invalid parameter: "userIds" must be a non-empty array';
    LOG.error(errorMsg, userIds);
    return Promise.reject(errorMsg);
  }

  if (!userIds.every(isNonEmptyString)) {
    errorMsg = 'invalid parameter: "userIds" must be an array of strings';
    LOG.error(errorMsg, userIds);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .post(`/${USERS_PATH}`, userIds)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
* `POST /principals/db/credential`
*
* @static
* @memberof lattice.PrincipalsApi
* @returns {Promise} - a Promise that resolves without a value
*
* @example
* PrincipalsApi.regenerateCredential();
*/
function regenerateCredential() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .post(`/${DB_PATH}/${CREDENTIAL_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/users/search/{searchQuery}`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @param {string} searchQuery
 * @returns {Promise<Map<String, Auth0UserBasic>>} - a Promise that will resolve with a map of matching users
 *
 * @example
 * PrincipalsApi.searchAllUsers("openlattice");
 */
function searchAllUsers(searchQuery :string) :Promise<*> {

  let errorMsg = '';

  if (!isNonEmptyString(searchQuery)) {
    errorMsg = 'invalid parameter: searchQuery must be a non-empty string';
    LOG.error(errorMsg, searchQuery);
    return Promise.reject(errorMsg);
  }

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${USERS_PATH}/${SEARCH_PATH}/${searchQuery}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

/**
 * `GET /principals/sync`
 *
 * @static
 * @memberof lattice.PrincipalsApi
 * @returns {Promise} - a Promise that resolves without a value
 *
 * @example
 * PrincipalsApi.syncUser();
 */
function syncUser() :Promise<*> {

  return getApiAxiosInstance(PRINCIPALS_API)
    .get(`/${SYNC_PATH}`)
    .then((axiosResponse) => axiosResponse.data)
    .catch((error :Error) => {
      LOG.error(error);
      return Promise.reject(error);
    });
}

export {
  getAllRoles,
  getAllUsers,
  getAtlasCredentials,
  getCurrentRoles,
  getSecurablePrincipal,
  getUser,
  getUsers,
  regenerateCredential,
  searchAllUsers,
  syncUser,
};
<|endoftext|>


<commit_before>export default {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "definitions": {
        "alarm": {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string"
                },
                "userId": {
                    "type": "string"
                },
                "sensorId": {
                    "type": "string"
                },
                "rule": {
                    "type": "string"
                },
                "type": {
                    "type": "string",
                    "enum": ["realtime", "daily", "monthly"]
                },
                "thresholdRule": {
                    "type": "string"
                },
                "threshold": {
                    "type": "number"
                },
                "unitOfMeasurement": {
                    "type": "string"
                },
                "measurementType": {
                    "type": "string"
                }
            },
            "additionalProperties": false,
            "required": [
                "name",
                "userId",
                "sensorId",
                "rule",
                "type",
                "threshold",
                "thresholdRule",
                "unitOfMeasurement",
                "measurementType"
            ]
        }
    }
};
<commit_msg>Added mandatory field in alarms api<commit_after>export default {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "definitions": {
        "alarm": {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string"
                },
                "userId": {
                    "type": "string"
                },
                "sensorId": {
                    "type": "string"
                },
                "rule": {
                    "type": "string"
                },
                "type": {
                    "type": "string",
                    "enum": ["realtime", "daily", "monthly"]
                },
                "thresholdRule": {
                    "type": "string"
                },
                "threshold": {
                    "type": "number"
                },
                "unitOfMeasurement": {
                    "type": "string"
                },
                "measurementType": {
                    "type": "string"
                },
                "email": {
                    "type": "boolean"
                }
            },
            "additionalProperties": false,
            "required": [
                "name",
                "userId",
                "sensorId",
                "rule",
                "type",
                "threshold",
                "thresholdRule",
                "unitOfMeasurement",
                "measurementType",
                "email"
            ]
        }
    }
};
<|endoftext|>