diff --git a/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.ts b/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.ts index 531e424f5f..c30a76afa2 100644 --- a/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.ts +++ b/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.ts @@ -7,19 +7,20 @@ import { } from 'src/app/analytics/analytics.enum'; import { AnalyticsService } from 'src/app/analytics/analytics.service'; import { LayerControlInfoPopoverComponent } from 'src/app/components/layer-control-info-popover/layer-control-info-popover.component'; +import { AREAS_OF_FOCUS } from 'src/app/models/area-of-focus.const'; import { Country, CountryDisasterSettings, DisasterType, } from 'src/app/models/country.model'; import { PlaceCode } from 'src/app/models/place-code.model'; -import { ApiService } from 'src/app/services/api.service'; import { CountryService } from 'src/app/services/country.service'; import { DisasterTypeService } from 'src/app/services/disaster-type.service'; import { EapActionsService } from 'src/app/services/eap-actions.service'; import { EventService } from 'src/app/services/event.service'; import { PlaceCodeService } from 'src/app/services/place-code.service'; import { AreaOfFocus } from 'src/app/types/area-of-focus'; +import { EapAction } from 'src/app/types/eap-action'; import { EventState } from 'src/app/types/event-state'; import { TriggeredArea } from 'src/app/types/triggered-area'; @@ -40,7 +41,7 @@ export class AreasOfFocusSummaryComponent implements OnInit, OnDestroy { public country: Country; public disasterType: DisasterType; public countryDisasterSettings: CountryDisasterSettings; - public areasOfFocus: AreaOfFocus[]; + public areasOfFocus: AreaOfFocus[] = AREAS_OF_FOCUS; public triggeredAreas: TriggeredArea[]; public trigger: boolean; public eventState: EventState; @@ -48,7 +49,6 @@ export class AreasOfFocusSummaryComponent implements OnInit, OnDestroy { constructor( private eapActionsService: EapActionsService, - private apiService: ApiService, public eventService: EventService, private placeCodeService: PlaceCodeService, private changeDetectorRef: ChangeDetectorRef, @@ -116,22 +116,24 @@ export class AreasOfFocusSummaryComponent implements OnInit, OnDestroy { this.calculateEAPActionStatus(this.triggeredAreas); }; - private onEachEAPAction = (areaOfFocus) => (action) => { - // And count the total # of (checked) tasks this way - if (areaOfFocus.id === action.aof) { - areaOfFocus.count += 1; - if (action.checked) { - areaOfFocus.countChecked += 1; + private onEachEAPAction = + (areaOfFocus: AreaOfFocus) => (action: EapAction) => { + // And count the total # of (checked) tasks this way + if (areaOfFocus.id === action.aof) { + areaOfFocus.count += 1; + if (action.checked) { + areaOfFocus.countChecked += 1; + } } - } - }; + }; - private onEachTriggeredArea = (areaOfFocus) => (area) => { - // And at each action within the area .. - area.eapActions.forEach(this.onEachEAPAction(areaOfFocus)); - }; + private onEachTriggeredArea = + (areaOfFocus: AreaOfFocus) => (area: TriggeredArea) => { + // And at each action within the area .. + area.eapActions.forEach(this.onEachEAPAction(areaOfFocus)); + }; - private calculateEAPActionStatus(triggeredAreas): void { + private calculateEAPActionStatus(triggeredAreas: TriggeredArea[]): void { if (this.placeCode) { triggeredAreas = triggeredAreas.filter( (a) => a.placeCode === this.placeCode?.placeCode, @@ -144,21 +146,12 @@ export class AreasOfFocusSummaryComponent implements OnInit, OnDestroy { triggeredAreas.forEach(this.onEachTriggeredArea(areaOfFocus)); }; - const onAreasOfFocusChange = (areasOfFocus: AreaOfFocus[]) => { - this.areasOfFocus = areasOfFocus; - - // Start calculation only when last area has eapActions attached to it - if (triggeredAreas[triggeredAreas.length - 1]?.eapActions) { - // For each area of focus .. - this.areasOfFocus.forEach(onEachAreaOfFocus); - } - this.changeDetectorRef.detectChanges(); - }; - - // Get areas of focus from db - if (triggeredAreas.length) { - this.apiService.getAreasOfFocus().subscribe(onAreasOfFocusChange); + // Start calculation only when last area has eapActions attached to it + if (triggeredAreas[triggeredAreas.length - 1]?.eapActions) { + // For each area of focus .. + this.areasOfFocus.forEach(onEachAreaOfFocus); } + this.changeDetectorRef.detectChanges(); } private onEventStateChange = (eventState: EventState) => { @@ -191,7 +184,7 @@ export class AreasOfFocusSummaryComponent implements OnInit, OnDestroy { component: this.constructor.name, }); - popover.present(); + void popover.present(); } public showAreasOfFocusSummary(): boolean { diff --git a/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html b/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html index 2b1f28a40b..3cc1e5ea18 100644 --- a/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html +++ b/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html @@ -56,8 +56,8 @@ [countryCodeISO3]="country?.countryCodeISO3" [areas]="[]" [adminAreaLabelPlural]="adminAreaLabelPlural" - [actionIndicatorLabel]="actionIndicatorLabel" - [actionIndicatorNumberFormat]="actionIndicatorNumberFormat" + [mainExposureIndicatorLabel]="mainExposureIndicatorLabel" + [mainExposureIndicatorNumberFormat]="mainExposureIndicatorNumberFormat" > } @else { @@ -73,8 +73,10 @@ [countryCodeISO3]="country?.countryCodeISO3" [areas]="triggeredAreas" [adminAreaLabelPlural]="adminAreaLabelPlural" - [actionIndicatorLabel]="actionIndicatorLabel" - [actionIndicatorNumberFormat]="actionIndicatorNumberFormat" + [mainExposureIndicatorLabel]="mainExposureIndicatorLabel" + [mainExposureIndicatorNumberFormat]=" + mainExposureIndicatorNumberFormat + " > } } @@ -118,7 +120,10 @@ " > - {{ area.actionsValue | compact: actionIndicatorNumberFormat }} + {{ + area.mainExposureValue + | compact: mainExposureIndicatorNumberFormat + }} } @else { diff --git a/interfaces/IBF-dashboard/src/app/components/chat/chat.component.ts b/interfaces/IBF-dashboard/src/app/components/chat/chat.component.ts index 74e3c9c86a..9b4ec01f5c 100644 --- a/interfaces/IBF-dashboard/src/app/components/chat/chat.component.ts +++ b/interfaces/IBF-dashboard/src/app/components/chat/chat.component.ts @@ -67,8 +67,8 @@ export class ChatComponent implements OnInit, OnDestroy { public adminAreaLabelPlural: string; public disasterTypeLabel: string; public disasterTypeName: string; - public actionIndicatorLabel: string; - public actionIndicatorNumberFormat: NumberFormat; + public mainExposureIndicatorLabel: string; + public mainExposureIndicatorNumberFormat: NumberFormat; public forecastInfo: string[]; public country: Country; public disasterType: DisasterType; @@ -221,11 +221,13 @@ export class ChatComponent implements OnInit, OnDestroy { this.disasterTypeLabel = this.disasterType.label; this.disasterTypeName = this.disasterType.disasterType; - const actionIndicator = this.indicators.find((indicator) => { - return indicator.name === this.disasterType.actionsUnit; + const mainExposureIndicator = this.indicators.find((indicator) => { + return indicator.name === this.disasterType.mainExposureIndicator; }); - this.actionIndicatorLabel = actionIndicator?.label.toLowerCase(); - this.actionIndicatorNumberFormat = actionIndicator?.numberFormatMap; + this.mainExposureIndicatorLabel = + mainExposureIndicator?.label.toLowerCase(); + this.mainExposureIndicatorNumberFormat = + mainExposureIndicator?.numberFormatMap; this.getForecastInfo(); this.updateSuccessMessage = this.translateService.instant( diff --git a/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.html b/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.html index 1fd7d05fd6..c238514ea3 100644 --- a/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.html +++ b/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.html @@ -146,7 +146,7 @@ @if (event.thresholdReached) { {{ '(' + - (actionIndicatorLabel | titlecase) + + (mainExposureIndicatorLabel | titlecase) + ' ' + (event.actionsValueSum | compact) + ')' @@ -188,7 +188,7 @@ nrTriggeredAreas: areas.length, adminAreaLabelPlural: adminAreaLabelPlural, eventName: selectedEvent?.split('_')[0], - actionIndicator: actionIndicatorLabel, + mainExposureIndicator: mainExposureIndicatorLabel, } " >

@@ -203,7 +203,7 @@ nrTriggeredAreas: areas.length, adminAreaLabelPlural: adminAreaLabelPlural, eventName: selectedEvent?.split('_')[0], - actionIndicator: actionIndicatorLabel, + mainExposureIndicator: mainExposureIndicatorLabel, } " >

@@ -219,10 +219,11 @@ @if (area.nameParent) { ({{ area.nameParent }}) } - @if (area.actionsValue && area.actionsValue > 0) { + @if (area.mainExposureValue && area.mainExposureValue > 0) { {{ ' - ' }} {{ - area.actionsValue | compact: actionIndicatorNumberFormat + area.mainExposureValue + | compact: mainExposureIndicatorNumberFormat }} } diff --git a/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.ts b/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.ts index 32f4a5391b..97ef8475fa 100644 --- a/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.ts +++ b/interfaces/IBF-dashboard/src/app/components/event-speech-bubble/event-speech-bubble.component.ts @@ -46,9 +46,9 @@ export class EventSpeechBubbleComponent implements AfterViewChecked, OnDestroy { @Input() public adminAreaLabelPlural: string; @Input() - public actionIndicatorLabel: string; + public mainExposureIndicatorLabel: string; @Input() - public actionIndicatorNumberFormat: NumberFormat; + public mainExposureIndicatorNumberFormat: NumberFormat; public typhoonLandfallText: string; public displayName: string; diff --git a/interfaces/IBF-dashboard/src/app/mocks/disaster-type.mock.ts b/interfaces/IBF-dashboard/src/app/mocks/disaster-type.mock.ts index e31bf4a754..9a6ffc7641 100644 --- a/interfaces/IBF-dashboard/src/app/mocks/disaster-type.mock.ts +++ b/interfaces/IBF-dashboard/src/app/mocks/disaster-type.mock.ts @@ -9,7 +9,7 @@ export const MOCK_DISASTERTYPE: DisasterType = { leadTimeUnit: LeadTimeUnit.day, minLeadTime: LeadTime.day0, maxLeadTime: LeadTime.day7, - actionsUnit: IbfLayerName.population_affected, - triggerUnit: IbfLayerName.alertThreshold, + mainExposureIndicator: IbfLayerName.population_affected, + triggerIndicator: IbfLayerName.alertThreshold, activeTrigger: false, }; diff --git a/interfaces/IBF-dashboard/src/app/mocks/triggered-areas.mock.ts b/interfaces/IBF-dashboard/src/app/mocks/triggered-areas.mock.ts index 9859fcadb6..88d8716ec4 100644 --- a/interfaces/IBF-dashboard/src/app/mocks/triggered-areas.mock.ts +++ b/interfaces/IBF-dashboard/src/app/mocks/triggered-areas.mock.ts @@ -3,7 +3,7 @@ import { TriggeredArea } from 'src/app/types/triggered-area'; export const MOCK_TRIGGEREDAREAS: TriggeredArea[] = [ { - actionsValue: 1, + mainExposureValue: 1, triggerValue: 1, displayName: 'Guba', eapActions: [], @@ -16,7 +16,7 @@ export const MOCK_TRIGGEREDAREAS: TriggeredArea[] = [ submitDisabled: false, }, { - actionsValue: 1, + mainExposureValue: 1, triggerValue: 1, displayName: 'Derkhale', eapActions: [], diff --git a/interfaces/IBF-dashboard/src/app/models/area-of-focus.const.ts b/interfaces/IBF-dashboard/src/app/models/area-of-focus.const.ts new file mode 100644 index 0000000000..c12a161752 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/models/area-of-focus.const.ts @@ -0,0 +1,53 @@ +import { AreaOfFocus } from 'src/app/types/area-of-focus'; + +export const AREAS_OF_FOCUS: AreaOfFocus[] = [ + { + id: 'disaster-risk-reduction', + label: 'Disaster Risk Reduction', + description: + 'Disaster Risk Reduction (DRR) is a systematic approach to identifying, assessing and reducing the risks of disaster.

It aims to reduce socio-economic vulnerabilities to disaster as well as dealing with the environmental and other hazards that trigger them.', + icon: 'Disaster risk reduction.svg', + }, + { + id: 'shelter', + label: 'Shelter', + description: + 'Shelter and Non-Food Items includes provision of shelter materials and non-food household item packages.

The theme also covers Camp Coordination and Camp Management.

Long-term/permanent reconstruction/rebuilding of housing is not covered by this area of focus.', + icon: 'Shelter.svg', + }, + { + id: 'livelihood', + label: 'Livelihoods & Basic Needs', + description: + "Disasters can take a devastating toll on people's food security livelihoods and their basic needs.

They can increase people's socio-economic vulnerability and seriously impact their ability to recover, which in turn affects their ability to cope with future shocks and stresses.

These actions are aimed at protecting these needs as preparation for forecasted hazards.", + icon: 'Livelihood.svg', + }, + { + id: 'health', + label: 'Health', + description: + 'Health includes emergency medical services, equipment and supplies; reproductive health; psycho-social support; mobile medical clinics; and disease control and surveillance.', + icon: 'Health.svg', + }, + { + id: 'wash', + label: 'WASH', + description: + 'Water, Sanitation, and Hygiene includes emergency provision of safe drinking water, hygiene and sanitation services, environmental sanitation and water supply, as well as hygiene promotion campaigns.', + icon: 'Water-Sanitation-and-Hygiene.svg', + }, + { + id: 'inclusion', + label: 'Protection, Gender and Inclusion', + description: + "People affected by disasters can have very different experiences.
A person's sex, gender identity, age, physical ability, race, nationality and many other factors can influence how they are vulnerable to, and affected by disasters, conflicts and crises. They can also affect how they respond and recover.

Emergencies can also make existing inequalities worse. This can be seen in the increase in incidences of sexual and gender-based violence (SGBV), violence against children and trafficking in human beings during and after emergencies.
", + icon: 'Gender.svg', + }, + { + id: 'migration', + label: 'Migration', + description: + 'Migration and displacement pose some of the biggest humanitarian challenges of our time.

These actions are aimed at supporting people on the move with saving lives and preventing suffering, help people cope with the risks and challenges of migration and work to protect and restore their dignity.', + icon: 'Internally-displaced.svg', + }, +]; diff --git a/interfaces/IBF-dashboard/src/app/models/country.model.ts b/interfaces/IBF-dashboard/src/app/models/country.model.ts index 1a737bacc4..95e83f9ed3 100644 --- a/interfaces/IBF-dashboard/src/app/models/country.model.ts +++ b/interfaces/IBF-dashboard/src/app/models/country.model.ts @@ -80,7 +80,7 @@ export class DisasterType { leadTimeUnit: LeadTimeUnit; minLeadTime: LeadTime; maxLeadTime: LeadTime; - actionsUnit: IbfLayerName; - triggerUnit: IbfLayerName; + mainExposureIndicator: IbfLayerName; + triggerIndicator: IbfLayerName; activeTrigger: boolean; } diff --git a/interfaces/IBF-dashboard/src/app/pages/dashboard/activation-log/activation.log.page.ts b/interfaces/IBF-dashboard/src/app/pages/dashboard/activation-log/activation.log.page.ts index e1e687f09f..88f959f91b 100644 --- a/interfaces/IBF-dashboard/src/app/pages/dashboard/activation-log/activation.log.page.ts +++ b/interfaces/IBF-dashboard/src/app/pages/dashboard/activation-log/activation.log.page.ts @@ -9,7 +9,7 @@ import { ApiService } from 'src/app/services/api.service'; import { DisasterTypeService } from 'src/app/services/disaster-type.service'; import { DisasterTypeKey } from 'src/app/types/disaster-type-key'; -type ActivationLogRecord = Record; +export type ActivationLogRecord = Record; @Component({ selector: 'app-activation-log', @@ -89,7 +89,7 @@ export class ActivationLogPage implements OnInit, OnDestroy { this.presentToast( this.translate.instant( 'activation-page.' + this.getEapKey() + '.copy-success', - ), + ) as string, 'ibf-primary', ), ) @@ -97,7 +97,7 @@ export class ActivationLogPage implements OnInit, OnDestroy { this.presentToast( this.translate.instant( 'activation-page.' + this.getEapKey() + '.copy-fail', - ), + ) as string, 'alert', ), ); diff --git a/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts b/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts index 056d7c7bf8..611c47b5f6 100644 --- a/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts @@ -166,7 +166,7 @@ export class AggregatesService { aggregate.areaStatus = Number(aggregate[IbfLayerName.alertThreshold]) > 0 ? AreaStatus.TriggeredOrWarned - : Number(aggregate[this.disasterType.actionsUnit]) > 0 && + : Number(aggregate[this.disasterType.mainExposureIndicator]) > 0 && this.eventState.events?.length > 0 ? AreaStatus.TriggeredOrWarned : AreaStatus.NonTriggeredOrWarned; // Refactor: What is this needed for? @@ -317,7 +317,7 @@ export class AggregatesService { ).weightVar; if (!weighingIndicatorName) { weighingIndicatorName = this.indicators.find( - (i) => i.name === this.disasterType.actionsUnit, + (i) => i.name === this.disasterType.mainExposureIndicator, )?.name; } diff --git a/interfaces/IBF-dashboard/src/app/services/api.service.ts b/interfaces/IBF-dashboard/src/app/services/api.service.ts index 6b973aacd8..b20bad90a9 100644 --- a/interfaces/IBF-dashboard/src/app/services/api.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/api.service.ts @@ -1,17 +1,19 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { tap } from 'rxjs/operators'; import { DEBUG_LOG } from 'src/app/config'; import { Country, DisasterType } from 'src/app/models/country.model'; import { CountryTriggers } from 'src/app/models/country-triggers.model'; import { User } from 'src/app/models/user/user.model'; +import { ActivationLogRecord } from 'src/app/pages/dashboard/activation-log/activation.log.page'; import { EventSummary } from 'src/app/services/event.service'; import { JwtService } from 'src/app/services/jwt.service'; import { AdminLevel } from 'src/app/types/admin-level'; import { AggregateRecord } from 'src/app/types/aggregate'; import { DisasterTypeKey } from 'src/app/types/disaster-type-key'; -import { IbfLayerName } from 'src/app/types/ibf-layer'; +import { IbfLayerMetadata, IbfLayerName } from 'src/app/types/ibf-layer'; +import { Indicator } from 'src/app/types/indicator-group'; import { LeadTime } from 'src/app/types/lead-time'; import { RecentDate } from 'src/app/types/recent-date'; import { TriggeredArea } from 'src/app/types/triggered-area'; @@ -52,14 +54,17 @@ export class ApiService { return headers; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get(path: string, anonymous = true, params = null): Observable { + get( + path: string, + anonymous = true, + params: HttpParams = null, + ): Observable { const url = `${environment.apiUrl}/${path}`; const security = this.showSecurity(anonymous); this.log(`ApiService GET: ${security} ${url}`); return this.http - .get(url, { + .get(url, { headers: this.createHeaders(anonymous), params, }) @@ -74,14 +79,13 @@ export class ApiService { ); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - post(path: string, body: object, anonymous = false): Observable { + post(path: string, body: object, anonymous = false): Observable { const url = `${environment.apiUrl}/${path}`; const security = this.showSecurity(anonymous); this.log(`ApiService POST: ${security} ${url}`, body); return this.http - .post(url, body, { + .post(url, body, { headers: this.createHeaders(anonymous), }) .pipe( @@ -96,14 +100,13 @@ export class ApiService { ); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - put(path: string, body: object, anonymous = false): Observable { + put(path: string, body: object, anonymous = false): Observable { const url = `${environment.apiUrl}/${path}`; const security = this.showSecurity(anonymous); this.log(`ApiService PUT: ${security} ${url}`, body); return this.http - .put(url, body, { + .put(url, body, { headers: this.createHeaders(anonymous), }) .pipe( @@ -154,19 +157,7 @@ export class ApiService { if (minimalInfo) { params = params.append('minimalInfo', String(minimalInfo)); } - return this.get(path, false, params).pipe( - map((countries) => { - return countries.map((country) => { - country.countryDisasterSettings?.map((disaster) => { - disaster.activeLeadTimes = disaster.activeLeadTimes.map( - (leadTime) => leadTime.leadTimeName, - ); - return disaster; - }); - return country; - }); - }), - ); + return this.get(path, false, params); } getTyphoonTrack( @@ -254,7 +245,7 @@ export class ApiService { params = params.append('placeCodeParent', placeCodeParent); } return this.get( - `admin-areas/${countryCodeISO3}/${disasterType}/${adminLevel}`, + `admin-areas/${countryCodeISO3}/${disasterType}/${adminLevel.toString()}`, false, params, ); @@ -279,7 +270,7 @@ export class ApiService { params = params.append('placeCodeParent', placeCodeParent); } return this.get( - `admin-areas/aggregates/${countryCodeISO3}/${disasterType}/${adminLevel}`, + `admin-areas/aggregates/${countryCodeISO3}/${disasterType}/${adminLevel.toString()}`, false, params, ); @@ -291,7 +282,7 @@ export class ApiService { adminLevel: number, leadTime: string, eventName: string, - ): Observable { + ): Observable { let params = new HttpParams(); if (eventName) { params = params.append('eventName', eventName); @@ -300,13 +291,16 @@ export class ApiService { params = params.append('leadTime', leadTime); } return this.get( - `event/triggered-areas/${countryCodeISO3}/${adminLevel}/${disasterType}`, + `event/triggered-areas/${countryCodeISO3}/${adminLevel.toString()}/${disasterType}`, false, params, ); } - getIndicators(countryCodeISO3: string, disasterType: DisasterTypeKey) { + getIndicators( + countryCodeISO3: string, + disasterType: DisasterTypeKey, + ): Observable { return this.get( `metadata/indicators/${countryCodeISO3}/${disasterType}`, false, @@ -319,21 +313,7 @@ export class ApiService { indicator: string, ): Observable<{ value: number; placeCode: string }[]> { return this.get( - `admin-area-data/${countryCodeISO3}/${adminLevel}/${indicator}`, - false, - ); - } - - getAdminAreaDynamicDataOne( - key: string, - placeCode: string, - leadTime: string, - eventName: string, - ) { - return this.get( - `admin-area-dynamic-data/single/${key}/${placeCode}/${leadTime}/${ - eventName || 'no-name' - }`, + `admin-area-data/${countryCodeISO3}/${adminLevel.toString()}/${indicator}`, false, ); } @@ -354,23 +334,22 @@ export class ApiService { params = params.append('leadTime', leadTime); } return this.get( - `admin-area-dynamic-data/${countryCodeISO3}/${adminLevel}/${indicator}/${disasterType}`, + `admin-area-dynamic-data/${countryCodeISO3}/${adminLevel.toString()}/${indicator}/${disasterType}`, false, params, ); } - getLayers(countryCodeISO3: string, disasterType: DisasterTypeKey) { + getLayers( + countryCodeISO3: string, + disasterType: DisasterTypeKey, + ): Observable { return this.get( `metadata/layers/${countryCodeISO3}/${disasterType}`, false, ); } - getAreasOfFocus() { - return this.get('eap-actions/areas-of-focus', false); - } - checkEapAction( action: string, countryCodeISO3: string, @@ -440,7 +419,10 @@ export class ApiService { return this.post(apiPath, body, false); } - getActivationLogs(countryCodeISO3?: string, disasterType?: DisasterTypeKey) { + getActivationLogs( + countryCodeISO3?: string, + disasterType?: DisasterTypeKey, + ): Observable { return this.get( `event/activation-log${ countryCodeISO3 && disasterType @@ -454,7 +436,7 @@ export class ApiService { ); } - dismissCommunityNotification(pointDataId: string) { + dismissCommunityNotification(pointDataId: string): Observable { return this.put( `point-data/community-notification/${pointDataId}`, {}, diff --git a/interfaces/IBF-dashboard/src/app/services/eap-actions.service.ts b/interfaces/IBF-dashboard/src/app/services/eap-actions.service.ts index c6f885f6d3..f6f5347cd6 100644 --- a/interfaces/IBF-dashboard/src/app/services/eap-actions.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/eap-actions.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { DateTime } from 'luxon'; import { BehaviorSubject, Observable } from 'rxjs'; +import { AREAS_OF_FOCUS } from 'src/app/models/area-of-focus.const'; import { Country, CountryDisasterSettings, @@ -109,7 +110,7 @@ export class EapActionsService { this.getTriggeredAreasApi(); }; - public getTriggeredAreasApi() { + private getTriggeredAreasApi() { if ( this.country && this.disasterType && @@ -134,11 +135,11 @@ export class EapActionsService { } } - private onTriggeredAreas = (triggeredAreas) => { + private onTriggeredAreas = (triggeredAreas: TriggeredArea[]) => { this.triggeredAreas = triggeredAreas; this.triggeredAreas.sort((a, b) => { if (a.triggerValue === b.triggerValue) { - return a.actionsValue > b.actionsValue ? -1 : 1; + return a.mainExposureValue > b.mainExposureValue ? -1 : 1; } else { return a.triggerValue > b.triggerValue ? -1 : 1; } @@ -149,6 +150,9 @@ export class EapActionsService { this.mapTriggerValueToAlertClass(area); this.filterEapActionsByMonth(area); area.eapActions.forEach((action) => { + action.aofLabel = AREAS_OF_FOCUS.find( + (aof) => aof.id === action.aof, + ).label; if (Object.keys(action.month).length) { Object.defineProperty(action, 'monthLong', { value: {}, @@ -175,7 +179,7 @@ export class EapActionsService { return this.triggeredAreaSubject.asObservable(); } - private formatDates = (triggeredArea) => { + private formatDates = (triggeredArea: TriggeredArea) => { triggeredArea.startDate = DateTime.fromISO( triggeredArea.startDate, ).toFormat('cccc, dd LLLL'); @@ -190,7 +194,7 @@ export class EapActionsService { // AlertLabel.alert does not need to be defined as {{alertLabel}} is not a variable in the non-eap copy }; - private filterEapActionsByMonth = (triggeredArea) => { + private filterEapActionsByMonth = (triggeredArea: TriggeredArea) => { if (!this.countryDisasterSettings.showMonthlyEapActions) { return; } @@ -243,7 +247,7 @@ export class EapActionsService { ); }; - private getRegion(triggeredArea): string { + private getRegion(triggeredArea: TriggeredArea): string { const nationwideKey = 'National'; if (!this.countryDisasterSettings.droughtRegions) { @@ -253,7 +257,7 @@ export class EapActionsService { const droughtRegions = Object.keys( this.countryDisasterSettings.droughtRegions, ); - const isTriggeredAreaInDroughtRegion = (droughtRegion): boolean => + const isTriggeredAreaInDroughtRegion = (droughtRegion: string): boolean => this.countryDisasterSettings.droughtRegions[droughtRegion].includes( triggeredArea.placeCode, ); @@ -264,7 +268,10 @@ export class EapActionsService { } } - private getCurrentRainSeasonName(region, monthOfSelectedLeadTime): string { + private getCurrentRainSeasonName( + region: string, + monthOfSelectedLeadTime: number, + ): string { const seasons = this.countryDisasterSettings.droughtSeasonRegions[region]; for (const season of Object.keys(seasons)) { if (seasons[season].rainMonths.includes(monthOfSelectedLeadTime)) { diff --git a/interfaces/IBF-dashboard/src/app/services/map.service.ts b/interfaces/IBF-dashboard/src/app/services/map.service.ts index d5094ce71f..a7f6d8f114 100644 --- a/interfaces/IBF-dashboard/src/app/services/map.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/map.service.ts @@ -348,7 +348,7 @@ export class MapService { show: true, data: adminRegions, viewCenter: this.adminLevel === adminLevel, - colorProperty: this.disasterType.actionsUnit, + colorProperty: this.disasterType.mainExposureIndicator, order: 0, }); } @@ -550,7 +550,7 @@ export class MapService { wms: layer.wms, colorProperty: layer.group === IbfLayerGroup.adminRegions - ? this.disasterType.actionsUnit + ? this.disasterType.mainExposureIndicator : layer.colorProperty, colorBreaks: layer.colorBreaks, numberFormatMap: layer.numberFormatMap, diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index 18c938cd71..5c5ba920ed 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -87,7 +87,7 @@ export class PointMarkerService { return markerInstance; } - private renderPopUpHTML(popupData): HTMLElement { + private renderPopUpHTML(popupData: CommunityNotification): HTMLElement { const popup = document.createElement('popup-component'); const factory = this.componentFactoryResolver.resolveComponentFactory( CommunityNotificationPopupComponent, @@ -108,7 +108,7 @@ export class PointMarkerService { return `${lat}, ${lng}`; } - private onMapMarkerClick = (analyticsEvent) => (): void => { + private onMapMarkerClick = (analyticsEvent: AnalyticsEvent) => (): void => { this.analyticsService.logEvent(analyticsEvent, { page: AnalyticsPage.dashboard, isActiveTrigger: this.eventService.state.events?.length > 0, @@ -444,7 +444,7 @@ export class PointMarkerService { 0, ); - const addComma = (n) => Math.round(n).toLocaleString('en-US'); + const addComma = (n: number) => Math.round(n).toLocaleString('en-US'); const headerContent = `${title}`; diff --git a/interfaces/IBF-dashboard/src/app/services/timeline.service.ts b/interfaces/IBF-dashboard/src/app/services/timeline.service.ts index 337bacfc59..0c33eef734 100644 --- a/interfaces/IBF-dashboard/src/app/services/timeline.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/timeline.service.ts @@ -20,7 +20,8 @@ import { LeadTimeTriggerKey, LeadTimeUnit, } from 'src/app/types/lead-time'; -import { TimelineState } from 'src/app/types/timeline-state'; +import { RecentDate } from 'src/app/types/recent-date'; +import { TimelineState, TimeStepButton } from 'src/app/types/timeline-state'; @Injectable({ providedIn: 'root', @@ -207,7 +208,7 @@ export class TimelineService { } } - private onRecentDates = (date) => { + private onRecentDates = (date: RecentDate) => { if (date.timestamp || date.date) { this.state.today = DateTime.fromISO(date.timestamp || date.date); } else { @@ -240,7 +241,7 @@ export class TimelineService { } } - private deactivateLeadTimeButton = (leadTimeButton) => + private deactivateLeadTimeButton = (leadTimeButton: TimeStepButton) => (leadTimeButton.active = false); public handleTimeStepButtonClick( @@ -397,7 +398,7 @@ export class TimelineService { if (undefinedLeadTimeEvents) { for (const event of undefinedLeadTimeEvents) { visibleLeadTimes.push({ - leadTime: event.firstLeadTime as LeadTime, + leadTime: event.firstLeadTime, eventName: event.eventName, undefined: true, }); @@ -407,7 +408,7 @@ export class TimelineService { return visibleLeadTimes; } - private getDateFromLeadTime(leadTime) { + private getDateFromLeadTime(leadTime: LeadTime) { const date = this.getLeadTimeDate( leadTime, LeadTimeTriggerKey[leadTime], @@ -562,9 +563,9 @@ export class TimelineService { const currentYear = todayLeadTime.year; const currentMonth = todayLeadTime.month; - let forecastMonthNumbers = []; + let forecastMonthNumbers: number[] = []; for (const season of this.getDroughtSeasons()) { - let filteredSeason; + let filteredSeason: number[]; if (season.includes(currentMonth)) { filteredSeason = season.filter((month) => { const shiftedMonth = this.shiftYear(month); diff --git a/interfaces/IBF-dashboard/src/app/types/triggered-area.ts b/interfaces/IBF-dashboard/src/app/types/triggered-area.ts index e41b7c97e1..b64ad31da7 100644 --- a/interfaces/IBF-dashboard/src/app/types/triggered-area.ts +++ b/interfaces/IBF-dashboard/src/app/types/triggered-area.ts @@ -2,7 +2,7 @@ import { AdminLevel } from 'src/app/types/admin-level'; import { EapAction } from 'src/app/types/eap-action'; export class TriggeredArea { - actionsValue: number; + mainExposureValue: number; triggerValue: number; displayName: string; eapActions: EapAction[]; diff --git a/interfaces/IBF-dashboard/src/assets/i18n/en.json b/interfaces/IBF-dashboard/src/assets/i18n/en.json index 5af06d8e79..a7a022720e 100644 --- a/interfaces/IBF-dashboard/src/assets/i18n/en.json +++ b/interfaces/IBF-dashboard/src/assets/i18n/en.json @@ -151,8 +151,8 @@ "welcome-below-trigger": "A warning for {{ disasterTypeLabel }} in {{ eventName }} was issued on {{ startDate }}, but it can currently not be predicted to reach trigger thresholds yet." }, "active-event": { - "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} triggered. They are listed below in order of {{ actionIndicator}} and are highlighted in the map with a red outline.", - "overview-below-trigger": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} exposed. They are listed below in order of {{ actionIndicator}}.", + "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} triggered. They are listed below in order of {{ mainExposureIndicator}} and are highlighted in the map with a red outline.", + "overview-below-trigger": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} exposed. They are listed below in order of {{ mainExposureIndicator}}.", "instruction": "Please select an area to monitor by selecting from the list or on the map and manage the trigger and the preplanned anticipatory actions (if applicable) of each area.", "place-name": "{{ adminAreaLabel }}: {{ placeName }}{{ parentName }}", "exposed": "Exposed Population:" @@ -184,7 +184,7 @@ } }, "active-event": { - "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} triggered. They are listed below in order of {{ actionIndicator}} and are highlighted in the map with a red outline.", + "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} triggered. They are listed below in order of {{ mainExposureIndicator}} and are highlighted in the map with a red outline.", "instruction": "Please select an area to monitor by selecting from the list or on the map and manage the trigger and the preplanned anticipatory actions of each area.", "place-name": "{{ adminAreaLabel }}: {{ placeName }}{{ parentName }}", "exposed": "Exposed Population:", @@ -226,8 +226,8 @@ } }, "active-event": { - "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} triggered for typhoon {{ eventName }}. They are listed below in order of {{ actionIndicator}} and are highlighted in the map with a red outline.", - "overview-below-trigger": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} exposed for typhoon {{ eventName }}. They are listed below in order of {{ actionIndicator}}.", + "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} triggered for typhoon {{ eventName }}. They are listed below in order of {{ mainExposureIndicator}} and are highlighted in the map with a red outline.", + "overview-below-trigger": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} exposed for typhoon {{ eventName }}. They are listed below in order of {{ mainExposureIndicator}}.", "instruction": "Please select an area to monitor by selecting from the list or on the map and manage the trigger and the preplanned anticipatory actions of each area.", "place-name": "{{ adminAreaLabel }}: {{ placeName }}{{ parentName }}", "exposed": "Affected population:" @@ -248,7 +248,7 @@ "welcome": "An alert for {{ disasterTypeLabel }} was issued on {{ startDate }}. It is estimated to arrive around {{ leadTime }} {{ timeUnit }}(s) from now." }, "active-event": { - "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} above alert threshold. They are listed below in order of {{ actionIndicator}} and are highlighted in the map with a red outline.", + "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} above alert threshold. They are listed below in order of {{ mainExposureIndicator}} and are highlighted in the map with a red outline.", "instruction": "Please select an area to monitor by selecting from the list or on the map and manage the alert and the preplanned anticipatory actions of each area.", "place-name": "{{ adminAreaLabel }}: {{ placeName }}{{ parentName }}", "exposed": "Exposed Population:" @@ -265,7 +265,7 @@ "welcome": "An alert for {{ disasterTypeLabel }} was issued on {{ startDate }}." }, "active-event": { - "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} above alert threshold. They are listed below in order of {{ actionIndicator}} and are highlighted in the map with a red outline.", + "overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} above alert threshold. They are listed below in order of {{ mainExposureIndicator}} and are highlighted in the map with a red outline.", "instruction": "You can click on the month tabs above the map to see the predictions for each month. Please select an area to monitor by selecting from the list or on the map and manage the trigger and the preplanned anticipatory actions of each area.", "place-name": "{{ adminAreaLabel }}: {{ placeName }}{{ parentName }}", "exposed": "Potential cases: up to" diff --git a/interfaces/IBF-dashboard/tsconfig.json b/interfaces/IBF-dashboard/tsconfig.json index 0e55582aea..c7bfd12200 100644 --- a/interfaces/IBF-dashboard/tsconfig.json +++ b/interfaces/IBF-dashboard/tsconfig.json @@ -14,7 +14,8 @@ "strict": false, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": false, + "noImplicitAny": false, // For now keep on false, but switch to true locally sometimes to clean up code in files you're touching + "noImplicitReturns": false, // Same as 'noImplicitAny' "noFallthroughCasesInSwitch": true, "sourceMap": true, "declaration": false, diff --git a/services/API-service/migration/1737713818319-RemoveLeadTimeEntity.ts b/services/API-service/migration/1737713818319-RemoveLeadTimeEntity.ts new file mode 100644 index 0000000000..4f40903304 --- /dev/null +++ b/services/API-service/migration/1737713818319-RemoveLeadTimeEntity.ts @@ -0,0 +1,61 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveLeadTimeEntity1737713818319 implements MigrationInterface { + name = 'RemoveLeadTimeEntity1737713818319'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "IBF-app"."admin-area-dynamic-data" DROP CONSTRAINT "FK_cb6c2fc0f20bcf164afc3e0301b"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."lines-data-dynamic-status" DROP CONSTRAINT "FK_2456d6fa601344982bacf47f6b9"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."dynamic-point-data" DROP CONSTRAINT "FK_289a1f52e25e270d9a28bd9d35a"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."typhoon-track" DROP CONSTRAINT "FK_7911edcf74dd1da5905dbc7e44e"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."country-disaster-settings" ADD "activeLeadTimes" json`, + ); + + // Drop old tables + await queryRunner.query( + `DROP TABLE "IBF-app"."disaster_lead_times_lead-time"`, + ); + await queryRunner.query( + `DROP TABLE "IBF-app"."country-disaster-settings_active_lead_times_lead-time"`, + ); + await queryRunner.query( + `DROP TABLE "IBF-app"."country_country_active_lead_times_lead-time"`, + ); + await queryRunner.query(`DROP TABLE "IBF-app"."glofas-station-forecast"`); + await queryRunner.query(`DROP TABLE "IBF-app"."lead-time"`); + + await queryRunner.query(`DROP TABLE "IBF-app"."dam-site"`); + await queryRunner.query(`DROP TABLE "IBF-app"."evacuation-center"`); + await queryRunner.query(`DROP TABLE "IBF-app"."glofas-station"`); + await queryRunner.query(`DROP TABLE "IBF-app"."health-site"`); + await queryRunner.query(`DROP TABLE "IBF-app"."rainfall-triggers"`); + await queryRunner.query(`DROP TABLE "IBF-app"."redcross-branch"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "IBF-app"."country-disaster-settings" DROP COLUMN "activeLeadTimes"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."typhoon-track" ADD CONSTRAINT "FK_7911edcf74dd1da5905dbc7e44e" FOREIGN KEY ("leadTime") REFERENCES "IBF-app"."lead-time"("leadTimeName") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."dynamic-point-data" ADD CONSTRAINT "FK_289a1f52e25e270d9a28bd9d35a" FOREIGN KEY ("leadTime") REFERENCES "IBF-app"."lead-time"("leadTimeName") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."lines-data-dynamic-status" ADD CONSTRAINT "FK_2456d6fa601344982bacf47f6b9" FOREIGN KEY ("leadTime") REFERENCES "IBF-app"."lead-time"("leadTimeName") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."admin-area-dynamic-data" ADD CONSTRAINT "FK_cb6c2fc0f20bcf164afc3e0301b" FOREIGN KEY ("leadTime") REFERENCES "IBF-app"."lead-time"("leadTimeName") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + } +} diff --git a/services/API-service/migration/1737716825902-RemoveAreaOfFocusEntity.ts b/services/API-service/migration/1737716825902-RemoveAreaOfFocusEntity.ts new file mode 100644 index 0000000000..7a90f2678b --- /dev/null +++ b/services/API-service/migration/1737716825902-RemoveAreaOfFocusEntity.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveAreaOfFocusEntity1737716825902 + implements MigrationInterface +{ + name = 'RemoveAreaOfFocusEntity1737716825902'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "IBF-app"."eap-action" DROP CONSTRAINT "FK_f3ce61c374e05d7b8b05b8485d2"`, + ); + + await queryRunner.query(`DROP TABLE "IBF-app"."area-of-focus"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "IBF-app"."eap-action" ADD CONSTRAINT "FK_f3ce61c374e05d7b8b05b8485d2" FOREIGN KEY ("areaOfFocusId") REFERENCES "IBF-app"."area-of-focus"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + } +} diff --git a/services/API-service/migration/1738676250370-RenameTriggerActionsUnit.ts b/services/API-service/migration/1738676250370-RenameTriggerActionsUnit.ts new file mode 100644 index 0000000000..71ec347294 --- /dev/null +++ b/services/API-service/migration/1738676250370-RenameTriggerActionsUnit.ts @@ -0,0 +1,55 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RenameTriggerActionsUnit1738676250370 + implements MigrationInterface +{ + name = 'RenameTriggerActionsUnit1738676250370'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "IBF-app"."event-place-code" RENAME COLUMN "actionsValue" TO "mainExposureValue"`, + ); + + // Create new columns + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" ADD "triggerIndicator" character varying NOT NULL DEFAULT 'alert_threshold'`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" ADD "mainExposureIndicator" character varying NOT NULL DEFAULT 'population_affected'`, + ); + + // Copy data from old to new column + await queryRunner.query( + `UPDATE "IBF-app"."disaster" SET "triggerIndicator" = "triggerUnit"`, + ); + await queryRunner.query( + `UPDATE "IBF-app"."disaster" SET "mainExposureIndicator" = "actionsUnit"`, + ); + + // Drop old column + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" DROP COLUMN "triggerUnit"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" DROP COLUMN "actionsUnit"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" DROP COLUMN "mainExposureIndicator"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" DROP COLUMN "triggerIndicator"`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" ADD "actionsUnit" character varying NOT NULL DEFAULT 'population_affected'`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."disaster" ADD "triggerUnit" character varying NOT NULL DEFAULT 'population_affected'`, + ); + await queryRunner.query( + `ALTER TABLE "IBF-app"."event-place-code" RENAME COLUMN "mainExposureValue" TO "actionsValue"`, + ); + } +} diff --git a/services/API-service/module-dependencies.md b/services/API-service/module-dependencies.md index 91899ed4a2..4297c0d160 100644 --- a/services/API-service/module-dependencies.md +++ b/services/API-service/module-dependencies.md @@ -19,6 +19,7 @@ graph LR AdminAreaDynamicDataModule-->EventModule AdminAreaDynamicDataModule-->CountryModule AdminAreaDynamicDataModule-->AdminAreaModule + DisasterTypeModule-->UserModule MetadataModule-->UserModule MetadataModule-->CountryModule MetadataModule-->EventModule diff --git a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.controller.ts b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.controller.ts index 689043455c..cd20d7e550 100644 --- a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.controller.ts +++ b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.controller.ts @@ -24,7 +24,7 @@ import { import { Roles } from '../../roles.decorator'; import { RolesGuard } from '../../roles.guard'; import { FILE_UPLOAD_API_FORMAT } from '../../shared/file-upload-api-format'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { UserRole } from '../user/user-role.enum'; import { AdminAreaDynamicDataService } from './admin-area-dynamic-data.service'; import { AdminDataReturnDto } from './dto/admin-data-return.dto'; @@ -91,28 +91,6 @@ export class AdminAreaDynamicDataController { ); } - @ApiOperation({ - summary: 'Get dynamic admin-area data value for one specific admin-area', - }) - @ApiParam({ name: 'indicator', required: true, type: 'string' }) - @ApiParam({ name: 'placeCode', required: true, type: 'string' }) - @ApiParam({ name: 'leadTime', required: true, type: 'string' }) - @ApiParam({ name: 'eventName', required: true, type: 'string' }) - @ApiResponse({ - status: 200, - description: 'Dynamic admin-area data value for one specific admin-area.', - type: Number, - }) - @Get('single/:indicator/:placeCode/:leadTime/:eventName') - public async getAdminAreaDataPerPcode(@Param() params): Promise { - return await this.adminAreaDynamicDataService.getDynamicAdminAreaDataPerPcode( - params.indicator as DynamicIndicator, - params.placeCode, - params.leadTime, - params.eventName, - ); - } - @Roles(UserRole.PipelineUser) @ApiOperation({ summary: diff --git a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.entity.ts b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.entity.ts index de6f172250..9c28a3b5be 100644 --- a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.entity.ts +++ b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.entity.ts @@ -8,9 +8,9 @@ import { } from 'typeorm'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { DynamicIndicator } from './enum/dynamic-data-unit'; +import { LeadTime } from './enum/lead-time.enum'; @Entity('admin-area-dynamic-data') export class AdminAreaDynamicDataEntity { @@ -24,7 +24,7 @@ export class AdminAreaDynamicDataEntity { }) public countryCodeISO3: string; - @ManyToOne((): typeof DisasterEntity => DisasterEntity) + @ManyToOne((): typeof DisasterTypeEntity => DisasterTypeEntity) @JoinColumn({ name: 'disasterType', referencedColumnName: 'disasterType', @@ -53,7 +53,6 @@ export class AdminAreaDynamicDataEntity { @Column({ nullable: true, type: 'real' }) public value: number; - @ManyToOne((): typeof LeadTimeEntity => LeadTimeEntity) - @JoinColumn({ name: 'leadTime', referencedColumnName: 'leadTimeName' }) - public leadTime: string; + @Column({ nullable: true }) + public leadTime: LeadTime; } diff --git a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.module.ts b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.module.ts index 268de513fd..3a95f9a4b6 100644 --- a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.module.ts +++ b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.module.ts @@ -4,7 +4,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { HelperService } from '../../shared/helper.service'; import { AdminAreaModule } from '../admin-area/admin-area.module'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { EventModule } from '../event/event.module'; import { TriggerPerLeadTime } from '../event/trigger-per-lead-time.entity'; import { UserModule } from '../user/user.module'; @@ -18,7 +18,7 @@ import { AdminAreaDynamicDataService } from './admin-area-dynamic-data.service'; TypeOrmModule.forFeature([ TriggerPerLeadTime, AdminAreaDynamicDataEntity, - DisasterEntity, + DisasterTypeEntity, CountryEntity, ]), UserModule, diff --git a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.service.ts b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.service.ts index ef42cecf5d..abdcac9215 100644 --- a/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.service.ts +++ b/services/API-service/src/api/admin-area-dynamic-data/admin-area-dynamic-data.service.ts @@ -3,14 +3,14 @@ import path from 'path'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { DataSource, In, IsNull, MoreThanOrEqual, Repository } from 'typeorm'; +import { DataSource, In, MoreThanOrEqual, Repository } from 'typeorm'; import { DisasterTypeGeoServerMapper } from '../../scripts/disaster-type-geoserver-file.mapper'; import { HelperService } from '../../shared/helper.service'; import { EventAreaService } from '../admin-area/services/event-area.service'; import { CountryEntity } from '../country/country.entity'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { UploadTriggerPerLeadTimeDto } from '../event/dto/upload-trigger-per-leadtime.dto'; import { EventService } from '../event/event.service'; import { AdminAreaDynamicDataEntity } from './admin-area-dynamic-data.entity'; @@ -29,8 +29,8 @@ interface RasterData { export class AdminAreaDynamicDataService { @InjectRepository(AdminAreaDynamicDataEntity) private readonly adminAreaDynamicDataRepo: Repository; - @InjectRepository(DisasterEntity) - private readonly disasterTypeRepository: Repository; + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; @InjectRepository(CountryEntity) private readonly countryRepository: Repository; @@ -79,7 +79,7 @@ export class AdminAreaDynamicDataService { await this.adminAreaDynamicDataRepo.save(areas); const disasterType = await this.disasterTypeRepository.findOne({ - select: ['triggerUnit'], + select: ['triggerIndicator'], where: { disasterType: uploadExposure.disasterType }, }); @@ -89,7 +89,7 @@ export class AdminAreaDynamicDataService { }); if ( - disasterType.triggerUnit === uploadExposure.dynamicIndicator && + disasterType.triggerIndicator === uploadExposure.dynamicIndicator && uploadExposure.exposurePlaceCodes.length > 0 && country.countryDisasterSettings.find( (s) => s.disasterType === uploadExposure.disasterType, @@ -228,26 +228,6 @@ export class AdminAreaDynamicDataService { return result; } - public async getDynamicAdminAreaDataPerPcode( - indicator: DynamicIndicator, - placeCode: string, - leadTime: string, - eventName: string, - ): Promise { - const result = await this.adminAreaDynamicDataRepo - .createQueryBuilder('dynamic') - .where({ - indicator, - placeCode, - leadTime, - eventName: eventName === 'no-name' || !eventName ? IsNull() : eventName, - }) - .select(['dynamic.value AS value']) - .orderBy('dynamic.date', 'DESC') - .execute(); - return result[0].value; - } - public async postRaster( data: RasterData, disasterType: DisasterType, diff --git a/services/API-service/src/api/admin-area-dynamic-data/dto/upload-admin-area-dynamic-data.dto.ts b/services/API-service/src/api/admin-area-dynamic-data/dto/upload-admin-area-dynamic-data.dto.ts index 2f66a190c2..fea495bf7d 100644 --- a/services/API-service/src/api/admin-area-dynamic-data/dto/upload-admin-area-dynamic-data.dto.ts +++ b/services/API-service/src/api/admin-area-dynamic-data/dto/upload-admin-area-dynamic-data.dto.ts @@ -12,7 +12,7 @@ import { } from 'class-validator'; import exposure from '../../../scripts/mock-data/drought/ETH/trigger/Belg JAS_Belg/upload-alert_threshold-2.json'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { DynamicIndicator } from '../enum/dynamic-data-unit'; import { LeadTime } from '../enum/lead-time.enum'; import { DynamicDataPlaceCodeDto } from './dynamic-data-place-code.dto'; @@ -37,6 +37,7 @@ export class UploadAdminAreaDynamicDataDto { @ApiProperty({ example: LeadTime.month0 }) @IsNotEmpty() @IsString() + @IsEnum(LeadTime) public leadTime: LeadTime; @ApiProperty({ example: DynamicIndicator.populationAffected }) diff --git a/services/API-service/src/api/admin-area/admin-area.module.ts b/services/API-service/src/api/admin-area/admin-area.module.ts index 37ab73e4cf..72640c08b6 100644 --- a/services/API-service/src/api/admin-area/admin-area.module.ts +++ b/services/API-service/src/api/admin-area/admin-area.module.ts @@ -5,7 +5,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { HelperService } from '../../shared/helper.service'; import { AdminAreaDynamicDataEntity } from '../admin-area-dynamic-data/admin-area-dynamic-data.entity'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { EventModule } from '../event/event.module'; import { UserModule } from '../user/user.module'; import { CountryModule } from './../country/country.module'; @@ -22,7 +22,7 @@ import { EventAreaService } from './services/event-area.service'; TypeOrmModule.forFeature([ AdminAreaEntity, CountryEntity, - DisasterEntity, + DisasterTypeEntity, AdminAreaDynamicDataEntity, EventAreaEntity, ]), diff --git a/services/API-service/src/api/admin-area/admin-area.service.ts b/services/API-service/src/api/admin-area/admin-area.service.ts index b5b003b7e0..a134bdfc0c 100644 --- a/services/API-service/src/api/admin-area/admin-area.service.ts +++ b/services/API-service/src/api/admin-area/admin-area.service.ts @@ -10,8 +10,8 @@ import { AdminAreaDataEntity } from '../admin-area-data/admin-area-data.entity'; import { AdminAreaDynamicDataEntity } from '../admin-area-dynamic-data/admin-area-dynamic-data.entity'; import { DynamicIndicator } from '../admin-area-dynamic-data/enum/dynamic-data-unit'; import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { EventService } from '../event/event.service'; import { AdminAreaEntity } from './admin-area.entity'; import { EventAreaService } from './services/event-area.service'; @@ -20,8 +20,8 @@ import { EventAreaService } from './services/event-area.service'; export class AdminAreaService { @InjectRepository(AdminAreaEntity) private readonly adminAreaRepository: Repository; - @InjectRepository(DisasterEntity) - private readonly disasterTypeRepository: Repository; + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; @InjectRepository(AdminAreaDynamicDataEntity) private readonly adminAreaDynamicDataRepo: Repository; @@ -128,7 +128,8 @@ export class AdminAreaService { leadTime: string, eventName: string, ): Promise { - const triggerUnit = await this.eventService.getTriggerUnit(disasterType); + const triggerIndicator = + await this.eventService.getTriggerIndicator(disasterType); const lastTriggeredDate = await this.helperService.getRecentDate( countryCodeISO3, disasterType, @@ -138,7 +139,7 @@ export class AdminAreaService { disasterType: disasterType, adminLevel: adminLevel, value: MoreThan(0), - indicator: triggerUnit as DynamicIndicator, + indicator: triggerIndicator as DynamicIndicator, timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( disasterType, @@ -294,7 +295,7 @@ export class AdminAreaService { private async getDisasterType( disasterType: DisasterType, - ): Promise { + ): Promise { return await this.disasterTypeRepository.findOne({ where: { disasterType: disasterType }, }); @@ -324,7 +325,7 @@ export class AdminAreaService { eventName: string, placeCodeParent?: string, ): Promise { - const disaster = await this.getDisasterType(disasterType); + const disasterTypeEntity = await this.getDisasterType(disasterType); const lastTriggeredDate = await this.helperService.getRecentDate( countryCodeISO3, disasterType, @@ -334,7 +335,7 @@ export class AdminAreaService { if (disasterType === DisasterType.FlashFloods && !eventName) { return await this.eventAreaService.getEventAreas( countryCodeISO3, - disaster, + disasterTypeEntity, lastTriggeredDate, ); } @@ -370,7 +371,7 @@ export class AdminAreaService { 'area."placeCodeParent" = parent."placeCode"', ) .addSelect([ - `dynamic.value AS ${disaster.actionsUnit}`, + `dynamic.value AS ${disasterTypeEntity.mainExposureIndicator}`, 'dynamic."leadTime"', 'dynamic."date"', 'parent.name AS "nameParent"', @@ -387,7 +388,7 @@ export class AdminAreaService { disasterType: disasterType, }) .andWhere('dynamic."indicator" = :indicator', { - indicator: disaster.actionsUnit, + indicator: disasterTypeEntity.mainExposureIndicator, }); if (leadTime) { adminAreasScript.andWhere('dynamic."leadTime" = :leadTime', { diff --git a/services/API-service/src/api/admin-area/event-area.entity.ts b/services/API-service/src/api/admin-area/event-area.entity.ts index 085245d300..d80bd807c2 100644 --- a/services/API-service/src/api/admin-area/event-area.entity.ts +++ b/services/API-service/src/api/admin-area/event-area.entity.ts @@ -10,8 +10,8 @@ import { } from 'typeorm'; import { CountryEntity } from '../country/country.entity'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; @Entity('event-area') export class EventAreaEntity { @@ -28,7 +28,7 @@ export class EventAreaEntity { public countryCodeISO3: string; @ApiProperty({ example: DisasterType.FlashFloods }) - @ManyToOne((): typeof DisasterEntity => DisasterEntity) + @ManyToOne((): typeof DisasterTypeEntity => DisasterTypeEntity) @JoinColumn({ name: 'disasterType', referencedColumnName: 'disasterType', diff --git a/services/API-service/src/api/admin-area/services/event-area.service.ts b/services/API-service/src/api/admin-area/services/event-area.service.ts index b292772d3e..1ee762d456 100644 --- a/services/API-service/src/api/admin-area/services/event-area.service.ts +++ b/services/API-service/src/api/admin-area/services/event-area.service.ts @@ -12,8 +12,8 @@ import { HelperService } from '../../../shared/helper.service'; import { AdminAreaDynamicDataEntity } from '../../admin-area-dynamic-data/admin-area-dynamic-data.entity'; import { AdminDataReturnDto } from '../../admin-area-dynamic-data/dto/admin-data-return.dto'; import { DynamicIndicator } from '../../admin-area-dynamic-data/enum/dynamic-data-unit'; -import { DisasterType } from '../../disaster/disaster-type.enum'; -import { DisasterEntity } from '../../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../../disaster-type/disaster-type.entity'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { DateDto } from '../../event/dto/date.dto'; import { EventService } from '../../event/event.service'; import { EventAreaEntity } from '../event-area.entity'; @@ -65,21 +65,21 @@ export class EventAreaService { public async getEventAreas( countryCodeISO3: string, - disaster: DisasterEntity, + disasterType: DisasterTypeEntity, lastTriggeredDate: DateDto, ): Promise { const eventAreas = []; const events = await this.eventService.getEventSummary( countryCodeISO3, - disaster.disasterType, + disasterType.disasterType, ); for await (const event of events) { const eventArea = await this.eventAreaRepository .createQueryBuilder('area') .where({ countryCodeISO3: countryCodeISO3, - disasterType: disaster.disasterType, + disasterType: disasterType.disasterType, eventAreaName: event.eventName, }) .select([ @@ -96,16 +96,16 @@ export class EventAreaService { .where({ timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( - disaster.disasterType, + disasterType.disasterType, lastTriggeredDate.timestamp, ), ), - disasterType: disaster.disasterType, - indicator: disaster.actionsUnit, + disasterType: disasterType.disasterType, + indicator: disasterType.mainExposureIndicator, eventName: event.eventName, }) .getRawOne(); - eventArea[disaster.actionsUnit] = aggregateValue.value; + eventArea[disasterType.mainExposureIndicator] = aggregateValue.value; eventAreas.push(eventArea); } @@ -114,7 +114,7 @@ export class EventAreaService { .createQueryBuilder('area') .where({ countryCodeISO3: countryCodeISO3, - disasterType: disaster.disasterType, + disasterType: disasterType.disasterType, }) .select([ 'area."eventAreaName" as "eventAreaName"', @@ -124,7 +124,7 @@ export class EventAreaService { for await (const eventArea of allEventAreas) { eventArea['eventName'] = eventArea.eventAreaName; eventArea['placeCode'] = eventArea.eventAreaName; - eventArea[disaster.actionsUnit] = 0; + eventArea[disasterType.mainExposureIndicator] = 0; eventAreas.push(eventArea); } diff --git a/services/API-service/src/api/country/country-disaster.entity.ts b/services/API-service/src/api/country/country-disaster.entity.ts index 042d9896d1..cdd2f687fd 100644 --- a/services/API-service/src/api/country/country-disaster.entity.ts +++ b/services/API-service/src/api/country/country-disaster.entity.ts @@ -4,15 +4,13 @@ import { Column, Entity, JoinColumn, - JoinTable, - ManyToMany, ManyToOne, PrimaryGeneratedColumn, } from 'typeorm'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; +import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { AdminLevel } from './admin-level.enum'; import { CountryEntity } from './country.entity'; @@ -29,7 +27,7 @@ export class CountryDisasterSettingsEntity { public country: CountryEntity; @ApiProperty({ example: DisasterType.Floods }) - @ManyToOne((): typeof DisasterEntity => DisasterEntity) + @ManyToOne((): typeof DisasterTypeEntity => DisasterTypeEntity) @JoinColumn({ name: 'disasterType', referencedColumnName: 'disasterType', @@ -48,12 +46,8 @@ export class CountryDisasterSettingsEntity { public defaultAdminLevel: AdminLevel; @ApiProperty() - @ManyToMany( - (): typeof LeadTimeEntity => LeadTimeEntity, - (leadTime): CountryDisasterSettingsEntity[] => leadTime.countries, - ) - @JoinTable() - public activeLeadTimes: LeadTimeEntity[]; + @Column('json', { nullable: true }) + public activeLeadTimes: LeadTime[]; @ApiProperty({ example: [3, 10] }) @Column('json', { nullable: true }) diff --git a/services/API-service/src/api/country/country.entity.ts b/services/API-service/src/api/country/country.entity.ts index f6ce47a078..e81cd3db6c 100644 --- a/services/API-service/src/api/country/country.entity.ts +++ b/services/API-service/src/api/country/country.entity.ts @@ -11,7 +11,7 @@ import { } from 'typeorm'; import { BoundingBox } from '../../shared/geo.model'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { NotificationInfoEntity } from '../notification/notifcation-info.entity'; import { UserEntity } from '../user/user.entity'; import { CountryDisasterSettingsEntity } from './country-disaster.entity'; @@ -88,10 +88,10 @@ export class CountryEntity { @ApiProperty() @ManyToMany( - (): typeof DisasterEntity => DisasterEntity, + (): typeof DisasterTypeEntity => DisasterTypeEntity, (disasterType): CountryEntity[] => disasterType.countries, ) - public disasterTypes: DisasterEntity[]; + public disasterTypes: DisasterTypeEntity[]; @OneToOne(() => NotificationInfoEntity, { cascade: true, diff --git a/services/API-service/src/api/country/country.module.ts b/services/API-service/src/api/country/country.module.ts index f0850e486b..57819e5fa4 100644 --- a/services/API-service/src/api/country/country.module.ts +++ b/services/API-service/src/api/country/country.module.ts @@ -2,8 +2,7 @@ import { HttpModule } from '@nestjs/axios'; import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { DisasterEntity } from '../disaster/disaster.entity'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { NotificationInfoEntity } from '../notification/notifcation-info.entity'; import { UserModule } from '../user/user.module'; import { CountryDisasterSettingsEntity } from './country-disaster.entity'; @@ -17,9 +16,8 @@ import { CountryService } from './country.service'; UserModule, TypeOrmModule.forFeature([ CountryEntity, - DisasterEntity, + DisasterTypeEntity, CountryDisasterSettingsEntity, - LeadTimeEntity, NotificationInfoEntity, ]), ], diff --git a/services/API-service/src/api/country/country.service.spec.ts b/services/API-service/src/api/country/country.service.spec.ts index 3e5a861836..3098cf65eb 100644 --- a/services/API-service/src/api/country/country.service.spec.ts +++ b/services/API-service/src/api/country/country.service.spec.ts @@ -5,8 +5,7 @@ import { In, Repository } from 'typeorm'; import countries from '../../scripts/json/countries.json'; import notificationInfos from '../../scripts/json/notification-info.json'; -import { DisasterEntity } from '../disaster/disaster.entity'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { NotificationInfoEntity } from '../notification/notifcation-info.entity'; import { CountryDisasterSettingsEntity } from './country-disaster.entity'; import { CountryEntity } from './country.entity'; @@ -17,14 +16,12 @@ import { NotificationInfoDto } from './dto/notification-info.dto'; describe('CountryService', () => { let service: CountryService; let countryRepository: Repository; - let disasterRepository: Repository; + let disasterTypeRepository: Repository; let countryDisasterSettingsRepository: Repository; - let leadTimeRepository: Repository; let notificationInfoRepository: Repository; const relations = [ 'countryDisasterSettings', - 'countryDisasterSettings.activeLeadTimes', 'disasterTypes', 'notificationInfo', ]; @@ -38,17 +35,13 @@ describe('CountryService', () => { useClass: Repository, }, { - provide: getRepositoryToken(DisasterEntity), + provide: getRepositoryToken(DisasterTypeEntity), useClass: Repository, }, { provide: getRepositoryToken(CountryDisasterSettingsEntity), useClass: Repository, }, - { - provide: getRepositoryToken(LeadTimeEntity), - useClass: Repository, - }, { provide: getRepositoryToken(NotificationInfoEntity), useClass: Repository, @@ -60,15 +53,12 @@ describe('CountryService', () => { countryRepository = module.get>( getRepositoryToken(CountryEntity), ); - disasterRepository = module.get>( - getRepositoryToken(DisasterEntity), + disasterTypeRepository = module.get>( + getRepositoryToken(DisasterTypeEntity), ); countryDisasterSettingsRepository = module.get< Repository >(getRepositoryToken(CountryDisasterSettingsEntity)); - leadTimeRepository = module.get>( - getRepositoryToken(LeadTimeEntity), - ); notificationInfoRepository = module.get>( getRepositoryToken(NotificationInfoEntity), ); @@ -109,14 +99,11 @@ describe('CountryService', () => { .spyOn(countryRepository, 'findOne') .mockResolvedValue(new CountryEntity()); jest - .spyOn(disasterRepository, 'find') - .mockResolvedValue([new DisasterEntity()]); + .spyOn(disasterTypeRepository, 'find') + .mockResolvedValue([new DisasterTypeEntity()]); jest .spyOn(countryRepository, 'save') .mockResolvedValue(new CountryEntity()); - jest - .spyOn(leadTimeRepository, 'find') - .mockResolvedValue([new LeadTimeEntity()]); jest .spyOn(countryDisasterSettingsRepository, 'save') .mockResolvedValue(new CountryDisasterSettingsEntity()); @@ -133,19 +120,14 @@ describe('CountryService', () => { where: { countryCodeISO3: country.countryCodeISO3 }, relations: ['countryDisasterSettings'], }); - expect(disasterRepository.find).toHaveBeenCalledWith({ + expect(disasterTypeRepository.find).toHaveBeenCalledWith({ where: country.disasterTypes.map((disasterType) => ({ disasterType, })), }); expect(countryRepository.save).toHaveBeenCalled(); - for (const countryDisasterSetting of country.countryDisasterSettings as CountryDisasterSettingsDto[]) { - expect(leadTimeRepository.find).toHaveBeenCalledWith({ - where: countryDisasterSetting.activeLeadTimes.map( - (leadTimeName) => ({ leadTimeName }), - ), - }); + for (const _countryDisasterSetting of country.countryDisasterSettings as CountryDisasterSettingsDto[]) { expect(countryDisasterSettingsRepository.save).toHaveBeenCalled(); expect( countryDisasterSettingsRepository.findOne, diff --git a/services/API-service/src/api/country/country.service.ts b/services/API-service/src/api/country/country.service.ts index 6541a24cc1..c788abc161 100644 --- a/services/API-service/src/api/country/country.service.ts +++ b/services/API-service/src/api/country/country.service.ts @@ -3,9 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { In, Repository } from 'typeorm'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; +import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { NotificationInfoEntity } from '../notification/notifcation-info.entity'; import { AdminLevel } from './admin-level.enum'; import { CountryDisasterSettingsEntity } from './country-disaster.entity'; @@ -21,18 +21,15 @@ import { NotificationInfoDto } from './dto/notification-info.dto'; export class CountryService { @InjectRepository(CountryEntity) private readonly countryRepository: Repository; - @InjectRepository(DisasterEntity) - private readonly disasterRepository: Repository; + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; @InjectRepository(CountryDisasterSettingsEntity) private readonly countryDisasterSettingsRepository: Repository; - @InjectRepository(LeadTimeEntity) - private readonly leadTimeRepository: Repository; @InjectRepository(NotificationInfoEntity) private readonly notificationInfoRepository: Repository; private readonly relations: string[] = [ 'countryDisasterSettings', - 'countryDisasterSettings.activeLeadTimes', 'disasterTypes', 'notificationInfo', ]; @@ -93,7 +90,7 @@ export class CountryService { countryEntity.adminRegionLabels = JSON.parse( JSON.stringify(country.adminRegionLabels), ); - countryEntity.disasterTypes = await this.disasterRepository.find({ + countryEntity.disasterTypes = await this.disasterTypeRepository.find({ where: country.disasterTypes .filter((disasterType) => { if (envDisasterTypes) { @@ -130,27 +127,27 @@ export class CountryService { await this.countryRepository.save(countryEntity); - for await (const disaster of country.countryDisasterSettings) { + for await (const disasterType of country.countryDisasterSettings) { const existingDisaster = countryEntity.countryDisasterSettings.find( - (d) => d.disasterType === disaster.disasterType, + (d) => d.disasterType === disasterType.disasterType, ); if (existingDisaster) { const savedDisaster = await this.addOrUpdateDisaster( existingDisaster, - disaster, + disasterType, ); countryEntity.countryDisasterSettings.push(savedDisaster); continue; } - const newDisaster = new CountryDisasterSettingsEntity(); - newDisaster.country = await this.countryRepository.findOne({ + const newDisasterType = new CountryDisasterSettingsEntity(); + newDisasterType.country = await this.countryRepository.findOne({ where: { countryCodeISO3: country.countryCodeISO3 }, }); - newDisaster.disasterType = disaster.disasterType as DisasterType; + newDisasterType.disasterType = disasterType.disasterType as DisasterType; const savedDisaster = await this.addOrUpdateDisaster( - newDisaster, - disaster, + newDisasterType, + disasterType, ); countryEntity.countryDisasterSettings.push(savedDisaster); } @@ -160,44 +157,38 @@ export class CountryService { private async addOrUpdateDisaster( countryDisasterSettingsEntity: CountryDisasterSettingsEntity, - disaster: CountryDisasterSettingsDto, + disasterType: CountryDisasterSettingsDto, ): Promise { countryDisasterSettingsEntity.adminLevels = - disaster.adminLevels as AdminLevel[]; + disasterType.adminLevels as AdminLevel[]; countryDisasterSettingsEntity.defaultAdminLevel = - disaster.defaultAdminLevel as AdminLevel; + disasterType.defaultAdminLevel as AdminLevel; - countryDisasterSettingsEntity.eapLink = disaster.eapLink; - countryDisasterSettingsEntity.eapAlertClasses = disaster.eapAlertClasses - ? JSON.parse(JSON.stringify([disaster.eapAlertClasses]))[0] + countryDisasterSettingsEntity.eapLink = disasterType.eapLink; + countryDisasterSettingsEntity.eapAlertClasses = disasterType.eapAlertClasses + ? JSON.parse(JSON.stringify([disasterType.eapAlertClasses]))[0] : null; countryDisasterSettingsEntity.droughtSeasonRegions = - disaster.droughtSeasonRegions - ? JSON.parse(JSON.stringify(disaster.droughtSeasonRegions)) + disasterType.droughtSeasonRegions + ? JSON.parse(JSON.stringify(disasterType.droughtSeasonRegions)) : null; countryDisasterSettingsEntity.droughtEndOfMonthPipeline = - disaster.droughtEndOfMonthPipeline; - countryDisasterSettingsEntity.droughtRegions = disaster.droughtRegions - ? JSON.parse(JSON.stringify(disaster.droughtRegions)) + disasterType.droughtEndOfMonthPipeline; + countryDisasterSettingsEntity.droughtRegions = disasterType.droughtRegions + ? JSON.parse(JSON.stringify(disasterType.droughtRegions)) : null; countryDisasterSettingsEntity.showMonthlyEapActions = - disaster.showMonthlyEapActions; + disasterType.showMonthlyEapActions; countryDisasterSettingsEntity.enableEarlyActions = - disaster.enableEarlyActions; + disasterType.enableEarlyActions; countryDisasterSettingsEntity.monthlyForecastInfo = - disaster.monthlyForecastInfo - ? JSON.parse(JSON.stringify(disaster.monthlyForecastInfo)) + disasterType.monthlyForecastInfo + ? JSON.parse(JSON.stringify(disasterType.monthlyForecastInfo)) : null; countryDisasterSettingsEntity.activeLeadTimes = - await this.leadTimeRepository.find({ - where: disaster.activeLeadTimes.map( - (countryLeadTime: string): object => { - return { leadTimeName: countryLeadTime }; - }, - ), - }); - countryDisasterSettingsEntity.isEventBased = disaster.isEventBased; + disasterType.activeLeadTimes as LeadTime[]; + countryDisasterSettingsEntity.isEventBased = disasterType.isEventBased; const saveResult = await this.countryDisasterSettingsRepository.save( countryDisasterSettingsEntity, diff --git a/services/API-service/src/api/country/dto/add-countries.dto.ts b/services/API-service/src/api/country/dto/add-countries.dto.ts index dfab4dc17b..84d6031cd7 100644 --- a/services/API-service/src/api/country/dto/add-countries.dto.ts +++ b/services/API-service/src/api/country/dto/add-countries.dto.ts @@ -3,7 +3,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty } from 'class-validator'; import { BoundingBox } from '../../../shared/geo.model'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { AdminLevel } from '../admin-level.enum'; export class CountryDto { diff --git a/services/API-service/src/api/disaster-type/disaster-type.controller.ts b/services/API-service/src/api/disaster-type/disaster-type.controller.ts new file mode 100644 index 0000000000..2b62eed59e --- /dev/null +++ b/services/API-service/src/api/disaster-type/disaster-type.controller.ts @@ -0,0 +1,34 @@ +import { Body, Controller, Post } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiOperation, + ApiResponse, + ApiTags, +} from '@nestjs/swagger'; + +import { Roles } from '../../roles.decorator'; +import { UserRole } from '../user/user-role.enum'; +import { DisasterTypeService } from './disaster-type.service'; +import { AddDisasterTypesDto } from './dto/add-disaster-type.dto'; + +@ApiBearerAuth() +@ApiTags('disaster-type') +@Controller('disaster-type') +export class DisasterTypeController { + public constructor( + private readonly disasterTypeService: DisasterTypeService, + ) {} + + @Roles(UserRole.Admin) + @ApiOperation({ summary: 'Adds or updates (if existing) disasterTypes' }) + @ApiResponse({ + status: 201, + description: 'Added and/or updated disasterType-properties.', + }) + @Post() + public async addOrUpdateDisasterTypes( + @Body() disasterTypes: AddDisasterTypesDto, + ): Promise { + await this.disasterTypeService.addOrUpdateDisasterTypes(disasterTypes); + } +} diff --git a/services/API-service/src/api/disaster/disaster.entity.ts b/services/API-service/src/api/disaster-type/disaster-type.entity.ts similarity index 76% rename from services/API-service/src/api/disaster/disaster.entity.ts rename to services/API-service/src/api/disaster-type/disaster-type.entity.ts index b648e2a537..b14bb94fd6 100644 --- a/services/API-service/src/api/disaster/disaster.entity.ts +++ b/services/API-service/src/api/disaster-type/disaster-type.entity.ts @@ -12,12 +12,12 @@ import { LeadTime, LeadTimeUnit, } from '../admin-area-dynamic-data/enum/lead-time.enum'; +import { CountryEntity } from '../country/country.entity'; import { UserEntity } from '../user/user.entity'; -import { CountryEntity } from './../country/country.entity'; import { DisasterType } from './disaster-type.enum'; @Entity('disaster') -export class DisasterEntity { +export class DisasterTypeEntity { @ApiProperty({ example: '6b9b7669-4839-4fdb-9645-9070a27bda86' }) @PrimaryGeneratedColumn('uuid') public id: string; @@ -30,13 +30,14 @@ export class DisasterEntity { @Column() public label: string; - @ApiProperty({ example: 'population_affected' }) - @Column({ default: 'population_affected' }) - public triggerUnit: string; + // REFACTOR: thisshould always be 'alert_threshold', so should not be a column + @ApiProperty({ example: 'alert_threshold' }) + @Column({ default: 'alert_threshold' }) + public triggerIndicator: string; @ApiProperty({ example: 'population_affected' }) @Column({ default: 'population_affected' }) - public actionsUnit: string; + public mainExposureIndicator: string; @ApiProperty({ example: false }) @Column({ default: false }) @@ -45,7 +46,7 @@ export class DisasterEntity { @ApiProperty({ example: [{ countryCodeISO3: 'UGA' }] }) @ManyToMany( (): typeof CountryEntity => CountryEntity, - (countries): DisasterEntity[] => countries.disasterTypes, + (countries): DisasterTypeEntity[] => countries.disasterTypes, ) @JoinTable() public countries: CountryEntity[]; @@ -64,7 +65,7 @@ export class DisasterEntity { @ManyToMany( (): typeof UserEntity => UserEntity, - (user): DisasterEntity[] => user.disasterTypes, + (user): DisasterTypeEntity[] => user.disasterTypes, ) public users: UserEntity[]; } diff --git a/services/API-service/src/api/disaster/disaster-type.enum.ts b/services/API-service/src/api/disaster-type/disaster-type.enum.ts similarity index 100% rename from services/API-service/src/api/disaster/disaster-type.enum.ts rename to services/API-service/src/api/disaster-type/disaster-type.enum.ts diff --git a/services/API-service/src/api/disaster-type/disaster-type.module.ts b/services/API-service/src/api/disaster-type/disaster-type.module.ts new file mode 100644 index 0000000000..4a11d484d8 --- /dev/null +++ b/services/API-service/src/api/disaster-type/disaster-type.module.ts @@ -0,0 +1,20 @@ +import { HttpModule } from '@nestjs/axios'; +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { UserModule } from '../user/user.module'; +import { DisasterTypeController } from './disaster-type.controller'; +import { DisasterTypeEntity } from './disaster-type.entity'; +import { DisasterTypeService } from './disaster-type.service'; + +@Module({ + imports: [ + HttpModule, + UserModule, + TypeOrmModule.forFeature([DisasterTypeEntity]), + ], + providers: [DisasterTypeService], + controllers: [DisasterTypeController], + exports: [DisasterTypeService], +}) +export class DisasterTypeModule {} diff --git a/services/API-service/src/api/disaster-type/disaster-type.service.spec.ts b/services/API-service/src/api/disaster-type/disaster-type.service.spec.ts new file mode 100644 index 0000000000..ddfcc7901f --- /dev/null +++ b/services/API-service/src/api/disaster-type/disaster-type.service.spec.ts @@ -0,0 +1,85 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; + +import { beforeEach, describe, expect, it } from '@jest/globals'; +import { Repository } from 'typeorm'; + +import disasterTypes from '../../scripts/json/disaster-types.json'; +import { + LeadTime, + LeadTimeUnit, +} from '../admin-area-dynamic-data/enum/lead-time.enum'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from './disaster-type.enum'; +import { DisasterTypeService } from './disaster-type.service'; +import { DisasterTypeDto } from './dto/add-disaster-type.dto'; + +describe('DisasterTypeService', () => { + let service: DisasterTypeService; + let disasterTypeRepository: Repository; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + DisasterTypeService, + { + provide: getRepositoryToken(DisasterTypeEntity), + useClass: Repository, + }, + ], + }).compile(); + + service = module.get(DisasterTypeService); + disasterTypeRepository = module.get>( + getRepositoryToken(DisasterTypeEntity), + ); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + describe('addOrUpdateDisasterTypes', () => { + it('should add or update disasterTypes', async () => { + // Arrange + jest + .spyOn(disasterTypeRepository, 'findOne') + .mockResolvedValue(new DisasterTypeEntity()); + jest + .spyOn(disasterTypeRepository, 'save') + .mockResolvedValue(new DisasterTypeEntity()); + + const disasterTypeDtos = disasterTypes.map( + (disasterType): DisasterTypeDto => { + const disasterTypeDto = new DisasterTypeDto(); + disasterTypeDto.disasterType = + disasterType.disasterType as DisasterType; + disasterTypeDto.label = disasterType.label; + disasterTypeDto.triggerIndicator = disasterType.triggerIndicator; + disasterTypeDto.mainExposureIndicator = + disasterType.mainExposureIndicator; + disasterTypeDto.showOnlyTriggeredAreas = + disasterType.showOnlyTriggeredAreas; + disasterTypeDto.leadTimeUnit = + disasterType.leadTimeUnit as LeadTimeUnit; + disasterTypeDto.minLeadTime = disasterType.minLeadTime as LeadTime; + disasterTypeDto.maxLeadTime = disasterType.maxLeadTime as LeadTime; + return disasterTypeDto; + }, + ); + + // Act + await service.addOrUpdateDisasterTypes({ + disasterTypes: disasterTypeDtos, + }); + + // Assert + for (const disasterType of disasterTypes) { + expect(disasterTypeRepository.findOne).toHaveBeenCalledWith({ + where: { disasterType: disasterType.disasterType }, + }); + expect(disasterTypeRepository.save).toHaveBeenCalled(); + } + }); + }); +}); diff --git a/services/API-service/src/api/disaster-type/disaster-type.service.ts b/services/API-service/src/api/disaster-type/disaster-type.service.ts new file mode 100644 index 0000000000..58c6d57a2c --- /dev/null +++ b/services/API-service/src/api/disaster-type/disaster-type.service.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + +import { DisasterTypeEntity } from './disaster-type.entity'; +import { + AddDisasterTypesDto, + DisasterTypeDto, +} from './dto/add-disaster-type.dto'; + +@Injectable() +export class DisasterTypeService { + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; + + public async addOrUpdateDisasterTypes( + disasterTypes: AddDisasterTypesDto, + ): Promise { + for await (const disasterType of disasterTypes.disasterTypes) { + const existingDisasterType = await this.disasterTypeRepository.findOne({ + where: { + disasterType: disasterType.disasterType, + }, + }); + if (existingDisasterType) { + await this.addOrUpdateDisasterType(existingDisasterType, disasterType); + continue; + } + + const newDisasterType = new DisasterTypeEntity(); + newDisasterType.disasterType = disasterType.disasterType; + await this.addOrUpdateDisasterType(newDisasterType, disasterType); + } + } + + private async addOrUpdateDisasterType( + disasterTypeEntity: DisasterTypeEntity, + disasterTypeDto: DisasterTypeDto, + ): Promise { + disasterTypeEntity.disasterType = disasterTypeDto.disasterType; + disasterTypeEntity.label = disasterTypeDto.label; + disasterTypeEntity.triggerIndicator = disasterTypeDto.triggerIndicator; + disasterTypeEntity.mainExposureIndicator = + disasterTypeDto.mainExposureIndicator; + disasterTypeEntity.showOnlyTriggeredAreas = + disasterTypeDto.showOnlyTriggeredAreas; + disasterTypeEntity.leadTimeUnit = disasterTypeDto.leadTimeUnit; + disasterTypeEntity.minLeadTime = disasterTypeDto.minLeadTime; + disasterTypeEntity.maxLeadTime = disasterTypeDto.maxLeadTime; + + await this.disasterTypeRepository.save(disasterTypeEntity); + } +} diff --git a/services/API-service/src/api/disaster-type/dto/add-disaster-type.dto.ts b/services/API-service/src/api/disaster-type/dto/add-disaster-type.dto.ts new file mode 100644 index 0000000000..04b5a84935 --- /dev/null +++ b/services/API-service/src/api/disaster-type/dto/add-disaster-type.dto.ts @@ -0,0 +1,49 @@ +import { ApiProperty } from '@nestjs/swagger'; + +import { IsNotEmpty } from 'class-validator'; + +import { + LeadTime, + LeadTimeUnit, +} from '../../admin-area-dynamic-data/enum/lead-time.enum'; +import { DisasterType } from '../disaster-type.enum'; + +export class DisasterTypeDto { + @ApiProperty({ example: 'DisasterType.Floods' }) + public disasterType: DisasterType; + + @ApiProperty({ example: 'flood' }) + public label: string; + + @ApiProperty({ + example: 'alert_threshold', + description: `List the 'indicator' here that is used to identify trigger status. Must be 'alert_threshold' at the moment.`, + }) + public triggerIndicator: string; + + @ApiProperty({ + example: 'population_affected', + description: `List the 'indicator' here that is used as main exposure indicator.`, + }) + public mainExposureIndicator: string; + + @ApiProperty({ default: false }) + public showOnlyTriggeredAreas: boolean; + + @ApiProperty({ example: LeadTimeUnit.day }) + public leadTimeUnit: LeadTimeUnit; + + @ApiProperty({ example: LeadTime.day0 }) + public minLeadTime: LeadTime; + + @ApiProperty({ example: LeadTime.day7 }) + public maxLeadTime: LeadTime; +} + +export class AddDisasterTypesDto { + @ApiProperty({ + example: [{}], + }) + @IsNotEmpty() + public disasterTypes: DisasterTypeDto[]; +} diff --git a/services/API-service/src/api/disaster/disaster.module.ts b/services/API-service/src/api/disaster/disaster.module.ts deleted file mode 100644 index 41c8039b28..0000000000 --- a/services/API-service/src/api/disaster/disaster.module.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Module } from '@nestjs/common'; - -@Module({}) -export class DisasterModule {} diff --git a/services/API-service/src/api/eap-actions/area-of-focus.entity.ts b/services/API-service/src/api/eap-actions/area-of-focus.entity.ts deleted file mode 100644 index 2e1cf58a1b..0000000000 --- a/services/API-service/src/api/eap-actions/area-of-focus.entity.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - -import { Column, Entity, OneToMany, PrimaryColumn } from 'typeorm'; - -import { EapActionEntity } from './eap-action.entity'; - -@Entity('area-of-focus') -export class AreaOfFocusEntity { - @ApiProperty({ example: 'shelter' }) - @PrimaryColumn() - public id: string; - - @ApiProperty({ example: 'Shelter' }) - @Column() - public label: string; - - @ApiProperty({ example: 'Shelter description' }) - @Column({ nullable: true }) - public description: string; - - @ApiProperty({ example: 'Shelter.svg' }) - @Column() - public icon: string; - - @OneToMany( - (): typeof EapActionEntity => EapActionEntity, - (areaOfFocus): AreaOfFocusEntity => areaOfFocus.areaOfFocus, - ) - public actions: EapActionEntity[]; -} diff --git a/services/API-service/src/api/eap-actions/dto/area-of-focus.dto.ts b/services/API-service/src/api/eap-actions/dto/area-of-focus.dto.ts new file mode 100644 index 0000000000..e72b28478f --- /dev/null +++ b/services/API-service/src/api/eap-actions/dto/area-of-focus.dto.ts @@ -0,0 +1,25 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class AreaOfFocusEnum { + public static readonly DISASTER_RISK_REDUCTION = 'disaster-risk-reduction'; + public static readonly SHELTER = 'shelter'; + public static readonly LIVELIHOOD = 'livelihood'; + public static readonly HEALTH = 'health'; + public static readonly WASH = 'wash'; + public static readonly INCLUSION = 'inclusion'; + public static readonly MIGRATION = 'migration'; +} + +export class AreaOfFocusDto { + @ApiProperty({ example: 'shelter' }) + public id: AreaOfFocusEnum; + + @ApiProperty({ example: 'Shelter' }) + public label: string; + + @ApiProperty({ example: 'Shelter description' }) + public description: string; + + @ApiProperty({ example: 'Shelter.svg' }) + public icon: string; +} diff --git a/services/API-service/src/api/eap-actions/dto/eap-action.dto.ts b/services/API-service/src/api/eap-actions/dto/eap-action.dto.ts index 8c8ae807ca..1c8812fc9d 100644 --- a/services/API-service/src/api/eap-actions/dto/eap-action.dto.ts +++ b/services/API-service/src/api/eap-actions/dto/eap-action.dto.ts @@ -1,11 +1,11 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString } from 'class-validator'; +import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator'; -import { DisasterType } from '../../disaster/disaster-type.enum'; -import { AreaOfFocusEntity } from '../area-of-focus.entity'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; +import { AreaOfFocusEnum } from './area-of-focus.dto'; -class EapActionDto { +export class EapActionDto { @ApiProperty({ example: 'UGA' }) @IsNotEmpty() @IsString() @@ -16,22 +16,28 @@ class EapActionDto { @IsString() public disasterType: string; - @ApiProperty({ example: JSON.parse(JSON.stringify({ id: 'drr' })) }) + @ApiProperty({ example: AreaOfFocusEnum.DISASTER_RISK_REDUCTION }) @IsNotEmpty() - public areaOfFocus: AreaOfFocusEntity; + @IsEnum(AreaOfFocusEnum) + public areaOfFocusId: AreaOfFocusEnum; - @ApiProperty({ example: 'drr-1' }) + @ApiProperty({ example: 'disaster-risk-reduction-1' }) @IsNotEmpty() @IsString() public action: string; - @ApiProperty({ example: 'DRR dummy action' }) + @ApiProperty({ example: 'Dummy action' }) @IsNotEmpty() @IsString() public label: string; - @ApiProperty({ example: null }) - public month: JSON; + @ApiProperty({ + example: null, + description: + 'Specify an optional calendar month (1-12) in which this action is applicable.', + }) + @IsOptional() + public month?: object; } export class AddEapActionsDto { @@ -40,9 +46,9 @@ export class AddEapActionsDto { { countryCodeISO3: 'UGA', disasterType: DisasterType.Floods, - action: 'drr-1', - areaOfFocus: { id: 'drr' }, - label: 'DRR dummy action', + action: 'disaster-risk-reduction-1', + areaOfFocus: AreaOfFocusEnum.DISASTER_RISK_REDUCTION, + label: 'Dummy action', month: null, }, ], diff --git a/services/API-service/src/api/eap-actions/eap-action.entity.ts b/services/API-service/src/api/eap-actions/eap-action.entity.ts index 51ac4442b5..d65cbe6a6d 100644 --- a/services/API-service/src/api/eap-actions/eap-action.entity.ts +++ b/services/API-service/src/api/eap-actions/eap-action.entity.ts @@ -8,8 +8,7 @@ import { } from 'typeorm'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; -import { AreaOfFocusEntity } from './area-of-focus.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { EapActionStatusEntity } from './eap-action-status.entity'; @Entity('eap-action') @@ -35,18 +34,15 @@ export class EapActionEntity { }) public countryCodeISO3: string; - @ManyToOne((): typeof DisasterEntity => DisasterEntity) + @ManyToOne((): typeof DisasterTypeEntity => DisasterTypeEntity) @JoinColumn({ name: 'disasterType', referencedColumnName: 'disasterType', }) public disasterType: string; - @ManyToOne( - (): typeof AreaOfFocusEntity => AreaOfFocusEntity, - (aof): EapActionEntity[] => aof.actions, - ) - public areaOfFocus: AreaOfFocusEntity; + @Column({ nullable: true }) + public areaOfFocusId: string; @OneToMany( (): typeof EapActionStatusEntity => EapActionStatusEntity, diff --git a/services/API-service/src/api/eap-actions/eap-actions.controller.ts b/services/API-service/src/api/eap-actions/eap-actions.controller.ts index 155f3348a6..82a0cd4d69 100644 --- a/services/API-service/src/api/eap-actions/eap-actions.controller.ts +++ b/services/API-service/src/api/eap-actions/eap-actions.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'; +import { Body, Controller, Param, Post, UseGuards } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, @@ -9,10 +9,9 @@ import { import { Roles } from '../../roles.decorator'; import { RolesGuard } from '../../roles.guard'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { UserRole } from '../user/user-role.enum'; import { UserDecorator } from '../user/user.decorator'; -import { AreaOfFocusEntity } from './area-of-focus.entity'; import { CheckEapActionDto } from './dto/check-eap-action.dto'; import { AddEapActionsDto } from './dto/eap-action.dto'; import { EapActionStatusEntity } from './eap-action-status.entity'; @@ -79,16 +78,4 @@ export class EapActionsController { eapActions, ); } - - @UseGuards(RolesGuard) - @ApiOperation({ summary: 'Get Areas of Focus (categories of EAP-actions)' }) - @ApiResponse({ - status: 200, - description: 'Areas of focus.', - type: [AreaOfFocusEntity], - }) - @Get('areas-of-focus') - public async getAreasOfFocus(): Promise { - return await this.eapActionsService.getAreasOfFocus(); - } } diff --git a/services/API-service/src/api/eap-actions/eap-actions.module.ts b/services/API-service/src/api/eap-actions/eap-actions.module.ts index b9e19d453e..291a075041 100644 --- a/services/API-service/src/api/eap-actions/eap-actions.module.ts +++ b/services/API-service/src/api/eap-actions/eap-actions.module.ts @@ -8,7 +8,6 @@ import { TriggerPerLeadTime } from '../event/trigger-per-lead-time.entity'; import { UserEntity } from '../user/user.entity'; import { UserModule } from '../user/user.module'; import { CountryEntity } from './../country/country.entity'; -import { AreaOfFocusEntity } from './area-of-focus.entity'; import { EapActionStatusEntity } from './eap-action-status.entity'; import { EapActionEntity } from './eap-action.entity'; import { EapActionsController } from './eap-actions.controller'; @@ -20,7 +19,6 @@ import { EapActionsService } from './eap-actions.service'; UserEntity, EapActionEntity, EapActionStatusEntity, - AreaOfFocusEntity, TriggerPerLeadTime, CountryEntity, EventPlaceCodeEntity, diff --git a/services/API-service/src/api/eap-actions/eap-actions.service.ts b/services/API-service/src/api/eap-actions/eap-actions.service.ts index 79853bd17c..93be8afdcc 100644 --- a/services/API-service/src/api/eap-actions/eap-actions.service.ts +++ b/services/API-service/src/api/eap-actions/eap-actions.service.ts @@ -4,10 +4,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { In, IsNull, Repository } from 'typeorm'; import { AdminAreaEntity } from '../admin-area/admin-area.entity'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { EventPlaceCodeEntity } from '../event/event-place-code.entity'; import { UserEntity } from '../user/user.entity'; -import { AreaOfFocusEntity } from './area-of-focus.entity'; import { CheckEapActionDto } from './dto/check-eap-action.dto'; import { AddEapActionsDto } from './dto/eap-action.dto'; import { EapActionStatusEntity } from './eap-action-status.entity'; @@ -26,8 +25,6 @@ export class EapActionsService { private readonly eapActionStatusRepository: Repository; @InjectRepository(EapActionEntity) private readonly eapActionRepository: Repository; - @InjectRepository(AreaOfFocusEntity) - private readonly areaOfFocusRepository: Repository; @InjectRepository(EventPlaceCodeEntity) private readonly eventPlaceCodeRepository: Repository; @InjectRepository(AdminAreaEntity) @@ -47,8 +44,10 @@ export class EapActionsService { }); if (existingEapAction) { existingEapAction.label = eapAction.label; - existingEapAction.areaOfFocus = eapAction.areaOfFocus; - existingEapAction.month = eapAction.month; + existingEapAction.areaOfFocusId = eapAction.areaOfFocusId as string; + existingEapAction.month = JSON.parse( + JSON.stringify(eapAction.month || {}), + ); eapActionsToSave.push(existingEapAction); continue; } @@ -58,8 +57,8 @@ export class EapActionsService { newEapAction.disasterType = eapAction.disasterType; newEapAction.action = eapAction.action; newEapAction.label = eapAction.label; - newEapAction.areaOfFocus = eapAction.areaOfFocus; - newEapAction.month = eapAction.month; + newEapAction.areaOfFocusId = eapAction.areaOfFocusId as string; + newEapAction.month = JSON.parse(JSON.stringify(eapAction.month || {})); eapActionsToSave.push(newEapAction); } return await this.eapActionRepository.save(eapActionsToSave); @@ -164,10 +163,6 @@ export class EapActionsService { } } - public async getAreasOfFocus(): Promise { - return await this.areaOfFocusRepository.find(); - } - public async getActionsWithStatus( countryCodeISO3: string, disasterType: string, @@ -213,8 +208,7 @@ export class EapActionsService { const eapActions = await this.eapActionRepository .createQueryBuilder('action') .select([ - 'area."label" AS "aofLabel"', - 'area.id AS aof', + 'action."areaOfFocusId" AS aof', 'action."action"', 'action."label"', 'action."disasterType"', @@ -232,7 +226,6 @@ export class EapActionsService { { placeCode }, ) .setParameters(eapActionsStates.getParameters()) - .leftJoin('action.areaOfFocus', 'area') .where('action."countryCodeISO3" = :countryCodeISO3', { countryCodeISO3: countryCodeISO3, }) diff --git a/services/API-service/src/api/event/dto/event-place-code.dto.ts b/services/API-service/src/api/event/dto/event-place-code.dto.ts index f41b79a732..5299baf550 100644 --- a/services/API-service/src/api/event/dto/event-place-code.dto.ts +++ b/services/API-service/src/api/event/dto/event-place-code.dto.ts @@ -3,11 +3,11 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString } from 'class-validator'; import { LeadTime } from '../../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; export class AffectedAreaDto { public placeCode: string; - public actionsValue: number; + public mainExposureValue: number; public triggerValue: number; public leadTime: LeadTime; } diff --git a/services/API-service/src/api/event/dto/trigger-per-leadtime.dto.ts b/services/API-service/src/api/event/dto/trigger-per-leadtime.dto.ts index 1aa1fe456e..48af6caf9f 100644 --- a/services/API-service/src/api/event/dto/trigger-per-leadtime.dto.ts +++ b/services/API-service/src/api/event/dto/trigger-per-leadtime.dto.ts @@ -1,6 +1,12 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { + IsBoolean, + IsEnum, + IsNotEmpty, + IsOptional, + IsString, +} from 'class-validator'; import { LeadTime } from '../../admin-area-dynamic-data/enum/lead-time.enum'; @@ -8,6 +14,7 @@ export class TriggerPerLeadTimeDto { @ApiProperty({ example: '7-day' }) @IsNotEmpty() @IsString() + @IsEnum(LeadTime) public leadTime: LeadTime; @ApiProperty({ default: false }) diff --git a/services/API-service/src/api/event/dto/upload-trigger-per-leadtime.dto.ts b/services/API-service/src/api/event/dto/upload-trigger-per-leadtime.dto.ts index b1ecbceee0..b6918325d6 100644 --- a/services/API-service/src/api/event/dto/upload-trigger-per-leadtime.dto.ts +++ b/services/API-service/src/api/event/dto/upload-trigger-per-leadtime.dto.ts @@ -11,7 +11,7 @@ import { } from 'class-validator'; import triggers from '../../../scripts/mock-data/floods/UGA/trigger/G5075/triggers-per-leadtime.json'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { TriggerPerLeadTimeDto } from './trigger-per-leadtime.dto'; export class UploadTriggerPerLeadTimeDto { diff --git a/services/API-service/src/api/event/event-place-code.entity.ts b/services/API-service/src/api/event/event-place-code.entity.ts index bef237b0a2..f845485e9f 100644 --- a/services/API-service/src/api/event/event-place-code.entity.ts +++ b/services/API-service/src/api/event/event-place-code.entity.ts @@ -10,7 +10,7 @@ import { } from 'typeorm'; import { AdminAreaEntity } from '../admin-area/admin-area.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { EapActionStatusEntity } from '../eap-actions/eap-action-status.entity'; import { UserEntity } from '../user/user.entity'; @@ -25,7 +25,7 @@ export class EventPlaceCodeEntity { ) public adminArea: AdminAreaEntity; - @ManyToOne((): typeof DisasterEntity => DisasterEntity) + @ManyToOne((): typeof DisasterTypeEntity => DisasterTypeEntity) @JoinColumn({ name: 'disasterType', referencedColumnName: 'disasterType', @@ -47,7 +47,7 @@ export class EventPlaceCodeEntity { public triggerValue: number; @Column({ type: 'float8', nullable: true }) - public actionsValue: number; + public mainExposureValue: number; @Column({ type: 'timestamp', nullable: true }) @Check(`"startDate" <= "endDate"`) diff --git a/services/API-service/src/api/event/event.module.ts b/services/API-service/src/api/event/event.module.ts index 92c8f45770..a77994222f 100644 --- a/services/API-service/src/api/event/event.module.ts +++ b/services/API-service/src/api/event/event.module.ts @@ -5,7 +5,7 @@ import { HelperService } from '../../shared/helper.service'; import { AdminAreaDynamicDataEntity } from '../admin-area-dynamic-data/admin-area-dynamic-data.entity'; import { AdminAreaEntity } from '../admin-area/admin-area.entity'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { TyphoonTrackModule } from '../typhoon-track/typhoon-track.module'; import { UserEntity } from '../user/user.entity'; import { CountryModule } from './../country/country.module'; @@ -27,7 +27,7 @@ import { TriggerPerLeadTime } from './trigger-per-lead-time.entity'; TriggerPerLeadTime, AdminAreaDynamicDataEntity, AdminAreaEntity, - DisasterEntity, + DisasterTypeEntity, UserEntity, CountryEntity, ]), diff --git a/services/API-service/src/api/event/event.service.ts b/services/API-service/src/api/event/event.service.ts index d4c71a6d51..05b3afd032 100644 --- a/services/API-service/src/api/event/event.service.ts +++ b/services/API-service/src/api/event/event.service.ts @@ -23,8 +23,8 @@ import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; import { AdminAreaEntity } from '../admin-area/admin-area.entity'; import { CountryDisasterSettingsEntity } from '../country/country-disaster.entity'; import { CountryEntity } from '../country/country.entity'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { TyphoonTrackService } from '../typhoon-track/typhoon-track.service'; import { UserEntity } from '../user/user.entity'; import { AdminAreaDynamicDataEntity } from './../admin-area-dynamic-data/admin-area-dynamic-data.entity'; @@ -50,8 +50,8 @@ export class EventService { private readonly adminAreaRepository: Repository; @InjectRepository(TriggerPerLeadTime) private readonly triggerPerLeadTimeRepository: Repository; - @InjectRepository(DisasterEntity) - private readonly disasterTypeRepository: Repository; + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; @InjectRepository(UserEntity) private readonly userRepository: Repository; @InjectRepository(CountryEntity) @@ -174,9 +174,9 @@ export class EventService { 'to_char(MIN("startDate") , \'yyyy-mm-dd\') AS "startDate"', 'to_char(MAX("endDate") , \'yyyy-mm-dd\') AS "endDate"', 'MAX(event."thresholdReached"::int)::boolean AS "thresholdReached"', - 'SUM(CASE WHEN event."actionsValue" > 0 OR event."triggerValue" > 0 THEN 1 ELSE 0 END) AS "nrAffectedAreas"', // This count is needed here, because the portal also needs the count of other events when in event view, which it cannot get any more from the triggeredAreas array length, which is then filtered on selected event only + 'SUM(CASE WHEN event."mainExposureValue" > 0 OR event."triggerValue" > 0 THEN 1 ELSE 0 END) AS "nrAffectedAreas"', // This count is needed here, because the portal also needs the count of other events when in event view, which it cannot get any more from the triggeredAreas array length, which is then filtered on selected event only 'MAX(event."triggerValue")::float AS "triggerValue"', - 'sum(event."actionsValue")::int AS "actionsValueSum"', + 'sum(event."mainExposureValue")::int AS "actionsValueSum"', ]) .andWhere('area."countryCodeISO3" = :countryCodeISO3', { countryCodeISO3: countryCodeISO3, @@ -271,13 +271,15 @@ export class EventService { await this.eventPlaceCodeRepo.remove(eventAreasToDelete); } - public async getTriggerUnit(disasterType: DisasterType): Promise { + public async getTriggerIndicator( + disasterType: DisasterType, + ): Promise { return ( await this.disasterTypeRepository.findOne({ - select: ['triggerUnit'], + select: ['triggerIndicator'], where: { disasterType }, }) - ).triggerUnit; + ).triggerIndicator; } private async getCountryDisasterSettings( @@ -303,13 +305,13 @@ export class EventService { countryCodeISO3, disasterType, ); - const triggerUnit = await this.getTriggerUnit(disasterType); + const triggerIndicator = await this.getTriggerIndicator(disasterType); const defaultAdminLevel = ( await this.getCountryDisasterSettings(countryCodeISO3, disasterType) ).defaultAdminLevel; const whereFiltersDynamicData = { - indicator: triggerUnit, // REFACTOR: trigger unit and indicator should not be used interchangeably + indicator: triggerIndicator, value: MoreThan(0), adminLevel, disasterType, @@ -359,7 +361,7 @@ export class EventService { 'area."placeCode" AS "placeCode"', 'area.name AS name', 'area."adminLevel" AS "adminLevel"', - 'event."actionsValue"', + 'event."mainExposureValue"', 'event."triggerValue"', 'event."eventPlaceCodeId"', 'event."stopped"', @@ -379,8 +381,8 @@ export class EventService { .andWhere('area."countryCodeISO3" = :countryCodeISO3', { countryCodeISO3: countryCodeISO3, }) - .andWhere('(event."actionsValue" > 0 OR event."triggerValue" > 0)') - .orderBy('event."actionsValue"', 'DESC') + .andWhere('(event."mainExposureValue" > 0 OR event."triggerValue" > 0)') + .orderBy('event."mainExposureValue"', 'DESC') .getRawMany(); for (const area of triggeredAreas) { @@ -408,10 +410,11 @@ export class EventService { eventName?: string, leadTime?: string, ): Promise { - const actionUnit = await this.getActionUnit(disasterType); + const mainExposureIndicator = + await this.getMainExposureIndicator(disasterType); const whereFilters = { placeCode: In(triggeredPlaceCodes), - indicator: actionUnit, + indicator: mainExposureIndicator, disasterType, timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( @@ -467,7 +470,7 @@ export class EventService { placeCode: area.placeCode, name: area.name, nameParent: null, - actionsValue: area.value, + mainExposureValue: area.value, triggerValue: null, // leave empty for now, as we don't show triggerValue on deeper levels stopped: area.stopped, startDate: area.startDate, @@ -493,8 +496,8 @@ export class EventService { 'event."startDate"', 'event.closed as closed', 'case when event.closed = true then event."endDate" end as "endDate"', - 'disaster."actionsUnit" as "exposureIndicator"', - 'event."actionsValue" as "exposureValue"', + 'disaster."mainExposureIndicator" as "exposureIndicator"', + 'event."mainExposureValue" as "exposureValue"', `CASE event."triggerValue" WHEN 1 THEN 'Trigger/alert' WHEN 0.7 THEN 'Medium warning' WHEN 0.3 THEN 'Low warning' END as "alertClass"`, 'event."eventPlaceCodeId" as "databaseId"', ]) @@ -650,13 +653,15 @@ export class EventService { ).map((area) => area.id); } - private async getActionUnit(disasterType: DisasterType): Promise { + private async getMainExposureIndicator( + disasterType: DisasterType, + ): Promise { return ( await this.disasterTypeRepository.findOne({ - select: ['actionsUnit'], + select: ['mainExposureIndicator'], where: { disasterType }, }) - ).actionsUnit; + ).mainExposureIndicator; } public async processEventAreas( @@ -701,7 +706,7 @@ export class EventService { adminLevel: number, eventName: string, ): Promise { - const triggerUnit = await this.getTriggerUnit(disasterType); + const triggerIndicator = await this.getTriggerIndicator(disasterType); const lastTriggeredDate = await this.helperService.getRecentDate( countryCodeISO3, @@ -709,7 +714,7 @@ export class EventService { ); const whereFilters = { - indicator: triggerUnit, // REFACTOR: trigger unit and indicator should not be used interchangeably + indicator: triggerIndicator, timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( disasterType, @@ -739,11 +744,12 @@ export class EventService { return []; } - const actionUnit = await this.getActionUnit(disasterType); + const mainExposureIndicator = + await this.getMainExposureIndicator(disasterType); const whereOptions = { placeCode: In(triggerPlaceCodesArray), - indicator: actionUnit, // REFACTOR: action unit and indicator should not be used interchangeably + indicator: mainExposureIndicator, timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( disasterType, @@ -761,7 +767,7 @@ export class EventService { const affectedAreas: AffectedAreaDto[] = await this.adminAreaDynamicDataRepo .createQueryBuilder('area') .select('area."placeCode"') - .addSelect('MAX(area.value) AS "actionsValue"') + .addSelect('MAX(area.value) AS "mainExposureValue"') .addSelect('MAX(area."leadTime") AS "leadTime"') .where(whereOptions) .groupBy('area."placeCode"') @@ -833,7 +839,7 @@ export class EventService { uploadDate.timestamp, ); - // .. lastly we update those records where actionsValue or triggerValue changed + // .. lastly we update those records where mainExposureValue or triggerValue changed await this.updateValues(unclosedEventAreas, affectedAreas); } @@ -864,13 +870,13 @@ export class EventService { ); if ( affectedArea && - (eventArea.actionsValue !== affectedArea.actionsValue || + (eventArea.mainExposureValue !== affectedArea.mainExposureValue || eventArea.triggerValue !== affectedArea.triggerValue) ) { eventArea.triggerValue = affectedArea.triggerValue; - eventArea.actionsValue = affectedArea.actionsValue; + eventArea.mainExposureValue = affectedArea.mainExposureValue; eventAreasToUpdate.push( - `('${eventArea.eventPlaceCodeId}',${eventArea.actionsValue},${eventArea.triggerValue})`, + `('${eventArea.eventPlaceCodeId}',${eventArea.mainExposureValue},${eventArea.triggerValue})`, ); } } @@ -879,7 +885,7 @@ export class EventService { const updateQuery = `UPDATE \ "${repository.metadata.schema}"."${repository.metadata.tableName}" epc \ SET \ - "actionsValue" = areas.actionValue::double precision, \ + "mainExposureValue" = areas.actionValue::double precision, \ "triggerValue" = areas.triggerValue::double precision \ FROM \ (VALUES ${eventAreasToUpdate.join(',')}) \ @@ -931,7 +937,7 @@ export class EventService { eventArea.eventName = eventName; eventArea.thresholdReached = area.triggerValue === 1; eventArea.triggerValue = area.triggerValue; - eventArea.actionsValue = +area.actionsValue; + eventArea.mainExposureValue = +area.mainExposureValue; eventArea.startDate = startDate.timestamp; eventArea.endDate = startDate.timestamp; eventArea.stopped = false; diff --git a/services/API-service/src/api/event/trigger-per-lead-time.entity.ts b/services/API-service/src/api/event/trigger-per-lead-time.entity.ts index 778baaf76c..57eb362330 100644 --- a/services/API-service/src/api/event/trigger-per-lead-time.entity.ts +++ b/services/API-service/src/api/event/trigger-per-lead-time.entity.ts @@ -8,7 +8,7 @@ import { import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; @Entity('trigger-per-lead-time') export class TriggerPerLeadTime { @@ -28,7 +28,7 @@ export class TriggerPerLeadTime { }) public countryCodeISO3: string; - @ManyToOne((): typeof DisasterEntity => DisasterEntity) + @ManyToOne((): typeof DisasterTypeEntity => DisasterTypeEntity) @JoinColumn({ name: 'disasterType', referencedColumnName: 'disasterType', diff --git a/services/API-service/src/api/lead-time/lead-time.entity.ts b/services/API-service/src/api/lead-time/lead-time.entity.ts deleted file mode 100644 index a14e29b1bb..0000000000 --- a/services/API-service/src/api/lead-time/lead-time.entity.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm'; - -import { CountryDisasterSettingsEntity } from '../country/country-disaster.entity'; - -@Entity('lead-time') -export class LeadTimeEntity { - @PrimaryGeneratedColumn('uuid') - public leadTimeId: string; - - @Column({ unique: true }) - public leadTimeName: string; - - @ManyToMany( - (): typeof CountryDisasterSettingsEntity => CountryDisasterSettingsEntity, - (country): LeadTimeEntity[] => country.activeLeadTimes, - ) - public countries: CountryDisasterSettingsEntity[]; - - @Column({ type: 'timestamp', default: (): string => 'CURRENT_TIMESTAMP' }) - public created: Date; -} diff --git a/services/API-service/src/api/lines-data/dto/upload-asset-exposure-status.dto.ts b/services/API-service/src/api/lines-data/dto/upload-asset-exposure-status.dto.ts index dd809b37b8..0ed101dfc0 100644 --- a/services/API-service/src/api/lines-data/dto/upload-asset-exposure-status.dto.ts +++ b/services/API-service/src/api/lines-data/dto/upload-asset-exposure-status.dto.ts @@ -9,7 +9,7 @@ import { } from 'class-validator'; import { LeadTime } from '../../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { LinesDataEnum } from '../lines-data.entity'; export class UploadLinesExposureStatusDto { @@ -20,6 +20,7 @@ export class UploadLinesExposureStatusDto { @ApiProperty({ example: LeadTime.hour1 }) @IsNotEmpty() @IsString() + @IsEnum(LeadTime) public leadTime: LeadTime; @ApiProperty({ example: new Date() }) diff --git a/services/API-service/src/api/lines-data/lines-data-dynamic-status.entity.ts b/services/API-service/src/api/lines-data/lines-data-dynamic-status.entity.ts index 2317dbed4e..19bc854ab9 100644 --- a/services/API-service/src/api/lines-data/lines-data-dynamic-status.entity.ts +++ b/services/API-service/src/api/lines-data/lines-data-dynamic-status.entity.ts @@ -10,7 +10,6 @@ import { } from 'typeorm'; import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; import { LinesDataEntity } from './lines-data.entity'; @Entity('lines-data-dynamic-status') @@ -31,10 +30,9 @@ export class LinesDataDynamicStatusEntity { public timestamp: Date; @ApiProperty({ example: LeadTime.hour1 }) - @ManyToOne((): typeof LeadTimeEntity => LeadTimeEntity) - @JoinColumn({ name: 'leadTime', referencedColumnName: 'leadTimeName' }) + @Column({ nullable: true }) @Index() - public leadTime: string; + public leadTime: LeadTime; @ApiProperty({ example: true }) @Column() diff --git a/services/API-service/src/api/metadata/dto/add-layers.dto.ts b/services/API-service/src/api/metadata/dto/add-layers.dto.ts index eba9aaffe7..3b430ec57b 100644 --- a/services/API-service/src/api/metadata/dto/add-layers.dto.ts +++ b/services/API-service/src/api/metadata/dto/add-layers.dto.ts @@ -2,7 +2,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsBoolean, IsEnum, IsIn, IsNotEmpty, IsString } from 'class-validator'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; export class LayerDto { @ApiProperty({ example: process.env.COUNTRIES }) diff --git a/services/API-service/src/api/metadata/metadata.module.ts b/services/API-service/src/api/metadata/metadata.module.ts index bba7858ad9..0f5ed2aabb 100644 --- a/services/API-service/src/api/metadata/metadata.module.ts +++ b/services/API-service/src/api/metadata/metadata.module.ts @@ -3,7 +3,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { HelperService } from '../../shared/helper.service'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { EventModule } from '../event/event.module'; import { UserModule } from '../user/user.module'; import { CountryModule } from './../country/country.module'; @@ -19,7 +19,7 @@ import { MetadataService } from './metadata.service'; TypeOrmModule.forFeature([ IndicatorMetadataEntity, LayerMetadataEntity, - DisasterEntity, + DisasterTypeEntity, ]), CountryModule, EventModule, diff --git a/services/API-service/src/api/metadata/metadata.service.ts b/services/API-service/src/api/metadata/metadata.service.ts index 536928b3fb..4b1e634f76 100644 --- a/services/API-service/src/api/metadata/metadata.service.ts +++ b/services/API-service/src/api/metadata/metadata.service.ts @@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { AddIndicatorsDto, IndicatorDto } from './dto/add-indicators.dto'; import { AddLayersDto, LayerDto } from './dto/add-layers.dto'; import { IndicatorMetadataEntity } from './indicator-metadata.entity'; diff --git a/services/API-service/src/api/notification/dto/content-trigger-email.dto.ts b/services/API-service/src/api/notification/dto/content-trigger-email.dto.ts index 9c90479d6e..4704d06527 100644 --- a/services/API-service/src/api/notification/dto/content-trigger-email.dto.ts +++ b/services/API-service/src/api/notification/dto/content-trigger-email.dto.ts @@ -1,5 +1,5 @@ import { CountryEntity } from '../../country/country.entity'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { IndicatorMetadataEntity } from '../../metadata/indicator-metadata.entity'; import { AdminAreaLabel } from './admin-area-notification-info.dto'; import { NotificationDataPerEventDto } from './notification-date-per-event.dto'; diff --git a/services/API-service/src/api/notification/dto/send-notification.dto.ts b/services/API-service/src/api/notification/dto/send-notification.dto.ts index 7b20380f1c..37a55e7a1c 100644 --- a/services/API-service/src/api/notification/dto/send-notification.dto.ts +++ b/services/API-service/src/api/notification/dto/send-notification.dto.ts @@ -8,7 +8,7 @@ import { IsString, } from 'class-validator'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; export class SendNotificationDto { @ApiProperty({ diff --git a/services/API-service/src/api/notification/email/email.service.ts b/services/API-service/src/api/notification/email/email.service.ts index ddb6108627..7b6ef81d56 100644 --- a/services/API-service/src/api/notification/email/email.service.ts +++ b/services/API-service/src/api/notification/email/email.service.ts @@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common'; import Mailchimp from 'mailchimp-api-v3'; import { EventSummaryCountry } from '../../../shared/data.model'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { CountryEntity } from './../../country/country.entity'; import { NotificationContentService } from './../notification-content/notification-content.service'; import { MjmlService } from './mjml.service'; diff --git a/services/API-service/src/api/notification/email/mjml/body-event.ts b/services/API-service/src/api/notification/email/mjml/body-event.ts index b49ae46fcb..9e46bd47da 100644 --- a/services/API-service/src/api/notification/email/mjml/body-event.ts +++ b/services/API-service/src/api/notification/email/mjml/body-event.ts @@ -1,5 +1,5 @@ import { LeadTime } from '../../../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../../../disaster/disaster-type.enum'; +import { DisasterType } from '../../../disaster-type/disaster-type.enum'; import { ContentEventEmail } from '../../dto/content-trigger-email.dto'; import { NotificationDataPerEventDto, diff --git a/services/API-service/src/api/notification/email/mjml/event-admin-area-table.ts b/services/API-service/src/api/notification/email/mjml/event-admin-area-table.ts index 86b0d28e4a..802c51029e 100644 --- a/services/API-service/src/api/notification/email/mjml/event-admin-area-table.ts +++ b/services/API-service/src/api/notification/email/mjml/event-admin-area-table.ts @@ -48,7 +48,7 @@ const getMjmlEventAdminAreaTable = ({ }); const isIndicatorAvailable = event.triggeredAreas.some( - ({ actionsValue }) => actionsValue, + ({ mainExposureValue }) => mainExposureValue, ); const subtitleContent = isIndicatorAvailable @@ -68,7 +68,7 @@ const getMjmlEventAdminAreaTable = ({ const adminAreaList = event.triggeredAreas.map((triggeredArea) => { return { exposed: toCompactNumber( - triggeredArea.actionsValue, + triggeredArea.mainExposureValue, indicatorMetadata.numberFormatMap, ), name: `${triggeredArea.name} ${ diff --git a/services/API-service/src/api/notification/notification-content/notification-content.module.ts b/services/API-service/src/api/notification/notification-content/notification-content.module.ts index 585dc94fc1..84f2c7748a 100644 --- a/services/API-service/src/api/notification/notification-content/notification-content.module.ts +++ b/services/API-service/src/api/notification/notification-content/notification-content.module.ts @@ -6,7 +6,7 @@ import { AdminAreaDataModule } from '../../admin-area-data/admin-area-data.modul import { AdminAreaDynamicDataModule } from '../../admin-area-dynamic-data/admin-area-dynamic-data.module'; import { AdminAreaModule } from '../../admin-area/admin-area.module'; import { CountryEntity } from '../../country/country.entity'; -import { DisasterEntity } from '../../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../../disaster-type/disaster-type.entity'; import { EventModule } from '../../event/event.module'; import { IndicatorMetadataEntity } from '../../metadata/indicator-metadata.entity'; import { NotificationContentService } from './notification-content.service'; @@ -16,7 +16,7 @@ import { NotificationContentService } from './notification-content.service'; TypeOrmModule.forFeature([ CountryEntity, IndicatorMetadataEntity, - DisasterEntity, + DisasterTypeEntity, ]), EventModule, AdminAreaDynamicDataModule, diff --git a/services/API-service/src/api/notification/notification-content/notification-content.service.ts b/services/API-service/src/api/notification/notification-content/notification-content.service.ts index a53b4f5aae..26642a92a9 100644 --- a/services/API-service/src/api/notification/notification-content/notification-content.service.ts +++ b/services/API-service/src/api/notification/notification-content/notification-content.service.ts @@ -8,8 +8,8 @@ import { NumberFormat } from '../../../shared/enums/number-format.enum'; import { HelperService } from '../../../shared/helper.service'; import { LeadTime } from '../../admin-area-dynamic-data/enum/lead-time.enum'; import { CountryEntity } from '../../country/country.entity'; -import { DisasterType } from '../../disaster/disaster-type.enum'; -import { DisasterEntity } from '../../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../../disaster-type/disaster-type.entity'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { EventService } from '../../event/event.service'; import { IndicatorMetadataEntity } from '../../metadata/indicator-metadata.entity'; import { AdminAreaLabel } from '../dto/admin-area-notification-info.dto'; @@ -25,8 +25,8 @@ export class NotificationContentService { private readonly countryRepository: Repository; @InjectRepository(IndicatorMetadataEntity) private readonly indicatorRepository: Repository; - @InjectRepository(DisasterEntity) - private readonly disasterRepository: Repository; + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; public constructor( private readonly eventService: EventService, @@ -71,7 +71,6 @@ export class NotificationContentService { 'disasterTypes', 'notificationInfo', 'countryDisasterSettings', - 'countryDisasterSettings.activeLeadTimes', ]; return await this.countryRepository.findOne({ @@ -82,8 +81,8 @@ export class NotificationContentService { private async getDisaster( disasterType: DisasterType, - ): Promise { - return await this.disasterRepository.findOne({ + ): Promise { + return await this.disasterTypeRepository.findOne({ where: { disasterType: disasterType }, }); } @@ -125,7 +124,9 @@ export class NotificationContentService { disasterType: DisasterType, ): Promise { return await this.indicatorRepository.findOne({ - where: { name: (await this.getDisaster(disasterType)).actionsUnit }, + where: { + name: (await this.getDisaster(disasterType)).mainExposureIndicator, + }, }); } @@ -241,7 +242,7 @@ export class NotificationContentService { numberFormat: NumberFormat, ) { const total = triggeredAreas.reduce( - (acc, { actionsValue }) => acc + actionsValue, + (acc, { mainExposureValue }) => acc + mainExposureValue, 0, ); diff --git a/services/API-service/src/api/notification/notification.service.ts b/services/API-service/src/api/notification/notification.service.ts index 0d331ec126..6c1e91138a 100644 --- a/services/API-service/src/api/notification/notification.service.ts +++ b/services/API-service/src/api/notification/notification.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { EventSummaryCountry } from '../../shared/data.model'; import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { EventService } from '../event/event.service'; import { TyphoonTrackService } from '../typhoon-track/typhoon-track.service'; import { diff --git a/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts b/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts index 2f3ccda96d..6d339c72e4 100644 --- a/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts +++ b/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts @@ -7,7 +7,7 @@ import { EXTERNAL_API } from '../../../config'; import { EventSummaryCountry } from '../../../shared/data.model'; import { HelperService } from '../../../shared/helper.service'; import { CountryEntity } from '../../country/country.entity'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { EventService } from '../../event/event.service'; import { UserEntity } from '../../user/user.entity'; import { LookupService } from '../lookup/lookup.service'; @@ -356,7 +356,7 @@ export class WhatsappService { const row = `- *${area.name}${ area.nameParent ? ' (' + area.nameParent + ')' : '' } - ${this.helperService.toCompactNumber( - area.actionsValue, + area.mainExposureValue, indicatorMetadata.numberFormatMap, )}*\n`; areaList += row; diff --git a/services/API-service/src/api/point-data/dto/upload-asset-exposure-status.dto.ts b/services/API-service/src/api/point-data/dto/upload-asset-exposure-status.dto.ts index 296ac650a6..ae3704fcaa 100644 --- a/services/API-service/src/api/point-data/dto/upload-asset-exposure-status.dto.ts +++ b/services/API-service/src/api/point-data/dto/upload-asset-exposure-status.dto.ts @@ -11,7 +11,7 @@ import { } from 'class-validator'; import { LeadTime } from '../../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../../disaster/disaster-type.enum'; +import { DisasterType } from '../../disaster-type/disaster-type.enum'; import { PointDataEnum } from '../point-data.entity'; export class UploadAssetExposureStatusDto { @@ -22,6 +22,7 @@ export class UploadAssetExposureStatusDto { @ApiProperty({ example: LeadTime.hour1 }) @IsNotEmpty() @IsString() + @IsEnum(LeadTime) public leadTime: LeadTime; @ApiProperty({ example: new Date() }) @@ -48,6 +49,7 @@ export class UploadDynamicPointDataDto { @ApiProperty({ example: LeadTime.hour1 }) @IsOptional() @IsString() + @IsEnum(LeadTime) public leadTime: LeadTime; @ApiProperty({ example: new Date() }) diff --git a/services/API-service/src/api/point-data/dynamic-point-data.entity.ts b/services/API-service/src/api/point-data/dynamic-point-data.entity.ts index 6b56bcde9d..6d6e922759 100644 --- a/services/API-service/src/api/point-data/dynamic-point-data.entity.ts +++ b/services/API-service/src/api/point-data/dynamic-point-data.entity.ts @@ -2,12 +2,11 @@ import { Column, Entity, Index, - JoinColumn, ManyToOne, PrimaryGeneratedColumn, } from 'typeorm'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; +import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; import { PointDataEntity } from './point-data.entity'; @Entity('dynamic-point-data') @@ -21,9 +20,8 @@ export class DynamicPointDataEntity { ) public point: PointDataEntity; - @ManyToOne((): typeof LeadTimeEntity => LeadTimeEntity) - @JoinColumn({ name: 'leadTime', referencedColumnName: 'leadTimeName' }) - public leadTime: string; + @Column({ nullable: true }) + public leadTime: LeadTime; @Column({ type: 'timestamp' }) @Index() diff --git a/services/API-service/src/api/point-data/point-data.service.ts b/services/API-service/src/api/point-data/point-data.service.ts index 58b221cb2e..09a81e3b61 100644 --- a/services/API-service/src/api/point-data/point-data.service.ts +++ b/services/API-service/src/api/point-data/point-data.service.ts @@ -6,7 +6,7 @@ import { IsNull, MoreThanOrEqual, Repository } from 'typeorm'; import { GeoJson } from '../../shared/geo.model'; import { HelperService } from '../../shared/helper.service'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { WhatsappService } from '../notification/whatsapp/whatsapp.service'; import { UploadDynamicPointDataDto } from './dto/upload-asset-exposure-status.dto'; import { CommunityNotificationDto } from './dto/upload-community-notifications.dto'; diff --git a/services/API-service/src/api/typhoon-track/dto/upload-typhoon-track.ts b/services/API-service/src/api/typhoon-track/dto/upload-typhoon-track.ts index 2b0bda2419..e262af634c 100644 --- a/services/API-service/src/api/typhoon-track/dto/upload-typhoon-track.ts +++ b/services/API-service/src/api/typhoon-track/dto/upload-typhoon-track.ts @@ -3,6 +3,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsArray, + IsEnum, IsNotEmpty, IsOptional, IsString, @@ -21,6 +22,7 @@ export class UploadTyphoonTrackDto { @ApiProperty({ example: LeadTime.hour72 }) @IsNotEmpty() @IsString() + @IsEnum(LeadTime) public leadTime: LeadTime; @ApiProperty({ example: 'Typhoon name' }) diff --git a/services/API-service/src/api/typhoon-track/typhoon-track.entity.ts b/services/API-service/src/api/typhoon-track/typhoon-track.entity.ts index 34180fe604..17a00ceebb 100644 --- a/services/API-service/src/api/typhoon-track/typhoon-track.entity.ts +++ b/services/API-service/src/api/typhoon-track/typhoon-track.entity.ts @@ -9,8 +9,8 @@ import { } from 'typeorm'; import { GeoJson } from '../../shared/geo.model'; +import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; import { CountryEntity } from '../country/country.entity'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; @Entity('typhoon-track') export class TyphoonTrackEntity { @@ -26,9 +26,8 @@ export class TyphoonTrackEntity { }) public countryCodeISO3: string; - @ManyToOne((): typeof LeadTimeEntity => LeadTimeEntity) - @JoinColumn({ name: 'leadTime', referencedColumnName: 'leadTimeName' }) - public leadTime: string; + @Column({ nullable: true }) + public leadTime: LeadTime; @Column({ type: 'date' }) public date: Date; diff --git a/services/API-service/src/api/typhoon-track/typhoon-track.service.ts b/services/API-service/src/api/typhoon-track/typhoon-track.service.ts index 359edc1991..d61b06d5af 100644 --- a/services/API-service/src/api/typhoon-track/typhoon-track.service.ts +++ b/services/API-service/src/api/typhoon-track/typhoon-track.service.ts @@ -6,7 +6,7 @@ import { InsertResult, MoreThanOrEqual, Repository } from 'typeorm'; import { DisasterSpecificProperties } from '../../shared/data.model'; import { GeoJson } from '../../shared/geo.model'; import { HelperService } from '../../shared/helper.service'; -import { DisasterType } from '../disaster/disaster-type.enum'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { TyphoonCategory } from './dto/trackpoint-details'; import { UploadTyphoonTrackDto } from './dto/upload-typhoon-track'; import { TyphoonTrackEntity } from './typhoon-track.entity'; diff --git a/services/API-service/src/api/user/dto/create-user.dto.ts b/services/API-service/src/api/user/dto/create-user.dto.ts index 248a03efcd..f0ecd3a491 100644 --- a/services/API-service/src/api/user/dto/create-user.dto.ts +++ b/services/API-service/src/api/user/dto/create-user.dto.ts @@ -13,7 +13,7 @@ import { } from 'class-validator'; import countries from '../../../scripts/json/countries.json'; -import disasterTypes from '../../../scripts/json/disasters.json'; +import disasterTypes from '../../../scripts/json/disaster-types.json'; import { UserRole } from '../user-role.enum'; import { UserStatus } from '../user-status.enum'; diff --git a/services/API-service/src/api/user/user.entity.ts b/services/API-service/src/api/user/user.entity.ts index e7de74318f..affd1d7795 100644 --- a/services/API-service/src/api/user/user.entity.ts +++ b/services/API-service/src/api/user/user.entity.ts @@ -12,7 +12,7 @@ import { } from 'typeorm'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { EapActionStatusEntity } from '../eap-actions/eap-action-status.entity'; import { EventPlaceCodeEntity } from '../event/event-place-code.entity'; import { UserRole } from './user-role.enum'; @@ -63,7 +63,7 @@ export class UserEntity { public countries: CountryEntity[]; @ManyToMany( - (): typeof DisasterEntity => DisasterEntity, + (): typeof DisasterTypeEntity => DisasterTypeEntity, (disasterType): UserEntity[] => disasterType.users, ) @JoinTable({ @@ -77,7 +77,7 @@ export class UserEntity { referencedColumnName: 'disasterType', }, }) - public disasterTypes: DisasterEntity[]; + public disasterTypes: DisasterTypeEntity[]; @Column({ default: UserStatus.Active }) public userStatus: UserStatus; diff --git a/services/API-service/src/api/user/user.module.ts b/services/API-service/src/api/user/user.module.ts index 8c5018ba50..768ae1b2ec 100644 --- a/services/API-service/src/api/user/user.module.ts +++ b/services/API-service/src/api/user/user.module.ts @@ -2,7 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { LookupModule } from '../notification/lookup/lookup.module'; import { UserController } from './user.controller'; import { UserEntity } from './user.entity'; @@ -10,7 +10,7 @@ import { UserService } from './user.service'; @Module({ imports: [ - TypeOrmModule.forFeature([UserEntity, CountryEntity, DisasterEntity]), + TypeOrmModule.forFeature([UserEntity, CountryEntity, DisasterTypeEntity]), LookupModule, ], providers: [UserService], diff --git a/services/API-service/src/api/user/user.service.spec.ts b/services/API-service/src/api/user/user.service.spec.ts index c72159bbb5..d142485308 100644 --- a/services/API-service/src/api/user/user.service.spec.ts +++ b/services/API-service/src/api/user/user.service.spec.ts @@ -2,21 +2,21 @@ import { LeadTime, LeadTimeUnit, } from '../admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../disaster/disaster-type.enum'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; +import { DisasterType } from '../disaster-type/disaster-type.enum'; import { LookupService } from '../notification/lookup/lookup.service'; import { UserRole } from './user-role.enum'; import { UserStatus } from './user-status.enum'; import { UserEntity } from './user.entity'; import { UserService } from './user.service'; -const disasters: DisasterEntity[] = [ +const disasterTypes: DisasterTypeEntity[] = [ { id: '1', disasterType: DisasterType.Floods, label: 'Floods', - triggerUnit: 'population_affected', - actionsUnit: 'population_affected', + triggerIndicator: 'population_affected', + mainExposureIndicator: 'population_affected', showOnlyTriggeredAreas: false, countries: [], leadTimeUnit: LeadTimeUnit.day, @@ -36,7 +36,7 @@ const user: UserEntity = { lastName: 'Example', userRole: UserRole.DisasterManager, countries: [], - disasterTypes: disasters, + disasterTypes: disasterTypes, userStatus: UserStatus.Active, password: '', created: new Date(), diff --git a/services/API-service/src/api/user/user.service.ts b/services/API-service/src/api/user/user.service.ts index d7fd8153e1..bc36de6b31 100644 --- a/services/API-service/src/api/user/user.service.ts +++ b/services/API-service/src/api/user/user.service.ts @@ -8,7 +8,7 @@ import jwt from 'jsonwebtoken'; import { In, Repository } from 'typeorm'; import { CountryEntity } from '../country/country.entity'; -import { DisasterEntity } from '../disaster/disaster.entity'; +import { DisasterTypeEntity } from '../disaster-type/disaster-type.entity'; import { LookupService } from '../notification/lookup/lookup.service'; import { CreateUserDto, LoginUserDto, UpdatePasswordDto } from './dto'; import { UserRole } from './user-role.enum'; @@ -21,8 +21,8 @@ export class UserService { private readonly userRepository: Repository; @InjectRepository(CountryEntity) private readonly countryRepository: Repository; - @InjectRepository(DisasterEntity) - private readonly disasterRepository: Repository; + @InjectRepository(DisasterTypeEntity) + private readonly disasterTypeRepository: Repository; private readonly relations: string[] = ['countries', 'disasterTypes']; @@ -83,7 +83,7 @@ export class UserService { newUser.countries = await this.countryRepository.find({ where: { countryCodeISO3: In(dto.countryCodesISO3) }, }); - newUser.disasterTypes = await this.disasterRepository.find({ + newUser.disasterTypes = await this.disasterTypeRepository.find({ where: { disasterType: In(dto.disasterTypes) }, }); @@ -175,9 +175,11 @@ export class UserService { ), disasterTypes: user.disasterTypes.length ? user.disasterTypes.map( - (disasterEntity): string => disasterEntity.disasterType, + (disasterTypeEntity): string => disasterTypeEntity.disasterType, ) - : (await this.disasterRepository.find()).map((d) => d.disasterType), + : (await this.disasterTypeRepository.find()).map( + (d) => d.disasterType, + ), exp: exp.getTime() / 1000, }, process.env.SECRET, diff --git a/services/API-service/src/app.module.ts b/services/API-service/src/app.module.ts index a77611388b..084f4c4bf3 100644 --- a/services/API-service/src/app.module.ts +++ b/services/API-service/src/app.module.ts @@ -5,7 +5,7 @@ import { AdminAreaDataModule } from './api/admin-area-data/admin-area-data.modul import { AdminAreaDynamicDataModule } from './api/admin-area-dynamic-data/admin-area-dynamic-data.module'; import { AdminAreaModule } from './api/admin-area/admin-area.module'; import { CountryModule } from './api/country/country.module'; -import { DisasterModule } from './api/disaster/disaster.module'; +import { DisasterTypeModule } from './api/disaster-type/disaster-type.module'; import { EapActionsModule } from './api/eap-actions/eap-actions.module'; import { EventModule } from './api/event/event.module'; import { LinesDataModule } from './api/lines-data/lines-data.module'; @@ -34,7 +34,7 @@ import { TypeOrmModule } from './typeorm.module'; MetadataModule, AdminAreaModule, AdminAreaDynamicDataModule, - DisasterModule, + DisasterTypeModule, AdminAreaDataModule, TyphoonTrackModule, NotificationModule, diff --git a/services/API-service/src/scripts/disaster-type-geoserver-file.mapper.ts b/services/API-service/src/scripts/disaster-type-geoserver-file.mapper.ts index fc0dd2e74e..91a7f9a9a0 100644 --- a/services/API-service/src/scripts/disaster-type-geoserver-file.mapper.ts +++ b/services/API-service/src/scripts/disaster-type-geoserver-file.mapper.ts @@ -1,4 +1,4 @@ -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; export class DisasterTypeGeoServerMapper { static getLayerStorePrefixForDisasterType( diff --git a/services/API-service/src/scripts/geoserver-sync.service.ts b/services/API-service/src/scripts/geoserver-sync.service.ts index 0e78e0b774..0707eb47e7 100644 --- a/services/API-service/src/scripts/geoserver-sync.service.ts +++ b/services/API-service/src/scripts/geoserver-sync.service.ts @@ -4,7 +4,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { INTERNAL_GEOSERVER_API_URL } from '../config'; import { DisasterTypeGeoServerMapper } from './disaster-type-geoserver-file.mapper'; import countries from './json/countries.json'; diff --git a/services/API-service/src/scripts/interfaces/country.interface.ts b/services/API-service/src/scripts/interfaces/country.interface.ts index 454349daad..6e371cd571 100644 --- a/services/API-service/src/scripts/interfaces/country.interface.ts +++ b/services/API-service/src/scripts/interfaces/country.interface.ts @@ -1,6 +1,6 @@ import { LeadTime } from '../../api/admin-area-dynamic-data/enum/lead-time.enum'; import { AdminLevel } from '../../api/country/admin-level.enum'; -import { DisasterType } from '../../api/disaster/disaster-type.enum'; +import { DisasterType } from '../../api/disaster-type/disaster-type.enum'; import { DroughtSeasonRegions } from './drought-season-regions.interface'; export interface Country { diff --git a/services/API-service/src/scripts/json/EAP-actions.json b/services/API-service/src/scripts/json/EAP-actions.json index 7c06cb8c28..3ba84dec1b 100644 --- a/services/API-service/src/scripts/json/EAP-actions.json +++ b/services/API-service/src/scripts/json/EAP-actions.json @@ -2,107 +2,85 @@ { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-1", "label": "Community sensitization and awareness (health risk, preventive measures of floods, hygiene)" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-2", "label": "Procure and distribute water purification chemicals (Aqua tab and Pur/water guard)" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-3", "label": "Conduct training for volunteers (CBS, community health and first Aid, community hygiene promoters)" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-4", "label": "Waste management (collect rubbish and manage it from Urban centers)" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-1", "label": "Cleaning water sources/desilting drainage channels/dredging in Urban areas" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-2", "label": "Community mapping - (map out designated centers, evacuation roots and holding stores)" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-3", "label": "Provision of shelter kit (Rope, Handsaw, Nails, shovel, hoe, Machete, Shears, Tie wire, Hammer and Tarpaulins)" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-4", "label": "Training of volunteers in shelter construction and management" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-5", "label": "Reinforcing housing structures (roofs and walls) using local available materials such as sand bags" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-6", "label": "Distribute water treatment products aquatabs, pur, water storage vessels and soap, sufficient for 30 days" }, { "countryCodeISO3": "UGA", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Cash and voucher Assistance (CVA) to facilitate evacuation and meet shelter needs to the affected population" }, { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "drr" }, - "action": "uga-drr-1", + "areaOfFocusId": "disaster-risk-reduction", + "action": "uga-disaster-risk-reduction-1", "label": "Early warning information and tailored advisories (when to plant, micro gardening)", "month": { "Karamoja": { "Karamoja": 2 }, @@ -112,8 +90,8 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "drr" }, - "action": "uga-drr-2", + "areaOfFocusId": "disaster-risk-reduction", + "action": "uga-disaster-risk-reduction-2", "label": "Peer education for behaviour change communication", "month": { "Karamoja": { "Karamoja": 2 }, @@ -123,7 +101,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "inclusion" }, + "areaOfFocusId": "inclusion", "action": "uga-inclusion-1", "label": "Sensitization/awareness raising on PGI + MHM kits", "month": { @@ -134,7 +112,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "wash" }, + "areaOfFocusId": "wash", "action": "uga-wash-1", "label": "Orientation of water user committees", "month": { @@ -145,7 +123,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-1", "label": "Demonstration of appropriate storage facilities and post harvest handling", "month": { @@ -156,7 +134,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "wash" }, + "areaOfFocusId": "wash", "action": "uga-wash-2", "label": "Training on bore hole repairs and maintenance", "month": { @@ -167,7 +145,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-2", "label": "Provision and distribution of improved seed varieties/planting materials", "month": { @@ -178,7 +156,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "wash" }, + "areaOfFocusId": "wash", "action": "uga-wash-3", "label": "Provide water storage vessels", "month": { @@ -189,7 +167,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "inclusion" }, + "areaOfFocusId": "inclusion", "action": "uga-inclusion-2", "label": "Apprenticeship training for girls and boys for income diversification (weaving, sowing, crafts)", "month": { @@ -200,7 +178,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-3", "label": "Massive vaccination of animals", "month": { @@ -211,7 +189,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-4", "label": "Preparing and storage of fodder/hay/foliage", "month": { @@ -222,7 +200,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-5", "label": "Food procurement for food assistance and shcool feeding", "month": { @@ -233,7 +211,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-6", "label": "Food assistance as per trigger calendar at the end of the seasons (possibly in collaboration with WFP on PGI conditions)", "month": { @@ -244,7 +222,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-7", "label": "School feeding programme for primary schools", "month": { @@ -255,7 +233,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "inclusion" }, + "areaOfFocusId": "inclusion", "action": "uga-inclusion-3", "label": "Sensitization/awareness raising on PGI + MHM kits", "month": { @@ -266,7 +244,7 @@ { "countryCodeISO3": "UGA", "disasterType": "drought", - "areaOfFocus": { "id": "livelihood" }, + "areaOfFocusId": "livelihood", "action": "uga-livelihood-8", "label": "Provision and distribution of improved seed varieties/planting materials for the new season ahead", "month": { @@ -277,108 +255,84 @@ { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-1", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-1", "label": "Dissemination of Early Warning (EW) information and possible Early Action (EA)." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-2", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-2", "label": "Assess the status of the safe havens to be used as evacuation centers such as Schools, Community halls, health facilities, Places of worship (church buildings, mosques, temples); in terms of; infrastructure, water availability, sanitation facilities and security." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-3", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-3", "label": "Activation of the rapid response teams (CDRTs, BDRTs, NDRTs) & refresher training." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-4", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-4", "label": "Preposition personal protection equipment for staff and volunteers." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-1", "label": "Assess the status of identified access and evacuation routes and inform communities of the safe routes to use and those to avoid" }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-2", "label": "Pre-position of non-food items (NFIs) such as shelter kits, mats, Insecticide Treated Nets (ITNs), plastic sheets, blankets, kitchen sets, water purification tablets, Jerricans, soap, PPEs such as rain coats, gumboots, restock FA kits among others to be distributed to flood prone households in case of evacuation." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-3", "label": "Pre-position and distribute Non Food Items (NFIs) such as tents and family kits to the high risk families." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Livestock protection such as pre-identification of alternative pasturelands and relocation of kraals to elevated grounds." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-2", "label": "Community sensitization on proper food storage, preservation and livestock protection. Assess the status of the safe areas for animals. Identify community stores where communities can keep their food. Provide food storage bags." }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-1", "label": "Preposition ambulatory services, mobile clinics, ambulances - mobilise the CHWs. Preposition rapid test kits (RDTs). Distribute ITNs (Insecticide Treated Nets)" }, { "countryCodeISO3": "ZMB", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-1", "label": "Identify the potential sanitation facilities at the evacuation centres. Pre-position and distribution of soap and 20 litre water storage containers." }, { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-01", "label": "Beneficiary identification and Registration", "month": { @@ -390,9 +344,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-02", "label": "Distribution of Drought Tolerant Seed", "month": { @@ -404,9 +356,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-03", "label": "Purchase of dipping and dosing chemicals", "month": { @@ -418,9 +368,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-04", "label": "Manning of dipping tanks and community mobilisation", "month": { @@ -432,9 +380,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-05", "label": "Identification of Boreholes", "month": { @@ -446,9 +392,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-06", "label": "Repair and rehabilitation of Boreholes", "month": { @@ -460,9 +404,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-07", "label": "Beneficiary identification and Registration", "month": { @@ -474,9 +416,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-08", "label": "Confirm minimum expenditure basket", "month": { @@ -488,9 +428,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-09", "label": "Initiate Framework Contracts", "month": { @@ -502,9 +440,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-10", "label": "Supplementary feeding to target schools", "month": { @@ -516,9 +452,7 @@ { "countryCodeISO3": "ZMB", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zmb-drought-11", "label": "MPCT to target households", "month": { @@ -530,198 +464,154 @@ { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-1", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-1", "label": "Send out early warning messages" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Set up Cash for Work for reinforcement of infrastructure" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-2", "label": "Preposition and distribute NFI's" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-3", "label": "Set up Cash and Voucher assistance" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-1", "label": "Establish camps/ Camp management structures" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-2", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-2", "label": "Assist with Evacuation orders" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-3", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-3", "label": "Deploy Search and Rescue teams" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-4", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-4", "label": "Activate contingency plans" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-2", "label": "Preposition tents and shelter kits" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-1", "label": "Distribute Pure/ Aquatabs and buckets" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-2", "label": "Distribute soap, hygiene and dignity kits" }, { "countryCodeISO3": "MWI", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-3", "label": "Protect critical WASH infrastructure" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-1", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-1", "label": "Dissemination of Early Warning Messages" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-2", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-2", "label": "Support Physical Evacuation" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-3", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-3", "label": "Placement of flood markers" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-1", "label": "Prepositioning and Distribution of shelter NFI" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-2", "label": "Advocate for clearing of drainages and construction of dykes" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Support provision of Veterinary Care services to protect and treat livestock" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-1", "label": "Activation of mobile health teams" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-2", "label": "Preposition of mobile health equipment and emergency medical supplies" }, { "countryCodeISO3": "KEN", "disasterType": "floods", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-1", "label": "Prepositioning and Distribution of wash NFI" }, { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Market analysis", "month": { @@ -734,10 +624,8 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-1", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-1", "label": "Pre-agreement with suppliers on procurement", "month": { "National": { @@ -749,9 +637,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-1", "label": "Preparatory activities for cash for water", "month": { @@ -764,9 +650,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-2", "label": "CVA or Market-based intervention", "month": { @@ -779,9 +663,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-2", "label": "Cash for water", "month": { @@ -794,10 +676,8 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-2", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-2", "label": "Disseminating early warning information", "month": { "National": { @@ -809,10 +689,8 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-3", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-3", "label": "Rangeland management", "month": { "National": { @@ -824,9 +702,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-3", "label": "Distribute pasture seed", "month": { @@ -839,9 +715,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-4", "label": "Advocation pasture management", "month": { @@ -854,9 +728,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-3", "label": "Installation of mass water storage tanks", "month": { @@ -869,9 +741,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-4", "label": "Rapid assessment of water facilities", "month": { @@ -884,9 +754,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-5", "label": "Destilting of water pans, repair of earth dams", "month": { @@ -899,9 +767,7 @@ { "countryCodeISO3": "KEN", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-6", "label": "Prioritize key/critical water facilities", "month": { @@ -914,162 +780,126 @@ { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-1", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-1", "label": "Awareness raising " }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-2", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-2", "label": "Support Individual safety measures – life jackets, elevated beddings" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-3", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-3", "label": "Evacuation" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "drr-4", + "areaOfFocusId": "disaster-risk-reduction", + "action": "disaster-risk-reduction-4", "label": "Provide forage and water for livestock" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-1", "label": "Water blockage and diversion measures" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-2", "label": "Support house enforcement" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Early harvesting the crops" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-2", "label": "Food distribution" }, { "countryCodeISO3": "ETH", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-3", "label": "Relocating the livestock from flood zones (including evacuation in the worst case)" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-1", "label": "Set up Malaria Emergency Medical Units (MEMUs)." }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-2", "label": " Mobilize Community Heath Volunteers (CHV) to monitor and report suspected cases" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-3", "label": "Community-based information dissemination on disease prevention and health promotion" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-4", "label": "Social media campaign on prevention and control measures" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "health" - }, + "areaOfFocusId": "health", "action": "health-5", "label": "Psychosocial support through welfare desk" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-1", "label": "Hygiene promotion on safe usage of water" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "wash-2", "label": "Cleaning of mosquito breeding sites, garbage disposal" }, { "countryCodeISO3": "ETH", "disasterType": "malaria", - "areaOfFocus": { - "id": "inclusion" - }, + "areaOfFocusId": "inclusion", "action": "inclusion-1", "label": "Protection, gender and inclusion: ensure all staff is trained, distribute guidelines, assess minimum standards at DEMUs and welfare desks" }, { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a1", "label": "A1. Rehabilitation of critical water facilities (boreholes, shallow wells, hand-dug wells with", "month": { @@ -1093,9 +923,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a2", "label": "A2. Demarcate and preserve drought time water sources (boreholes, birkas, ponds etc.)", "month": { @@ -1119,9 +947,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a3", "label": "A3. Promote water preservation and wise utilization techniques", "month": { @@ -1145,9 +971,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a4", "label": "A4. Introduce water preservation and wise utilization techniques", "month": { @@ -1171,9 +995,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a5", "label": "A5. Engage the WSH sector - Water treatment", "month": { @@ -1197,9 +1019,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a6", "label": "A6. Awareness creation", "month": { @@ -1223,9 +1043,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a7", "label": "A7. Conflict negotiation", "month": { @@ -1249,9 +1067,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a8", "label": "A8. Pre-position of relevant medicines (for malaria, water-borne diseases, first aid equipment, mosquito nets)", "month": { @@ -1275,9 +1091,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a9", "label": "A9. Promote awareness on water born disease control (such as cholera), use of mosquito net, basic sanitation (latrine, hand washing, drinking water treatment etc.)", "month": { @@ -1301,9 +1115,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a10", "label": "A10. Support water harvesting in schools/other social service providers", "month": { @@ -1327,9 +1139,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a11", "label": "A11. Training for Red Cross local staff, DAS, health extensions, local leaders", "month": { @@ -1353,9 +1163,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "wash" - }, + "areaOfFocusId": "wash", "action": "eth-drought-a12", "label": "A12. Cleaning and de-silting of water sources - river, springs, wells to avoid mosquitoes breeding in stagnant water", "month": { @@ -1379,9 +1187,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b1", "label": "B1. Promote food saving", "month": { @@ -1405,9 +1211,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b2", "label": "B2. Promote planting of short maturing and drought tolerant vegetable and crop varieties", "month": { @@ -1431,9 +1235,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b3", "label": "B3. Preposition short maturing, drought tolerant vegetable, healty and nutritious crop and vegetable varieties", "month": { @@ -1457,9 +1259,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b4", "label": "B4. Provide and distribute short maturing, drought tolerant vegetable, healty and nutritious crop and vegetable varieties", "month": { @@ -1483,9 +1283,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b5", "label": "B5. Promote safe usage of alternative foods (wild foods, fishing, hunting etc.)", "month": { @@ -1509,9 +1307,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b6", "label": "B6, Water harvesting on the farmland + soil moisture conservation", "month": { @@ -1535,9 +1331,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b7", "label": "B7. Asset protection intervention, through cash for work / food for work", "month": { @@ -1561,9 +1355,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b8", "label": "B8. Providing improved storage materials/equipment (triple bag, metal silo) to reduce post harvest losses", "month": { @@ -1587,9 +1379,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b9", "label": "B9. Training for Red Cross local staff, DAS, health extensions, local leaders", "month": { @@ -1613,9 +1403,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b10", "label": "B10. Training selected women on screening of early malnutrition signs and symptoms to refer to health centers", "month": { @@ -1639,9 +1427,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-b11", "label": "B11. Awareness creation for target communities", "month": { @@ -1665,9 +1451,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c1", "label": "C1. Vaccination", "month": { @@ -1691,9 +1475,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c2", "label": "C2. Pre-stocking of vet medicines and equipment", "month": { @@ -1717,9 +1499,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c3", "label": "C3. Provide short maturing forage seed/planting for livestock and cash for abimal feed production", "month": { @@ -1743,9 +1523,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c4", "label": "C4. Engage cooperatives, private investors in provision of animal feed and contract signing", "month": { @@ -1769,9 +1547,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c5", "label": "C5. Provide cash/in kind for animal feed", "month": { @@ -1795,9 +1571,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c6", "label": "C6. Promote systematic destocking (together with marketing)", "month": { @@ -1821,9 +1595,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c7", "label": "C7. Promote systematic migration with livestock to other pasture and water available areas (herd splitting like browsers can stay behind a bit longer) whenever it is applicable", "month": { @@ -1847,9 +1619,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c8", "label": "C8. Conflict resolution or negotiation of resource sharing", "month": { @@ -1873,9 +1643,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c9", "label": "C9. Introduce temporary slaughter houses (communities also can make dry meat-qwanta) whenever it is applicable", "month": { @@ -1899,9 +1667,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c10", "label": "C10. Promoting area closure (rangeland management)", "month": { @@ -1925,9 +1691,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c11", "label": "C11. Training for Red Cross local staff, DAS, health extension, local leaders", "month": { @@ -1951,9 +1715,7 @@ { "countryCodeISO3": "ETH", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "eth-drought-c12", "label": "C12. Awareness creation", "month": { @@ -1977,144 +1739,112 @@ { "countryCodeISO3": "PHL", "disasterType": "typhoon", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Early Harvesting" }, { "countryCodeISO3": "PHL", "disasterType": "typhoon", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-2", "label": "Evacuation Of Livestock And Assets" }, { "countryCodeISO3": "PHL", "disasterType": "typhoon", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "shelter-1", "label": "Distribution Of Shelter Strengthening Kit (SSK)" }, { "countryCodeISO3": "PHL", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-1", "label": "Harvest crops and fish early" }, { "countryCodeISO3": "PHL", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-2", "label": "Evacuate livestock and assets" }, { "countryCodeISO3": "PHL", "disasterType": "floods", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "livelihood-3", "label": "Relocate small businesses" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "ssd-drr-01", + "areaOfFocusId": "disaster-risk-reduction", + "action": "ssd-disaster-risk-reduction-01", "label": "Activate the SSRC Emergency Office Center Call number for 24/7 hours for people to call in" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "ssd-drr-02", + "areaOfFocusId": "disaster-risk-reduction", + "action": "ssd-disaster-risk-reduction-02", "label": "Prepare National Disaster Response Team (NDRT) bags ready for surge deployment" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "ssd-drr-03", + "areaOfFocusId": "disaster-risk-reduction", + "action": "ssd-disaster-risk-reduction-03", "label": "Dissemination of early warning messages to communities at risk of being affected by floods (e.g., through mass media, and through community meetings)" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "ssd-drr-04", + "areaOfFocusId": "disaster-risk-reduction", + "action": "ssd-disaster-risk-reduction-04", "label": "Organize pre-disaster meetings with relevant actors including relevant ministries and departments" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "ssd-drr-05", + "areaOfFocusId": "disaster-risk-reduction", + "action": "ssd-disaster-risk-reduction-05", "label": "Activation of trained South Sudan Red Cross Volunteers/staff and Community Disaster Response Teams (CDRTs)" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "ssd-shelter-01", "label": "Engage communities in identification of safe locations for evacuation in case of emergencies" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "ssd-shelter-02", "label": "Support evacuating of communities' at-risk areas" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "shelter" - }, + "areaOfFocusId": "shelter", "action": "ssd-shelter-03", "label": "Preposition of Essential Households Items (e.g., mosquito nets, first aid kits, water purifiers, blankets, etc.) for 3,500 households" }, { "countryCodeISO3": "SSD", "disasterType": "floods", - "areaOfFocus": { - "id": "drr" - }, - "action": "ssd-drr-06", + "areaOfFocusId": "disaster-risk-reduction", + "action": "ssd-disaster-risk-reduction-06", "label": "Participate in stakeholders' coordination meetings with relevant state/National line ministries, and other humanitarian Actors on flood responses" }, { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-01", "label": "Beneficiary identification and Registration", "month": { @@ -2126,9 +1856,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-02", "label": "Distribution of Drought Tolerant Seed", "month": { @@ -2140,9 +1868,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-03", "label": "Purchase of dipping and dosing chemicals", "month": { @@ -2154,9 +1880,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-04", "label": "Manning of dipping tanks and community mobilisation", "month": { @@ -2168,9 +1892,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-05", "label": "Identification of Boreholes", "month": { @@ -2182,9 +1904,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-06", "label": "Repair and rehabilitation of Boreholes", "month": { @@ -2196,9 +1916,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-07", "label": "Beneficiary identification and Registration", "month": { @@ -2210,9 +1928,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-08", "label": "Confirm minimum expenditure basket", "month": { @@ -2224,9 +1940,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-09", "label": "Initiate Framework Contracts", "month": { @@ -2238,9 +1952,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-10", "label": "Supplementary feeding to target schools", "month": { @@ -2252,9 +1964,7 @@ { "countryCodeISO3": "ZWE", "disasterType": "drought", - "areaOfFocus": { - "id": "livelihood" - }, + "areaOfFocusId": "livelihood", "action": "zwe-drought-11", "label": "MPCT to target households", "month": { diff --git a/services/API-service/src/scripts/json/areas-of-focus.json b/services/API-service/src/scripts/json/areas-of-focus.json deleted file mode 100644 index a9858fa3de..0000000000 --- a/services/API-service/src/scripts/json/areas-of-focus.json +++ /dev/null @@ -1,44 +0,0 @@ -[ - { - "id": "drr", - "label": "Disaster Risk Reduction", - "description": "(DRR) is a systematic approach to identifying, assessing and reducing the risks of disaster.

It aims to reduce socio-economic vulnerabilities to disaster as well as dealing with the environmental and other hazards that trigger them.", - "icon": "Disaster risk reduction.svg" - }, - { - "id": "shelter", - "label": "Shelter", - "description": "Shelter and Non-Food Items includes provision of shelter materials and non-food household item packages.

The theme also covers Camp Coordination and Camp Management.

Long-term/permanent reconstruction/rebuilding of housing is not covered by this area of focus.", - "icon": "Shelter.svg" - }, - { - "id": "livelihood", - "label": "Livelihoods & Basic Needs", - "description": "Disasters can take a devastating toll on people's food security livelihoods and their basic needs.

They can increase people's socio-economic vulnerability and seriously impact their ability to recover, which in turn affects their ability to cope with future shocks and stresses.

These actions are aimed at protecting these needs as preparation for forecasted hazards.", - "icon": "Livelihood.svg" - }, - { - "id": "health", - "label": "Health", - "description": "Health includes emergency medical services, equipment and supplies; reproductive health; psycho-social support; mobile medical clinics; and disease control and surveillance.", - "icon": "Health.svg" - }, - { - "id": "wash", - "label": "WASH", - "description": "Water, Sanitation, and Hygiene includes emergency provision of safe drinking water, hygiene and sanitation services, environmental sanitation and water supply, as well as hygiene promotion campaigns.", - "icon": "Water-Sanitation-and-Hygiene.svg" - }, - { - "id": "inclusion", - "label": "Protection, Gender and Inclusion", - "description": "People affected by disasters can have very different experiences.
A person's sex, gender identity, age, physical ability, race, nationality and many other factors can influence how they are vulnerable to, and affected by disasters, conflicts and crises. They can also affect how they respond and recover.

Emergencies can also make existing inequalities worse. This can be seen in the increase in incidences of sexual and gender-based violence (SGBV), violence against children and trafficking in human beings during and after emergencies.
  • Protection - addressing violence and keeping people safe from harm
  • Gender and diversity - addressing discrimination and understanding people's different needs, risks and capacities
  • Inclusion - actively addressing exclusion by meaningfully involving and engaging excluded people in our work
", - "icon": "Gender.svg" - }, - { - "id": "migration", - "label": "Migration", - "description": "Migration and displacement pose some of the biggest humanitarian challenges of our time.

These actions are aimed at supporting people on the move with saving lives and preventing suffering, help people cope with the risks and challenges of migration and work to protect and restore their dignity.", - "icon": "Internally-displaced.svg" - } -] diff --git a/services/API-service/src/scripts/json/disasters.json b/services/API-service/src/scripts/json/disaster-types.json similarity index 66% rename from services/API-service/src/scripts/json/disasters.json rename to services/API-service/src/scripts/json/disaster-types.json index e9d4582be3..175f763fd3 100644 --- a/services/API-service/src/scripts/json/disasters.json +++ b/services/API-service/src/scripts/json/disaster-types.json @@ -2,8 +2,8 @@ { "disasterType": "floods", "label": "flood", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": true, "leadTimeUnit": "day", "minLeadTime": "0-day", @@ -12,8 +12,8 @@ { "disasterType": "heavy-rain", "label": "heavy rainfall", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": true, "leadTimeUnit": "day", "minLeadTime": "1-day", @@ -22,8 +22,8 @@ { "disasterType": "malaria", "label": "malaria", - "triggerUnit": "alert_threshold", - "actionsUnit": "potential_cases", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "potential_cases", "showOnlyTriggeredAreas": false, "leadTimeUnit": "month", "minLeadTime": "0-month", @@ -32,8 +32,8 @@ { "disasterType": "drought", "label": "drought", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": true, "leadTimeUnit": "month", "minLeadTime": "0-month", @@ -42,8 +42,8 @@ { "disasterType": "typhoon", "label": "typhoon", - "triggerUnit": "alert_threshold", - "actionsUnit": "houses_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "houses_affected", "showOnlyTriggeredAreas": false, "leadTimeUnit": "hour", "minLeadTime": "0-hour", @@ -52,8 +52,8 @@ { "disasterType": "flash-floods", "label": "flash flood", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": false, "leadTimeUnit": "hour", "minLeadTime": "0-hour", diff --git a/services/API-service/src/scripts/json/lead-times.json b/services/API-service/src/scripts/json/lead-times.json deleted file mode 100644 index 8ff1fab55c..0000000000 --- a/services/API-service/src/scripts/json/lead-times.json +++ /dev/null @@ -1,569 +0,0 @@ -[ - { - "leadTimeName": "0-day" - }, - { - "leadTimeName": "1-day" - }, - { - "leadTimeName": "2-day" - }, - { - "leadTimeName": "3-day" - }, - { - "leadTimeName": "4-day" - }, - { - "leadTimeName": "5-day" - }, - { - "leadTimeName": "6-day" - }, - { - "leadTimeName": "7-day" - }, - { - "leadTimeName": "0-month" - }, - { - "leadTimeName": "1-month" - }, - { - "leadTimeName": "2-month" - }, - { - "leadTimeName": "3-month" - }, - { - "leadTimeName": "4-month" - }, - { - "leadTimeName": "5-month" - }, - { - "leadTimeName": "6-month" - }, - { - "leadTimeName": "7-month" - }, - { - "leadTimeName": "8-month" - }, - { - "leadTimeName": "9-month" - }, - { - "leadTimeName": "10-month" - }, - { - "leadTimeName": "11-month" - }, - { - "leadTimeName": "0-hour" - }, - { - "leadTimeName": "1-hour" - }, - { - "leadTimeName": "2-hour" - }, - { - "leadTimeName": "3-hour" - }, - { - "leadTimeName": "4-hour" - }, - { - "leadTimeName": "5-hour" - }, - { - "leadTimeName": "6-hour" - }, - { - "leadTimeName": "7-hour" - }, - { - "leadTimeName": "8-hour" - }, - { - "leadTimeName": "9-hour" - }, - { - "leadTimeName": "10-hour" - }, - { - "leadTimeName": "11-hour" - }, - { - "leadTimeName": "12-hour" - }, - { - "leadTimeName": "13-hour" - }, - { - "leadTimeName": "14-hour" - }, - { - "leadTimeName": "15-hour" - }, - { - "leadTimeName": "16-hour" - }, - { - "leadTimeName": "17-hour" - }, - { - "leadTimeName": "18-hour" - }, - { - "leadTimeName": "19-hour" - }, - { - "leadTimeName": "20-hour" - }, - { - "leadTimeName": "21-hour" - }, - { - "leadTimeName": "22-hour" - }, - { - "leadTimeName": "23-hour" - }, - { - "leadTimeName": "24-hour" - }, - { - "leadTimeName": "25-hour" - }, - { - "leadTimeName": "26-hour" - }, - { - "leadTimeName": "27-hour" - }, - { - "leadTimeName": "28-hour" - }, - { - "leadTimeName": "29-hour" - }, - { - "leadTimeName": "30-hour" - }, - { - "leadTimeName": "31-hour" - }, - { - "leadTimeName": "32-hour" - }, - { - "leadTimeName": "33-hour" - }, - { - "leadTimeName": "34-hour" - }, - { - "leadTimeName": "35-hour" - }, - { - "leadTimeName": "36-hour" - }, - { - "leadTimeName": "37-hour" - }, - { - "leadTimeName": "38-hour" - }, - { - "leadTimeName": "39-hour" - }, - { - "leadTimeName": "40-hour" - }, - { - "leadTimeName": "41-hour" - }, - { - "leadTimeName": "42-hour" - }, - { - "leadTimeName": "43-hour" - }, - { - "leadTimeName": "44-hour" - }, - { - "leadTimeName": "45-hour" - }, - { - "leadTimeName": "46-hour" - }, - { - "leadTimeName": "47-hour" - }, - { - "leadTimeName": "48-hour" - }, - { - "leadTimeName": "49-hour" - }, - { - "leadTimeName": "50-hour" - }, - { - "leadTimeName": "51-hour" - }, - { - "leadTimeName": "52-hour" - }, - { - "leadTimeName": "53-hour" - }, - { - "leadTimeName": "54-hour" - }, - { - "leadTimeName": "55-hour" - }, - { - "leadTimeName": "56-hour" - }, - { - "leadTimeName": "57-hour" - }, - { - "leadTimeName": "58-hour" - }, - { - "leadTimeName": "59-hour" - }, - { - "leadTimeName": "60-hour" - }, - { - "leadTimeName": "61-hour" - }, - { - "leadTimeName": "62-hour" - }, - { - "leadTimeName": "63-hour" - }, - { - "leadTimeName": "64-hour" - }, - { - "leadTimeName": "65-hour" - }, - { - "leadTimeName": "66-hour" - }, - { - "leadTimeName": "67-hour" - }, - { - "leadTimeName": "68-hour" - }, - { - "leadTimeName": "69-hour" - }, - { - "leadTimeName": "70-hour" - }, - { - "leadTimeName": "71-hour" - }, - { - "leadTimeName": "72-hour" - }, - { - "leadTimeName": "73-hour" - }, - { - "leadTimeName": "74-hour" - }, - { - "leadTimeName": "75-hour" - }, - { - "leadTimeName": "76-hour" - }, - { - "leadTimeName": "77-hour" - }, - { - "leadTimeName": "78-hour" - }, - { - "leadTimeName": "79-hour" - }, - { - "leadTimeName": "80-hour" - }, - { - "leadTimeName": "81-hour" - }, - { - "leadTimeName": "82-hour" - }, - { - "leadTimeName": "83-hour" - }, - { - "leadTimeName": "84-hour" - }, - { - "leadTimeName": "85-hour" - }, - { - "leadTimeName": "86-hour" - }, - { - "leadTimeName": "87-hour" - }, - { - "leadTimeName": "88-hour" - }, - { - "leadTimeName": "89-hour" - }, - { - "leadTimeName": "90-hour" - }, - { - "leadTimeName": "91-hour" - }, - { - "leadTimeName": "92-hour" - }, - { - "leadTimeName": "93-hour" - }, - { - "leadTimeName": "94-hour" - }, - { - "leadTimeName": "95-hour" - }, - { - "leadTimeName": "96-hour" - }, - { - "leadTimeName": "97-hour" - }, - { - "leadTimeName": "98-hour" - }, - { - "leadTimeName": "99-hour" - }, - { - "leadTimeName": "100-hour" - }, - { - "leadTimeName": "101-hour" - }, - { - "leadTimeName": "102-hour" - }, - { - "leadTimeName": "103-hour" - }, - { - "leadTimeName": "104-hour" - }, - { - "leadTimeName": "105-hour" - }, - { - "leadTimeName": "106-hour" - }, - { - "leadTimeName": "107-hour" - }, - { - "leadTimeName": "108-hour" - }, - { - "leadTimeName": "109-hour" - }, - { - "leadTimeName": "110-hour" - }, - { - "leadTimeName": "111-hour" - }, - { - "leadTimeName": "112-hour" - }, - { - "leadTimeName": "113-hour" - }, - { - "leadTimeName": "114-hour" - }, - { - "leadTimeName": "115-hour" - }, - { - "leadTimeName": "116-hour" - }, - { - "leadTimeName": "117-hour" - }, - { - "leadTimeName": "118-hour" - }, - { - "leadTimeName": "119-hour" - }, - { - "leadTimeName": "120-hour" - }, - { - "leadTimeName": "121-hour" - }, - { - "leadTimeName": "122-hour" - }, - { - "leadTimeName": "123-hour" - }, - { - "leadTimeName": "124-hour" - }, - { - "leadTimeName": "125-hour" - }, - { - "leadTimeName": "126-hour" - }, - { - "leadTimeName": "127-hour" - }, - { - "leadTimeName": "128-hour" - }, - { - "leadTimeName": "129-hour" - }, - { - "leadTimeName": "130-hour" - }, - { - "leadTimeName": "131-hour" - }, - { - "leadTimeName": "132-hour" - }, - { - "leadTimeName": "133-hour" - }, - { - "leadTimeName": "134-hour" - }, - { - "leadTimeName": "135-hour" - }, - { - "leadTimeName": "136-hour" - }, - { - "leadTimeName": "137-hour" - }, - { - "leadTimeName": "138-hour" - }, - { - "leadTimeName": "139-hour" - }, - { - "leadTimeName": "140-hour" - }, - { - "leadTimeName": "141-hour" - }, - { - "leadTimeName": "142-hour" - }, - { - "leadTimeName": "143-hour" - }, - { - "leadTimeName": "144-hour" - }, - { - "leadTimeName": "145-hour" - }, - { - "leadTimeName": "146-hour" - }, - { - "leadTimeName": "147-hour" - }, - { - "leadTimeName": "148-hour" - }, - { - "leadTimeName": "149-hour" - }, - { - "leadTimeName": "150-hour" - }, - { - "leadTimeName": "151-hour" - }, - { - "leadTimeName": "152-hour" - }, - { - "leadTimeName": "153-hour" - }, - { - "leadTimeName": "154-hour" - }, - { - "leadTimeName": "155-hour" - }, - { - "leadTimeName": "156-hour" - }, - { - "leadTimeName": "157-hour" - }, - { - "leadTimeName": "158-hour" - }, - { - "leadTimeName": "159-hour" - }, - { - "leadTimeName": "160-hour" - }, - { - "leadTimeName": "161-hour" - }, - { - "leadTimeName": "162-hour" - }, - { - "leadTimeName": "163-hour" - }, - { - "leadTimeName": "164-hour" - }, - { - "leadTimeName": "165-hour" - }, - { - "leadTimeName": "166-hour" - }, - { - "leadTimeName": "167-hour" - }, - { - "leadTimeName": "168-hour" - } -] diff --git a/services/API-service/src/scripts/mock-helper.service.ts b/services/API-service/src/scripts/mock-helper.service.ts index fe6b7d76cd..87564ec3a6 100644 --- a/services/API-service/src/scripts/mock-helper.service.ts +++ b/services/API-service/src/scripts/mock-helper.service.ts @@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common'; import { AdminAreaDynamicDataService } from '../api/admin-area-dynamic-data/admin-area-dynamic-data.service'; import { LeadTime } from '../api/admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { UploadLinesExposureStatusDto } from '../api/lines-data/dto/upload-asset-exposure-status.dto'; import { LinesDataEnum } from '../api/lines-data/lines-data.entity'; import { LinesDataService } from '../api/lines-data/lines-data.service'; @@ -119,7 +119,7 @@ export class MockHelperService { console.log( 'Mock raster file not found' + ` for country: ${selectedCountry.countryCodeISO3}` + - ` for disaster: ${disasterType}` + + ` for disasterType: ${disasterType}` + ` for leadtime: ${leadTime}. Skipping.`, ); return; diff --git a/services/API-service/src/scripts/mock.controller.ts b/services/API-service/src/scripts/mock.controller.ts index 84f0e054bc..7fad31aac3 100644 --- a/services/API-service/src/scripts/mock.controller.ts +++ b/services/API-service/src/scripts/mock.controller.ts @@ -25,7 +25,7 @@ import { IsString, } from 'class-validator'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { UserRole } from '../api/user/user-role.enum'; import { Roles } from '../roles.decorator'; import { RolesGuard } from '../roles.guard'; diff --git a/services/API-service/src/scripts/mock.service.ts b/services/API-service/src/scripts/mock.service.ts index be343ffc40..322886cb61 100644 --- a/services/API-service/src/scripts/mock.service.ts +++ b/services/API-service/src/scripts/mock.service.ts @@ -12,7 +12,7 @@ import { AdminAreaService } from '../api/admin-area/admin-area.service'; import { AdminLevel } from '../api/country/admin-level.enum'; import { CountryEntity } from '../api/country/country.entity'; import { CountryDisasterSettingsDto } from '../api/country/dto/add-countries.dto'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { EapActionStatusEntity } from '../api/eap-actions/eap-action-status.entity'; import { EventPlaceCodeEntity } from '../api/event/event-place-code.entity'; import { EventService } from '../api/event/event.service'; diff --git a/services/API-service/src/scripts/scripts.controller.ts b/services/API-service/src/scripts/scripts.controller.ts index bed3cd737e..dd0fea78cb 100644 --- a/services/API-service/src/scripts/scripts.controller.ts +++ b/services/API-service/src/scripts/scripts.controller.ts @@ -16,7 +16,7 @@ import { import { IsIn, IsNotEmpty, IsOptional, IsString } from 'class-validator'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { UserRole } from '../api/user/user-role.enum'; import { Roles } from '../roles.decorator'; import { RolesGuard } from '../roles.guard'; diff --git a/services/API-service/src/scripts/scripts.module.ts b/services/API-service/src/scripts/scripts.module.ts index 5b64351a34..a329af784e 100644 --- a/services/API-service/src/scripts/scripts.module.ts +++ b/services/API-service/src/scripts/scripts.module.ts @@ -11,9 +11,9 @@ import { AdminAreaEntity } from '../api/admin-area/admin-area.entity'; import { AdminAreaModule } from '../api/admin-area/admin-area.module'; import { CountryEntity } from '../api/country/country.entity'; import { CountryModule } from '../api/country/country.module'; +import { DisasterTypeModule } from '../api/disaster-type/disaster-type.module'; import { EventModule } from '../api/event/event.module'; import { TriggerPerLeadTime } from '../api/event/trigger-per-lead-time.entity'; -import { LeadTimeEntity } from '../api/lead-time/lead-time.entity'; import { LinesDataModule } from '../api/lines-data/lines-data.module'; import { MetadataModule } from '../api/metadata/metadata.module'; import { PointDataModule } from '../api/point-data/point-data.module'; @@ -42,7 +42,6 @@ import SeedProd from './seed-prod'; EventPlaceCodeEntity, EapActionStatusEntity, AdminAreaEntity, - LeadTimeEntity, CountryEntity, TriggerPerLeadTime, AdminAreaDynamicDataEntity, @@ -50,6 +49,7 @@ import SeedProd from './seed-prod'; AdminAreaModule, AdminAreaDynamicDataModule, CountryModule, + DisasterTypeModule, EventModule, TyphoonTrackModule, UserModule, diff --git a/services/API-service/src/scripts/scripts.service.ts b/services/API-service/src/scripts/scripts.service.ts index 5732505c39..c57d910e45 100644 --- a/services/API-service/src/scripts/scripts.service.ts +++ b/services/API-service/src/scripts/scripts.service.ts @@ -11,7 +11,7 @@ import { DynamicIndicator } from '../api/admin-area-dynamic-data/enum/dynamic-da import { LeadTime } from '../api/admin-area-dynamic-data/enum/lead-time.enum'; import { AdminLevel } from '../api/country/admin-level.enum'; import { CountryEntity } from '../api/country/country.entity'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { EapActionStatusEntity } from '../api/eap-actions/eap-action-status.entity'; import { EventPlaceCodeEntity } from '../api/event/event-place-code.entity'; import { EventService } from '../api/event/event.service'; diff --git a/services/API-service/src/scripts/seed-init.ts b/services/API-service/src/scripts/seed-init.ts index 918e8ce8b0..d2e3cba437 100644 --- a/services/API-service/src/scripts/seed-init.ts +++ b/services/API-service/src/scripts/seed-init.ts @@ -9,24 +9,22 @@ import { import { CountryEntity } from '../api/country/country.entity'; import { CountryService } from '../api/country/country.service'; import { NotificationInfoDto } from '../api/country/dto/notification-info.dto'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; -import { DisasterEntity } from '../api/disaster/disaster.entity'; -import { AreaOfFocusEntity } from '../api/eap-actions/area-of-focus.entity'; +import { DisasterTypeEntity } from '../api/disaster-type/disaster-type.entity'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; +import { DisasterTypeService } from '../api/disaster-type/disaster-type.service'; +import { DisasterTypeDto } from '../api/disaster-type/dto/add-disaster-type.dto'; import { EapActionEntity } from '../api/eap-actions/eap-action.entity'; -import { LeadTimeEntity } from '../api/lead-time/lead-time.entity'; import { IndicatorMetadataEntity } from '../api/metadata/indicator-metadata.entity'; import { LayerMetadataEntity } from '../api/metadata/layer-metadata.entity'; import { NotificationInfoEntity } from '../api/notification/notifcation-info.entity'; import { UserRole } from '../api/user/user-role.enum'; import { UserStatus } from '../api/user/user-status.enum'; import { UserEntity } from '../api/user/user.entity'; -import areasOfFocus from './json/areas-of-focus.json'; import countries from './json/countries.json'; -import disasters from './json/disasters.json'; +import disasterTypes from './json/disaster-types.json'; import eapActions from './json/EAP-actions.json'; import indicatorMetadata from './json/indicator-metadata.json'; import layerMetadata from './json/layer-metadata.json'; -import leadTimes from './json/lead-times.json'; import notificationInfo from './json/notification-info.json'; import users from './json/users.json'; import { InterfaceScript } from './scripts.module'; @@ -47,6 +45,7 @@ export class SeedInit implements InterfaceScript { private seedPointData: SeedPointData, private seedLineData: SeedLineData, private countryService: CountryService, + private disasterTypeService: DisasterTypeService, ) { this.seedHelper = new SeedHelper(dataSource); } @@ -55,36 +54,28 @@ export class SeedInit implements InterfaceScript { await this.seedHelper.truncateAll(); // ***** CREATE DISASTER ***** - console.log('Seed Disasters...'); - const disasterRepository = this.dataSource.getRepository(DisasterEntity); - const disasterEntities = disasters.map((disaster): DisasterEntity => { - const disasterEntity = new DisasterEntity(); - disasterEntity.disasterType = disaster.disasterType as DisasterType; - disasterEntity.label = disaster.label; - disasterEntity.triggerUnit = disaster.triggerUnit; - disasterEntity.actionsUnit = disaster.actionsUnit; - disasterEntity.showOnlyTriggeredAreas = disaster.showOnlyTriggeredAreas; - disasterEntity.leadTimeUnit = disaster.leadTimeUnit as LeadTimeUnit; - disasterEntity.minLeadTime = disaster.minLeadTime as LeadTime; - disasterEntity.maxLeadTime = disaster.maxLeadTime as LeadTime; - return disasterEntity; - }); - - await disasterRepository.save(disasterEntities); - - // ***** CREATE LEAD TIMES ***** - console.log('Seed Lead Times...'); - const leadTimeRepository = this.dataSource.getRepository(LeadTimeEntity); - - const leadTimeEntities = await Promise.all( - leadTimes.map(async (leadTime): Promise => { - const leadTimeEntity = new LeadTimeEntity(); - leadTimeEntity.leadTimeName = leadTime.leadTimeName; - return leadTimeEntity; - }), + console.log('Seed Disaster types...'); + const disasterTypeDtos = disasterTypes.map( + (disasterType): DisasterTypeDto => { + const disasterTypeDto = new DisasterTypeDto(); + disasterTypeDto.disasterType = + disasterType.disasterType as DisasterType; + disasterTypeDto.label = disasterType.label; + disasterTypeDto.triggerIndicator = disasterType.triggerIndicator; + disasterTypeDto.mainExposureIndicator = + disasterType.mainExposureIndicator; + disasterTypeDto.showOnlyTriggeredAreas = + disasterType.showOnlyTriggeredAreas; + disasterTypeDto.leadTimeUnit = + disasterType.leadTimeUnit as LeadTimeUnit; + disasterTypeDto.minLeadTime = disasterType.minLeadTime as LeadTime; + disasterTypeDto.maxLeadTime = disasterType.maxLeadTime as LeadTime; + return disasterTypeDto; + }, ); - - await leadTimeRepository.save(leadTimeEntities); + await this.disasterTypeService.addOrUpdateDisasterTypes({ + disasterTypes: disasterTypeDtos, + }); // ***** CREATE COUNTRIES ***** console.log(`Seed Countries... ${process.env.COUNTRIES}`); @@ -151,6 +142,8 @@ export class SeedInit implements InterfaceScript { } } + const disasterTypeRepository = + this.dataSource.getRepository(DisasterTypeEntity); const userEntities = await Promise.all( selectedUsers.map(async (user): Promise => { const userEntity = new UserEntity(); @@ -170,7 +163,7 @@ export class SeedInit implements InterfaceScript { }); userEntity.disasterTypes = !user.disasterTypes ? [] - : await disasterRepository.find({ + : await disasterTypeRepository.find({ where: user.disasterTypes.map((disasterType: string): object => { return { disasterType: disasterType, @@ -185,27 +178,22 @@ export class SeedInit implements InterfaceScript { await userRepository.save(userEntities); - // ***** CREATE AREAS OF FOCUS ***** - console.log('Seed Areas of Focus...'); - const areaOfFocusRepository = - this.dataSource.getRepository(AreaOfFocusEntity); - await areaOfFocusRepository.save(areasOfFocus); - // ***** CREATE EAP ACTIONS ***** console.log('Seed EAP Actions...'); - class EapAction { - countryCodeISO3: string; - disasterType: string; - areaOfFocus: object; - action: string; - label: string; - month?: object; - } - const filteredActions: EapAction[] = eapActions.filter( - (action: EapAction): boolean => { + const filteredActions: EapActionEntity[] = eapActions + .map((action): EapActionEntity => { + const eapActionEntity = new EapActionEntity(); + eapActionEntity.countryCodeISO3 = action.countryCodeISO3; + eapActionEntity.disasterType = action.disasterType; + eapActionEntity.action = action.action; + eapActionEntity.label = action.label; + eapActionEntity.areaOfFocusId = action.areaOfFocusId as string; + eapActionEntity.month = JSON.parse(JSON.stringify(action.month || {})); + return eapActionEntity; + }) + .filter((action: EapActionEntity): boolean => { return envCountries.includes(action.countryCodeISO3); - }, - ); + }); const eapActionRepository = this.dataSource.getRepository(EapActionEntity); await eapActionRepository.save(filteredActions); diff --git a/services/API-service/src/shared/data.model.ts b/services/API-service/src/shared/data.model.ts index c1a5725c0e..7bf47fd4cc 100644 --- a/services/API-service/src/shared/data.model.ts +++ b/services/API-service/src/shared/data.model.ts @@ -38,7 +38,7 @@ export class TriggeredArea { public nameParent: string; @ApiProperty({ example: 100 }) - public actionsValue: number; + public mainExposureValue: number; @ApiProperty({ example: 1 }) public triggerValue: number; diff --git a/services/API-service/src/shared/helper.service.ts b/services/API-service/src/shared/helper.service.ts index 96e1e5fd56..0fccf97c46 100644 --- a/services/API-service/src/shared/helper.service.ts +++ b/services/API-service/src/shared/helper.service.ts @@ -8,7 +8,7 @@ import { LeadTime, LeadTimeUnit, } from '../api/admin-area-dynamic-data/enum/lead-time.enum'; -import { DisasterType } from '../api/disaster/disaster-type.enum'; +import { DisasterType } from '../api/disaster-type/disaster-type.enum'; import { DateDto } from '../api/event/dto/date.dto'; import { TriggerPerLeadTime } from '../api/event/trigger-per-lead-time.entity'; import { NumberFormat } from './enums/number-format.enum'; diff --git a/tests/e2e/Pages/ActionSummaryComponent.ts b/tests/e2e/Pages/ActionSummaryComponent.ts index c72376269d..315a931e52 100644 --- a/tests/e2e/Pages/ActionSummaryComponent.ts +++ b/tests/e2e/Pages/ActionSummaryComponent.ts @@ -1,6 +1,6 @@ import { Locator, Page } from 'playwright'; -import areasOfFocus from '../../../services/API-service/src/scripts/json/areas-of-focus.json'; +import { AREAS_OF_FOCUS } from '../../../interfaces/IBF-dashboard/src/app/models/area-of-focus.const'; import DashboardPage from './DashboardPage'; class ActionsSummaryComponent extends DashboardPage { @@ -22,14 +22,14 @@ class ActionsSummaryComponent extends DashboardPage { for (let i = 0; i < counttoolTipInfoButton; i++) { const toolTipInfoButton = this.tooltipButton.nth(i); - const descriptionText = areasOfFocus[i].description?.replace( + const descriptionText = AREAS_OF_FOCUS[i].description?.replace( /
|
    |
  • ||<\/ul>|<\/li>|<\/strong>/g, '', ); await toolTipInfoButton.click(); await this.page.waitForTimeout(200); - await this.validateLabel({ text: areasOfFocus[i].label }); + await this.validateLabel({ text: AREAS_OF_FOCUS[i].label }); await this.validateDescription({ text: descriptionText }); await this.page.getByTestId('close-matrix-icon').click(); } diff --git a/tests/integration/helpers/API-service/json/disasters.json b/tests/integration/helpers/API-service/json/disasters.json index e9d4582be3..175f763fd3 100644 --- a/tests/integration/helpers/API-service/json/disasters.json +++ b/tests/integration/helpers/API-service/json/disasters.json @@ -2,8 +2,8 @@ { "disasterType": "floods", "label": "flood", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": true, "leadTimeUnit": "day", "minLeadTime": "0-day", @@ -12,8 +12,8 @@ { "disasterType": "heavy-rain", "label": "heavy rainfall", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": true, "leadTimeUnit": "day", "minLeadTime": "1-day", @@ -22,8 +22,8 @@ { "disasterType": "malaria", "label": "malaria", - "triggerUnit": "alert_threshold", - "actionsUnit": "potential_cases", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "potential_cases", "showOnlyTriggeredAreas": false, "leadTimeUnit": "month", "minLeadTime": "0-month", @@ -32,8 +32,8 @@ { "disasterType": "drought", "label": "drought", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": true, "leadTimeUnit": "month", "minLeadTime": "0-month", @@ -42,8 +42,8 @@ { "disasterType": "typhoon", "label": "typhoon", - "triggerUnit": "alert_threshold", - "actionsUnit": "houses_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "houses_affected", "showOnlyTriggeredAreas": false, "leadTimeUnit": "hour", "minLeadTime": "0-hour", @@ -52,8 +52,8 @@ { "disasterType": "flash-floods", "label": "flash flood", - "triggerUnit": "alert_threshold", - "actionsUnit": "population_affected", + "triggerIndicator": "alert_threshold", + "mainExposureIndicator": "population_affected", "showOnlyTriggeredAreas": false, "leadTimeUnit": "hour", "minLeadTime": "0-hour",