UNPKG

@codetanzania/ewea-event

Version:

A representation of an entity which define and track an instance(or occurrence) of an emergency(or disaster) event.

1,739 lines (1,670 loc) 86.7 kB
import { COLLECTION_NAME_EVENT, POPULATION_MAX_DEPTH, COLLECTION_NAME_EVENTCHANGELOG, MODEL_NAME_EVENT, MODEL_NAME_EVENTCHANGELOG } from '@codetanzania/ewea-internals'; import { idOf, uniq, parseTemplate, join, compact, mergeObjects, pkg } from '@lykmapipo/common'; import { getString, apiVersion as apiVersion$1 } from '@lykmapipo/env'; import { isObjectId, ObjectId, model, createSchema, copyInstance, connect } from '@lykmapipo/mongoose-common'; import { mount } from '@lykmapipo/express-common'; import { Router, getFor, schemaFor, downloadFor, postFor, getByIdFor, patchFor, putFor, deleteFor, start as start$1 } from '@lykmapipo/express-rest-actions'; import { FileTypes, uploaderFor, createModels } from '@lykmapipo/file'; import { parallel, waterfall } from 'async'; import { map, get, pick, forEach, omit, includes, union } from 'lodash'; import '@lykmapipo/mongoose-sequenceable'; import actions from 'mongoose-rest-actions'; import exportable from '@lykmapipo/mongoose-exportable'; import { Predefine } from '@lykmapipo/predefine'; import { sendCampaign, Contact } from '@lykmapipo/postman'; import { Point } from 'mongoose-geojson-schemas'; import { Party } from '@codetanzania/emis-stakeholder'; import moment from 'moment'; // common constants const DEFAULT_COUNTRY_CODE = getString('DEFAULT_COUNTRY_CODE', 'TZ'); const COUNTRY_CODE = getString('COUNTRY_CODE', DEFAULT_COUNTRY_CODE); // event schema const EVENT_SCHEMA_OPTIONS = { collection: COLLECTION_NAME_EVENT }; // event options const EVENT_OPTION_SELECT = { group: 1, type: 1, number: 1 }; const EVENT_OPTION_AUTOPOPULATE = { select: EVENT_OPTION_SELECT, maxDepth: POPULATION_MAX_DEPTH, }; // event stages const EVENT_STAGE_ALERT = 'Alert'; const EVENT_STAGE_EVENT = 'Event'; const EVENT_STAGES = [EVENT_STAGE_ALERT, EVENT_STAGE_EVENT]; // changelog schema const CHANGELOG_SCHEMA_OPTIONS = { collection: COLLECTION_NAME_EVENTCHANGELOG, }; // changelog use const CHANGELOG_USE_CHANGE = 'change'; const CHANGELOG_USE_NOTIFICATION = 'notification'; const CHANGELOG_USE_NEED = 'need'; const CHANGELOG_USE_EFFECT = 'effect'; const CHANGELOG_USE_ASSESSMENT = 'assessment'; const CHANGELOG_USE_ACTION = 'action'; const CHANGELOG_USE_EXPOSURE = 'exposure'; const CHANGELOG_USES = [ CHANGELOG_USE_CHANGE, CHANGELOG_USE_NOTIFICATION, CHANGELOG_USE_NEED, CHANGELOG_USE_EFFECT, CHANGELOG_USE_ASSESSMENT, CHANGELOG_USE_ACTION, CHANGELOG_USE_EXPOSURE, ]; // relation options const PREDEFINE_OPTION_SELECT = { 'strings.name': 1, 'strings.color': 1, 'strings.code': 1, }; const PREDEFINE_OPTION_AUTOPOPULATE = { select: PREDEFINE_OPTION_SELECT, maxDepth: POPULATION_MAX_DEPTH, }; const EVENT_UPDATE_ARRAY_FIELDS = ['areas', 'agencies', 'focals']; const EVENT_UPDATE_IGNORED_FIELDS = [ '_id', 'id', 'event', 'keyword', 'number', // 'location', ignore for changelog // 'address', ignore for changelog 'createdAt', 'use', ]; const EVENT_CHANGELOG_RELATED_FIELDS = [ 'group', 'type', 'level', 'severity', 'certainty', 'status', 'urgency', ]; const EVENT_RELATION_PREDEFINE_FIELDS = { // group: undefined, // TODO: default group(Unknown) type: undefined, // TODO: default type(Unknown) level: { 'strings.name.en': 'White', namespace: 'EventLevel' }, severity: { 'strings.name.en': 'Unknown', namespace: 'EventSeverity' }, certainty: { 'strings.name.en': 'Unknown', namespace: 'EventCertainty' }, status: { 'strings.name.en': 'Actual', namespace: 'EventStatus' }, urgency: { 'strings.name.en': 'Unknown', namespace: 'EventUrgency' }, response: { 'strings.name.en': 'None', namespace: 'EventResponse' }, }; // TODO: refactor to areSameObjectId(vali8&common) const deduplicate = (a, b) => { // grab actual ids const idOfA = idOf(a) || a; const idOfB = idOf(b) || b; // convert to string const idA = isObjectId(idOfA) ? idOfA.toString() : idOfA; const idB = isObjectId(idOfB) ? idOfB.toString() : idOfB; // check if are equal return idA === idB; }; const SMTP_FROM_NAME = getString('SMTP_FROM_NAME', 'EWEA Notification'); // TODO event notification channels // TODO event changelog notification channels // TODO use localized templates // TODO per changelog field message template /* templates */ const TEMPLATES_EVENT_NOTIFICATION_FOOTER = '\n\nRegards,\n{sender}'; const TEMPLATES_EVENT_NOTIFICATION_TITLE = '{level} Advisory: {type} {stage} - No. {number}'; const TEMPLATES_EVENT_NOTIFICATION_MESSAGE = 'Causes: {causes} \n\nDescription: {description} \n\nInstructions: {instructions} \n\nAreas: {areas} \n\nPlaces: {places}'; const TEMPLATES_EVENT_STATUS_UPDATE_TITLE = 'Status Update: {type} {stage} - No. {number}'; const TEMPLATES_EVENT_STATUS_UPDATE_MESSAGE = 'Causes: {causes} \n\nDescription: {description} \n\nInstructions: {instructions} \n\nAreas: {areas} \n\nPlaces: {places} \n\nUpdates: {updates}'; // TODO // sendMessage // sendActionNotification // sendActionsNotification // send create event notification const sendEventNotification = (event, done) => { // prepare recipient criteria // TODO: handle agencies, focals let areaIds = map([].concat(event.areas), (area) => { return get(area, '_id'); }); areaIds = uniq(areaIds).concat(null); const criteria = { area: { $in: areaIds } }; // prepare notification title/subject const subject = parseTemplate(TEMPLATES_EVENT_NOTIFICATION_TITLE, { level: get(event, 'level.strings.name.en'), type: get(event, 'type.strings.name.en'), stage: event.stage, number: event.number, }); // prepare notification areas body let areaNames = map([].concat(event.areas), (area) => { return get(area, 'strings.name.en', 'N/A'); }); areaNames = uniq(areaNames); // prepare notification body const body = parseTemplate(TEMPLATES_EVENT_NOTIFICATION_MESSAGE, { causes: get(event, 'causes', 'N/A'), description: get(event, 'description', 'N/A'), instructions: get(event, 'instructions', 'N/A'), areas: areaNames.join(', '), places: get(event, 'places', 'N/A'), }); // prepare notification footer const footer = parseTemplate(TEMPLATES_EVENT_NOTIFICATION_FOOTER, { sender: SMTP_FROM_NAME, }); // prepare notification message const message = body + footer; // send campaign sendCampaign({ criteria, subject, message }, done); }; // send event changes/changelogs notifications const sendEventUpdates = (event, changelog, done) => { // prepare recipient criteria // TODO: handle agencies, focals let areaIds = map([].concat(event.areas), (area) => { return get(area, '_id'); }); areaIds = uniq(areaIds).concat(null); const criteria = { area: { $in: areaIds } }; // prepare notification title/subject const subject = parseTemplate(TEMPLATES_EVENT_STATUS_UPDATE_TITLE, { type: get(event, 'type.strings.name.en'), stage: event.stage, number: event.number, }); // prepare notification areas body let areaNames = map([].concat(event.areas), (area) => { return get(area, 'strings.name.en', 'N/A'); }); areaNames = uniq(areaNames); // prepare updates // TODO: compute updates from other changelog attributes i.e // agencies, focals, areas, effect, need, impacts etc // TODO: changes from event instructions, interventions, // impacts, constraints, remarks, const updates = changelog.comment || 'N/A'; // prepare notification body const body = parseTemplate(TEMPLATES_EVENT_STATUS_UPDATE_MESSAGE, { causes: get(event, 'causes', 'N/A'), description: get(event, 'description', 'N/A'), instructions: get(event, 'instructions', 'N/A'), areas: areaNames.join(', '), places: get(event, 'places', 'N/A'), updates, }); // prepare notification footer const footer = parseTemplate(TEMPLATES_EVENT_NOTIFICATION_FOOTER, { sender: SMTP_FROM_NAME, }); // prepare notification message const message = body + footer; // send campaign sendCampaign({ criteria, subject, message }, done); }; /** * @name group * @description Event group underwhich an event belongs to. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca23631a92c2d616253', * strings: { name: { en: 'Meteorological' }, code: 'MAT' }, * } */ const group = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name type * @description Event type underwhich an event belongs to. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Flood' }, code: 'FL' }, * } */ const type = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name level * @description Event awareness level underwhich an event belongs to. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.5.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Orange' } }, * } */ const level = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name severity * @description Currently assigned severity of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca23631a92c2d616250', * strings: { name: { en: 'Extreme' } }, * } */ const severity = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name certainty * @description Currently assigned certainty of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616284', * strings: { name: { en: 'Possible' } }, * } */ const certainty = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name status * @description Currently assigned status of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616284', * strings: { name: { en: 'Actual' } }, * } */ const status = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name urgency * @description Currently assigned urgency of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616284', * strings: { name: { en: 'Immediate' } }, * } */ const urgency = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name response * @description Currently assigned response of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616284', * strings: { name: { en: 'Evacuate' } }, * } */ const response = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name function * @alias fanction * @description Group event response activities(i.e actions) * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Communication and Warning' } }, * } */ const fanction = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name action * @alias action * @description Define an event response activity. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Disseminating warning information' } }, * } */ const action = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name catalogue * @alias catalogue * @description Define an event response activity catalogue. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Disseminating warning information' } }, * } */ const catalogue = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name indicator * @alias indicator * @description Define indicator used to assess need, effects, situation * and characteristics of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Damages and Losses' } }, * } */ const indicator = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name topic * @alias topic * @description Define topic used to assess need, effects, situation * and characteristics of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Water' } }, * } */ const topic = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name question * @alias question * @description Define a question used to assess need and effects of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Food' } }, * } */ const question = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name need * @alias need * @description Define a question used to assess need of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Food' } }, * } */ const need = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name effect * @alias effect * @description Define a question used to assess effects of an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'Houses Damaged' } }, * } */ const effect = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name unit * @alias unit * @description Define unit of measure of an event need, effects, situation * or characteristics. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: '5dde6ca33631a92c2d616298', * strings: { name: { en: 'gallon' } }, * } */ const unit = { type: ObjectId, ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name areas * @description Affected administrative area(s) of an event(or changelog). * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * [ * { * _id: '5de2f17cec283f52aa3cacf7', * strings: { name: { en: 'Ilala' } }, * geos: { geometry: { ... } }, * }, * { * _id: '5de2f2ec7d0c71547d456b10', * strings: { name: { en: 'Temeke' } }, * geos: { geometry: { ... } }, * }, * ] */ const areas = { type: [ObjectId], ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, duplicate: deduplicate, aggregatable: { unwind: true }, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => join(v, ', ', 'strings.name.en'), default: 'NA', }, default: undefined, }; /** * @name location * @description A geo-point specifying longitude and latitude pair * of the address of an event(or changelog). * * @type {object} * @property {object} type - schema(data) type * @property {boolean} index - ensure database index * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * type: 'Point', * coordinates: [39.2155451, -6.7269984], * } */ const location = Point; /** * @name address * @description A human readable description of location of an * event(or changelog). * * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * Tandale */ const address = { type: String, trim: true, index: true, searchable: true, taggable: true, exportable: true, fake: { generator: 'address', type: 'county', }, }; /** * @name reporter * @description A party i.e civilian, customer etc which the event. * * @memberof Event * * @type {object} * @property {object} type - schema(data) type * @property {boolean} index - ensure database index * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * name: "Jane Doe", * mobile: "+255715463739", * email: "jane.doe@example.com", * } */ const reporter = Contact; // TODO: index, test /** * @name initiator * @alias changer * @description A party(i.e company, organization, individual etc) who * initiated(or record) an event changelog(or changes). * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: "5bcda2c073dd0700048fb846", * name: "Jane Doe", * mobile: "+255715463739", * email: "jane.doe@example.com", * } */ const initiator = { type: ObjectId, ref: Party.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: Party.OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'name'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name verifier * @alias approver * @description A party(i.e company, organization, individual etc) who * verify(or approve) an event changelog(or changes). * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * { * _id: "5bcda2c073dd0700048fb846", * name: "Jane Doe", * mobile: "+255715463739", * email: "jane.doe@example.com", * } */ const verifier = { type: ObjectId, ref: Party.MODEL_NAME, // required: true, index: true, exists: true, autopopulate: Party.OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => get(v, 'name'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name groups * @description Set of party groups(e.g Scouts, Religious Institutions etc) * who are responding to an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * [{ * _id: '5dde6ca23631a92c2d616253', * strings: { name: { en: 'Scouts' } }, * }] */ const groups = { type: [ObjectId], ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, duplicate: deduplicate, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => join(v, ', ', 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name roles * @description Set of party roles(e.g Ward Executive Officer etc) who are * responding to an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * [{ * _id: '5dde6ca23631a92c2d616253', * strings: { name: { en: 'Ward Executive Officer' } }, * }] */ const roles = { type: [ObjectId], ref: Predefine.MODEL_NAME, // required: true, index: true, exists: true, duplicate: deduplicate, autopopulate: PREDEFINE_OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => join(v, ', ', 'strings.name.en'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name agencies * @alias organizations * @description Set of agencies(or organizations) who are responding to * an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * [{ * _id: "5bcda2c073dd0700048fb846", * name: "Police Force", * mobile: "+255715463739", * email: "police.force@example.com", * }] */ const agencies = { type: [ObjectId], ref: Party.MODEL_NAME, // required: true, index: true, exists: true, duplicate: deduplicate, autopopulate: Party.OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => join(v, ', ', 'name'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name focals * @alias responder * @description Set of people(or individuals) who are responding to an event. * * @memberof Event * @memberof ChangeLog * * @type {object} * @property {object} type - schema(data) type * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto populate(eager loading) options * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} aggregatable - allow field use for aggregation * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * [{ * _id: "5bcda2c073dd0700048fb846", * name: "Jane Doe", * mobile: "+255715463739", * email: "jane.doe@example.com", * }] */ const focals = { type: [ObjectId], ref: Party.MODEL_NAME, // required: true, index: true, exists: true, duplicate: deduplicate, autopopulate: Party.OPTION_AUTOPOPULATE, taggable: true, exportable: { format: (v) => join(v, ', ', 'name'), default: 'NA', }, aggregatable: { unwind: true }, default: undefined, }; /** * @name stage * @description Human readable evolving step of an event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {string[]} enum - collection of allowed values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 0.1.0 * @instance * @example * Alert */ const stage = { type: String, trim: true, enum: EVENT_STAGES, index: true, searchable: true, taggable: true, exportable: true, default: EVENT_STAGE_ALERT, fake: true, }; /** * @name number * @description Human readable, unique identifier of an event. * * It consist of two letters to identify the event(or disaster) type * (e.g. FL - flood); the year of the event; a six-digit, sequential * event number; and the three-letter ISO code for country of occurrence * e.g FL-2001-000033-TZA. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} uppercase - force value to uppercase * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} unique - ensure unique database index * @property {boolean} searchable - allow searching * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * FL-2018-000033-TZA */ const number = { type: String, trim: true, uppercase: true, required: true, index: true, // unique: true, searchable: true, taggable: true, exportable: true, sequenceable: { prefix: function prefix() { const eventTypeCode = get(this, 'type.strings.code', ''); const year = moment(new Date()).format('YYYY'); return compact([eventTypeCode, year]).join('-'); }, suffix: COUNTRY_CODE, length: 6, pad: '0', separator: '-', }, fake: { generator: 'random', type: 'uuid', }, }; /** * @name causes * @description A brief human readable summary about cause(s) of an event. * * @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} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * Heavy rainfall */ const causes = { type: String, trim: true, // required: true, index: true, searchable: true, taggable: true, exportable: true, fake: { generator: 'lorem', type: 'sentence', }, }; /** * @name description * @description A brief summary about an event i.e additional details * that clarify more about an event. * * @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} searchable - allow for searching * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * Overflowing water from the dam. */ const description = { type: String, trim: true, // required: true, index: true, searchable: true, exportable: true, fake: { generator: 'lorem', type: 'sentence', }, }; /** * @name places * @description Human readable text describing the affected area(s) * of an event. * * @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} searchable - allow searching * @property {boolean} taggable - allow field use for tagging * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 0.1.0 * @instance * @example * Ilala, Temeke, Dar es Salaam */ const places = { type: String, trim: true, // required: true, index: true, searchable: true, taggable: true, exportable: true, fake: { generator: 'address', type: 'county', }, }; /** * @name instructions * @description A brief human readable, caution(s) to be taken by * responders on an event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} index - ensure database index * @property {boolean} searchable - allow searching * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 0.1.0 * @instance * @example * Continue monitor the situation */ const instructions = { type: String, trim: true, index: true, searchable: true, exportable: true, fake: { generator: 'lorem', type: 'sentence', }, }; /** * @name interventions * @description A brief human readable interventions and directives * of an event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * Affected victims were evacuated and relocated */ const interventions = { type: [String], trim: true, index: true, searchable: true, exportable: true, fake: { generator: 'lorem', type: 'sentence', }, }; /** * @name impacts * @description A brief human readable effect(s) an event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} exportable - allow field use for exporting * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 0.1.0 * @instance * @example * 55 people affected, 72 houses destroyed and 9 schools damaged */ const impacts = { type: String, trim: true, index: true, searchable: true, exportable: true, fake: { generator: 'lorem', type: 'sentence', }, }; /** * @name constraints * @description A brief human readable gaps and constraints * about an event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} exportable - allow field use for exporting * @property {object} fake -