UNPKG

@codetanzania/majifix-priority

Version:

A representation an entity which provides a way to prioritize service and service request(issues) in order of their importance.

597 lines (548 loc) 15.6 kB
'use strict'; const common = require('@lykmapipo/common'); const env = require('@lykmapipo/env'); const expressRestActions = require('@lykmapipo/express-rest-actions'); const _ = require('lodash'); const mongooseCommon = require('@lykmapipo/mongoose-common'); const mongooseLocaleSchema = require('mongoose-locale-schema'); const actions = require('mongoose-rest-actions'); const exportable = require('@lykmapipo/mongoose-exportable'); const majifixJurisdiction = require('@codetanzania/majifix-jurisdiction'); const majifixCommon = require('@codetanzania/majifix-common'); /* constants */ const OPTION_SELECT = { name: 1, color: 1 }; const OPTION_AUTOPOPULATE = { select: OPTION_SELECT, maxDepth: majifixCommon.POPULATION_MAX_DEPTH, }; const SCHEMA_OPTIONS = { collection: majifixCommon.COLLECTION_NAME_PRIORITY }; const INDEX_UNIQUE = { jurisdiction: 1, ...mongooseLocaleSchema.localizedIndexesFor('name'), }; /** * @module Priority * @name Priority * @description A representation an entity which provides a way * to prioritize service and service request(issues) * in order of their importance. * * @requires https://github.com/CodeTanzania/majifix-jurisdiction * @author Benson Maruchu <benmaruchu@gmail.com> * @author lally elias <lallyelias87@gmail.com> * * @license MIT * @since 0.1.0 * @version 1.0.0 * @public */ const PrioritySchema = mongooseCommon.createSchema( { /** * @name jurisdiction * @description jurisdiction under which this priority belongs. * * This is applicable where multiple jurisdiction(s) utilize * same Majifix system(or platform). * * If not available a priority is applicable to all jurisdictions. * * @type {object} * @property {object} type - schema(data) type * @property {string} ref - referenced collection * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - jurisdiction population options * @property {object} autopopulate.select - jurisdiction fields to * select when populating * @property {boolean} index - ensure database index * * @since 0.1.0 * @version 1.0.0 * @instance */ jurisdiction: { type: mongooseCommon.ObjectId, ref: majifixJurisdiction.Jurisdiction.MODEL_NAME, exists: { refresh: true, select: majifixJurisdiction.Jurisdiction.OPTION_SELECT, }, autopopulate: majifixJurisdiction.Jurisdiction.OPTION_AUTOPOPULATE, index: true, }, /** * @name name * @description Human readable name of the priority * e.g High, Low, Medium. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field to be exported * @property {boolean} searchable - allow for searching * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.0.0 * @instance */ name: mongooseLocaleSchema.localize({ type: String, trim: true, index: true, taggable: true, exportable: true, searchable: true, fake: { generator: 'commerce', type: 'productName', unique: true, }, }), /** * @name weight * @description Weight of the priority to help in ordering * service request(issue) based on priority. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} index - ensure database index * @property {boolean} exportable - allow field to be exported * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.0.0 * @instance */ weight: { type: Number, index: true, exportable: true, default: 0, fake: true, }, /** * @name color * @description A color code used to differentiate a service request * priority visually. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} uppercase - force upper-casing * @property {boolean} exportable - allow field to be exported * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.0.0 * @instance */ color: { type: String, trim: true, exportable: true, uppercase: true, default: () => common.randomColor(), fake: true, }, /** * @name default * @description Tells whether a priority is the default. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} index - ensure database index * @property {boolean} exportable - allow field to be exported * @property {boolean} default - default value set when none provided * @property {object|boolean} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * false * */ default: { type: Boolean, index: true, exportable: true, default: false, fake: true, }, }, SCHEMA_OPTIONS, actions, exportable ); /* *------------------------------------------------------------------------------ * Indexes *------------------------------------------------------------------------------ */ /** * @name index * @description ensure unique compound index on priority name and jurisdiction * to force unique priority definition * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @private */ PrioritySchema.index(INDEX_UNIQUE, { unique: true }); /* *------------------------------------------------------------------------------ * Hooks *------------------------------------------------------------------------------ */ /** * @name validate * @description priority schema pre validation hook * @param {Function} done callback to invoke on success or error * @returns {object|Error} valid instance or error * @since 0.1.0 * @version 1.0.0 * @private */ PrioritySchema.pre('validate', function preValidate(next) { return this.preValidate(next); }); /* *------------------------------------------------------------------------------ * Instance *------------------------------------------------------------------------------ */ /** * @name preValidate * @description priority schema pre validation hook logic * @param {Function} done callback to invoke on success or error * @returns {object|Error} valid instance or error * @since 0.1.0 * @version 1.0.0 * @instance */ PrioritySchema.methods.preValidate = function preValidate(done) { // ensure name for all locales this.name = mongooseLocaleSchema.localizedValuesFor(this.name); // set default color if not set if (_.isEmpty(this.color)) { this.color = common.randomColor(); } // continue return done(null, this); }; /** * @name beforeDelete * @function beforeDelete * @description pre delete priority logics * @param {Function} done callback to invoke on success or error * @returns {object|Error} valid instance or error * @since 0.1.0 * @version 1.0.0 * @instance */ PrioritySchema.methods.beforeDelete = function beforeDelete(done) { // restrict delete if // collect dependencies model name const dependencies = [ majifixCommon.MODEL_NAME_SERVICEGROUP, majifixCommon.MODEL_NAME_SERVICE, majifixCommon.MODEL_NAME_SERVICEREQUEST, ]; // path to check const path = majifixCommon.PATH_NAME_PRIORITY; // do check dependencies return majifixCommon.checkDependenciesFor(this, { path, dependencies }, done); }; /* *------------------------------------------------------------------------------ * Statics *------------------------------------------------------------------------------ */ /* static constants */ PrioritySchema.statics.MODEL_NAME = majifixCommon.MODEL_NAME_PRIORITY; PrioritySchema.statics.OPTION_SELECT = OPTION_SELECT; PrioritySchema.statics.OPTION_AUTOPOPULATE = OPTION_AUTOPOPULATE; /** * @name findDefault * @function findDefault * @description find default priority * @param {Function} done a callback to invoke on success or failure * @returns {Priority} default priority * * @since 0.1.0 * @version 1.0.0 * @static * @deprecated */ PrioritySchema.statics.findDefault = done => { // refs const Priority = mongooseCommon.model(majifixCommon.MODEL_NAME_PRIORITY); // obtain default priority return Priority.getOneOrDefault({}, done); }; /** * @name prepareSeedCriteria * @function prepareSeedCriteria * @description define seed data criteria * @param {object} seed priority to be seeded * @returns {object} packed criteria for seeding * * @author lally elias <lallyelias87@gmail.com> * @since 1.5.0 * @version 0.1.0 * @static */ PrioritySchema.statics.prepareSeedCriteria = seed => { const names = mongooseLocaleSchema.localizedKeysFor('name'); const copyOfSeed = seed; copyOfSeed.name = mongooseLocaleSchema.localizedValuesFor(seed.name); const criteria = common.idOf(copyOfSeed) ? _.pick(copyOfSeed, '_id') : _.pick(copyOfSeed, 'jurisdiction', ...names); return criteria; }; /** * @name getOneOrDefault * @function getOneOrDefault * @description Find existing priority or default based on given criteria * @param {object} criteria valid query criteria * @param {Function} done callback to invoke on success or error * @returns {object|Error} found priority or error * * @author lally elias <lallyelias87@gmail.com> * @since 1.5.0 * @version 0.1.0 * @static * @example * * const criteria = { _id: '...'}; * Priority.getOneOrDefault(criteria, (error, found) => { ... }); * */ PrioritySchema.statics.getOneOrDefault = (criteria, done) => { // normalize criteria const { _id, ...filters } = common.mergeObjects(criteria); const allowId = !_.isEmpty(_id); const allowFilters = !_.isEmpty(filters); const byDefault = common.mergeObjects({ default: true }); const byId = common.mergeObjects({ _id }); const byFilters = common.mergeObjects(filters); const or = common.compact([ allowId ? byId : undefined, allowFilters ? byFilters : undefined, byDefault, ]); const filter = { $or: or }; // refs const Priority = mongooseCommon.model(majifixCommon.MODEL_NAME_PRIORITY); // query return Priority.findOne(filter) .orFail() .exec(done); }; /* export priority model */ const Priority = mongooseCommon.model( majifixCommon.MODEL_NAME_PRIORITY, PrioritySchema ); /* constants */ const API_VERSION = env.getString('API_VERSION', '1.0.0'); const PATH_SINGLE = '/priorities/:id'; const PATH_LIST = '/priorities'; const PATH_EXPORT = '/priorities/export'; const PATH_SCHEMA = '/priorities/schema/'; const PATH_JURISDICTION = '/jurisdictions/:jurisdiction/priorities'; /** * @name PriorityHttpRouter * @namespace PriorityHttpRouter * * @description A representation an entity which provides a way * to prioritize service and service request(issues) * in order of their importance. * * @author Benson Maruchu <benmaruchu@gmail.com> * @author lally elias <lallyelias87@gmail.com> * @license MIT * @since 0.1.0 * @version 1.0.0 * @public */ const router = new expressRestActions.Router({ version: API_VERSION, }); /** * @memberof PriorityHttpRouter * @name GetPriorities * @description Returns a list of priorities */ router.get( PATH_LIST, expressRestActions.getFor({ get: (options, done) => Priority.get(options, done), }) ); /** * @name GetPrioritySchema * @memberof PriorityHttpRouter * @description Returns priority json schema definition */ router.get( PATH_SCHEMA, expressRestActions.schemaFor({ getSchema: (query, done) => { const jsonSchema = Priority.jsonSchema(); return done(null, jsonSchema); }, }) ); /** * @name ExportPriorities * @memberof PriorityHttpRouter * @description Export priorities as csv */ router.get( PATH_EXPORT, expressRestActions.downloadFor({ download: (options, done) => { const fileName = `priorities_exports_${Date.now()}.csv`; const readStream = Priority.exportCsv(options); return done(null, { fileName, readStream }); }, }) ); /** * @name PostPriority * @memberof PriorityHttpRouter * @description Create new Priority */ router.post( PATH_LIST, expressRestActions.postFor({ post: (body, done) => Priority.post(body, done), }) ); /** * @name GetPriority * @memberof PriorityHttpRouter * @description Get existing priority */ router.get( PATH_SINGLE, expressRestActions.getByIdFor({ getById: (options, done) => Priority.getById(options, done), }) ); /** * @name PatchPriority * @memberof PriorityHttpRouter * @description Patch existing priority */ router.patch( PATH_SINGLE, expressRestActions.patchFor({ patch: (options, done) => Priority.patch(options, done), }) ); /** * @name PutPriority * @memberof PriorityHttpRouter * @description Put existing priority */ router.put( PATH_SINGLE, expressRestActions.putFor({ put: (options, done) => Priority.put(options, done), }) ); /** * @name DeletePriority * @memberof PriorityHttpRouter * @description Delete existing priority */ router.delete( PATH_SINGLE, expressRestActions.deleteFor({ del: (options, done) => Priority.del(options, done), soft: true, }) ); /** * @name GetJurisdictionPriorities * @memberof PriorityHttpRouter * @description Returns a list of priorities of specified jurisdiction */ router.get( PATH_JURISDICTION, expressRestActions.getFor({ get: (options, done) => Priority.get(options, done), }) ); /** * @name majifix-priority * @version 0.1.0 * @description A representation an entity which provides a way * to prioritize service and service request(issues) * in order of their importance. * * @author Benson Maruchu <benmaruchu@gmail.com> * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @license MIT * @example * * const { Priority, start } = require('@codetanzania/majifix-priority'); * start(error => { ... }); * */ /** * @name info * @description package information * @type {object} * * @author lally elias <lallyelias87@gmail.com> * @author rijkerd <richardaggrey7@gmail.com> * @since 1.0.0 * @version 0.1.0 */ const info = common.pkg( `${__dirname}/package.json`, 'name', 'description', 'version', 'license', 'homepage', 'repository', 'bugs', 'sandbox', 'contributors' ); /** * @name apiVersion * @description http router api version * @type {string} * * @author lally elias <lallyelias87@gmail.com> * @author rijkerd <richardaggrey7@gmail.com> * @since 0.1.0 * @version 0.1.0 */ const apiVersion = env.apiVersion(); Object.defineProperty(exports, 'start', { enumerable: true, get: function() { return expressRestActions.start; }, }); exports.Priority = Priority; exports.apiVersion = apiVersion; exports.info = info; exports.priorityRouter = router;