@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
JavaScript
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 -