From 17b3fa67e8cab918ba3215b86a5269125e3fba05 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:47:49 +1300 Subject: [PATCH 1/9] Remove references to disaster in codebase --- .../pages/resources/DisasterResponsePage.jsx | 73 ---------- .../admin-panel/src/pages/resources/index.js | 1 - packages/admin-panel/src/routes.jsx | 6 - .../central-server/src/apiV2/GETDisasters.js | 83 ----------- .../src/apiV2/import/importDisaster.js | 129 ------------------ .../central-server/src/apiV2/import/index.js | 2 - packages/central-server/src/apiV2/index.js | 5 - .../database/src/modelClasses/Disaster.js | 31 ----- .../src/modelClasses/DisasterEvent.js | 18 --- packages/database/src/modelClasses/Entity.js | 2 - packages/database/src/modelClasses/index.js | 4 - packages/database/src/records.js | 2 - .../src/testUtilities/upsertDummyRecord.js | 5 +- .../models-extra/dashboard-item/components.ts | 1 - 14 files changed, 1 insertion(+), 361 deletions(-) delete mode 100644 packages/admin-panel/src/pages/resources/DisasterResponsePage.jsx delete mode 100644 packages/central-server/src/apiV2/GETDisasters.js delete mode 100644 packages/central-server/src/apiV2/import/importDisaster.js delete mode 100644 packages/database/src/modelClasses/Disaster.js delete mode 100644 packages/database/src/modelClasses/DisasterEvent.js diff --git a/packages/admin-panel/src/pages/resources/DisasterResponsePage.jsx b/packages/admin-panel/src/pages/resources/DisasterResponsePage.jsx deleted file mode 100644 index 0543f363e9..0000000000 --- a/packages/admin-panel/src/pages/resources/DisasterResponsePage.jsx +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Tupaia MediTrak - * Copyright (c) 2017 Beyond Essential Systems Pty Ltd - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { ResourcePage } from './ResourcePage'; - -const id = { - Header: 'id', - source: 'id', - editable: false, -}; - -const type = { - Header: 'Type', - source: 'type', - editable: false, -}; - -const description = { - Header: 'Description', - source: 'description', - type: 'tooltip', -}; - -const name = { - Header: 'Name', - source: 'name', -}; - -const countryCode = { - Header: 'Country', - source: 'country.name', -}; - -const point = { - Header: 'Point', - source: 'entity.point', - filterable: false, - type: 'tooltip', -}; - -const bounds = { - Header: 'Bounds', - source: 'entity.bounds', - filterable: false, - type: 'tooltip', -}; - -const DISASTER_FIELDS = [id, type, description, name, countryCode, point, bounds]; - -const IMPORT_CONFIG = { - title: 'Import Disasters', - actionConfig: { - importEndpoint: 'disasters', - }, -}; - -export const DisasterResponsePage = ({ getHeaderEl }) => ( - -); - -DisasterResponsePage.propTypes = { - getHeaderEl: PropTypes.func.isRequired, -}; diff --git a/packages/admin-panel/src/pages/resources/index.js b/packages/admin-panel/src/pages/resources/index.js index dee4a5ca59..96b49e0976 100644 --- a/packages/admin-panel/src/pages/resources/index.js +++ b/packages/admin-panel/src/pages/resources/index.js @@ -20,7 +20,6 @@ export { QuestionsPage } from './QuestionsPage'; export { OptionSetsPage } from './OptionSetsPage'; export { UsersPage } from './UsersPage'; export { SocialFeedPage } from './SocialFeedPage'; -export { DisasterResponsePage } from './DisasterResponsePage'; export { DataGroupsPage, DataElementsPage } from './DataSourcesPage'; export { DataTablesPage } from './DataTablesPage'; export { AccessRequestsPage } from './AccessRequestsPage'; diff --git a/packages/admin-panel/src/routes.jsx b/packages/admin-panel/src/routes.jsx index 2987e226f5..2e06d2d87f 100644 --- a/packages/admin-panel/src/routes.jsx +++ b/packages/admin-panel/src/routes.jsx @@ -21,7 +21,6 @@ import { SurveysPage, QuestionsPage, UsersPage, - DisasterResponsePage, AccessRequestsPage, MapOverlaysPage, MapOverlayGroupsPage, @@ -228,11 +227,6 @@ export const ROUTES = [ to: '/strive', component: StrivePage, }, - { - label: 'Disaster', - to: '/disaster', - component: DisasterResponsePage, - }, { label: 'Entity Hierarchy', to: '/hierarchy', diff --git a/packages/central-server/src/apiV2/GETDisasters.js b/packages/central-server/src/apiV2/GETDisasters.js deleted file mode 100644 index 661eb2b5a5..0000000000 --- a/packages/central-server/src/apiV2/GETDisasters.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Tupaia - * Copyright (c) 2017 - 2020 Beyond Essential Systems Pty Ltd - */ - -import { GETHandler } from './GETHandler'; -import { - assertAnyPermissions, - assertBESAdminAccess, - assertAdminPanelAccess, - hasBESAdminAccess, - TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, -} from '../permissions'; - -const createDBFilter = (accessPolicy, criteria) => { - if (hasBESAdminAccess(accessPolicy)) { - return criteria; // no additional criteria, BES Admin users have full access - } - const permittedCountryCodes = accessPolicy.getEntitiesAllowed( - TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, - ); - const { countryCode: incomingCountryCode } = criteria; - if (!incomingCountryCode) { - return { ...criteria, countryCode: permittedCountryCodes }; - } - - const countryCodesRequested = Array.isArray(incomingCountryCode) - ? incomingCountryCode - : [incomingCountryCode]; - const countryCodesFilter = countryCodesRequested.filter(c => permittedCountryCodes.includes(c)); - return { ...criteria, countryCode: countryCodesFilter }; -}; - -/** - * Handles endpoints: - * - /disasters - * - /disasters/:disasterId - */ -export class GETDisasters extends GETHandler { - permissionsFilteredInternally = true; - - customJoinConditions = { - country: { - nearTableKey: 'disaster.countryCode', - farTableKey: 'country.code', - }, - entity: { - nearTableKey: 'disaster.countryCode', - farTableKey: 'entity.code', - }, - }; - - async assertUserHasAccess() { - return this.assertPermissions( - assertAnyPermissions([assertBESAdminAccess, assertAdminPanelAccess]), - 'You need either BES Admin or Tupaia Admin Panel access to view disasters', - ); - } - - async findSingleRecord(disasterId, options) { - const disaster = await super.findSingleRecord(disasterId, options); - - const adminPanelAccessChecker = accessPolicy => { - const { countryCode } = disaster; - if (!accessPolicy.allows(countryCode, TUPAIA_ADMIN_PANEL_PERMISSION_GROUP)) { - throw new Error( - `Access to disaster with id ${disasterId} requires admin panel access for ${countryCode}`, - ); - } - }; - - await this.assertPermissions( - assertAnyPermissions([assertBESAdminAccess, adminPanelAccessChecker]), - ); - - return disaster; - } - - async getPermissionsFilter(criteria, options) { - const dbConditions = createDBFilter(this.accessPolicy, criteria); - return { dbConditions, dbOptions: options }; - } -} diff --git a/packages/central-server/src/apiV2/import/importDisaster.js b/packages/central-server/src/apiV2/import/importDisaster.js deleted file mode 100644 index 2e76f43f7c..0000000000 --- a/packages/central-server/src/apiV2/import/importDisaster.js +++ /dev/null @@ -1,129 +0,0 @@ -import xlsx from 'xlsx'; - -import { DatabaseError, respond, ObjectValidator, fieldHasContent } from '@tupaia/utils'; -import { assertBESAdminAccess } from '../../permissions'; - -const TAB_NAMES = { - DISASTER: 'Disaster', - DISASTER_EVENT: 'DisasterEvent', - ENTITY: 'Entity', -}; - -const disasterFieldValidators = { - id: [fieldHasContent], - type: [fieldHasContent], - description: [fieldHasContent], - name: [fieldHasContent], - countryCode: [fieldHasContent], -}; - -const entityFieldValidators = { - id: [], - point: [fieldHasContent], - code: [fieldHasContent], - parent_id: [fieldHasContent], - name: [fieldHasContent], - country_code: [fieldHasContent], -}; - -const disasterEventFieldValidators = { - id: [fieldHasContent], - date: [fieldHasContent], - type: [fieldHasContent], - organisationUnitCode: [fieldHasContent], - disasterId: [fieldHasContent], -}; - -export async function importDisaster(req, res) { - const { models } = req; - - await req.assertPermissions(assertBESAdminAccess); - - try { - const workbook = xlsx.readFile(req.file.path); - - const getDataAndValidate = async (sheet, validater) => { - const sheetData = xlsx.utils.sheet_to_json(sheet); - const createDisasterValidater = new ObjectValidator(validater); - - await createDisasterValidater.validate(sheetData[0]); - return sheetData; - }; - - await models.wrapInTransaction(async transactingModels => { - for (const disasterSheet of Object.entries(workbook.Sheets)) { - const [tabName, sheet] = disasterSheet; - - switch (tabName) { - case TAB_NAMES.DISASTER: { - const sheetData = await getDataAndValidate(sheet, disasterFieldValidators); - - sheetData.forEach(async entry => { - await transactingModels.disaster.updateOrCreate( - { - id: entry.id, - }, - entry, - ); - }); - - break; - } - case TAB_NAMES.DISASTER_EVENT: { - const sheetData = await getDataAndValidate(sheet, disasterEventFieldValidators); - - for (const entry of sheetData) { - await transactingModels.disasterEvent.updateOrCreate( - { - id: entry.id, - }, - entry, - ); - } - - break; - } - case TAB_NAMES.ENTITY: { - const sheetData = await getDataAndValidate(sheet, entityFieldValidators); - - const intialData = sheetData.map(item => { - return { - code: item.code, - parent_id: item.parent_id, - name: item.name, - country_code: item.country_code, - type: transactingModels.entity.types.DISASTER, - }; - }); - - for (const entry of intialData) { - await transactingModels.entity.updateOrCreate( - { - code: entry.code, - }, - entry, - ); - } - - for (const entry of sheetData) { - await transactingModels.entity.updatePointCoordinatesFormatted( - entry.code, - entry.point, - ); - } - break; - } - default: - // just ignore any tabs we're not interested in - } - } - }); - } catch (error) { - if (error.respond) { - throw error; // Already a custom error with a responder - } else { - throw new DatabaseError('importing disaster sets', error); - } - } - respond(res, { message: 'Imported disaster details' }); -} diff --git a/packages/central-server/src/apiV2/import/index.js b/packages/central-server/src/apiV2/import/index.js index 169a4751b2..02a09b931d 100644 --- a/packages/central-server/src/apiV2/import/index.js +++ b/packages/central-server/src/apiV2/import/index.js @@ -13,7 +13,6 @@ import { importEntities } from './importEntities'; import { importStriveLabResults } from './importStriveLabResults'; import { importUsers } from './importUsers'; import { importSurveyResponses, constructImportEmail } from './importSurveyResponses'; -import { importDisaster } from './importDisaster'; import { getTempDirectory } from '../../utilities'; import { importDataElements } from './importDataElements'; import { importDataElementDataServices } from './importDataElementDataServices'; @@ -48,7 +47,6 @@ importRoutes.post( upload.single('surveyResponses'), catchAsyncErrors(importSurveyResponses), ); -importRoutes.post('/disasters', upload.single('disasters'), catchAsyncErrors(importDisaster)); importRoutes.post('/users', upload.single('users'), catchAsyncErrors(importUsers)); importRoutes.post('/optionSets', upload.single('optionSets'), catchAsyncErrors(importOptionSets)); importRoutes.post( diff --git a/packages/central-server/src/apiV2/index.js b/packages/central-server/src/apiV2/index.js index f3c9dbe9f3..94d05f6c49 100644 --- a/packages/central-server/src/apiV2/index.js +++ b/packages/central-server/src/apiV2/index.js @@ -27,7 +27,6 @@ import { BESAdminEditHandler } from './EditHandler'; import { BESAdminGETHandler, TupaiaAdminGETHandler } from './GETHandler'; import { GETCountries } from './GETCountries'; import { GETClinics } from './GETClinics'; -import { GETDisasters } from './GETDisasters'; import { GETDataElements, EditDataElements, DeleteDataElements } from './dataElements'; import { GETDataGroups, EditDataGroups, DeleteDataGroups } from './dataGroups'; import { GETDataTables } from './dataTables'; @@ -181,7 +180,6 @@ apiV2.get('/me', useRouteHandler(GETUserForMe)); apiV2.get('/me/rewards', allowAnyone(getUserRewards)); apiV2.get('/me/countries', allowAnyone(getCountryAccessList)); apiV2.get('/answers/:recordId?', useRouteHandler(GETAnswers)); -apiV2.get('/disasters/:recordId?', useRouteHandler(GETDisasters)); apiV2.get('/dashboards/:recordId?', useRouteHandler(GETDashboards)); apiV2.get('/dashboards/:parentRecordId/dashboardRelations', useRouteHandler(GETDashboardRelations)); apiV2.get( @@ -301,7 +299,6 @@ apiV2.post('/dashboards', useRouteHandler(CreateDashboard)); apiV2.post('/dashboardMailingLists', useRouteHandler(CreateDashboardMailingList)); apiV2.post('/dashboardMailingListEntries', useRouteHandler(CreateDashboardMailingListEntry)); apiV2.post('/mapOverlayGroups', useRouteHandler(CreateMapOverlayGroups)); -apiV2.post('/disasters', useRouteHandler(BESAdminCreateHandler)); apiV2.post('/feedItems', useRouteHandler(CreateFeedItems)); apiV2.post('/indicators', useRouteHandler(BESAdminCreateHandler)); apiV2.post('/permissionGroups', useRouteHandler(BESAdminCreateHandler)); @@ -330,7 +327,6 @@ apiV2.put('/surveyScreenComponents/:recordId', useRouteHandler(EditSurveyScreenC apiV2.put('/dataElements/:recordId', useRouteHandler(EditDataElements)); apiV2.put('/dataGroups/:recordId', useRouteHandler(EditDataGroups)); apiV2.put('/dataTables/:recordId', useRouteHandler(BESAdminEditHandler)); -apiV2.put('/disasters/:recordId', useRouteHandler(BESAdminEditHandler)); apiV2.put('/feedItems/:recordId', useRouteHandler(EditFeedItems)); apiV2.put('/options/:recordId', useRouteHandler(EditOptions)); apiV2.put('/optionSets/:recordId', useRouteHandler(EditOptionSets)); @@ -369,7 +365,6 @@ apiV2.delete('/surveyScreenComponents/:recordId', useRouteHandler(DeleteSurveySc apiV2.delete('/dataElements/:recordId', useRouteHandler(DeleteDataElements)); apiV2.delete('/dataGroups/:recordId', useRouteHandler(DeleteDataGroups)); apiV2.delete('/dataTables/:recordId', useRouteHandler(BESAdminDeleteHandler)); -apiV2.delete('/disasters/:recordId', useRouteHandler(BESAdminDeleteHandler)); apiV2.delete('/entities/:recordId', useRouteHandler(DeleteEntity)); apiV2.delete('/feedItems/:recordId', useRouteHandler(BESAdminDeleteHandler)); apiV2.delete('/options/:recordId', useRouteHandler(DeleteOptions)); diff --git a/packages/database/src/modelClasses/Disaster.js b/packages/database/src/modelClasses/Disaster.js deleted file mode 100644 index 79c1a01403..0000000000 --- a/packages/database/src/modelClasses/Disaster.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Tupaia - * Copyright (c) 2017 - 2020 Beyond Essential Systems Pty Ltd - */ - -import { DatabaseModel } from '../DatabaseModel'; -import { DatabaseRecord } from '../DatabaseRecord'; -import { RECORDS } from '../records'; - -class DisasterRecord extends DatabaseRecord { - static databaseRecord = RECORDS.DISASTER; -} - -export class DisasterModel extends DatabaseModel { - get DatabaseRecordClass() { - return DisasterRecord; - } - - async getAllDisasterDetails() { - return this.database.executeSql(` - SELECT - *, - "disaster".type, - ST_AsGeoJSON("point") as point, - ST_AsGeoJSON("bounds") as bounds - FROM "disaster" - LEFT JOIN "entity" - ON "disaster"."id" = "entity"."code"; - `); - } -} diff --git a/packages/database/src/modelClasses/DisasterEvent.js b/packages/database/src/modelClasses/DisasterEvent.js deleted file mode 100644 index 5f594d130b..0000000000 --- a/packages/database/src/modelClasses/DisasterEvent.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Tupaia - * Copyright (c) 2017 - 2020 Beyond Essential Systems Pty Ltd - */ - -import { DatabaseModel } from '../DatabaseModel'; -import { DatabaseRecord } from '../DatabaseRecord'; -import { RECORDS } from '../records'; - -class DisasterEventRecord extends DatabaseRecord { - static databaseRecord = RECORDS.DISASTER_EVENT; -} - -export class DisasterEventModel extends DatabaseModel { - get DatabaseRecordClass() { - return DisasterEventRecord; - } -} diff --git a/packages/database/src/modelClasses/Entity.js b/packages/database/src/modelClasses/Entity.js index ed17174f46..5157bb9f31 100644 --- a/packages/database/src/modelClasses/Entity.js +++ b/packages/database/src/modelClasses/Entity.js @@ -17,7 +17,6 @@ import { QUERY_CONJUNCTIONS } from '../TupaiaDatabase'; const CASE = 'case'; const CASE_CONTACT = 'case_contact'; const COUNTRY = 'country'; -const DISASTER = 'disaster'; const DISTRICT = 'district'; const FACILITY = 'facility'; const SUB_FACILITY = 'sub_facility'; @@ -45,7 +44,6 @@ const ENTITY_TYPES = { CASE, CASE_CONTACT, COUNTRY, - DISASTER, DISTRICT, FACILITY, SUB_FACILITY, diff --git a/packages/database/src/modelClasses/index.js b/packages/database/src/modelClasses/index.js index 9439c4ac0a..d6ca017897 100644 --- a/packages/database/src/modelClasses/index.js +++ b/packages/database/src/modelClasses/index.js @@ -21,8 +21,6 @@ import { DataElementModel } from './DataElement'; import { DataGroupModel } from './DataGroup'; import { DataServiceSyncGroupModel } from './DataServiceSyncGroup'; import { DataTableModel } from './DataTable'; -import { DisasterModel } from './Disaster'; -import { DisasterEventModel } from './DisasterEvent'; import { EntityModel } from './Entity'; import { EntityHierarchyModel } from './EntityHierarchy'; import { EntityRelationModel } from './EntityRelation'; @@ -85,8 +83,6 @@ export const modelClasses = { DataServiceSyncGroup: DataServiceSyncGroupModel, DataTable: DataTableModel, DhisInstance: DhisInstanceModel, - Disaster: DisasterModel, - DisasterEvent: DisasterEventModel, Entity: EntityModel, EntityHierarchy: EntityHierarchyModel, EntityRelation: EntityRelationModel, diff --git a/packages/database/src/records.js b/packages/database/src/records.js index c8b66bf378..2db952c5fc 100644 --- a/packages/database/src/records.js +++ b/packages/database/src/records.js @@ -27,8 +27,6 @@ export const RECORDS = { DHIS_INSTANCE: 'dhis_instance', DHIS_SYNC_LOG: 'dhis_sync_log', DHIS_SYNC_QUEUE: 'dhis_sync_queue', - DISASTER: 'disaster', - DISASTER_EVENT: 'disasterEvent', ENTITY_HIERARCHY: 'entity_hierarchy', ENTITY_RELATION: 'entity_relation', ENTITY: 'entity', diff --git a/packages/database/src/testUtilities/upsertDummyRecord.js b/packages/database/src/testUtilities/upsertDummyRecord.js index 11dd4d7597..0e5c87cac5 100644 --- a/packages/database/src/testUtilities/upsertDummyRecord.js +++ b/packages/database/src/testUtilities/upsertDummyRecord.js @@ -8,12 +8,9 @@ import { generateValueOfType } from './generateValueOfType'; import { generateId } from '../utilities'; import { RECORDS } from '../records'; -const { DISASTER, ENTITY, SURVEY_RESPONSE } = RECORDS; +const { ENTITY, SURVEY_RESPONSE } = RECORDS; const CUSTOM_DUMMY_VALUES = { - [DISASTER]: { - type: 'cyclone', - }, [ENTITY]: { type: 'facility', // default testing entity should be facility country_code: 'DL', // use demo land by default in testing diff --git a/packages/types/src/types/models-extra/dashboard-item/components.ts b/packages/types/src/types/models-extra/dashboard-item/components.ts index 06fcd0cafa..e1534f3a3c 100644 --- a/packages/types/src/types/models-extra/dashboard-item/components.ts +++ b/packages/types/src/types/models-extra/dashboard-item/components.ts @@ -6,7 +6,6 @@ import type { BaseConfig } from './common'; enum VizComponentName { - ActiveDisasters = 'ActiveDisasters', ProjectDescription = 'ProjectDescription', NoAccessDashboard = 'NoAccessDashboard', NoDataAtLevelDashboard = 'NoDataAtLevelDashboard', From c93220dfbad6191ef45c70681cc966d7cfc16679 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:32:22 +1300 Subject: [PATCH 2/9] Add migrations --- ...22-RemoveDisasterTables-modifies-schema.js | 30 +++++ ...-RemoveDisasterDashboards-modifies-data.js | 120 ++++++++++++++++++ ...55-RemoveDisasterEntities-modifies-data.js | 56 ++++++++ ...RemoveDisasterPermissions-modifies-data.js | 62 +++++++++ ...emoveDisasterEntityType-modifies-schema.js | 46 +++++++ 5 files changed, 314 insertions(+) create mode 100644 packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js create mode 100644 packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js create mode 100644 packages/database/src/migrations/20240319014555-RemoveDisasterEntities-modifies-data.js create mode 100644 packages/database/src/migrations/20240320230959-RemoveDisasterPermissions-modifies-data.js create mode 100644 packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js diff --git a/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js b/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js new file mode 100644 index 0000000000..9d3530eba8 --- /dev/null +++ b/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js @@ -0,0 +1,30 @@ +'use strict'; + +var dbm; +var type; +var seed; + +/** + * We receive the dbmigrate dependency from dbmigrate initially. + * This enables us to not have to rely on NODE_PATH. + */ +exports.setup = function (options, seedLink) { + dbm = options.dbmigrate; + type = dbm.dataType; + seed = seedLink; +}; + +exports.up = async function (db) { + return db.runSql(` + DROP TABLE IF EXISTS "disasterEvent"; + DROP TABLE IF EXISTS "disaster"; + `); +}; + +exports.down = function (db) { + return null; +}; + +exports._meta = { + version: 1, +}; diff --git a/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js b/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js new file mode 100644 index 0000000000..d4ce3b1333 --- /dev/null +++ b/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js @@ -0,0 +1,120 @@ +'use strict'; + +var dbm; +var type; +var seed; + +const DISASTER_DASHBOARD_CODES = [ + 'TO_Disaster_Response', + 'DL_Disaster_Response', + 'VU_Disaster_Response', + 'disaster_Disaster_Response', +]; + +const convertArrayToString = array => { + return array.map(item => `'${item}'`).join(','); +}; + +// remove the disaster project code from dashboard relations with multiple project codes including disaster +const removeDisasterFromSharedDashboard = async db => { + const { rows: disasterDashboardRelationsWithMultipleProjectCodes } = await db.runSql(` + SELECT * + FROM dashboard_relation + WHERE project_codes @> ARRAY['disaster'] AND array_length(project_codes, 1) > 1; + `); + await Promise.all( + disasterDashboardRelationsWithMultipleProjectCodes.map(async relation => { + const updatedProjectCodes = relation.project_codes.filter(code => code !== 'disaster'); + await db.runSql(` + UPDATE dashboard_relation + SET project_codes = '{${updatedProjectCodes.join(',')}}' + WHERE id = '${relation.id}'; + `); + }), + ); +}; + +// Get all dashboards that are related to disasters +const getDashboards = async db => { + const { rows: dashboards } = await db.runSql(` + SELECT * from dashboard + where code IN (${convertArrayToString(DISASTER_DASHBOARD_CODES)}); + `); + return dashboards; +}; + +// Get all dashboard relations that are related to disasters +const getDashboardRelations = async (db, dashboardIds) => { + const { rows: dashboardRelations } = await db.runSql(` + SELECT * from dashboard_relation + where dashboard_id IN (${convertArrayToString(dashboardIds)}); + `); + return dashboardRelations; +}; + +// Remove dashboard relations that are related to disasters +const removeDashboardRelations = async (db, dashboardIds) => { + await db.runSql(` + DELETE from dashboard_relation + where dashboard_id IN (${convertArrayToString(dashboardIds)}); + `); +}; + +// Remove dashboards that are related to disasters +const removeDashboards = async (db, dashboardIds) => { + await db.runSql(` + DELETE from dashboard + where id IN (${convertArrayToString(dashboardIds)}); + `); +}; + +// Remove dashboard items that are related to disasters and don't have any other dashboard relations outside of the disaster dashboards +const removeDisasterDashboardItems = async (db, dashboardIds, dashboardItemIds) => { + // get a list of dashboard items that don't have a dashboard relation outside of the disaster dashboards + const { rows: dashboardItemsWithOtherRelations } = await db.runSql(` + SELECT DISTINCT child_id from dashboard_relation + where child_id IN (${convertArrayToString(dashboardItemIds)}) + AND dashboard_id NOT IN (${convertArrayToString(dashboardIds)}); + `); + + const dashboardItemsToRemove = dashboardItemIds.filter( + id => !dashboardItemsWithOtherRelations.map(item => item.child_id).includes(id), + ); + + if (dashboardItemsToRemove.length === 0) return; + + await db.runSql(` + DELETE from dashboard_item + where id IN (${convertArrayToString(dashboardItemsToRemove)}); + `); +}; + +/** + * We receive the dbmigrate dependency from dbmigrate initially. + * This enables us to not have to rely on NODE_PATH. + */ +exports.setup = function (options, seedLink) { + dbm = options.dbmigrate; + type = dbm.dataType; + seed = seedLink; +}; + +exports.up = async function (db) { + await removeDisasterFromSharedDashboard(db); + const dashboards = await getDashboards(db); + const dashboardIds = dashboards.map(dashboard => dashboard.id); + const dashboardRelations = await getDashboardRelations(db, dashboardIds); + const dashboardItemIds = dashboardRelations.map(relation => relation.child_id); + await removeDashboardRelations(db, dashboardIds); + await removeDisasterDashboardItems(db, dashboardIds, dashboardItemIds); + await removeDashboards(db, dashboardIds); + return null; +}; + +exports.down = function (db) { + return null; +}; + +exports._meta = { + version: 1, +}; diff --git a/packages/database/src/migrations/20240319014555-RemoveDisasterEntities-modifies-data.js b/packages/database/src/migrations/20240319014555-RemoveDisasterEntities-modifies-data.js new file mode 100644 index 0000000000..9fd155dc88 --- /dev/null +++ b/packages/database/src/migrations/20240319014555-RemoveDisasterEntities-modifies-data.js @@ -0,0 +1,56 @@ +'use strict'; + +var dbm; +var type; +var seed; + +/** + * We receive the dbmigrate dependency from dbmigrate initially. + * This enables us to not have to rely on NODE_PATH. + */ +exports.setup = function (options, seedLink) { + dbm = options.dbmigrate; + type = dbm.dataType; + seed = seedLink; +}; + +// Remove disaster entities, where disaster is the entity code (project entity) or type +const removeEntities = async db => { + return db.runSql(` + DELETE FROM "entity" WHERE "code" = 'disaster' OR "type" = 'disaster'; + `); +}; + +// Remove disaster entity hierarchy +const removeEntityHierarchy = async db => { + return db.runSql(` + DELETE FROM "entity_hierarchy" WHERE "name" = 'disaster'; + `); +}; + +// Remove disaster entity relations +const removeEntityRelations = async db => { + const { rows } = await db.runSql(` + SELECT * FROM "entity" WHERE "code" = 'disaster'; + `); + const projectEntity = rows[0]; + if (!projectEntity) return; + + await db.runSql(` + DELETE FROM "entity_relation" WHERE "parent_id" = '${projectEntity.id}'; + `); +}; + +exports.up = async function (db) { + await removeEntityRelations(db); + await removeEntities(db); + await removeEntityHierarchy(db); +}; + +exports.down = function (db) { + return null; +}; + +exports._meta = { + version: 1, +}; diff --git a/packages/database/src/migrations/20240320230959-RemoveDisasterPermissions-modifies-data.js b/packages/database/src/migrations/20240320230959-RemoveDisasterPermissions-modifies-data.js new file mode 100644 index 0000000000..49a44e6217 --- /dev/null +++ b/packages/database/src/migrations/20240320230959-RemoveDisasterPermissions-modifies-data.js @@ -0,0 +1,62 @@ +'use strict'; + +var dbm; +var type; +var seed; + +const DISASTER_PERMISSION_GROUPS = ['Disaster Response Admin', 'Disaster Response']; + +const convertArrayToString = array => { + return array.map(item => `'${item}'`).join(','); +}; + +// Get all permission groups that are related to disasters +const getPermissionGroups = async db => { + const { rows: permissionGroups } = await db.runSql(` + SELECT * from permission_group + where name IN (${convertArrayToString(DISASTER_PERMISSION_GROUPS)}); + `); + return permissionGroups; +}; + +// Remove user entity permissions that are related to disasters +const removeUserEntityPermissions = async (db, permissionGroups) => { + await db.runSql(` + DELETE from user_entity_permission + where permission_group_id IN (${convertArrayToString(permissionGroups.map(p => p.id))}); + `); +}; + +// Remove permission groups that are related to disasters +const removePermissionGroups = async (db, permissionGroups) => { + await db.runSql(` + DELETE from permission_group + where id IN (${convertArrayToString(permissionGroups.map(p => p.id))}); + `); +}; + +/** + * We receive the dbmigrate dependency from dbmigrate initially. + * This enables us to not have to rely on NODE_PATH. + */ +exports.setup = function (options, seedLink) { + dbm = options.dbmigrate; + type = dbm.dataType; + seed = seedLink; +}; + +exports.up = async function (db) { + const permissionGroups = await getPermissionGroups(db); + if (permissionGroups.length === 0) return; + + await removeUserEntityPermissions(db, permissionGroups); + await removePermissionGroups(db, permissionGroups); +}; + +exports.down = function (db) { + return null; +}; + +exports._meta = { + version: 1, +}; diff --git a/packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js b/packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js new file mode 100644 index 0000000000..dffa3a39ce --- /dev/null +++ b/packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js @@ -0,0 +1,46 @@ +'use strict'; + +import { TupaiaDatabase } from '../TupaiaDatabase'; +import { replaceEnum } from '../utilities/migration'; + +var dbm; +var type; +var seed; + +/** + * We receive the dbmigrate dependency from dbmigrate initially. + * This enables us to not have to rely on NODE_PATH. + */ +exports.setup = function (options, seedLink) { + dbm = options.dbmigrate; + type = dbm.dataType; + seed = seedLink; +}; + +const getExistingEnumOptions = async db => { + const rows = await db.executeSql(` + SELECT UNNEST(enum_range(null::entity_type)) as type; + `); + return rows.map(row => row.type); +}; + +exports.up = async function () { + const db = new TupaiaDatabase(); + + const existingEnumOptions = await getExistingEnumOptions(db); + if (!existingEnumOptions.includes('disaster')) { + return; + } + const newEnumOptions = existingEnumOptions.filter(option => option !== 'disaster'); + await replaceEnum(db, 'entity_type', newEnumOptions); + + db.closeConnections(); +}; + +exports.down = function (db) { + return null; +}; + +exports._meta = { + version: 1, +}; From 0623df95b76bdc7ad77a8b2ce094997ae630343c Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:37:50 +1300 Subject: [PATCH 3/9] Undo entity type migration --- ...emoveDisasterEntityType-modifies-schema.js | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js diff --git a/packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js b/packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js deleted file mode 100644 index dffa3a39ce..0000000000 --- a/packages/database/src/migrations/20240320232259-RemoveDisasterEntityType-modifies-schema.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -import { TupaiaDatabase } from '../TupaiaDatabase'; -import { replaceEnum } from '../utilities/migration'; - -var dbm; -var type; -var seed; - -/** - * We receive the dbmigrate dependency from dbmigrate initially. - * This enables us to not have to rely on NODE_PATH. - */ -exports.setup = function (options, seedLink) { - dbm = options.dbmigrate; - type = dbm.dataType; - seed = seedLink; -}; - -const getExistingEnumOptions = async db => { - const rows = await db.executeSql(` - SELECT UNNEST(enum_range(null::entity_type)) as type; - `); - return rows.map(row => row.type); -}; - -exports.up = async function () { - const db = new TupaiaDatabase(); - - const existingEnumOptions = await getExistingEnumOptions(db); - if (!existingEnumOptions.includes('disaster')) { - return; - } - const newEnumOptions = existingEnumOptions.filter(option => option !== 'disaster'); - await replaceEnum(db, 'entity_type', newEnumOptions); - - db.closeConnections(); -}; - -exports.down = function (db) { - return null; -}; - -exports._meta = { - version: 1, -}; From 0ff73a7c9fd00e16c1901070f3291e853c8bef1e Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:38:05 +1300 Subject: [PATCH 4/9] Generate types --- packages/types/src/schemas/schemas.ts | 224 ++++---------------------- packages/types/src/types/models.ts | 40 ----- 2 files changed, 28 insertions(+), 236 deletions(-) diff --git a/packages/types/src/schemas/schemas.ts b/packages/types/src/schemas/schemas.ts index 02edf12bb8..7dd8ac15e7 100644 --- a/packages/types/src/schemas/schemas.ts +++ b/packages/types/src/schemas/schemas.ts @@ -1876,7 +1876,6 @@ export const MatrixPresentationOptionsSchema = { export const VizComponentNameSchema = { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" @@ -2259,7 +2258,6 @@ export const ComponentConfigSchema = { }, "componentName": { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" @@ -20922,7 +20920,6 @@ export const DashboardItemConfigSchema = { }, "componentName": { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" @@ -37975,11 +37972,13 @@ export const EntityQuestionConfigSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -38018,11 +38017,13 @@ export const EntityQuestionConfigSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -38483,11 +38484,13 @@ export const SurveyScreenComponentConfigSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -38526,11 +38529,13 @@ export const SurveyScreenComponentConfigSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -39000,6 +39005,18 @@ export const RecentEntitiesForCountrySchema = { "items": { "type": "string" } + }, + "health_clinic_boundary": { + "type": "array", + "items": { + "type": "string" + } + }, + "enumeration_area": { + "type": "array", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -41100,7 +41117,6 @@ export const DashboardItemSchema = { }, "componentName": { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" @@ -49518,7 +49534,6 @@ export const DashboardItemCreateSchema = { }, "componentName": { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" @@ -57930,7 +57945,6 @@ export const DashboardItemUpdateSchema = { }, "componentName": { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" @@ -65450,11 +65464,13 @@ export const DashboardRelationSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -65539,11 +65555,13 @@ export const DashboardRelationCreateSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -65623,11 +65641,13 @@ export const DashboardRelationUpdateSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -66761,195 +66781,6 @@ export const DhisSyncQueueUpdateSchema = { "additionalProperties": false } -export const DisasterSchema = { - "type": "object", - "properties": { - "countryCode": { - "type": "string" - }, - "description": { - "type": "string" - }, - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "type": { - "enum": [ - "cyclone", - "earthquake", - "eruption", - "flood", - "tsunami" - ], - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "countryCode", - "id", - "name", - "type" - ] -} - -export const DisasterCreateSchema = { - "type": "object", - "properties": { - "countryCode": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "type": { - "enum": [ - "cyclone", - "earthquake", - "eruption", - "flood", - "tsunami" - ], - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "countryCode", - "name", - "type" - ] -} - -export const DisasterUpdateSchema = { - "type": "object", - "properties": { - "countryCode": { - "type": "string" - }, - "description": { - "type": "string" - }, - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "type": { - "enum": [ - "cyclone", - "earthquake", - "eruption", - "flood", - "tsunami" - ], - "type": "string" - } - }, - "additionalProperties": false -} - -export const DisasterEventSchema = { - "type": "object", - "properties": { - "date": { - "type": "string", - "format": "date-time" - }, - "disasterId": { - "type": "string" - }, - "id": { - "type": "string" - }, - "organisationUnitCode": { - "type": "string" - }, - "type": { - "enum": [ - "end", - "resolve", - "start" - ], - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "date", - "disasterId", - "id", - "organisationUnitCode", - "type" - ] -} - -export const DisasterEventCreateSchema = { - "type": "object", - "properties": { - "date": { - "type": "string", - "format": "date-time" - }, - "disasterId": { - "type": "string" - }, - "organisationUnitCode": { - "type": "string" - }, - "type": { - "enum": [ - "end", - "resolve", - "start" - ], - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "date", - "disasterId", - "organisationUnitCode", - "type" - ] -} - -export const DisasterEventUpdateSchema = { - "type": "object", - "properties": { - "date": { - "type": "string", - "format": "date-time" - }, - "disasterId": { - "type": "string" - }, - "id": { - "type": "string" - }, - "organisationUnitCode": { - "type": "string" - }, - "type": { - "enum": [ - "end", - "resolve", - "start" - ], - "type": "string" - } - }, - "additionalProperties": false -} - export const EntitySchema = { "type": "object", "properties": { @@ -83403,11 +83234,13 @@ export const EntityResponseSchema = { "country", "disaster", "district", + "enumeration_area", "facility", "farm", "fetp_graduate", "field_station", "fiji_aspen_facility", + "health_clinic_boundary", "household", "incident", "incident_reported", @@ -84551,7 +84384,6 @@ export const DashboardWithMetadataSchema = { }, "componentName": { "enum": [ - "ActiveDisasters", "NoAccessDashboard", "NoDataAtLevelDashboard", "ProjectDescription" diff --git a/packages/types/src/types/models.ts b/packages/types/src/types/models.ts index 0321a3da86..de96dcd973 100644 --- a/packages/types/src/types/models.ts +++ b/packages/types/src/types/models.ts @@ -627,46 +627,6 @@ export interface DhisSyncQueueUpdate { 'record_type'?: string; 'type'?: string; } -export interface Disaster { - 'countryCode': string; - 'description'?: string | null; - 'id': string; - 'name': string; - 'type': DisasterType; -} -export interface DisasterCreate { - 'countryCode': string; - 'description'?: string | null; - 'name': string; - 'type': DisasterType; -} -export interface DisasterUpdate { - 'countryCode'?: string; - 'description'?: string | null; - 'id'?: string; - 'name'?: string; - 'type'?: DisasterType; -} -export interface DisasterEvent { - 'date': Date; - 'disasterId': string; - 'id': string; - 'organisationUnitCode': string; - 'type': DisasterEventType; -} -export interface DisasterEventCreate { - 'date': Date; - 'disasterId': string; - 'organisationUnitCode': string; - 'type': DisasterEventType; -} -export interface DisasterEventUpdate { - 'date'?: Date; - 'disasterId'?: string; - 'id'?: string; - 'organisationUnitCode'?: string; - 'type'?: DisasterEventType; -} export interface Entity { 'attributes': EntityAttributes; 'bounds'?: string | null; From 54d8df3d04f1874a09ec5e901e13af81fde92ea9 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Thu, 21 Mar 2024 15:06:02 +1300 Subject: [PATCH 5/9] FIx tests --- .../src/tests/apiV2/GETDisasters.test.js | 129 ------------------ .../src/tests/apiV2/helpers.test.js | 36 ++--- .../src/tests/apiV2/surveyResponse.test.js | 2 +- .../src/tests/hooks/questionHooks.test.js | 8 +- .../ui-map-components/src/constants/colors.ts | 1 - .../src/apiV1/dataBuilders/index.js | 1 - ...countDisasterAffectedFacilitiesByStatus.js | 47 ------- .../countDisasterAffectedFacilitiesByType.js | 68 --------- ...sterAffectedOrganisationOperationalData.js | 70 ---------- .../disasterSurveyResponseDownloads.js | 46 ------- .../dataBuilders/modules/disaster/index.js | 5 - .../web-config-server/src/apiV1/disasters.js | 90 ------------ packages/web-config-server/src/apiV1/index.js | 2 - 13 files changed, 23 insertions(+), 482 deletions(-) delete mode 100644 packages/central-server/src/tests/apiV2/GETDisasters.test.js delete mode 100644 packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByStatus.js delete mode 100644 packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByType.js delete mode 100644 packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterAffectedOrganisationOperationalData.js delete mode 100644 packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterSurveyResponseDownloads.js delete mode 100644 packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/index.js delete mode 100644 packages/web-config-server/src/apiV1/disasters.js diff --git a/packages/central-server/src/tests/apiV2/GETDisasters.test.js b/packages/central-server/src/tests/apiV2/GETDisasters.test.js deleted file mode 100644 index a8bfe25d21..0000000000 --- a/packages/central-server/src/tests/apiV2/GETDisasters.test.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Tupaia - * Copyright (c) 2017 - 2020 Beyond Essential Systems Pty Ltd - */ - -import { expect } from 'chai'; -import { findOrCreateDummyRecord } from '@tupaia/database'; -import { TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, BES_ADMIN_PERMISSION_GROUP } from '../../permissions'; -import { TestableApp } from '../testUtilities'; - -const getFilterString = filter => `filter=${JSON.stringify(filter)}`; - -describe('Permissions checker for GETDisasters', async () => { - const DEFAULT_POLICY = { - DL: ['Public'], - KI: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Admin'], - SB: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Royal Australasian College of Surgeons'], - VU: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Admin'], - LA: ['Admin'], - }; - - const BES_ADMIN_POLICY = { - SB: [BES_ADMIN_PERMISSION_GROUP], - }; - - const app = new TestableApp(); - const { models } = app; - let disaster1; - let disaster2; - let disaster3; - let filter; - let filterString; - - before(async () => { - // Set up test disasters in the database - disaster1 = await findOrCreateDummyRecord(models.disaster, { - name: 'Test disaster 1', - countryCode: 'VU', - }); - disaster2 = await findOrCreateDummyRecord(models.disaster, { - name: 'Test disaster 2', - countryCode: 'KI', - }); - disaster3 = await findOrCreateDummyRecord(models.disaster, { - name: 'Test disaster 3', - countryCode: 'LA', - }); - filter = { - id: { comparator: 'in', comparisonValue: [disaster1.id, disaster2.id, disaster3.id] }, - }; - filterString = getFilterString(filter); - }); - - afterEach(() => { - app.revokeAccess(); - }); - - describe('GET /disasters/:id', async () => { - it('Sufficient permissions: returns a requested disaster that user has access to', async () => { - await app.grantAccess(DEFAULT_POLICY); - const { body: result } = await app.get(`disasters/${disaster1.id}`); - - expect(result.id).to.equal(disaster1.id); - }); - - it('Insufficient permissions: throws an error if requesting disaster that user does not have access to', async () => { - await app.grantAccess(DEFAULT_POLICY); - const { body: result } = await app.get(`disasters/${disaster3.id}`); - - expect(result).to.have.keys('error'); - }); - }); - - describe('GET /disasters', async () => { - it('Sufficient permissions: returns only disasters the user has permission to', async () => { - await app.grantAccess(DEFAULT_POLICY); - const { body: results } = await app.get(`disasters?${filterString}`); - - expect(results.map(r => r.id)).to.deep.equal([disaster1.id, disaster2.id]); - }); - - it('Sufficient permissions: returns all disasters if the user has BES admin access', async () => { - await app.grantAccess(BES_ADMIN_POLICY); - const { body: results } = await app.get(`disasters?${filterString}`); - - expect(results.map(r => r.id)).to.deep.equal([disaster1.id, disaster2.id, disaster3.id]); - }); - - it('Returns disasters respecting single country code supplied', async () => { - await app.grantAccess(BES_ADMIN_POLICY); - const filterWithCountryCode = { ...filter, countryCode: 'KI' }; - const { body: results } = await app.get( - `disasters?${getFilterString(filterWithCountryCode)}`, - ); - - expect(results.map(r => r.id)).to.deep.equal([disaster2.id]); - }); - - it('Returns disasters respecting multiple country codes supplied', async () => { - await app.grantAccess(BES_ADMIN_POLICY); - const filterWithCountryCode = { ...filter, countryCode: ['KI', 'LA'] }; - const { body: results } = await app.get( - `disasters?${getFilterString(filterWithCountryCode)}`, - ); - - expect(results.map(r => r.id)).to.deep.equal([disaster2.id, disaster3.id]); - }); - - it('Insufficient permissions: returns an empty array if users do not have access to any disaster', async () => { - const policy = { - DL: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Public'], - }; - await app.grantAccess(policy); - const { body: results } = await app.get(`disasters?${filterString}`); - - expect(results).to.be.empty; - }); - - it('Insufficient permissions: throws an error if user does not have admin panel access anywhere', async () => { - const policy = { - DL: ['Public'], - }; - await app.grantAccess(policy); - const { body: result } = await app.get(`disasters`); - - expect(result).to.have.keys('error'); - }); - }); -}); diff --git a/packages/central-server/src/tests/apiV2/helpers.test.js b/packages/central-server/src/tests/apiV2/helpers.test.js index 86cbde119a..0561557df8 100644 --- a/packages/central-server/src/tests/apiV2/helpers.test.js +++ b/packages/central-server/src/tests/apiV2/helpers.test.js @@ -83,43 +83,43 @@ describe('Requests record types that require a through join', () => { }); it('returns record types that require two through joins', () => { const customJoinConditions = { - country: { - through: 'entity', - nearTableKey: 'entity.country_code', - farTableKey: 'country.code', + question: { + through: 'answer', + nearTableKey: 'answer.question_id', + farTableKey: 'question.id', }, - disaster: { - through: 'country', - nearTableKey: 'country.code', - farTableKey: 'disaster.countryCode', + survey_screen_component: { + through: 'question', + nearTableKey: 'question.id', + farTableKey: 'survey_screen_component.question_id', }, }; const results = getQueryOptionsForColumns( - ['survey_response.id', 'country.name', 'disaster.type'], + ['survey_response.id', 'question.id', 'survey_screen_component.component_number'], 'survey_response', customJoinConditions, null, ); expect(results.sort).to.have.ordered.members([ 'survey_response.id', - 'entity.id', - 'country.id', - 'disaster.id', + 'answer.id', + 'question.id', + 'survey_screen_component.id', ]); expect(results.multiJoin).to.deep.equal([ { - joinWith: 'entity', - joinCondition: ['entity.id', 'survey_response.entity_id'], + joinWith: 'answer', + joinCondition: ['survey_response.id', 'answer.survey_response_id'], joinType: null, }, { - joinWith: 'country', - joinCondition: ['country.code', 'entity.country_code'], + joinWith: 'question', + joinCondition: ['answer.question_id', 'question.id'], joinType: null, }, { - joinWith: 'disaster', - joinCondition: ['disaster.countryCode', 'country.code'], + joinWith: 'survey_screen_component', + joinCondition: ['question.id', 'survey_screen_component.question_id'], joinType: null, }, ]); diff --git a/packages/central-server/src/tests/apiV2/surveyResponse.test.js b/packages/central-server/src/tests/apiV2/surveyResponse.test.js index 5aecda08b3..74654e9607 100644 --- a/packages/central-server/src/tests/apiV2/surveyResponse.test.js +++ b/packages/central-server/src/tests/apiV2/surveyResponse.test.js @@ -68,7 +68,7 @@ describe('surveyResponse endpoint', () => { await upsertEntity({ id: ENTITY_NON_CLINIC_ID, code: ENTITY_NON_CLINIC_ID, - type: 'disaster', + type: 'village', }); // This question will not be part of the survey diff --git a/packages/central-server/src/tests/hooks/questionHooks.test.js b/packages/central-server/src/tests/hooks/questionHooks.test.js index d2fbecd3db..bd1d5e5479 100644 --- a/packages/central-server/src/tests/hooks/questionHooks.test.js +++ b/packages/central-server/src/tests/hooks/questionHooks.test.js @@ -390,7 +390,7 @@ describe('Question hooks', () => { 'TEST_create-code': 'test_code', 'TEST_create-name': 'Test Dynamic Entity', 'TEST_create-image-url': TEST_URL, - 'TEST_create-type': 'disaster', + 'TEST_create-type': 'village', }, }, }); @@ -402,7 +402,7 @@ describe('Question hooks', () => { expect(entity.parent_id).to.equal(ENTITY_ID); expect(entity.name).to.equal('Test Dynamic Entity'); expect(entity.image_url).to.equal(TEST_URL); - expect(entity.type).to.equal('disaster'); + expect(entity.type).to.equal('village'); }); it('Should not create a duplicate entity', async () => { @@ -421,7 +421,7 @@ describe('Question hooks', () => { 'TEST_create-code': DUP_CODE, 'TEST_create-name': 'Dupe Entity', 'TEST_create-image-url': TEST_URL, - 'TEST_create-type': 'disaster', + 'TEST_create-type': 'village', }, }, }); @@ -431,7 +431,7 @@ describe('Question hooks', () => { const midEntity = await models.entity.findOne({ code: DUP_CODE }); expect(midEntity).to.not.be.null; expect(midEntity.name).to.equal('Dupe Entity'); - expect(midEntity.type).to.equal('disaster'); + expect(midEntity.type).to.equal('village'); expect(midEntity.image_url).to.equal(TEST_URL); // submit a second survey response with slightly different data diff --git a/packages/ui-map-components/src/constants/colors.ts b/packages/ui-map-components/src/constants/colors.ts index 6845fae0aa..5e5029df55 100644 --- a/packages/ui-map-components/src/constants/colors.ts +++ b/packages/ui-map-components/src/constants/colors.ts @@ -73,4 +73,3 @@ export const BREWER_AUTO = [ export const YES_COLOR = BREWER_PALETTE.green; export const NO_COLOR = BREWER_PALETTE.red; export const UNKNOWN_COLOR = 'grey'; -export const DEFAULT_DISASTER_COLOR = 'orange'; diff --git a/packages/web-config-server/src/apiV1/dataBuilders/index.js b/packages/web-config-server/src/apiV1/dataBuilders/index.js index 41c107790a..05a0f22316 100644 --- a/packages/web-config-server/src/apiV1/dataBuilders/index.js +++ b/packages/web-config-server/src/apiV1/dataBuilders/index.js @@ -19,7 +19,6 @@ export * from './generic/unique'; export * from './generic/reportServer'; /** Modules */ -export * from './modules/disaster'; export * from './modules/msupply'; export * from './modules/pehs'; export * from './modules/tonga'; diff --git a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByStatus.js b/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByStatus.js deleted file mode 100644 index 341bdc0866..0000000000 --- a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByStatus.js +++ /dev/null @@ -1,47 +0,0 @@ -import { convertDateRangeToPeriodString } from '@tupaia/utils'; - -const AFFECTED_STATUS_DATA_ELEMENT_CODE = 'DP_NEW008'; - -// Counts not calculated from survey question -const TO_BE_COMPLETED = 'To be completed'; - -export const countDisasterAffectedFacilitiesByStatus = async ( - { models, entity, dataBuilderConfig, query, fetchHierarchyId }, - aggregator, - dhisApi, -) => { - const { disasterStartDate, disasterEndDate } = query; - const { dataServices, optionSetCode } = dataBuilderConfig; - - if (!disasterStartDate) return { data: [] }; // show no data message in view. - - const period = convertDateRangeToPeriodString(disasterStartDate, disasterEndDate || Date.now()); - const hierarchyId = await fetchHierarchyId(); - const facilities = await entity.getDescendantsOfType(hierarchyId, models.entity.types.FACILITY); - const options = await dhisApi.getOptionSetOptions({ code: optionSetCode }); - const { results } = await aggregator.fetchAnalytics([AFFECTED_STATUS_DATA_ELEMENT_CODE], { - ...query, - dataServices, - period, - }); - - /* eslint-disable no-param-reassign */ - const returnData = results.reduce( - (statusCounts, result) => { - const optionValue = options[result.value]; - if (!statusCounts[optionValue]) statusCounts[optionValue] = { name: optionValue, value: 0 }; - statusCounts[optionValue].value += 1; - - return statusCounts; - }, - { - // each facility with a completed survey will be mapped to one of the status' above, - // so the difference between results and all facilities is = to - // the amount of facilities that haven't completed the survey. - [TO_BE_COMPLETED]: { name: TO_BE_COMPLETED, value: facilities.length - results.length }, - }, - ); - /* eslint-enable no-param-reassign */ - - return { data: Object.values(returnData) }; -}; diff --git a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByType.js b/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByType.js deleted file mode 100644 index d51e5c3520..0000000000 --- a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/countDisasterAffectedFacilitiesByType.js +++ /dev/null @@ -1,68 +0,0 @@ -import keyBy from 'lodash.keyby'; -import { convertDateRangeToPeriodString } from '@tupaia/utils'; - -const AFFECTED_STATUS_DATA_ELEMENT_CODE = 'DP_NEW008'; - -// values from survey that indicate facility is affected -const FACILITY_AFFECTED_VALUES = ['Partially affected', 'Completely affected']; -// presentationOption headers -const FACILITY_AFFECTED = 'Affected'; -const FACILITY_UNAFFECTED = 'Unaffected'; -const FACILITY_STATUS_UNKNOWN = 'Unknown'; - -// Number of Operational Facilities by Facility Type -export const countDisasterAffectedFacilitiesByType = async ( - { models, dataBuilderConfig, query, entity, fetchHierarchyId }, - aggregator, - dhisApi, -) => { - const { disasterStartDate, disasterEndDate } = query; - const { dataServices, optionSetCode } = dataBuilderConfig; - - if (!disasterStartDate) return { data: [] }; - const options = await dhisApi.getOptionSetOptions({ code: optionSetCode }); - const period = convertDateRangeToPeriodString(disasterStartDate, disasterEndDate || Date.now()); - const hierarchyId = await fetchHierarchyId(); - const facilities = await entity.getDescendantsOfType(hierarchyId, models.entity.types.FACILITY); - const facilityMetadatas = await models.facility.find({ - code: facilities.map(facility => facility.code), - }); - const { results } = await aggregator.fetchAnalytics([AFFECTED_STATUS_DATA_ELEMENT_CODE], { - ...query, - dataServices, - period, - }); - - const facilitiesByCode = keyBy(facilities, 'code'); - const facilityMetadatasByCode = keyBy(facilityMetadatas, 'code'); - const facilityStatuses = new Map( - results.map(result => { - const { organisationUnit: facilityCode } = result; - const organisationUnitName = facilitiesByCode[facilityCode].name; - const optionValue = options[result.value]; - const facilityIsAffected = FACILITY_AFFECTED_VALUES.includes(optionValue); - const value = facilityIsAffected ? FACILITY_AFFECTED : FACILITY_UNAFFECTED; - - return [organisationUnitName, value]; - }), - ); - - const statusCountsByFacilityType = {}; - facilities.forEach(facility => { - const { name, code } = facility; - const { type_name: facilityTypeName } = facilityMetadatasByCode[code]; - const facilityAffectedStatus = facilityStatuses.get(name) || FACILITY_STATUS_UNKNOWN; - - if (!statusCountsByFacilityType[facilityTypeName]) { - statusCountsByFacilityType[facilityTypeName] = { - name: facilityTypeName, - [FACILITY_UNAFFECTED]: 0, - [FACILITY_STATUS_UNKNOWN]: 0, - [FACILITY_AFFECTED]: 0, - }; - } - statusCountsByFacilityType[facilityTypeName][facilityAffectedStatus]++; - }); - - return { data: Array.from(Object.values(statusCountsByFacilityType)) }; -}; diff --git a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterAffectedOrganisationOperationalData.js b/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterAffectedOrganisationOperationalData.js deleted file mode 100644 index 9b5cc83b68..0000000000 --- a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterAffectedOrganisationOperationalData.js +++ /dev/null @@ -1,70 +0,0 @@ -import { convertDateRangeToPeriodString } from '@tupaia/utils'; - -const DATA_ELEMENT_CODES = { - currentBeds: ['DP9'], - normalBeds: ['DP_NEW001'], - facilityAffectedStatus: ['DP_NEW008'], -}; - -export const disasterAffectedOrganisationOperationalData = async ( - { models, dataBuilderConfig, query, entity, fetchHierarchyId }, - aggregator, -) => { - const { organisationUnitCode, disasterStartDate } = query; - const { dataServices } = dataBuilderConfig; - - if (!disasterStartDate) return { data: [] }; - - const hierarchyId = await fetchHierarchyId(); - const facilities = await entity.getDescendantsOfType(hierarchyId, models.entity.types.FACILITY); - const { results: facilityStatusResults } = await aggregator.fetchAnalytics( - DATA_ELEMENT_CODES.facilityAffectedStatus, - { - dataServices, - period: convertDateRangeToPeriodString(disasterStartDate, Date.now()), - organisationUnitCode, - }, - ); - const operationalFacilities = facilityStatusResults.filter( - result => result.value === 0 || result.value === 1, - ); // 0 === 'Not affected', 1 === 'Partially affected' - const { results: operationalInpatientBedResults } = await aggregator.fetchAnalytics( - DATA_ELEMENT_CODES.currentBeds, - { - dataServices, - organisationUnitCode, - period: convertDateRangeToPeriodString(disasterStartDate, Date.now()), - }, - ); - const totalOperationalInpatientBeds = operationalInpatientBedResults.reduce( - (total, orgUnit) => total + orgUnit.value, - 0, - ); - - const { results: normalInpatientBedsResults } = await aggregator.fetchAnalytics( - DATA_ELEMENT_CODES.normalBeds, - { - dataServices, - organisationUnitCode, - }, - ); - const totalNormalInpatientBeds = normalInpatientBedsResults.reduce( - (total, orgUnit) => total + orgUnit.value, - 0, - ); - - return { - data: [ - { - name: 'Number of known operational facilities', - value: operationalFacilities.length, - total: facilities.length, - }, - { - name: 'Number of operational inpatient beds', - value: totalOperationalInpatientBeds, - total: totalNormalInpatientBeds, - }, - ], - }; -}; diff --git a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterSurveyResponseDownloads.js b/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterSurveyResponseDownloads.js deleted file mode 100644 index 420cc729fe..0000000000 --- a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/disasterSurveyResponseDownloads.js +++ /dev/null @@ -1,46 +0,0 @@ -import { composeBuiltData } from '/apiV1/utils'; -import { latestDataValueDate } from '/apiV1/dataBuilders/generic/latestData'; -import { latestDownloadLink } from '/apiV1/dataBuilders/generic/dataDownload'; - -export const disasterSurveyResponseDownloads = async ( - { dataBuilderConfig, query, entity, req }, - aggregator, - dhisApi, -) => { - const { preConfig, postConfig } = dataBuilderConfig; - - const preDownloadLink = await latestDownloadLink({ req, query, dataBuilderConfig: preConfig }); - const preDisasterSurveyData = await latestDataValueDate( - { - dataBuilderConfig: { ...preConfig, name: dataBuilderConfig.name }, - entity, - }, - aggregator, - dhisApi, - ); - - const postQuery = { - ...query, - startDate: query.disasterStartDate, - }; - const postDownloadLink = await latestDownloadLink({ - req, - query: postQuery, - dataBuilderConfig: postConfig, - }); - const postDisasterSurveyData = await latestDataValueDate( - { - dataBuilderConfig: { ...postConfig, name: dataBuilderConfig.name }, - entity, - }, - aggregator, - dhisApi, - ); - - return composeBuiltData( - preDisasterSurveyData, - preDownloadLink, - postDisasterSurveyData, - postDownloadLink, - ); -}; diff --git a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/index.js b/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/index.js deleted file mode 100644 index e8fa569123..0000000000 --- a/packages/web-config-server/src/apiV1/dataBuilders/modules/disaster/index.js +++ /dev/null @@ -1,5 +0,0 @@ -/** Disaster Module specific dataBuilders */ -export { disasterAffectedOrganisationOperationalData } from './disasterAffectedOrganisationOperationalData'; -export { disasterSurveyResponseDownloads } from './disasterSurveyResponseDownloads'; -export { countDisasterAffectedFacilitiesByType } from './countDisasterAffectedFacilitiesByType'; -export { countDisasterAffectedFacilitiesByStatus } from './countDisasterAffectedFacilitiesByStatus'; diff --git a/packages/web-config-server/src/apiV1/disasters.js b/packages/web-config-server/src/apiV1/disasters.js deleted file mode 100644 index f53aca24fe..0000000000 --- a/packages/web-config-server/src/apiV1/disasters.js +++ /dev/null @@ -1,90 +0,0 @@ -import { respond, translateBounds, translatePoint } from '@tupaia/utils'; - -// disaster event types (match disasterEvent.type enum in postgres) -const DISASTER_EVENT_START = 'start'; -const DISASTER_EVENT_END = 'end'; -const DISASTER_EVENT_RESOLVE = 'resolve'; - -// disaster status types -const DISASTER_PENDING = 'pending'; // no events yet -const DISASTER_ACTIVE = 'active'; // has events that have started but not ended -const DISASTER_ENDED = 'ended'; // has events that have ended but not resolved -const DISASTER_RESOLVED = 'resolved'; // all events have resolved - -const DISASTER_STATUS_PRIORITIES = [ - DISASTER_PENDING, - DISASTER_EVENT_RESOLVE, - DISASTER_EVENT_END, - DISASTER_EVENT_START, -]; - -const DISASTER_STATUSES = [DISASTER_PENDING, DISASTER_RESOLVED, DISASTER_ENDED, DISASTER_ACTIVE]; - -function determineDisasterDetails(events) { - // start and end dates for the entire disaster - let earliest = null; - let latest = null; - - // latest received state for each org unit - const orgUnitStates = {}; - - events - .sort((a, b) => a.date - b.date) - .forEach(({ date, type, organisationUnitCode }) => { - orgUnitStates[organisationUnitCode] = type; - if (date > latest || !latest) { - latest = date; - } - if (date < earliest || !earliest) { - earliest = date; - } - }); - - // get "worst" condition from all affected units - const overallPriority = Object.values(orgUnitStates).reduce((state, current) => { - const priority = DISASTER_STATUS_PRIORITIES.indexOf(current); - return Math.max(priority, state); - }, 0); - - // map worst org unit status to overall disaster status - const status = DISASTER_STATUSES[overallPriority]; - - return { - status, - startDate: earliest, - endDate: status !== DISASTER_ACTIVE ? latest : null, - }; -} - -// get events from database and annotate disaster with more detailed info -async function addAdditionalDetails(models, disaster) { - const events = await models.disasterEvent.find({ - disasterId: disaster.code, - }); - - const details = determineDisasterDetails(events); - const location = (await models.entity.findOne({ code: disaster.countryCode })).name; - - return { - ...disaster, - ...details, - location, - }; -} - -export async function disasters(req, res) { - const { models } = req; - const allDisasters = await models.disaster.getAllDisasterDetails(); - const allDisastersWithExtraDetails = await Promise.all( - allDisasters.map(d => addAdditionalDetails(models, d)), - ); - const responseData = allDisastersWithExtraDetails - .filter(d => d.status !== DISASTER_RESOLVED) - .map(({ bounds, point, ...d }) => ({ - ...d, - bounds: translateBounds(bounds), - coordinates: translatePoint(point), - })); - - respond(res, { disasters: responseData }); -} diff --git a/packages/web-config-server/src/apiV1/index.js b/packages/web-config-server/src/apiV1/index.js index 23cf4d4371..2d1f97ffd6 100755 --- a/packages/web-config-server/src/apiV1/index.js +++ b/packages/web-config-server/src/apiV1/index.js @@ -29,7 +29,6 @@ import OrgUnitSearchHandler from './organisationUnitSearch'; import OrganisationUnitHandler from './organisationUnit'; import DashboardsHandler from './dashboards'; import { ReportHandler } from './report'; -import { disasters } from './disasters'; import { getProjects } from './projects'; import { getLandingPage } from './landingPages'; @@ -59,7 +58,6 @@ export const getRoutesForApiV1 = () => { api.get('/organisationUnitSearch', handleWith(OrgUnitSearchHandler)); api.get('/measures', handleWith(MeasuresHandler)); api.get('/measureData', handleWith(MeasuresDataHandler)); - api.get('/disasters', catchAsyncErrors(disasters)); api.get('/projects', catchAsyncErrors(getProjects)); api.get('/dashboards', handleWith(DashboardsHandler)); // New style dashboards api.get('/report/:reportCode', handleWith(ReportHandler)); From c366a87ecaa7561dd5d1ddd592eb61c35254c58f Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Thu, 21 Mar 2024 15:32:01 +1300 Subject: [PATCH 6/9] Fix helpers test --- .../central-server/src/tests/apiV2/helpers.test.js | 13 +++++++++---- .../src/tests/apiV2/requestPasswordReset.test.js | 2 +- ...010415-RemoveDisasterDashboards-modifies-data.js | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/central-server/src/tests/apiV2/helpers.test.js b/packages/central-server/src/tests/apiV2/helpers.test.js index 0561557df8..eaa65499e6 100644 --- a/packages/central-server/src/tests/apiV2/helpers.test.js +++ b/packages/central-server/src/tests/apiV2/helpers.test.js @@ -81,8 +81,13 @@ describe('Requests record types that require a through join', () => { }, ]); }); - it('returns record types that require two through joins', () => { + it('returns record types that require multiple through joins', () => { const customJoinConditions = { + answer: { + through: 'survey_response', + nearTableKey: 'survey_response.id', + farTableKey: 'answer.survey_response_id', + }, question: { through: 'answer', nearTableKey: 'answer.question_id', @@ -109,17 +114,17 @@ describe('Requests record types that require a through join', () => { expect(results.multiJoin).to.deep.equal([ { joinWith: 'answer', - joinCondition: ['survey_response.id', 'answer.survey_response_id'], + joinCondition: ['answer.survey_response_id', 'survey_response.id'], joinType: null, }, { joinWith: 'question', - joinCondition: ['answer.question_id', 'question.id'], + joinCondition: ['question.id', 'answer.question_id'], joinType: null, }, { joinWith: 'survey_screen_component', - joinCondition: ['question.id', 'survey_screen_component.question_id'], + joinCondition: ['survey_screen_component.question_id', 'question.id'], joinType: null, }, ]); diff --git a/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js b/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js index bd8fbad421..18fb9e388c 100644 --- a/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js +++ b/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js @@ -10,7 +10,7 @@ import { createBearerHeader, randomEmail, randomString } from '@tupaia/utils'; import { getAuthorizationHeader, TestableApp } from '../testUtilities'; -describe('Reset Password', () => { +describe.only('Reset Password', () => { const app = new TestableApp(); const { models } = app; const { VERIFIED } = models.user.emailVerifiedStatuses; diff --git a/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js b/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js index d4ce3b1333..a1bacf76ba 100644 --- a/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js +++ b/packages/database/src/migrations/20240319010415-RemoveDisasterDashboards-modifies-data.js @@ -22,6 +22,7 @@ const removeDisasterFromSharedDashboard = async db => { FROM dashboard_relation WHERE project_codes @> ARRAY['disaster'] AND array_length(project_codes, 1) > 1; `); + if (disasterDashboardRelationsWithMultipleProjectCodes.length === 0) return; await Promise.all( disasterDashboardRelationsWithMultipleProjectCodes.map(async relation => { const updatedProjectCodes = relation.project_codes.filter(code => code !== 'disaster'); @@ -54,6 +55,7 @@ const getDashboardRelations = async (db, dashboardIds) => { // Remove dashboard relations that are related to disasters const removeDashboardRelations = async (db, dashboardIds) => { + if (dashboardIds.length === 0) return; await db.runSql(` DELETE from dashboard_relation where dashboard_id IN (${convertArrayToString(dashboardIds)}); @@ -62,6 +64,7 @@ const removeDashboardRelations = async (db, dashboardIds) => { // Remove dashboards that are related to disasters const removeDashboards = async (db, dashboardIds) => { + if (dashboardIds.length === 0) return; await db.runSql(` DELETE from dashboard where id IN (${convertArrayToString(dashboardIds)}); @@ -70,6 +73,7 @@ const removeDashboards = async (db, dashboardIds) => { // Remove dashboard items that are related to disasters and don't have any other dashboard relations outside of the disaster dashboards const removeDisasterDashboardItems = async (db, dashboardIds, dashboardItemIds) => { + if (dashboardIds.length === 0 || dashboardItemIds.length === 0) return; // get a list of dashboard items that don't have a dashboard relation outside of the disaster dashboards const { rows: dashboardItemsWithOtherRelations } = await db.runSql(` SELECT DISTINCT child_id from dashboard_relation @@ -102,13 +106,13 @@ exports.setup = function (options, seedLink) { exports.up = async function (db) { await removeDisasterFromSharedDashboard(db); const dashboards = await getDashboards(db); + if (dashboards.length === 0) return; const dashboardIds = dashboards.map(dashboard => dashboard.id); const dashboardRelations = await getDashboardRelations(db, dashboardIds); const dashboardItemIds = dashboardRelations.map(relation => relation.child_id); await removeDashboardRelations(db, dashboardIds); await removeDisasterDashboardItems(db, dashboardIds, dashboardItemIds); await removeDashboards(db, dashboardIds); - return null; }; exports.down = function (db) { From 75909f5da4e42de8f33e32e2233768b97803eb93 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 22 Mar 2024 08:06:41 +1300 Subject: [PATCH 7/9] Remove only test --- .../central-server/src/tests/apiV2/requestPasswordReset.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js b/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js index 18fb9e388c..bd8fbad421 100644 --- a/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js +++ b/packages/central-server/src/tests/apiV2/requestPasswordReset.test.js @@ -10,7 +10,7 @@ import { createBearerHeader, randomEmail, randomString } from '@tupaia/utils'; import { getAuthorizationHeader, TestableApp } from '../testUtilities'; -describe.only('Reset Password', () => { +describe('Reset Password', () => { const app = new TestableApp(); const { models } = app; const { VERIFIED } = models.user.emailVerifiedStatuses; From a1602edaa1a4e91acff367c4b11a5bbc164d8787 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:38:39 +1300 Subject: [PATCH 8/9] Update packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js Co-authored-by: Rohan Port <59544282+rohan-bes@users.noreply.github.com> --- .../20240319010222-RemoveDisasterTables-modifies-schema.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js b/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js index 9d3530eba8..2c78fbd07f 100644 --- a/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js +++ b/packages/database/src/migrations/20240319010222-RemoveDisasterTables-modifies-schema.js @@ -18,6 +18,8 @@ exports.up = async function (db) { return db.runSql(` DROP TABLE IF EXISTS "disasterEvent"; DROP TABLE IF EXISTS "disaster"; + DROP TYPE IF EXISTS disaster_type; + DROP TYPE IF EXISTS disaster_event_type; `); }; From ba080ccccda4617707d4c77c9a6129e8fad939d9 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:07:00 +1300 Subject: [PATCH 9/9] Generate types --- packages/types/src/schemas/schemas.ts | 20 -------------------- packages/types/src/types/models.ts | 12 ------------ 2 files changed, 32 deletions(-) diff --git a/packages/types/src/schemas/schemas.ts b/packages/types/src/schemas/schemas.ts index efaec65f6e..aa92d14c1e 100644 --- a/packages/types/src/schemas/schemas.ts +++ b/packages/types/src/schemas/schemas.ts @@ -82139,26 +82139,6 @@ export const EntityTypeSchema = { "type": "string" } -export const DisasterTypeSchema = { - "enum": [ - "cyclone", - "earthquake", - "eruption", - "flood", - "tsunami" - ], - "type": "string" -} - -export const DisasterEventTypeSchema = { - "enum": [ - "end", - "resolve", - "start" - ], - "type": "string" -} - export const DataTableTypeSchema = { "enum": [ "analytics", diff --git a/packages/types/src/types/models.ts b/packages/types/src/types/models.ts index 849c0ffd86..b4db325d02 100644 --- a/packages/types/src/types/models.ts +++ b/packages/types/src/types/models.ts @@ -1752,18 +1752,6 @@ export enum EntityType { 'health_clinic_boundary' = 'health_clinic_boundary', 'enumeration_area' = 'enumeration_area', } -export enum DisasterType { - 'cyclone' = 'cyclone', - 'eruption' = 'eruption', - 'earthquake' = 'earthquake', - 'tsunami' = 'tsunami', - 'flood' = 'flood', -} -export enum DisasterEventType { - 'start' = 'start', - 'end' = 'end', - 'resolve' = 'resolve', -} export enum DataTableType { 'analytics' = 'analytics', 'events' = 'events',