-
-
-
-
-
e.activeTrigger)
- .length > 1
- );
+ return this.eventState?.events.length > 1;
}
private onDisasterTypeChange = (disasterType: DisasterType) => {
diff --git a/interfaces/IBF-dashboard/src/app/components/export-view/export-view.component.ts b/interfaces/IBF-dashboard/src/app/components/export-view/export-view.component.ts
index 8a826a30e..4d96608a4 100644
--- a/interfaces/IBF-dashboard/src/app/components/export-view/export-view.component.ts
+++ b/interfaces/IBF-dashboard/src/app/components/export-view/export-view.component.ts
@@ -33,7 +33,7 @@ export class ExportViewComponent {
this.analyticsService.logEvent(AnalyticsEvent.exportView, {
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
diff --git a/interfaces/IBF-dashboard/src/app/components/ibf-guide-button/ibf-guide-button.component.ts b/interfaces/IBF-dashboard/src/app/components/ibf-guide-button/ibf-guide-button.component.ts
index 01c7c29e6..83b578256 100644
--- a/interfaces/IBF-dashboard/src/app/components/ibf-guide-button/ibf-guide-button.component.ts
+++ b/interfaces/IBF-dashboard/src/app/components/ibf-guide-button/ibf-guide-button.component.ts
@@ -60,7 +60,7 @@ export class IbfGuideButtonComponent implements OnDestroy {
this.analyticsService.logEvent(AnalyticsEvent.watchIbfGuide, {
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
diff --git a/interfaces/IBF-dashboard/src/app/components/map/map.component.ts b/interfaces/IBF-dashboard/src/app/components/map/map.component.ts
index 7a4db3e8c..9286e8b03 100644
--- a/interfaces/IBF-dashboard/src/app/components/map/map.component.ts
+++ b/interfaces/IBF-dashboard/src/app/components/map/map.component.ts
@@ -385,7 +385,7 @@ export class MapComponent implements AfterViewInit, OnDestroy {
IbfLayerName.schools,
].includes(layerName) &&
this.disasterType.disasterType === DisasterTypeKey.flashFloods &&
- this.eventState.activeTrigger
+ this.eventState.events?.length > 0
);
}
@@ -638,7 +638,7 @@ export class MapComponent implements AfterViewInit, OnDestroy {
this.analyticsService.logEvent(AnalyticsEvent.mapPlaceSelect, {
placeCode,
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
diff --git a/interfaces/IBF-dashboard/src/app/components/matrix/matrix.component.ts b/interfaces/IBF-dashboard/src/app/components/matrix/matrix.component.ts
index 437d053d3..5458dac44 100644
--- a/interfaces/IBF-dashboard/src/app/components/matrix/matrix.component.ts
+++ b/interfaces/IBF-dashboard/src/app/components/matrix/matrix.component.ts
@@ -84,7 +84,7 @@ export class MatrixComponent implements OnDestroy {
mapLayerName: layer.name,
mapLayerStatus: layer.active,
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
@@ -96,7 +96,7 @@ export class MatrixComponent implements OnDestroy {
mapLayerName: layer.name,
mapLayerStatus: !layer.active,
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
diff --git a/interfaces/IBF-dashboard/src/app/components/timeline/timeline.component.ts b/interfaces/IBF-dashboard/src/app/components/timeline/timeline.component.ts
index 063415838..2e3a6f893 100644
--- a/interfaces/IBF-dashboard/src/app/components/timeline/timeline.component.ts
+++ b/interfaces/IBF-dashboard/src/app/components/timeline/timeline.component.ts
@@ -54,7 +54,7 @@ export class TimelineComponent implements OnInit, OnDestroy {
this.analyticsService.logEvent(AnalyticsEvent.leadTime, {
page: AnalyticsPage.dashboard,
leadTime,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
diff --git a/interfaces/IBF-dashboard/src/app/components/user-state/user-state.component.ts b/interfaces/IBF-dashboard/src/app/components/user-state/user-state.component.ts
index 33f49eca9..202a60327 100644
--- a/interfaces/IBF-dashboard/src/app/components/user-state/user-state.component.ts
+++ b/interfaces/IBF-dashboard/src/app/components/user-state/user-state.component.ts
@@ -89,7 +89,7 @@ export class UserStateComponent implements OnInit {
public doLogout() {
this.analyticsService.logEvent(AnalyticsEvent.logOut, {
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
diff --git a/interfaces/IBF-dashboard/src/app/mocks/backend-mock-scenario-component/backend-mock-scenario.component.ts b/interfaces/IBF-dashboard/src/app/mocks/backend-mock-scenario-component/backend-mock-scenario.component.ts
index 3a2c902e6..1c5e0e131 100644
--- a/interfaces/IBF-dashboard/src/app/mocks/backend-mock-scenario-component/backend-mock-scenario.component.ts
+++ b/interfaces/IBF-dashboard/src/app/mocks/backend-mock-scenario-component/backend-mock-scenario.component.ts
@@ -31,8 +31,6 @@ export class BackendMockScenarioComponent implements OnInit, OnDestroy {
private alertInputSecretPlaceholderNode = 'alert-input-secret-placeholder';
private alertButtonCancelLabel: string;
private alertButtonCancelLabelNode = 'alert-button-cancel';
- private alertButtonOldEventLabel: string;
- private alertButtonOldEventLabelNode = 'alert-button-old-event';
private alertButtonNoTriggerLabel: string;
private alertButtonNoTriggerLabelNode = 'alert-button-no-trigger';
private alertButtonTriggerLabel: string;
@@ -90,8 +88,6 @@ export class BackendMockScenarioComponent implements OnInit, OnDestroy {
translatedStrings[this.alertButtonCancelLabelNode];
this.alertButtonNoTriggerLabel =
translatedStrings[this.alertButtonNoTriggerLabelNode];
- this.alertButtonOldEventLabel =
- translatedStrings[this.alertButtonOldEventLabelNode];
this.alertButtonTriggerLabel =
translatedStrings[this.alertButtonTriggerLabelNode];
this.alertErrorApiError = translatedStrings[this.alertErrorApiErrorNode];
@@ -131,14 +127,6 @@ export class BackendMockScenarioComponent implements OnInit, OnDestroy {
text: this.alertButtonCancelLabel,
role: 'cancel',
},
- {
- text: this.alertButtonOldEventLabel,
- cssClass: 'no-trigger-scenario-button',
- handler: (data) => {
- this.mockApiRefresh(data.secret, true, true, true, alert);
- return false;
- },
- },
{
text: this.alertButtonNoTriggerLabel,
cssClass: 'no-trigger-scenario-button',
diff --git a/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts b/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts
index 7c5e12283..3297e7d32 100644
--- a/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts
+++ b/interfaces/IBF-dashboard/src/app/services/aggregates.service.ts
@@ -176,7 +176,7 @@ export class AggregatesService {
: aggregate[IbfLayerName.alertThreshold] > 0
? AreaStatus.TriggeredOrWarned
: aggregate[this.disasterType.actionsUnit] > 0 &&
- this.eventState.activeTrigger
+ this.eventState.events?.length > 0
? AreaStatus.TriggeredOrWarned
: AreaStatus.NonTriggeredOrWarnd;
};
diff --git a/interfaces/IBF-dashboard/src/app/services/event.service.ts b/interfaces/IBF-dashboard/src/app/services/event.service.ts
index a40360520..7fd0758a1 100644
--- a/interfaces/IBF-dashboard/src/app/services/event.service.ts
+++ b/interfaces/IBF-dashboard/src/app/services/event.service.ts
@@ -19,7 +19,6 @@ export class EventSummary {
endDate: string;
endDateLabel: string;
thresholdReached: boolean;
- activeTrigger: boolean;
eventName: string;
firstLeadTime?: string;
firstLeadTimeLabel?: string;
@@ -49,7 +48,6 @@ export class EventService {
events: null,
event: null,
thresholdReached: null,
- activeTrigger: null,
};
public state = this.nullState;
@@ -91,9 +89,7 @@ export class EventService {
};
public switchEvent(eventName: string) {
- const event = this.state.activeTrigger
- ? this.state.events.find((e) => e.eventName === eventName)
- : this.state.event;
+ const event = this.state.events.find((e) => e.eventName === eventName);
// Trigger a different 'event' subject in this case ..
// .. so that timelineService can distinguish between initial event switch and manual event switch
this.setEventManually(event);
@@ -105,7 +101,6 @@ export class EventService {
private setEventInitially(event: EventSummary) {
this.state.event = event;
- this.state.activeTrigger = this.setOverallActiveTrigger();
this.state.thresholdReached = this.setOverallThresholdReached();
this.initialEventStateSubject.next(this.state);
this.setAlertState();
@@ -113,7 +108,6 @@ export class EventService {
private setEventManually(event: EventSummary) {
this.state.event = event;
- this.state.activeTrigger = this.setOverallActiveTrigger();
this.state.thresholdReached = this.setOverallThresholdReached();
this.manualEventStateSubject.next(this.state);
this.setAlertState();
@@ -159,8 +153,8 @@ export class EventService {
events,
) => {
disasterType.activeTrigger =
- events.filter((e: EventSummary) => e.activeTrigger && e.thresholdReached)
- .length > 0 || false;
+ events.filter((e: EventSummary) => e.thresholdReached).length > 0 ||
+ false;
callback(disasterType);
};
@@ -313,7 +307,7 @@ export class EventService {
private setAlertState = () => {
const dashboardElement = document.getElementById('ibf-dashboard-interface');
if (dashboardElement) {
- if (this.state.activeTrigger && this.state.thresholdReached) {
+ if (this.state.thresholdReached) {
dashboardElement.classList.remove('no-alert');
dashboardElement.classList.add('trigger-alert');
} else {
@@ -348,15 +342,6 @@ export class EventService {
}
}
- public isOldEvent = () => this.state.event && !this.state.activeTrigger;
-
- private setOverallActiveTrigger() {
- return this.state.event
- ? this.state.event.activeTrigger
- : this.state.events?.filter((e: EventSummary) => e.activeTrigger).length >
- 0;
- }
-
private setOverallThresholdReached() {
return this.state.event
? this.state.event.thresholdReached
diff --git a/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts b/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts
index 0bb4aa7ba..3207063bb 100644
--- a/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts
+++ b/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts
@@ -127,10 +127,9 @@ export class MapLegendService {
);
}
- const colors =
- this.eventState?.activeTrigger && this.eventState?.thresholdReached
- ? this.mapService.state.colorGradientTriggered
- : this.mapService.state.colorGradient;
+ const colors = this.eventState?.thresholdReached
+ ? this.mapService.state.colorGradientTriggered
+ : this.mapService.state.colorGradient;
const getColor = this.getFeatureColorByColorsAndColorThresholds(
colors,
diff --git a/interfaces/IBF-dashboard/src/app/services/map.service.ts b/interfaces/IBF-dashboard/src/app/services/map.service.ts
index f572bf4e1..5a89de2c8 100644
--- a/interfaces/IBF-dashboard/src/app/services/map.service.ts
+++ b/interfaces/IBF-dashboard/src/app/services/map.service.ts
@@ -407,7 +407,7 @@ export class MapService {
return indicatorOrLayer.active === LayerActivation.yes
? true
: indicatorOrLayer.active === LayerActivation.ifTrigger &&
- this.eventState?.activeTrigger
+ this.eventState?.events?.length > 0
? true
: false;
}
@@ -429,10 +429,9 @@ export class MapService {
colorProperty: indicator.name,
colorBreaks: indicator.colorBreaks,
numberFormatMap: indicator.numberFormatMap,
- legendColor:
- this.eventState.activeTrigger && this.eventState.thresholdReached
- ? this.state.colorGradientTriggered[2]
- : this.state.colorGradient[2],
+ legendColor: this.eventState.thresholdReached
+ ? this.state.colorGradientTriggered[2]
+ : this.state.colorGradient[2],
group:
indicator.name === IbfLayerName.alertThreshold
? IbfLayerGroup.outline
@@ -517,7 +516,7 @@ export class MapService {
): boolean => {
if (
layer.group === IbfLayerGroup.outline &&
- this.eventState?.activeTrigger
+ this.eventState?.events?.length > 0
) {
return true;
}
@@ -761,10 +760,9 @@ export class MapService {
placeCodeParent: string,
): string => {
let adminRegionFillColor = this.state.defaultFillColor;
- const currentColorGradient =
- this.eventState.activeTrigger && this.eventState.thresholdReached
- ? this.state.colorGradientTriggered
- : this.state.colorGradient;
+ const currentColorGradient = this.eventState.thresholdReached
+ ? this.state.colorGradientTriggered
+ : this.state.colorGradient;
const area = this.getAreaByPlaceCode(placeCode, placeCodeParent);
switch (true) {
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 e589ec76c..93f03894b 100644
--- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts
+++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts
@@ -110,7 +110,7 @@ export class PointMarkerService {
private onMapMarkerClick = (analyticsEvent) => (): void => {
this.analyticsService.logEvent(analyticsEvent, {
page: AnalyticsPage.dashboard,
- isActiveTrigger: this.eventService.state.activeTrigger,
+ isActiveTrigger: this.eventService.state.events?.length > 0,
component: this.constructor.name,
});
};
diff --git a/interfaces/IBF-dashboard/src/app/services/timeline.service.ts b/interfaces/IBF-dashboard/src/app/services/timeline.service.ts
index 6fc907d58..6ba3f62dc 100644
--- a/interfaces/IBF-dashboard/src/app/services/timeline.service.ts
+++ b/interfaces/IBF-dashboard/src/app/services/timeline.service.ts
@@ -148,9 +148,8 @@ export class TimelineService {
);
}
- private onTriggerPerLeadTime = (triggers) => {
- // TODO: test regression effects here better + nothing happens with input anymore now? + use this somehow to highlight relevant leadTimes per event?
- // this.triggersAllEvents = { ...this.triggersAllEvents, ...triggers };
+ private onTriggerPerLeadTime = (triggersPerLeadTime: CountryTriggers) => {
+ this.triggersAllEvents = triggersPerLeadTime;
this.state.timeStepButtons = [];
const visibleLeadTimes = this.getVisibleLeadTimes();
@@ -186,7 +185,7 @@ export class TimelineService {
this.eventState.event
? ((this.eventState.event.firstTriggerLeadTime ||
this.eventState.event.firstLeadTime) as LeadTime)
- : this.eventState.activeTrigger
+ : this.eventState.events?.length > 0
? null
: this.getFallbackNoTriggerLeadTime(this.disasterType.disasterType),
null,
@@ -224,29 +223,7 @@ export class TimelineService {
this.disasterType.disasterType,
null,
)
- .subscribe((response) => {
- this.triggersAllEvents = response;
- });
-
- const events = this.eventState?.events;
- if (events?.length) {
- for (const event of events) {
- if (event.activeTrigger) {
- this.apiService
- .getTriggerPerLeadTime(
- this.country.countryCodeISO3,
- this.disasterType.disasterType,
- event?.eventName,
- )
- .subscribe(this.onTriggerPerLeadTime);
- } else {
- this.onTriggerPerLeadTime(null);
- }
- }
- }
- if (!events || !events.length) {
- this.onTriggerPerLeadTime(null);
- }
+ .subscribe(this.onTriggerPerLeadTime);
};
public loadTimeStepButtons(): void {
@@ -526,26 +503,31 @@ export class TimelineService {
}
} else if (disasterType.disasterType === DisasterTypeKey.typhoon) {
const events = this.eventState?.events;
- const relevantLeadTimes = this.eventState?.activeTrigger
- ? events
- .filter((e) => !e.disasterSpecificProperties?.typhoonNoLandfallYet)
- .map((e) => e.firstLeadTime)
- : [];
+ const relevantLeadTimes =
+ this.eventState?.events?.length > 0
+ ? events
+ .filter(
+ (e) => !e.disasterSpecificProperties?.typhoonNoLandfallYet,
+ )
+ .map((e) => e.firstLeadTime)
+ : [];
return relevantLeadTimes.includes(leadTime);
} else if (disasterType.disasterType === DisasterTypeKey.flashFloods) {
const events = this.eventState?.events;
if (!events.length) {
return leadTime === LeadTime.hour1;
}
- const relevantLeadTimes = this.eventState?.activeTrigger
- ? events.map((e) => e.firstLeadTime)
- : [];
+ const relevantLeadTimes =
+ this.eventState?.events?.length > 0
+ ? events.map((e) => e.firstLeadTime)
+ : [];
return relevantLeadTimes.includes(leadTime);
} else if (disasterType.disasterType === DisasterTypeKey.floods) {
const events = this.eventState?.events;
- const relevantLeadTimes = this.eventState?.activeTrigger
- ? events.map((e) => e.firstLeadTime)
- : [];
+ const relevantLeadTimes =
+ this.eventState?.events?.length > 0
+ ? events.map((e) => e.firstLeadTime)
+ : [];
return relevantLeadTimes.includes(leadTime);
} else {
return true;
diff --git a/interfaces/IBF-dashboard/src/app/types/event-state.ts b/interfaces/IBF-dashboard/src/app/types/event-state.ts
index 412fdc75e..166a7a27c 100644
--- a/interfaces/IBF-dashboard/src/app/types/event-state.ts
+++ b/interfaces/IBF-dashboard/src/app/types/event-state.ts
@@ -3,6 +3,5 @@ import { EventSummary } from '../services/event.service';
export class EventState {
events: EventSummary[];
event: EventSummary;
- activeTrigger: boolean;
thresholdReached: boolean;
}
diff --git a/interfaces/IBF-dashboard/src/app/types/triggered-area.ts b/interfaces/IBF-dashboard/src/app/types/triggered-area.ts
index 8302b2299..4a118e17d 100644
--- a/interfaces/IBF-dashboard/src/app/types/triggered-area.ts
+++ b/interfaces/IBF-dashboard/src/app/types/triggered-area.ts
@@ -4,7 +4,6 @@ import { EapAction } from './eap-action';
export class TriggeredArea {
actionsValue: number;
triggerValue: number;
- activeTrigger: boolean;
displayName: string;
eapActions: EapAction[];
eventPlaceCodeId: string;
diff --git a/interfaces/IBF-dashboard/src/assets/i18n/en.json b/interfaces/IBF-dashboard/src/assets/i18n/en.json
index f3bd31a2c..9366645bf 100644
--- a/interfaces/IBF-dashboard/src/assets/i18n/en.json
+++ b/interfaces/IBF-dashboard/src/assets/i18n/en.json
@@ -39,7 +39,6 @@
"alert-message": "Are you sure you want to mock the situation for {{ countryName }} {{ disasterTypeLabel }}?",
"alert-input-secret-placeholder": "Please enter the reset secret",
"alert-button-cancel": "Cancel",
- "alert-button-old-event": "Old event",
"alert-button-no-trigger": "No Trigger",
"alert-button-trigger": "Trigger",
"alert-error-api-error": "Failed to set mock scenario.",
@@ -150,9 +149,6 @@
"welcome": "First warning on {{firstLeadTimeDate}}",
"welcome-below-trigger": "First trigger on {{firstTriggerLeadTimeDate}}."
},
- "active-event-no-trigger": {
- "welcome": "There is no active alert any more, as can be seen in the map, which always reflects the latest forecast. However, you can still see here the EAP-actions that relate to the event that started on {{ startDate }} and ended on {{ endDate }}. These actions stay visible here for 7 days after the end-date."
- },
"active-event": {
"overview": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} exposed. They are listed below by alert level and by {{ actionIndicator}}. Only triggered {{adminAreaLabelPlural}} are highlighted in the map with a red outline.",
"overview-below-trigger": "There are {{ nrTriggeredAreas }} {{ adminAreaLabelPlural }} exposed. They are listed below by alert level and by {{ actionIndicator}}.",
@@ -210,9 +206,6 @@
"welcome": "A {{ disasterTypeLabel }} trigger warning was issued on {{ startDate }} for {{ firstLeadTimeDate }}.",
"welcome-duration": "A {{ disasterTypeLabel }} trigger warning was issued on {{ startDate }} for {{ firstLeadTimeDate }} with a duration of {{ duration}} month(s)."
},
- "active-event-no-trigger": {
- "welcome": "There is no active trigger any more, as can be seen in the map, which always reflects the latest forecast. However, you can still see here the EAP-actions that relate to the event that started on {{ startDate }} and ended on {{ endDate }}. These actions stay visible here for 7 days after the end-date."
- },
"clear-out": {
"regional": {
"warning": "Please be aware that the EAP-actions for some areas related to this trigger will be automatically cleared out by the IBF-Portal after this month, due to the start of the next rainy season in those areas.",
@@ -297,9 +290,6 @@
"header-ongoing": "Ongoing alert: {{ disasterTypeLabel }}",
"welcome": "An alert for {{ disasterTypeLabel }} was issued on {{ startDate }}. It is estimated to arrive around {{ leadTime }} {{ timeUnit }}(s) from now."
},
- "active-event-no-trigger": {
- "welcome": "There is no active alert any more, as can be seen in the map, which always reflects the latest forecast. However, you can still see here the EAP-actions that relate to the event that started on {{ startDate }} and ended on {{ endDate }}. These actions stay visible here for 7 days after the end-date."
- },
"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.",
"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.",
@@ -322,9 +312,6 @@
"header-ongoing": "Ongoing alert: {{ disasterTypeLabel }}",
"welcome": "An alert for {{ disasterTypeLabel }} was issued on {{ startDate }}. The alert is issued for {{ firstLeadTimeDate }}."
},
- "active-event-no-trigger": {
- "welcome": "There is no alert active any more (as you can see in the map). However, you can still see here the SOP actions that relate to the event that started on {{ startDate }} and ended on {{ endDate }}. These actions stay visible here until the end of the month."
- },
"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.",
"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.",
@@ -348,11 +335,9 @@
},
"active-event-active-trigger": {
"header": "Alert: {{ disasterTypeLabel }}",
+ "header-ongoing": "Ongoing alert: {{ disasterTypeLabel }}",
"welcome": "An alert for {{ disasterTypeLabel }} was issued on {{ startDate }}. The alert is issued for {{ firstLeadTimeDate }}."
},
- "active-event-no-trigger": {
- "welcome": "There is no alert active any more (as you can see in the map). However, you can still see here the SOP actions that relate to the event that started on {{ startDate }} and ended on {{ endDate }}. These actions stay visible here until the end of the month."
- },
"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.",
"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.",
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..8de49409f
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl-78a8bf6d:18e521c29db:-7ffc
+ flood_extent_0-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 15:20:09.39 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_0-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/flood_extent_0-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/flood_extent_0-day_UGA/coverage.xml
new file mode 100644
index 000000000..ee49baf44
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/flood_extent_0-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl-78a8bf6d:18e521c29db:-7ffa
+ flood_extent_0-day_UGA
+ flood_extent_0-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_0-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_0-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_0-day_UGA_flood_extent_0-day_UGA
+
+
+ CoverageStoreInfoImpl-78a8bf6d:18e521c29db:-7ffc
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ VRT
+ GeoPackage (mosaic)
+ AIG
+ RPFTOC
+ NITF
+ ImagePyramid
+ ArcGrid
+ GEOTIFF
+ ENVIHdr
+ DTED
+ EHdr
+ ERDASImg
+ GIF
+ PNG
+ JPEG
+ TIFF
+ RST
+ ImageMosaic
+ SRP
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_0-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/flood_extent_0-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/flood_extent_0-day_UGA/layer.xml
new file mode 100644
index 000000000..de005437f
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_0-day_UGA/flood_extent_0-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_0-day_UGA
+ LayerInfoImpl-78a8bf6d:18e521c29db:-7ff9
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl-78a8bf6d:18e521c29db:-7ffa
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 15:24:10.896 UTC
+ 2024-03-18 15:24:11.43 UTC
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..5c17e1385
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ffc
+ flood_extent_1-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 14:47:29.131 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_1-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/flood_extent_1-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/flood_extent_1-day_UGA/coverage.xml
new file mode 100644
index 000000000..1bf718a64
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/flood_extent_1-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7ff6
+ flood_extent_1-day_UGA
+ flood_extent_1-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_1-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_1-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_1-day_UGA_flood_extent_1-day_UGA
+
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ffc
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ ImagePyramid
+ RST
+ GIF
+ PNG
+ JPEG
+ TIFF
+ GEOTIFF
+ NITF
+ ArcGrid
+ DTED
+ AIG
+ GeoPackage (mosaic)
+ ImageMosaic
+ SRP
+ ERDASImg
+ VRT
+ ENVIHdr
+ RPFTOC
+ EHdr
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_1-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/flood_extent_1-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/flood_extent_1-day_UGA/layer.xml
new file mode 100644
index 000000000..2a7f15ba6
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_1-day_UGA/flood_extent_1-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_1-day_UGA
+ LayerInfoImpl--18a5c506:18e5207e95d:-7ff5
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7ff6
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 14:47:30.361 UTC
+ 2024-03-18 14:47:30.453 UTC
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..49696c722
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ffb
+ flood_extent_2-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 14:47:29.267 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_2-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/flood_extent_2-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/flood_extent_2-day_UGA/coverage.xml
new file mode 100644
index 000000000..935a0f0d7
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/flood_extent_2-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7ff4
+ flood_extent_2-day_UGA
+ flood_extent_2-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_2-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_2-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_2-day_UGA_flood_extent_2-day_UGA
+
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ffb
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ ImagePyramid
+ RST
+ GIF
+ PNG
+ JPEG
+ TIFF
+ GEOTIFF
+ NITF
+ ArcGrid
+ DTED
+ AIG
+ GeoPackage (mosaic)
+ ImageMosaic
+ SRP
+ ERDASImg
+ VRT
+ ENVIHdr
+ RPFTOC
+ EHdr
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_2-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/flood_extent_2-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/flood_extent_2-day_UGA/layer.xml
new file mode 100644
index 000000000..b6136d44f
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_2-day_UGA/flood_extent_2-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_2-day_UGA
+ LayerInfoImpl--18a5c506:18e5207e95d:-7ff3
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7ff4
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 14:47:30.734 UTC
+ 2024-03-18 14:47:30.811 UTC
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..d72f77ab2
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ffa
+ flood_extent_3-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 14:47:29.337 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_3-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/flood_extent_3-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/flood_extent_3-day_UGA/coverage.xml
new file mode 100644
index 000000000..6c7dc1842
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/flood_extent_3-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7ff2
+ flood_extent_3-day_UGA
+ flood_extent_3-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_3-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_3-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_3-day_UGA_flood_extent_3-day_UGA
+
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ffa
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ ImagePyramid
+ RST
+ GIF
+ PNG
+ JPEG
+ TIFF
+ GEOTIFF
+ NITF
+ ArcGrid
+ DTED
+ AIG
+ GeoPackage (mosaic)
+ ImageMosaic
+ SRP
+ ERDASImg
+ VRT
+ ENVIHdr
+ RPFTOC
+ EHdr
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_3-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/flood_extent_3-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/flood_extent_3-day_UGA/layer.xml
new file mode 100644
index 000000000..b79c5192a
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_3-day_UGA/flood_extent_3-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_3-day_UGA
+ LayerInfoImpl--18a5c506:18e5207e95d:-7ff1
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7ff2
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 14:47:30.958 UTC
+ 2024-03-18 14:47:31.0 UTC
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..ce98993e8
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl-78a8bf6d:18e521c29db:-7ffb
+ flood_extent_4-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 15:20:09.241 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_4-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/flood_extent_4-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/flood_extent_4-day_UGA/coverage.xml
new file mode 100644
index 000000000..32411f444
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/flood_extent_4-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl-78a8bf6d:18e521c29db:-7ff8
+ flood_extent_4-day_UGA
+ flood_extent_4-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_4-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_4-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_4-day_UGA_flood_extent_4-day_UGA
+
+
+ CoverageStoreInfoImpl-78a8bf6d:18e521c29db:-7ffb
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ VRT
+ GeoPackage (mosaic)
+ AIG
+ RPFTOC
+ NITF
+ ImagePyramid
+ ArcGrid
+ GEOTIFF
+ ENVIHdr
+ DTED
+ EHdr
+ ERDASImg
+ GIF
+ PNG
+ JPEG
+ TIFF
+ RST
+ ImageMosaic
+ SRP
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_4-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/flood_extent_4-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/flood_extent_4-day_UGA/layer.xml
new file mode 100644
index 000000000..4c2b4e6e7
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_4-day_UGA/flood_extent_4-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_4-day_UGA
+ LayerInfoImpl-78a8bf6d:18e521c29db:-7ff7
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl-78a8bf6d:18e521c29db:-7ff8
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 15:24:11.620 UTC
+ 2024-03-18 15:24:11.746 UTC
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..843bb996f
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ff8
+ flood_extent_6-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 14:47:29.405 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_6-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/flood_extent_6-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/flood_extent_6-day_UGA/coverage.xml
new file mode 100644
index 000000000..a9e147a89
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/flood_extent_6-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7fee
+ flood_extent_6-day_UGA
+ flood_extent_6-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_6-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_6-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_6-day_UGA_flood_extent_6-day_UGA
+
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ff8
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ ImagePyramid
+ RST
+ GIF
+ PNG
+ JPEG
+ TIFF
+ GEOTIFF
+ NITF
+ ArcGrid
+ DTED
+ AIG
+ GeoPackage (mosaic)
+ ImageMosaic
+ SRP
+ ERDASImg
+ VRT
+ ENVIHdr
+ RPFTOC
+ EHdr
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_6-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/flood_extent_6-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/flood_extent_6-day_UGA/layer.xml
new file mode 100644
index 000000000..5e3f16472
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_6-day_UGA/flood_extent_6-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_6-day_UGA
+ LayerInfoImpl--18a5c506:18e5207e95d:-7fed
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7fee
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 14:47:31.252 UTC
+ 2024-03-18 14:47:31.287 UTC
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/coveragestore.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/coveragestore.xml
new file mode 100644
index 000000000..a2619fac5
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/coveragestore.xml
@@ -0,0 +1,12 @@
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ff7
+ flood_extent_7-day_UGA
+ GeoTIFF
+ true
+
+ WorkspaceInfoImpl-48cab08a:175ace47603:-7ffb
+
+ <__default>false
+ 2024-03-18 14:47:29.457 UTC
+ file:workspaces/ibf-system/ibf-pipeline/output/flood_extents/flood_extent_7-day_UGA.tif
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/flood_extent_7-day_UGA/coverage.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/flood_extent_7-day_UGA/coverage.xml
new file mode 100644
index 000000000..108b2cf5d
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/flood_extent_7-day_UGA/coverage.xml
@@ -0,0 +1,129 @@
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7fec
+ flood_extent_7-day_UGA
+ flood_extent_7-day_UGA
+
+ NamespaceInfoImpl-48cab08a:175ace47603:-7ffa
+
+ flood_extent_7-day_UGA
+ Generated from GeoTIFF
+
+ flood_extent_7-day_UGA
+ WCS
+ GeoTIFF
+
+ GEOGCS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+ AUTHORITY["EPSG","6326"]],
+ PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+ UNIT["degree", 0.017453292519943295],
+ AXIS["Geodetic longitude", EAST],
+ AXIS["Geodetic latitude", NORTH],
+ AUTHORITY["EPSG","4326"]]
+ EPSG:4326
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+
+ 29.572498778
+ 35.000831587
+ -1.4808333329999996
+ 4.230833333
+ EPSG:4326
+
+ REPROJECT_TO_DECLARED
+ true
+
+ flood_extent_7-day_UGA_flood_extent_7-day_UGA
+
+
+ CoverageStoreInfoImpl--18a5c506:18e5207e95d:-7ff7
+
+ false
+ false
+ GeoTIFF
+
+
+ 0 0
+ 6514 6854
+
+
+ 8.333332528400369E-4
+ -8.333333332360665E-4
+ 0.0
+ 0.0
+ 29.57291544462642
+ 4.230416666333381
+
+ EPSG:4326
+
+
+ ImagePyramid
+ RST
+ GIF
+ PNG
+ JPEG
+ TIFF
+ GEOTIFF
+ NITF
+ ArcGrid
+ DTED
+ AIG
+ GeoPackage (mosaic)
+ ImageMosaic
+ SRP
+ ERDASImg
+ VRT
+ ENVIHdr
+ RPFTOC
+ EHdr
+
+
+ nearest neighbor
+ bilinear
+ bicubic
+
+ nearest neighbor
+
+
+ GRAY_INDEX
+ GridSampleDimension[-Infinity,Infinity]
+
+ -inf
+ inf
+
+
+ 3.4028234663852886E38
+
+
+ REAL_32BITS
+
+
+
+
+ EPSG:4326
+
+
+ EPSG:4326
+
+
+
+ InputTransparentColor
+
+
+
+ SUGGESTED_TILE_SIZE
+ 512,512
+
+
+ RescalePixels
+ true
+
+
+ flood_extent_7-day_UGA
+
\ No newline at end of file
diff --git a/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/flood_extent_7-day_UGA/layer.xml b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/flood_extent_7-day_UGA/layer.xml
new file mode 100644
index 000000000..2e8565775
--- /dev/null
+++ b/services/API-service/geoserver-volume/geoserver-layers/flood_extent_7-day_UGA/flood_extent_7-day_UGA/layer.xml
@@ -0,0 +1,19 @@
+
+ flood_extent_7-day_UGA
+ LayerInfoImpl--18a5c506:18e5207e95d:-7feb
+ RASTER
+
+ StyleInfoImpl-48cab08a:175ace47603:-7ff7
+
+
+ CoverageInfoImpl--18a5c506:18e5207e95d:-7fec
+
+ true
+ false
+
+ 0
+ 0
+
+ 2024-03-18 14:47:31.402 UTC
+ 2024-03-18 14:47:31.428 UTC
+
\ No newline at end of file
diff --git a/services/API-service/migration/1710512991479-rename-mock-rasters.ts b/services/API-service/migration/1710512991479-rename-mock-rasters.ts
new file mode 100644
index 000000000..4ce5f8a52
--- /dev/null
+++ b/services/API-service/migration/1710512991479-rename-mock-rasters.ts
@@ -0,0 +1,38 @@
+import { MigrationInterface, QueryRunner } from 'typeorm';
+import * as fs from 'fs';
+import * as path from 'path';
+
+export class RenameMockRasters1710512991479 implements MigrationInterface {
+ public async up(_queryRunner: QueryRunner): Promise {
+ const directoryPath = './geoserver-volume/raster-files/mock-output/';
+ const ugandaFloodsBasicPath = `${directoryPath}/flood_extent_day_UGA.tif`;
+ if (fs.existsSync(ugandaFloodsBasicPath)) {
+ // Do not run the migration another time if it has already been run on test servers
+ return;
+ }
+
+ if (fs.existsSync(directoryPath)) {
+ const files = fs.readdirSync(directoryPath);
+ console.log('🚀 ~ RenameMockRasters1710512991479 ~ up ~ files:', files);
+
+ files.forEach((file) => {
+ if (!file.includes('hour_MWI')) {
+ const newFilename = file.replace(
+ /_[0-9]+-(hour|day|month)_/g,
+ '_$1_',
+ );
+ fs.renameSync(
+ path.join(directoryPath, file),
+ path.join(directoryPath, newFilename),
+ );
+ }
+ });
+ } else {
+ console.log(`Directory ${directoryPath} does not exist`);
+ }
+ }
+
+ public async down(_queryRunner: QueryRunner): Promise {
+ // If you want to revert the renaming, you would need to implement the logic here
+ }
+}
diff --git a/services/API-service/migration/1710755059526-RemoveActiveTrigger.ts b/services/API-service/migration/1710755059526-RemoveActiveTrigger.ts
new file mode 100644
index 000000000..e41a06f90
--- /dev/null
+++ b/services/API-service/migration/1710755059526-RemoveActiveTrigger.ts
@@ -0,0 +1,17 @@
+import { MigrationInterface, QueryRunner } from 'typeorm';
+
+export class RemoveActiveTrigger1710755059526 implements MigrationInterface {
+ name = 'RemoveActiveTrigger1710755059526';
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ `ALTER TABLE "IBF-app"."event-place-code" DROP COLUMN "activeTrigger"`,
+ );
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ `ALTER TABLE "IBF-app"."event-place-code" ADD "activeTrigger" boolean NOT NULL DEFAULT true`,
+ );
+ }
+}
diff --git a/services/API-service/package.json b/services/API-service/package.json
index d1b535818..cbacf60be 100644
--- a/services/API-service/package.json
+++ b/services/API-service/package.json
@@ -19,7 +19,8 @@
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
"migration:generate": "npm run typeorm migration:generate -- -d ./appdatasource.ts",
"migration:run": "npm run typeorm migration:run -- -d ./appdatasource.ts",
- "migration:revert": "npm run typeorm migration:revert -- -d ./appdatasource.ts"
+ "migration:revert": "npm run typeorm migration:revert -- -d ./appdatasource.ts",
+ "migration:create": "npm run typeorm migration:create -- "
},
"private": true,
"dependencies": {
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 5b8033ca5..768569e08 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
@@ -15,6 +15,7 @@ import fs from 'fs';
import { CountryEntity } from '../country/country.entity';
import { HelperService } from '../../shared/helper.service';
import { EventAreaService } from '../admin-area/services/event-area.service';
+import { DisasterTypeGeoServerMapper } from '../../scripts/disaster-type-geoserver-file.mapper';
@Injectable()
export class AdminAreaDynamicDataService {
@@ -231,16 +232,9 @@ export class AdminAreaDynamicDataService {
data: any,
disasterType: DisasterType,
): Promise {
- let subfolder: string;
- if (
- [DisasterType.Floods, DisasterType.FlashFloods].includes(disasterType)
- ) {
- subfolder = 'flood_extents';
- } else if (
- [DisasterType.HeavyRain, DisasterType.Drought].includes(disasterType)
- ) {
- subfolder = 'rainfall_extents';
- } else {
+ const subfolder =
+ DisasterTypeGeoServerMapper.getSubfolderForDisasterType(disasterType);
+ if (subfolder === '') {
throw new HttpException(
'Disaster Type not allowed',
HttpStatus.BAD_REQUEST,
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 7eec292eb..42f6f65ec 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
@@ -72,7 +72,7 @@ export class EventAreaService {
countryCodeISO3,
disaster.disasterType,
);
- for await (const event of events.filter((e) => e.activeTrigger)) {
+ for await (const event of events) {
const eventArea = await this.eventAreaRepository
.createQueryBuilder('area')
.where({
@@ -142,7 +142,7 @@ export class EventAreaService {
);
const aggregateRecords = [];
- for await (const event of events.filter((e) => e.activeTrigger)) {
+ for await (const event of events) {
const aggregateValues = await this.getEventAreaAggregatesPerIndicator(
disasterType,
lastTriggeredDate,
@@ -171,7 +171,7 @@ export class EventAreaService {
);
const records = [];
- for await (const event of events.filter((e) => e.activeTrigger)) {
+ for await (const event of events) {
const aggregateValues = await this.getEventAreaAggregatesPerIndicator(
disasterType,
lastTriggeredDate,
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 7ece43abc..69fb297d3 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
@@ -53,9 +53,6 @@ export class EventPlaceCodeEntity {
@Column({ type: 'timestamp', nullable: true })
public manualStoppedDate: Date;
- @Column({ default: true })
- public activeTrigger: boolean;
-
@Column({ default: false })
public stopped: boolean;
diff --git a/services/API-service/src/api/event/event.service.ts b/services/API-service/src/api/event/event.service.ts
index 7a3ba0e18..8c9fa2521 100644
--- a/services/API-service/src/api/event/event.service.ts
+++ b/services/API-service/src/api/event/event.service.ts
@@ -18,10 +18,7 @@ import {
} from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
-import {
- LeadTime,
- LeadTimeUnit,
-} from '../admin-area-dynamic-data/enum/lead-time.enum';
+import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum';
import { UploadTriggerPerLeadTimeDto } from './dto/upload-trigger-per-leadtime.dto';
import { TriggerPerLeadTime } from './trigger-per-lead-time.entity';
import { EventSummaryCountry, TriggeredArea } from '../../shared/data.model';
@@ -76,23 +73,16 @@ export class EventService {
.addSelect([
'to_char(MIN("startDate") , \'yyyy-mm-dd\') AS "startDate"',
'to_char(MAX("endDate") , \'yyyy-mm-dd\') AS "endDate"',
- 'MAX(event."activeTrigger"::int)::boolean AS "activeTrigger"',
'MAX(event."thresholdReached"::int)::boolean AS "thresholdReached"',
])
- .where('closed = :closed', {
+ .where({
closed: false,
+ endDate: MoreThanOrEqual(recentDate.date),
+ disasterType: disasterType,
})
- .andWhere('"endDate" >= :date', { date: recentDate.date })
- .andWhere(
- // for typhoon/flash-floods filter also on activeTrigger = true, thereby disabling old-event scenario
- `(event."disasterType" NOT IN ('typhoon','flash-floods') OR (event."disasterType" IN ('typhoon','flash-floods') AND event."activeTrigger" = true))`,
- )
.andWhere('area."countryCodeISO3" = :countryCodeISO3', {
countryCodeISO3: countryCodeISO3,
})
- .andWhere('event."disasterType" = :disasterType', {
- disasterType: disasterType,
- })
.getRawMany();
for await (const event of eventSummary) {
@@ -299,7 +289,6 @@ export class EventService {
'event."actionsValue"',
'event."triggerValue"',
'event."eventPlaceCodeId"',
- 'event."activeTrigger"',
'event."stopped"',
'event."startDate"',
'event."manualStoppedDate" AS "stoppedDate"',
@@ -327,11 +316,7 @@ export class EventService {
const triggeredAreas = await triggeredAreasQuery.getRawMany();
for (const area of triggeredAreas) {
- if (
- triggeredPlaceCodes.length === 0 &&
- disasterType === DisasterType.Typhoon
- ) {
- // Exception to speed up typhoon performance. Works because old-event is switched off for typhoon. Should be refactored better.
+ if (triggeredPlaceCodes.length === 0) {
area.eapActions = [];
} else if (area.triggerValue < 1) {
// Do not show actions for below-trigger events/areas
@@ -612,10 +597,7 @@ export class EventService {
date,
);
- // Then set all events to inactive
- await this.setAllEventsToInactive(countryCodeISO3, disasterType);
-
- // update active ones to true + update population and end_date
+ // update existing event areas + update population and end_date
await this.updateExistingEventAreas(
countryCodeISO3,
disasterType,
@@ -623,7 +605,7 @@ export class EventService {
eventName,
);
- // add new ones
+ // add new event areas
await this.addNewEventAreas(
countryCodeISO3,
disasterType,
@@ -631,62 +613,10 @@ export class EventService {
eventName,
);
- // close old events
+ // close old event areas
await this.closeEventsAutomatic(countryCodeISO3, disasterType, eventName);
}
- private async setAllEventsToInactive(
- countryCodeISO3: string,
- disasterType: DisasterType,
- ) {
- const countryAdminAreaIds = await this.getCountryAdminAreaIds(
- countryCodeISO3,
- );
- // only set records that are not updated yet in this sequence of pipeline runs (e.g. multiple events in 1 day)
- // after the 1st event this means everything is updated ..
- // .. and from the 2nd event onwards if will not be set to activeTrigger=false again ..
- const recentDate = await this.helperService.getRecentDate(
- countryCodeISO3,
- disasterType,
- );
- const cutoffDate = this.helperService.getUploadCutoffMoment(
- disasterType,
- recentDate.timestamp,
- );
- const endDate = await this.getEndDate(disasterType, cutoffDate);
-
- // .. but only check on endDate if eventName is not null > I cannot remember why..
- const eventAreas = await this.eventPlaceCodeRepo.find({
- where: [
- {
- adminArea: { id: In(countryAdminAreaIds) },
- disasterType: disasterType,
- activeTrigger: true,
- endDate: LessThan(endDate),
- },
- {
- adminArea: { id: In(countryAdminAreaIds) },
- disasterType: disasterType,
- activeTrigger: true,
- eventName: IsNull(),
- },
- ],
- });
-
- if (eventAreas.length) {
- await this.eventPlaceCodeRepo
- .createQueryBuilder()
- .update()
- .set({
- activeTrigger: false,
- })
- .where({
- eventPlaceCodeId: In(eventAreas.map((area) => area.eventPlaceCodeId)),
- })
- .execute();
- }
- }
-
private async getAffectedAreas(
countryCodeISO3: string,
disasterType: DisasterType,
@@ -797,14 +727,12 @@ export class EventService {
const idsToUpdateAboveThreshold = [];
const idsToUpdateBelowThreshold = [];
const uploadDate = await this.getRecentDate(countryCodeISO3, disasterType);
- const endDate = await this.getEndDate(disasterType, uploadDate.timestamp);
unclosedEventAreas.forEach((eventArea) => {
const affectedArea = affectedAreas.find(
(area) => area.placeCode === eventArea.adminArea.placeCode,
);
if (affectedArea) {
- eventArea.activeTrigger = true;
- eventArea.endDate = endDate;
+ eventArea.endDate = uploadDate.timestamp;
if (affectedArea.triggerValue === 1) {
eventArea.thresholdReached = true;
idsToUpdateAboveThreshold.push(eventArea.eventPlaceCodeId);
@@ -815,10 +743,18 @@ export class EventService {
}
});
// .. first fire one query to update all rows that need thresholdReached = true
- await this.updateEvents(idsToUpdateAboveThreshold, true, endDate);
+ await this.updateEvents(
+ idsToUpdateAboveThreshold,
+ true,
+ uploadDate.timestamp,
+ );
// .. then fire one query to update all rows that need thresholdReached = false
- await this.updateEvents(idsToUpdateBelowThreshold, false, endDate);
+ await this.updateEvents(
+ idsToUpdateBelowThreshold,
+ false,
+ uploadDate.timestamp,
+ );
// .. lastly we update those records where actionsValue or triggerValue changed
await this.updateValues(unclosedEventAreas, affectedAreas);
@@ -834,7 +770,6 @@ export class EventService {
.createQueryBuilder()
.update()
.set({
- activeTrigger: true,
thresholdReached: aboveThreshold,
endDate: endDate,
})
@@ -921,11 +856,7 @@ export class EventService {
eventArea.triggerValue = area.triggerValue;
eventArea.actionsValue = +area.actionsValue;
eventArea.startDate = startDate.timestamp;
- eventArea.endDate = await this.getEndDate(
- disasterType,
- startDate.timestamp,
- );
- eventArea.activeTrigger = true;
+ eventArea.endDate = startDate.timestamp;
eventArea.stopped = false;
eventArea.manualStoppedDate = null;
eventArea.disasterType = disasterType;
@@ -948,7 +879,7 @@ export class EventService {
disasterType,
);
const whereFilters = {
- endDate: LessThan(uploadDate.timestamp),
+ endDate: LessThan(uploadDate.timestamp), // If the area was not prolongued earlier, then the endDate is not updated and is therefore less than the uploadDate
adminArea: In(countryAdminAreaIds),
disasterType: disasterType,
closed: false,
@@ -976,20 +907,6 @@ export class EventService {
await this.eventPlaceCodeRepo.save(aboveThresholdEvents);
}
- private async getEndDate(
- disasterType: DisasterType,
- passedDate: Date,
- ): Promise {
- const today = new Date(JSON.parse(JSON.stringify(passedDate)));
-
- const disasterTypeEntity = await this.disasterTypeRepository.findOne({
- where: { disasterType: disasterType },
- });
- return disasterTypeEntity.leadTimeUnit === LeadTimeUnit.month
- ? new Date(today.getFullYear(), today.getMonth() + 1, 0, 23, 59, 59)
- : new Date(today.setDate(today.getDate() + 7));
- }
-
public async postEventMapImage(
countryCodeISO3: string,
disasterType: DisasterType,
diff --git a/services/API-service/src/api/notification/notification.service.ts b/services/API-service/src/api/notification/notification.service.ts
index ae8c0b790..7d0858fa8 100644
--- a/services/API-service/src/api/notification/notification.service.ts
+++ b/services/API-service/src/api/notification/notification.service.ts
@@ -97,9 +97,8 @@ export class NotificationService {
const date = uploadDate ? new Date(uploadDate) : new Date();
const yesterdayActiveDate = new Date(date.setDate(date.getDate() + 6)); // determine yesterday still active events by endDate lying (7 - 1) days in the future
if (
- !event.activeTrigger &&
new Date(event.endDate) >=
- new Date(yesterdayActiveDate.setHours(0, 0, 0, 0))
+ new Date(yesterdayActiveDate.setHours(0, 0, 0, 0))
) {
return true;
}
@@ -112,7 +111,7 @@ export class NotificationService {
disasterType: DisasterType,
countryCodeISO3: string,
): Promise {
- let send = event.activeTrigger;
+ let send = true;
if (disasterType === DisasterType.Typhoon) {
send = await this.typhoonTrackService.shouldSendNotification(
countryCodeISO3,
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 31ee97bed..2fac18d72 100644
--- a/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts
+++ b/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts
@@ -246,9 +246,9 @@ export class WhatsappService {
country.countryCodeISO3,
disasterType.disasterType,
);
- const activeEvents = events
- .filter((event) => event.activeTrigger)
- .sort((a, b) => (a.firstLeadTime > b.firstLeadTime ? 1 : -1));
+ const activeEvents = events.sort((a, b) =>
+ a.firstLeadTime > b.firstLeadTime ? 1 : -1,
+ );
if (activeEvents.length === 0) {
const noTriggerMessage = this.configureNoTriggerMessage(
country,
diff --git a/services/API-service/src/config.ts b/services/API-service/src/config.ts
index 97f9e8d7b..fac93bbce 100644
--- a/services/API-service/src/config.ts
+++ b/services/API-service/src/config.ts
@@ -14,6 +14,8 @@ const rootUrl =
process.env.NODE_ENV === 'development'
? `http://localhost:${process.env.LOCAL_PORT_IBF_SERVICE}/`
: process.env.EXTERNAL_API_SERVICE_URL;
+export const INTERNAL_GEOSERVER_API_URL =
+ 'http://ibf-geoserver:8080/geoserver/rest';
export const EXTERNAL_API = {
root: rootUrl,
whatsAppStatus: baseApiUrl + API_PATHS.whatsAppStatus,
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
new file mode 100644
index 000000000..db066465c
--- /dev/null
+++ b/services/API-service/src/scripts/disaster-type-geoserver-file.mapper.ts
@@ -0,0 +1,73 @@
+import { DisasterType } from '../api/disaster/disaster-type.enum';
+
+export class DisasterTypeGeoServerMapper {
+ static getLayerStorePrefixForDisasterType(
+ disasterType: DisasterType,
+ ): string {
+ if (disasterType === DisasterType.Floods) {
+ return 'flood_extent';
+ } else if (disasterType === DisasterType.HeavyRain) {
+ return 'rainfall_extent';
+ } else if (disasterType === DisasterType.Drought) {
+ return 'rainfall_forecast';
+ } else if (disasterType === DisasterType.FlashFloods) {
+ return 'flood_extent';
+ }
+ return '';
+ }
+
+ static getDestFilePrefixForDisasterType(
+ disasterType: DisasterType,
+ countryCode: string,
+ ): string {
+ if (disasterType === DisasterType.Floods) {
+ return 'flood_extent';
+ } else if (disasterType === DisasterType.HeavyRain) {
+ if (countryCode === 'EGY') {
+ return 'rain_rp';
+ } else if (countryCode === 'UGA') {
+ return 'rainfall_extent';
+ }
+ } else if (disasterType === DisasterType.Drought) {
+ return 'rain_rp';
+ } else if (disasterType === DisasterType.FlashFloods) {
+ return 'flood_extent';
+ }
+ return '';
+ }
+
+ static getSubfolderForDisasterType(disasterType: DisasterType): string {
+ let subfolder = '';
+ if (
+ [DisasterType.Floods, DisasterType.FlashFloods].includes(disasterType)
+ ) {
+ subfolder = 'flood_extents';
+ } else if (
+ [DisasterType.HeavyRain, DisasterType.Drought].includes(disasterType)
+ ) {
+ subfolder = 'rainfall_extents';
+ }
+ return subfolder;
+ }
+
+ // DOES not work for heavy rain as it will be phased out
+ static getStyleForCountryAndDisasterType(
+ countryCode: string,
+ disasterType: DisasterType,
+ ): string {
+ if (disasterType === DisasterType.Drought) {
+ return 'rainfall_extent_drought';
+ } else if (disasterType === DisasterType.FlashFloods) {
+ return 'flood_extent_MWI_flash-floods';
+ } else if (disasterType === DisasterType.Floods) {
+ if (countryCode === 'PHL') {
+ return 'flood_extent_PHL';
+ } else {
+ return 'flood_extent';
+ }
+ }
+ throw new Error(
+ `No style found for disaster type' ${disasterType} and country code ${countryCode}`,
+ );
+ }
+}
diff --git a/services/API-service/src/scripts/geoserver-sync.service.ts b/services/API-service/src/scripts/geoserver-sync.service.ts
new file mode 100644
index 000000000..936ab5753
--- /dev/null
+++ b/services/API-service/src/scripts/geoserver-sync.service.ts
@@ -0,0 +1,218 @@
+import { HttpService } from '@nestjs/axios';
+import { Injectable } from '@nestjs/common';
+import { firstValueFrom } from 'rxjs';
+import { INTERNAL_GEOSERVER_API_URL } from '../config';
+import countries from './json/countries.json';
+import { DisasterType } from '../api/disaster/disaster-type.enum';
+import { DisasterTypeGeoServerMapper } from './disaster-type-geoserver-file.mapper';
+
+const workspaceName = 'ibf-system';
+
+class RecourceNameObject {
+ resourceName: string;
+ disasterType: DisasterType;
+ countryCodeISO3: string;
+}
+
+@Injectable()
+export class GeoserverSyncService {
+ constructor(private httpService: HttpService) {}
+
+ public async sync(
+ countryCodeISO3?: string,
+ disasterType?: DisasterType,
+ ): Promise {
+ const countriesCopy = JSON.parse(JSON.stringify(countries));
+ const filteredCountries = countriesCopy.filter((country: any) => {
+ return countryCodeISO3
+ ? country.countryCodeISO3 === countryCodeISO3
+ : true;
+ });
+ // also filter by disaster type
+ for (const country of filteredCountries) {
+ const disasterSettings = country.countryDisasterSettings.filter(
+ (disasterSetting: any) => {
+ return disasterType
+ ? disasterSetting.disasterType === disasterType
+ : true;
+ },
+ );
+ country.countryDisasterSettings = disasterSettings;
+ }
+ const geoserverResourceNameObjects =
+ this.generateGeoserverResourceNames(filteredCountries);
+ console.log(
+ '🚀 ~ GeoseverSyncService ~ geoserverResourceNameObjects:',
+ geoserverResourceNameObjects,
+ );
+ await this.syncStores(geoserverResourceNameObjects);
+ await this.syncLayers(geoserverResourceNameObjects);
+ }
+
+ private async syncStores(expectedStoreNameObjects: RecourceNameObject[]) {
+ const foundStoreNames = await this.getStoreNamesFromGeoserver(
+ workspaceName,
+ );
+ console.log(
+ '🚀 ~ GeoseverSyncService ~ syncStores ~ foundStoreNames:',
+ foundStoreNames,
+ );
+ const missingStoreNames = expectedStoreNameObjects.filter(
+ (o) => !foundStoreNames.includes(o.resourceName),
+ );
+ console.log(
+ '🚀 ~ GeoseverSyncService ~ syncStores ~ missingStoreNames:',
+ missingStoreNames,
+ );
+ await this.postStoreNamesToGeoserver(missingStoreNames);
+ }
+
+ private generateGeoserverResourceNames(
+ filteredCountries: any[],
+ ): RecourceNameObject[] {
+ const resourceNameObjects = [];
+ for (const country of filteredCountries) {
+ resourceNameObjects.push(...this.generateStoreNameForCountry(country));
+ }
+ return resourceNameObjects;
+ }
+
+ private generateStoreNameForCountry(country: any): RecourceNameObject[] {
+ const resourceNameObjects = [];
+ const countryCode = country.countryCodeISO3;
+ for (const disasterSetting of country.countryDisasterSettings) {
+ if (disasterSetting.disasterType == DisasterType.Floods) {
+ for (const leadTime of disasterSetting.activeLeadTimes) {
+ const disasterTypeStorePrefix =
+ DisasterTypeGeoServerMapper.getLayerStorePrefixForDisasterType(
+ disasterSetting.disasterType,
+ );
+ const resourceName = `${disasterTypeStorePrefix}_${leadTime}_${countryCode}`;
+ resourceNameObjects.push({
+ resourceName: resourceName,
+ disasterType: disasterSetting.disasterType,
+ countryCodeISO3: countryCode,
+ });
+ }
+ }
+ }
+ return resourceNameObjects;
+ }
+
+ private async getStoreNamesFromGeoserver(workspaceName: string) {
+ const data = await this.get(`workspaces/${workspaceName}/coveragestores`);
+ const storeNames = data.coverageStores.coverageStore.map(
+ (store: any) => store.name,
+ );
+ return storeNames;
+ }
+
+ private async postStoreNamesToGeoserver(
+ resourceNameObjects: RecourceNameObject[],
+ ) {
+ for (const resourceNameObject of resourceNameObjects) {
+ const subfolder = DisasterTypeGeoServerMapper.getSubfolderForDisasterType(
+ resourceNameObject.disasterType,
+ );
+ const url = `workspaces/${workspaceName}/coveragestores`; // replace with the correct API endpoint
+ const body = {
+ coverageStore: {
+ name: resourceNameObject.resourceName,
+ workspace: workspaceName,
+ enabled: true,
+ type: 'GeoTIFF',
+ url: `file:workspaces/ibf-system/ibf-pipeline/output/${subfolder}/${resourceNameObject.resourceName}.tif`,
+ },
+ };
+ const result = await this.post(url, body);
+ console.log(
+ 'Updated geoserver with ',
+ result,
+ 'please commit the resulting config changes of geoserver to git.',
+ );
+ }
+ }
+
+ public async syncLayers(expectedLayerNames: RecourceNameObject[]) {
+ const foundLayerNames = await this.getLayerNamesFromGeoserver(
+ workspaceName,
+ );
+ const missingLayerNames = expectedLayerNames.filter(
+ (o) => !foundLayerNames.includes(o.resourceName),
+ );
+ await this.postLayerNamesToGeoserver(missingLayerNames);
+ }
+
+ private async getLayerNamesFromGeoserver(workspaceName: string) {
+ const data = await this.get(`workspaces/${workspaceName}/layers`);
+ const layerNames = data.layers.layer.map((layer: any) => layer.name);
+ return layerNames;
+ }
+
+ private async postLayerNamesToGeoserver(
+ resourceNameObjects: RecourceNameObject[],
+ ) {
+ for (const resourceNameObject of resourceNameObjects) {
+ const publishLayerUrl = `workspaces/${workspaceName}/coveragestores/${resourceNameObject.resourceName}/coverages`;
+ const publishLayerBody = {
+ coverage: {
+ name: resourceNameObject.resourceName,
+ title: resourceNameObject.resourceName,
+ nativeName: resourceNameObject.resourceName,
+ },
+ };
+ await this.post(publishLayerUrl, publishLayerBody);
+ // Set the default style for the layer
+ const styleName =
+ DisasterTypeGeoServerMapper.getStyleForCountryAndDisasterType(
+ resourceNameObject.countryCodeISO3,
+ resourceNameObject.disasterType,
+ );
+ const styleUrl = `layers/${resourceNameObject.resourceName}`;
+ const body = {
+ layer: {
+ defaultStyle: {
+ name: `${workspaceName}:${styleName}`,
+ },
+ },
+ };
+ await this.put(styleUrl, body);
+ }
+ }
+
+ private async post(path: string, body: any) {
+ const url = `${INTERNAL_GEOSERVER_API_URL}/${path}`;
+ const headers = this.getHeaders();
+ const result = await firstValueFrom(
+ this.httpService.post(url, body, { headers }),
+ );
+ return result.data;
+ }
+
+ private async put(path: string, body: any) {
+ const url = `${INTERNAL_GEOSERVER_API_URL}/${path}`;
+ const headers = this.getHeaders();
+ const result = await firstValueFrom(
+ this.httpService.put(url, body, { headers }),
+ );
+ return result.data;
+ }
+
+ private async get(path: string) {
+ const url = `${INTERNAL_GEOSERVER_API_URL}/${path}`;
+ const headers = this.getHeaders();
+ const result = await firstValueFrom(this.httpService.get(url, { headers }));
+ return result.data;
+ }
+
+ private getHeaders() {
+ const username = 'admin';
+ return {
+ Authorization:
+ 'Basic ' +
+ Buffer.from(
+ username + ':' + process.env.GEOSERVER_ADMIN_PASSWORD,
+ ).toString('base64'),
+ };
+ }
+}
diff --git a/services/API-service/src/scripts/json/countries.json b/services/API-service/src/scripts/json/countries.json
index 5bd82fc42..3c29c6833 100644
--- a/services/API-service/src/scripts/json/countries.json
+++ b/services/API-service/src/scripts/json/countries.json
@@ -41,7 +41,8 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
},
{
"disasterType": "drought",
@@ -295,7 +296,8 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
},
{
"disasterType": "drought",
@@ -392,7 +394,8 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
},
{
"disasterType": "flash-floods",
@@ -478,7 +481,8 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
}
],
"adminRegionLabels": {
@@ -534,7 +538,8 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
},
{
"disasterType": "drought",
@@ -641,14 +646,16 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
},
{
"disasterType": "malaria",
"adminLevels": [3],
"defaultAdminLevel": 3,
"activeLeadTimes": ["0-month", "1-month", "2-month"],
- "eapLink": "https://docs.google.com/document/d/1v7FNVaYIS1_5zTn-KDWe3gZmjvRxljsXR9EutAF0wuk/edit?usp=sharing"
+ "eapLink": "https://docs.google.com/document/d/1v7FNVaYIS1_5zTn-KDWe3gZmjvRxljsXR9EutAF0wuk/edit?usp=sharing",
+ "isEventBased": true
},
{
"disasterType": "drought",
@@ -898,7 +905,8 @@
"adminLevels": [2],
"defaultAdminLevel": 2,
"activeLeadTimes": ["0-month", "1-month", "2-month"],
- "eapLink": "https://rodekruis.sharepoint.com/sites/510-CRAVK-510/_layouts/15/guestaccess.aspx?docid=0f9249b35da4d4c0a985b33393fc388df&authkey=AQSLnnafGF-M2t1CGIg0hdA&expiration=2022-06-29T22%3A00%3A00.000Z&e=2asHJm"
+ "eapLink": "https://rodekruis.sharepoint.com/sites/510-CRAVK-510/_layouts/15/guestaccess.aspx?docid=0f9249b35da4d4c0a985b33393fc388df&authkey=AQSLnnafGF-M2t1CGIg0hdA&expiration=2022-06-29T22%3A00%3A00.000Z&e=2asHJm",
+ "isEventBased": true
},
{
"disasterType": "typhoon",
@@ -1095,7 +1103,8 @@
"color": "ibf-glofas-trigger",
"value": 1
}
- }
+ },
+ "isEventBased": true
}
],
"adminRegionLabels": {
diff --git a/services/API-service/src/scripts/mock.service.ts b/services/API-service/src/scripts/mock.service.ts
index 3275c0e07..8d5db37a5 100644
--- a/services/API-service/src/scripts/mock.service.ts
+++ b/services/API-service/src/scripts/mock.service.ts
@@ -26,6 +26,9 @@ import { InjectRepository } from '@nestjs/typeorm';
import { AdminAreaDynamicDataEntity } from '../api/admin-area-dynamic-data/admin-area-dynamic-data.entity';
import { EapActionStatusEntity } from '../api/eap-actions/eap-action-status.entity';
import { TriggerPerLeadTime } from '../api/event/trigger-per-lead-time.entity';
+import { DEBUG } from '../config';
+import { DisasterTypeGeoServerMapper } from './disaster-type-geoserver-file.mapper';
+import { GeoserverSyncService } from './geoserver-sync.service';
import { AdminAreaService } from '../api/admin-area/admin-area.service';
class Scenario {
@@ -52,6 +55,7 @@ export class MockService {
private linesDataService: LinesDataService,
private pointDataService: PointDataService,
private glofasStationService: GlofasStationService,
+ private geoServerSyncService: GeoserverSyncService,
private adminAreaService: AdminAreaService,
) {}
@@ -406,36 +410,17 @@ export class MockService {
console.log(
`Seeding disaster extent raster file for country: ${selectedCountry.countryCodeISO3} for leadtime: ${leadTime}`,
);
-
- let sourceFileName, destFileName;
- if (disasterType === DisasterType.Floods) {
- sourceFileName = `flood_extent_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- destFileName = sourceFileName;
- } else if (disasterType === DisasterType.HeavyRain) {
- // Use 3-day mock for every lead-time
- sourceFileName = `rainfall_extent_3-day_${
- selectedCountry.countryCodeISO3
- }${triggered ? '-triggered' : ''}.tif`;
- if (selectedCountry.countryCodeISO3 === 'EGY') {
- destFileName = `rain_rp_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- } else if (selectedCountry.countryCodeISO3 === 'UGA') {
- destFileName = `rainfall_extent_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- }
- } else if (disasterType === DisasterType.Drought) {
- // Use 0-month mock for every lead-time
- sourceFileName = `rainfall_forecast_0-month_${
- selectedCountry.countryCodeISO3
- }${triggered ? '-triggered' : ''}.tif`;
- destFileName = `rain_rp_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- } else if (disasterType === DisasterType.FlashFloods) {
- if (leadTime === LeadTime.hour24 || leadTime === LeadTime.hour6) {
- sourceFileName = `flood_extent_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- } else {
- continue;
- }
- destFileName = sourceFileName;
- }
-
+ const sourceFileName = this.getMockRasterSourceFileName(
+ disasterType,
+ selectedCountry.countryCodeISO3,
+ leadTime,
+ triggered,
+ );
+ const destFileName = this.getMockRasterDestFileName(
+ disasterType,
+ leadTime,
+ selectedCountry.countryCodeISO3,
+ );
let file;
try {
file = fs.readFileSync(
@@ -455,6 +440,88 @@ export class MockService {
disasterType,
);
}
+ // Add the needed stores and layers to geoserver, only do this in debug mode
+ // The resulting XML files should be commited to git and will end up on the servers that way
+ if (DEBUG) {
+ await this.geoServerSyncService.sync(
+ selectedCountry.countryCodeISO3,
+ disasterType,
+ );
+ }
+ }
+
+ private getMockRasterSourceFileName(
+ disasterType: DisasterType,
+ countryCodeISO3: string,
+ leadTime: string,
+ triggered?: boolean,
+ ) {
+ const directoryPath = './geoserver-volume/raster-files/mock-output/';
+ const leadTimeUnit = leadTime.replace(/\d+-/, '');
+
+ const files = fs.readdirSync(directoryPath);
+
+ const layerStorePrefix =
+ DisasterTypeGeoServerMapper.getLayerStorePrefixForDisasterType(
+ disasterType,
+ );
+
+ // Only for HeavyRain and Drought we have triggered and non-triggered files
+ const suffix =
+ triggered &&
+ [DisasterType.HeavyRain, DisasterType.Drought].includes(disasterType)
+ ? '-triggered.tif'
+ : '.tif';
+ const filename = `${layerStorePrefix}_${leadTimeUnit}_${countryCodeISO3}${suffix}`;
+ const fileExists = files.includes(filename);
+ if (fileExists) {
+ return filename;
+ } else {
+ // new code
+ const leadTimeNumber = parseInt(leadTime.split('-')[0]);
+ const closestFiles = files.filter(
+ (file) =>
+ file.startsWith(layerStorePrefix) &&
+ file.endsWith(`${leadTimeUnit}_${countryCodeISO3}${suffix}`),
+ );
+ // if no files are found, return null
+ if (closestFiles.length === 0) {
+ console.log(
+ 'No closest files found for the given lead time',
+ layerStorePrefix,
+ leadTimeUnit,
+ countryCodeISO3,
+ suffix,
+ );
+ return null;
+ }
+ const numbersFromClosestFiles = closestFiles.map((file) =>
+ parseInt(file.split('_')[2]),
+ );
+ // from the numbers, find the closest number to the leadTimeNumber
+ let closestNumber = numbersFromClosestFiles[0];
+ for (let i = 1; i < numbersFromClosestFiles.length; i++) {
+ if (
+ Math.abs(numbersFromClosestFiles[i] - leadTimeNumber) <
+ Math.abs(closestNumber - leadTimeNumber)
+ ) {
+ closestNumber = numbersFromClosestFiles[i];
+ }
+ }
+ return null;
+ }
+ }
+
+ private getMockRasterDestFileName(
+ disasterType: DisasterType,
+ leadTime: string,
+ countryCode: string,
+ ): string {
+ const prefix = DisasterTypeGeoServerMapper.getDestFilePrefixForDisasterType(
+ disasterType,
+ countryCode,
+ );
+ return `${prefix}_${leadTime}_${countryCode}.tif`;
}
private async mockMapImageFile(
diff --git a/services/API-service/src/scripts/scripts.controller.ts b/services/API-service/src/scripts/scripts.controller.ts
index dbd7c7847..831827036 100644
--- a/services/API-service/src/scripts/scripts.controller.ts
+++ b/services/API-service/src/scripts/scripts.controller.ts
@@ -5,6 +5,8 @@ import {
Res,
HttpStatus,
UseGuards,
+ Patch,
+ HttpException,
} from '@nestjs/common';
import {
ApiBearerAuth,
@@ -26,7 +28,7 @@ import { RolesGuard } from '../roles.guard';
import { DisasterType } from '../api/disaster/disaster-type.enum';
import { Roles } from '../roles.decorator';
import { UserRole } from '../api/user/user-role.enum';
-import { MockService } from './mock.service';
+import { GeoserverSyncService } from './geoserver-sync.service';
class ResetDto {
@ApiProperty({ example: 'fill_in_secret' })
@@ -123,6 +125,7 @@ export class ScriptsController {
public constructor(
private scriptsService: ScriptsService,
private seedInit: SeedInit,
+ private geoseverSyncService: GeoserverSyncService,
) {}
@Roles(UserRole.Admin)
diff --git a/services/API-service/src/scripts/scripts.module.ts b/services/API-service/src/scripts/scripts.module.ts
index e198b4d26..be0ae113d 100644
--- a/services/API-service/src/scripts/scripts.module.ts
+++ b/services/API-service/src/scripts/scripts.module.ts
@@ -31,6 +31,8 @@ import SeedLineData from './seed-line-data';
import { ORMConfig } from '../../ormconfig';
import { MockService } from './mock.service';
import { MockController } from './mock.controller';
+import { GeoserverSyncService } from './geoserver-sync.service';
+import { HttpModule } from '@nestjs/axios';
@Module({
imports: [
@@ -55,6 +57,7 @@ import { MockController } from './mock.controller';
PointDataModule,
LinesDataModule,
AdminAreaDataModule,
+ HttpModule,
],
providers: [
SeedInit,
@@ -66,6 +69,7 @@ import { MockController } from './mock.controller';
SeedLineData,
SeedRainfallData,
MockService,
+ GeoserverSyncService,
],
controllers: [ScriptsController, MockController],
})
diff --git a/services/API-service/src/scripts/scripts.service.ts b/services/API-service/src/scripts/scripts.service.ts
index 09db3f740..aeb54354c 100644
--- a/services/API-service/src/scripts/scripts.service.ts
+++ b/services/API-service/src/scripts/scripts.service.ts
@@ -30,6 +30,9 @@ import { LinesDataEnum } from '../api/lines-data/lines-data.entity';
import { PointDataEnum } from '../api/point-data/point-data.entity';
import { UploadDynamicPointDataDto } from '../api/point-data/dto/upload-asset-exposure-status.dto';
import { PointDataService } from '../api/point-data/point-data.service';
+import { DisasterTypeGeoServerMapper } from './disaster-type-geoserver-file.mapper';
+import { GeoserverSyncService } from './geoserver-sync.service';
+import { DEBUG } from '../config';
@Injectable()
export class ScriptsService {
@@ -57,6 +60,7 @@ export class ScriptsService {
private metadataService: MetadataService,
private linesDataService: LinesDataService,
private pointDataService: PointDataService,
+ private geoServerSyncService: GeoserverSyncService,
) {}
public async mockAll(mockAllInput: MockAll) {
@@ -1072,36 +1076,17 @@ export class ScriptsService {
console.log(
`Seeding disaster extent raster file for country: ${selectedCountry.countryCodeISO3} for leadtime: ${leadTime}`,
);
-
- let sourceFileName, destFileName;
- if (disasterType === DisasterType.Floods) {
- sourceFileName = `flood_extent_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- destFileName = sourceFileName;
- } else if (disasterType === DisasterType.HeavyRain) {
- // Use 3-day mock for every lead-time
- sourceFileName = `rainfall_extent_3-day_${
- selectedCountry.countryCodeISO3
- }${triggered ? '-triggered' : ''}.tif`;
- if (selectedCountry.countryCodeISO3 === 'EGY') {
- destFileName = `rain_rp_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- } else if (selectedCountry.countryCodeISO3 === 'UGA') {
- destFileName = `rainfall_extent_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- }
- } else if (disasterType === DisasterType.Drought) {
- // Use 0-month mock for every lead-time
- sourceFileName = `rainfall_forecast_0-month_${
- selectedCountry.countryCodeISO3
- }${triggered ? '-triggered' : ''}.tif`;
- destFileName = `rain_rp_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- } else if (disasterType === DisasterType.FlashFloods) {
- if (leadTime === LeadTime.hour24 || leadTime === LeadTime.hour6) {
- sourceFileName = `flood_extent_${leadTime}_${selectedCountry.countryCodeISO3}.tif`;
- } else {
- continue;
- }
- destFileName = sourceFileName;
- }
-
+ const sourceFileName = this.getMockRasterSourceFileName(
+ disasterType,
+ selectedCountry.countryCodeISO3,
+ leadTime,
+ triggered,
+ );
+ const destFileName = this.getMockRasterDestFileName(
+ disasterType,
+ leadTime,
+ selectedCountry.countryCodeISO3,
+ );
let file;
try {
file = fs.readFileSync(
@@ -1121,6 +1106,89 @@ export class ScriptsService {
disasterType,
);
}
+
+ // Add the needed stores and layers to geoserver, only do this in debug mode
+ // The resulting XML files should be commited to git and will end up on the servers that way
+ if (DEBUG) {
+ await this.geoServerSyncService.sync(
+ selectedCountry.countryCodeISO3,
+ disasterType,
+ );
+ }
+ }
+
+ private getMockRasterSourceFileName(
+ disasterType: DisasterType,
+ countryCodeISO3: string,
+ leadTime: string,
+ triggered?: boolean,
+ ) {
+ const directoryPath = './geoserver-volume/raster-files/mock-output/';
+ const leadTimeUnit = leadTime.replace(/\d+-/, '');
+
+ const files = fs.readdirSync(directoryPath);
+
+ const layerStorePrefix =
+ DisasterTypeGeoServerMapper.getLayerStorePrefixForDisasterType(
+ disasterType,
+ );
+
+ // Only for HeavyRain and Drought we have triggered and non-triggered files
+ const suffix =
+ triggered &&
+ [DisasterType.HeavyRain, DisasterType.Drought].includes(disasterType)
+ ? '-triggered.tif'
+ : '.tif';
+ const filename = `${layerStorePrefix}_${leadTimeUnit}_${countryCodeISO3}${suffix}`;
+ const fileExists = files.includes(filename);
+ if (fileExists) {
+ return filename;
+ } else {
+ // new code
+ const leadTimeNumber = parseInt(leadTime.split('-')[0]);
+ const closestFiles = files.filter(
+ (file) =>
+ file.startsWith(layerStorePrefix) &&
+ file.endsWith(`${leadTimeUnit}_${countryCodeISO3}${suffix}`),
+ );
+ // if no files are found, return null
+ if (closestFiles.length === 0) {
+ console.log(
+ 'No closest files found for the given lead time',
+ layerStorePrefix,
+ leadTimeUnit,
+ countryCodeISO3,
+ suffix,
+ );
+ return null;
+ }
+ const numbersFromClosestFiles = closestFiles.map((file) =>
+ parseInt(file.split('_')[2]),
+ );
+ // from the numbers, find the closest number to the leadTimeNumber
+ let closestNumber = numbersFromClosestFiles[0];
+ for (let i = 1; i < numbersFromClosestFiles.length; i++) {
+ if (
+ Math.abs(numbersFromClosestFiles[i] - leadTimeNumber) <
+ Math.abs(closestNumber - leadTimeNumber)
+ ) {
+ closestNumber = numbersFromClosestFiles[i];
+ }
+ }
+ return null;
+ }
+ }
+
+ private getMockRasterDestFileName(
+ disasterType: DisasterType,
+ leadTime: string,
+ countryCode: string,
+ ): string {
+ const prefix = DisasterTypeGeoServerMapper.getDestFilePrefixForDisasterType(
+ disasterType,
+ countryCode,
+ );
+ return `${prefix}_${leadTime}_${countryCode}.tif`;
}
private async mockMapImageFile(