UNPKG

@codetanzania/majifix-common

Version:
327 lines (290 loc) 12 kB
import { forEach, isEmpty, join, split, snakeCase } from 'lodash'; import { parallel } from 'async'; import { mergeObjects, idOf } from '@lykmapipo/common'; import { getString, getNumber } from '@lykmapipo/env'; import { toCollectionName, copyInstance, isInstance, model } from '@lykmapipo/mongoose-common'; // // constants // /* models name */ const MODEL_NAME_ACCOUNT = 'Account'; const MODEL_NAME_ALERT = 'Alert'; const MODEL_NAME_CONTENT = 'Content'; const MODEL_NAME_CHANGELOG = 'ChangeLog'; const MODEL_NAME_ITEM = 'Predefine'; const MODEL_NAME_JURISDICTION = 'Jurisdiction'; const MODEL_NAME_PARTY = 'Party'; const MODEL_NAME_PERMISSION = 'Permission'; const MODEL_NAME_PREDEFINE = 'Predefine'; const MODEL_NAME_PRIORITY = 'Priority'; const MODEL_NAME_ROLE = 'Role'; const MODEL_NAME_STATUS = 'Status'; const MODEL_NAME_SERVICEGROUP = 'ServiceGroup'; const MODEL_NAME_SERVICE = 'Service'; const MODEL_NAME_SERVICEREQUEST = 'ServiceRequest'; const MODEL_NAME_SERVICETYPE = 'Predefine'; const MODEL_NAME_ZONE = 'Predefine'; /* collections name */ const COLLECTION_NAME_ACCOUNT = toCollectionName(MODEL_NAME_ACCOUNT); const COLLECTION_NAME_ALERT = toCollectionName(MODEL_NAME_ALERT); const COLLECTION_NAME_CONTENT = toCollectionName(MODEL_NAME_CONTENT); const COLLECTION_NAME_CHANGELOG = toCollectionName(MODEL_NAME_CHANGELOG); const COLLECTION_NAME_ITEM = toCollectionName(MODEL_NAME_ITEM); const COLLECTION_NAME_JURISDICTION = toCollectionName( MODEL_NAME_JURISDICTION ); const COLLECTION_NAME_PARTY = toCollectionName(MODEL_NAME_PARTY); const COLLECTION_NAME_PERMISSION = toCollectionName( MODEL_NAME_PERMISSION ); const COLLECTION_NAME_PREDEFINE = toCollectionName(MODEL_NAME_PREDEFINE); const COLLECTION_NAME_PRIORITY = toCollectionName(MODEL_NAME_PRIORITY); const COLLECTION_NAME_ROLE = toCollectionName(MODEL_NAME_ROLE); const COLLECTION_NAME_STATUS = toCollectionName(MODEL_NAME_STATUS); const COLLECTION_NAME_SERVICEGROUP = toCollectionName( MODEL_NAME_SERVICEGROUP ); const COLLECTION_NAME_SERVICE = toCollectionName(MODEL_NAME_SERVICE); const COLLECTION_NAME_SERVICEREQUEST = toCollectionName( MODEL_NAME_SERVICEREQUEST ); const COLLECTION_NAME_SERVICETYPE = toCollectionName( MODEL_NAME_SERVICETYPE ); const COLLECTION_NAME_ZONE = toCollectionName(MODEL_NAME_ZONE); /* paths name */ const PATH_NAME_ACCOUNT = 'account'; const PATH_NAME_ASSIGNEE = 'assignee'; const PATH_NAME_CONTENT = 'content'; const PATH_NAME_ITEM = 'item'; const PATH_NAME_JURISDICTION = 'jurisdiction'; const PATH_NAME_OPERATOR = 'operator'; const PATH_NAME_PARTY = 'party'; const PATH_NAME_PERMISSION = 'permission'; const PATH_NAME_PRIORITY = 'priority'; const PATH_NAME_ROLE = 'role'; const PATH_NAME_STATUS = 'status'; const PATH_NAME_SERVICEGROUP = 'group'; const PATH_NAME_SERVICE = 'service'; const PATH_NAME_SERVICEREQUEST = 'request'; const PATH_NAME_SERVICETYPE = 'type'; const PATH_NAME_ZONE = 'zone'; /* population options */ const POPULATION_MAX_DEPTH = 1; const POPULATION_DEFAULT = { maxDepth: POPULATION_MAX_DEPTH }; /* pedefines namespaces */ // TODO use models name const PREDEFINE_NAMESPACE_PRIORITY = 'Priority'; const PREDEFINE_NAMESPACE_STATUS = 'Status'; const PREDEFINE_NAMESPACE_SERVICEGROUP = 'ServiceGroup'; const PREDEFINE_NAMESPACE_SERVICETYPE = 'ServiceType'; const PREDEFINE_NAMESPACE_SERVICE = 'Service'; const PREDEFINE_NAMESPACE_BLOCKREASON = 'BlockReason'; /* pedefines buckets */ // TODO use collections name const PREDEFINE_BUCKET_PRIORITY = 'priorities'; const PREDEFINE_BUCKET_STATUS = 'status'; const PREDEFINE_BUCKET_SERVICEGROUP = 'servicegroups'; const PREDEFINE_BUCKET_SERVICETYPE = 'servicetypes'; const PREDEFINE_BUCKET_SERVICE = 'services'; const PREDEFINE_BUCKET_BLOCKREASON = 'blockreasons'; /* visibilities */ const VISIBILITY_PUBLIC = 'Public'; const VISIBILITY_PRIVATE = 'Private'; const VISIBILITIES = [VISIBILITY_PRIVATE, VISIBILITY_PUBLIC]; /* counters */ const COUNTER_YEAR_FORMAT = getString('COUNTER_YEAR_FORMAT', 'YY'); const COUNTER_PREFIX = getString('COUNTER_PREFIX', ''); const COUNTER_PAD_SIZE = getNumber('COUNTER_PAD_SIZE', 4); /* contact methods */ const CONTACT_METHOD_PHONE_CALL = 'Call'; const CONTACT_METHOD_EMAIL = 'Email'; const CONTACT_METHOD_SMS = 'SMS'; const CONTACT_METHOD_USSD = 'USSD'; const CONTACT_METHOD_VISIT = 'Visit'; const CONTACT_METHOD_LETTER = 'Letter'; const CONTACT_METHOD_FAX = 'Fax'; const CONTACT_METHOD_MOBILE_APP = 'Mobile'; const CONTACT_METHOD_WEBSITE = 'Website'; const CONTACT_METHODS = [ CONTACT_METHOD_PHONE_CALL, CONTACT_METHOD_EMAIL, CONTACT_METHOD_SMS, CONTACT_METHOD_USSD, CONTACT_METHOD_VISIT, CONTACT_METHOD_LETTER, CONTACT_METHOD_FAX, CONTACT_METHOD_MOBILE_APP, CONTACT_METHOD_WEBSITE, ]; const CONTACT_METHODS_WEB = [ CONTACT_METHOD_PHONE_CALL, CONTACT_METHOD_EMAIL, CONTACT_METHOD_SMS, CONTACT_METHOD_VISIT, CONTACT_METHOD_LETTER, CONTACT_METHOD_FAX, ]; /* workspaces */ const WORKSPACE_CALL_CENTER = 'Call Center'; const WORKSPACE_CUSTOMER_CARE = 'Customer Care'; const WORKSPACE_TECHNICAL = 'Technical'; const WORKSPACE_SURVEY = 'Survey'; const WORKSPACE_OTHER = 'Other'; const WORKSPACES = [ WORKSPACE_CALL_CENTER, WORKSPACE_CUSTOMER_CARE, WORKSPACE_TECHNICAL, WORKSPACE_SURVEY, WORKSPACE_OTHER, ]; /* party relation name */ const RELATION_NAME_INTERNAL = 'Internal'; const RELATION_NAME_CUSTOMER = 'Customer'; const RELATION_NAME_CIVILIAN = 'Civilian'; const RELATION_NAME_AGENCY = 'Agency'; const RELATION_NAME_APP = 'App'; const RELATION_NAMES = [ RELATION_NAME_INTERNAL, RELATION_NAME_CUSTOMER, RELATION_NAME_CIVILIAN, RELATION_NAME_AGENCY, RELATION_NAME_APP, ]; /* party relation types */ const RELATION_TYPE_WORKER = 'Worker'; const RELATION_TYPE_INDIVIDUAL = 'Individual'; const RELATION_TYPE_ORGANIZATION = 'Organization'; const RELATION_TYPE_APP = 'App'; const RELATION_TYPES = [ RELATION_TYPE_WORKER, RELATION_TYPE_INDIVIDUAL, RELATION_TYPE_ORGANIZATION, RELATION_TYPE_APP, ]; // // utilities // /** * @function unlocalize * @name unlocalize * @description Flatten a given localize schema path value * to unlocalized object * @param {string} path prefix to used on unlocalized key * @param {object} data object to unlocalized * @returns {object} unlocalize schema paths * @author lally elias <lallyelias87@gmail.com> * @license MIT * @since 0.1.0 * @version 0.1.0 * @static * @public * @example * * const obj = mergeObjects('group',{ en: 'One', sw: 'Moja' }); * // => { group_en: 'One', group_sw: 'Moja' }; */ const unlocalize = (path, data) => { // prepare unlocalized data const unlocalized = {}; // prepare localized const localized = copyInstance(data); // unlocalize each locale for a path forEach(localized, (value, locale) => { // handle default locale const DEFAULT_LOCALE = getString('DEFAULT_LOCALE', 'en'); if (locale === DEFAULT_LOCALE) { unlocalized[path] = value; } // handle other locales const key = `${path}_${locale}`; unlocalized[key] = value; }); // return unlocalized object return mergeObjects(unlocalized); }; /** * @function checkDependenciesFor * @name checkDependenciesFor * @description Check if there are dependencies with instances already * saved before deleting the parent model * @param {object} parent valid mongoose model instance * @param {object} optns valid options * @param {string} optns.path parent path on dependant * @param {boolean} [optns.self=false] whether to perform self check for * existence, for hierarchical models * @param {string[]} optns.dependencies model name of the dependants * @param {Function} done a callback to invoke on success or failure * @returns {Function} dependencies cleaner * @author lally elias <lallyelias87@gmail.com> * @license MIT * @since 0.5.0 * @version 0.1.0 * @static * @public * @example * * const path = 'jurisdiction'; * const dependencies = ['Service']; * checkDependenciesFor(instance, { path, dependencies }, done); */ const checkDependenciesFor = (parent, optns, done) => { // ensure options const options = mergeObjects(optns); // obtain path const { path, dependencies } = options; // ensure valid model instance for parent if (!isInstance(parent)) { return done(); } // ensure parent path if (isEmpty(path)) { return done(); } // ensure dependencies if (isEmpty(dependencies)) { return done(); } // accumaltor for dependencies checker const dependants = {}; // check for provided dependency const checkDependency = dependency => { const dependantKey = `check${dependency}Dependency`; const Dependant = model(dependency); const dependantLabel = join(split(snakeCase(dependency), '_'), ' '); const criteria = { [path]: idOf(parent), }; // restrict per existing model // collect dependant cleaner if (Dependant && !isEmpty(criteria)) { dependants[dependantKey] = next => { Dependant.countDocuments(criteria, (error, count) => { let exception = error; // warn can not delete due to dependencies if (count && count > 0) { const errorMessage = ` Fail to Delete. ${count} ${dependantLabel} depend on it `; exception = new Error(errorMessage); } // ensure error status if (exception && !exception.status) { exception.status = 400; } // return next(exception, parent); }); }; } }; // check for each dependency forEach(dependencies, checkDependency); // check for all dependencies if (!isEmpty(dependants)) { return parallel(dependants, error => done(error, parent)); } // continue return done(); }; export { COLLECTION_NAME_ACCOUNT, COLLECTION_NAME_ALERT, COLLECTION_NAME_CHANGELOG, COLLECTION_NAME_CONTENT, COLLECTION_NAME_ITEM, COLLECTION_NAME_JURISDICTION, COLLECTION_NAME_PARTY, COLLECTION_NAME_PERMISSION, COLLECTION_NAME_PREDEFINE, COLLECTION_NAME_PRIORITY, COLLECTION_NAME_ROLE, COLLECTION_NAME_SERVICE, COLLECTION_NAME_SERVICEGROUP, COLLECTION_NAME_SERVICEREQUEST, COLLECTION_NAME_SERVICETYPE, COLLECTION_NAME_STATUS, COLLECTION_NAME_ZONE, CONTACT_METHODS, CONTACT_METHODS_WEB, CONTACT_METHOD_EMAIL, CONTACT_METHOD_FAX, CONTACT_METHOD_LETTER, CONTACT_METHOD_MOBILE_APP, CONTACT_METHOD_PHONE_CALL, CONTACT_METHOD_SMS, CONTACT_METHOD_USSD, CONTACT_METHOD_VISIT, CONTACT_METHOD_WEBSITE, COUNTER_PAD_SIZE, COUNTER_PREFIX, COUNTER_YEAR_FORMAT, MODEL_NAME_ACCOUNT, MODEL_NAME_ALERT, MODEL_NAME_CHANGELOG, MODEL_NAME_CONTENT, MODEL_NAME_ITEM, MODEL_NAME_JURISDICTION, MODEL_NAME_PARTY, MODEL_NAME_PERMISSION, MODEL_NAME_PREDEFINE, MODEL_NAME_PRIORITY, MODEL_NAME_ROLE, MODEL_NAME_SERVICE, MODEL_NAME_SERVICEGROUP, MODEL_NAME_SERVICEREQUEST, MODEL_NAME_SERVICETYPE, MODEL_NAME_STATUS, MODEL_NAME_ZONE, PATH_NAME_ACCOUNT, PATH_NAME_ASSIGNEE, PATH_NAME_CONTENT, PATH_NAME_ITEM, PATH_NAME_JURISDICTION, PATH_NAME_OPERATOR, PATH_NAME_PARTY, PATH_NAME_PERMISSION, PATH_NAME_PRIORITY, PATH_NAME_ROLE, PATH_NAME_SERVICE, PATH_NAME_SERVICEGROUP, PATH_NAME_SERVICEREQUEST, PATH_NAME_SERVICETYPE, PATH_NAME_STATUS, PATH_NAME_ZONE, POPULATION_DEFAULT, POPULATION_MAX_DEPTH, PREDEFINE_BUCKET_BLOCKREASON, PREDEFINE_BUCKET_PRIORITY, PREDEFINE_BUCKET_SERVICE, PREDEFINE_BUCKET_SERVICEGROUP, PREDEFINE_BUCKET_SERVICETYPE, PREDEFINE_BUCKET_STATUS, PREDEFINE_NAMESPACE_BLOCKREASON, PREDEFINE_NAMESPACE_PRIORITY, PREDEFINE_NAMESPACE_SERVICE, PREDEFINE_NAMESPACE_SERVICEGROUP, PREDEFINE_NAMESPACE_SERVICETYPE, PREDEFINE_NAMESPACE_STATUS, RELATION_NAMES, RELATION_NAME_AGENCY, RELATION_NAME_APP, RELATION_NAME_CIVILIAN, RELATION_NAME_CUSTOMER, RELATION_NAME_INTERNAL, RELATION_TYPES, RELATION_TYPE_APP, RELATION_TYPE_INDIVIDUAL, RELATION_TYPE_ORGANIZATION, RELATION_TYPE_WORKER, VISIBILITIES, VISIBILITY_PRIVATE, VISIBILITY_PUBLIC, WORKSPACES, WORKSPACE_CALL_CENTER, WORKSPACE_CUSTOMER_CARE, WORKSPACE_OTHER, WORKSPACE_SURVEY, WORKSPACE_TECHNICAL, checkDependenciesFor, unlocalize };