diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 5817633b..f79e4193 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,7 +6,7 @@ - -### :art: Screenshots +### :video_camera: Screenshots/Screen capture ### :fire: Is there anything the reviewer should know to test it? diff --git a/i18n/en.pot b/i18n/en.pot index 4c969129..0b0c8aa5 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2023-06-12T22:53:44.873Z\n" -"PO-Revision-Date: 2023-06-12T22:53:44.873Z\n" +"POT-Creation-Date: 2024-04-16T06:03:13.568Z\n" +"PO-Revision-Date: 2024-04-16T06:03:13.568Z\n" msgid "" "THIS NEW RELEASE INCLUDES SHARING SETTINGS PER INSTANCES. FOR THIS VERSION " diff --git a/package.json b/package.json index 307ea80c..8e59a5bc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "metadata-synchronization", "description": "Advanced metadata & data synchronization utility", - "version": "2.17.0", + "version": "2.17.1", "license": "GPL-3.0", "author": "EyeSeeTea team", "homepage": ".", diff --git a/src/data/metadata/MetadataD2ApiRepository.ts b/src/data/metadata/MetadataD2ApiRepository.ts index 8d7815ed..2614560e 100644 --- a/src/data/metadata/MetadataD2ApiRepository.ts +++ b/src/data/metadata/MetadataD2ApiRepository.ts @@ -555,7 +555,33 @@ export class MetadataD2ApiRepository implements MetadataRepository { const response = await Promise.all(promises); const results = _.deepMerge({}, ...response); if (results.system) delete results.system; - return results; + + const metadata = await this.validateEventVisualizationsByIds(results); + return metadata; + } + + private async validateEventVisualizationsByIds(metadata: any) { + if (!metadata.eventCharts || !metadata.eventReports) return metadata; + + const chartsMetadata = _(metadata.eventCharts) + .map(eventChart => { + return this.isEventReport(eventChart.type) ? undefined : eventChart; + }) + .compact() + .value(); + + const eventReportsMetadata = _(metadata.eventReports) + .map(eventReport => { + return this.isEventReport(eventReport.type) ? eventReport : undefined; + }) + .compact() + .value(); + + return { ...metadata, eventReports: eventReportsMetadata, eventCharts: chartsMetadata }; + } + + private isEventReport(visualizationType: D2VisualizationType): boolean { + return visualizationType === "PIVOT_TABLE" || visualizationType === "LINE_LIST"; } private getApiModel(type: keyof MetadataEntities): Model { @@ -660,3 +686,5 @@ function getFilterAsString(filter: FilterBase): string[] { ) ); } + +type D2VisualizationType = "LINE_LIST" | "PIVOT_TABLE"; diff --git a/src/data/metadata/__tests__/integration/local-instance-mapped.spec.ts b/src/data/metadata/__tests__/integration/local-instance-mapped.spec.ts index 058299a1..51a225b0 100644 --- a/src/data/metadata/__tests__/integration/local-instance-mapped.spec.ts +++ b/src/data/metadata/__tests__/integration/local-instance-mapped.spec.ts @@ -147,6 +147,21 @@ describe("Sync local instance mapped", () => { id: "Db5532sXKXT", })); + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKXT", + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + externalAccess: false, + }, + })); + const addAggregatedToDb = async (schema: Schema, request: Request) => { schema.db.dataValueSets.insert(JSON.parse(request.requestBody)); diff --git a/src/data/metadata/__tests__/integration/sync-aggregated.spec.ts b/src/data/metadata/__tests__/integration/sync-aggregated.spec.ts index c2007766..0615bad3 100644 --- a/src/data/metadata/__tests__/integration/sync-aggregated.spec.ts +++ b/src/data/metadata/__tests__/integration/sync-aggregated.spec.ts @@ -214,6 +214,36 @@ describe("Sync aggregated", () => { id: "Db5532sXKX1", })); + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKXT", + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + externalAccess: false, + }, + })); + + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKX1", + externalAccess: false, + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + }, + })); + const addAggregatedToDb = async (schema: Schema, request: Request) => { schema.db.dataValueSets.insert(JSON.parse(request.requestBody)); diff --git a/src/data/metadata/__tests__/integration/sync-events.spec.ts b/src/data/metadata/__tests__/integration/sync-events.spec.ts index ccd9834b..a84e7f84 100644 --- a/src/data/metadata/__tests__/integration/sync-events.spec.ts +++ b/src/data/metadata/__tests__/integration/sync-events.spec.ts @@ -227,6 +227,36 @@ describe("Sync events", () => { id: "Db5532sXKX1", })); + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKXT", + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + externalAccess: false, + }, + })); + + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKX1", + externalAccess: false, + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + }, + })); + // local.get("/trackedEntityInstances", async () => ({ // trackedEntityInstances: [], // })); diff --git a/src/data/metadata/__tests__/integration/sync-metadata.spec.ts b/src/data/metadata/__tests__/integration/sync-metadata.spec.ts index 4e4dc1a5..04b186b7 100644 --- a/src/data/metadata/__tests__/integration/sync-metadata.spec.ts +++ b/src/data/metadata/__tests__/integration/sync-metadata.spec.ts @@ -90,6 +90,36 @@ describe("Sync metadata", () => { id: "Db5532sXKX1", })); + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKXT", + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + externalAccess: false, + }, + })); + + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKX1", + externalAccess: false, + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + }, + })); + const addMetadataToDb = async (schema: Schema, request: Request) => { schema.db.metadata.insert(JSON.parse(request.requestBody)); diff --git a/src/data/storage/StorageDataStoreClient.ts b/src/data/storage/StorageDataStoreClient.ts index 355aced7..7d97e77b 100644 --- a/src/data/storage/StorageDataStoreClient.ts +++ b/src/data/storage/StorageDataStoreClient.ts @@ -82,10 +82,14 @@ export class StorageDataStoreClient extends StorageClient { const metadata = await this.getMetadataByKey(key); if (!metadata) return undefined; + const { object } = await this.api.sharing.get({ type: "dataStore", id: metadata.id }).getData(); + + if (!object) return undefined; + return { user: { name: "", ...metadata.user }, - userAccesses: metadata.userAccesses, - userGroupAccesses: metadata.userGroupAccesses, + userAccesses: object.userAccesses || [], + userGroupAccesses: object.userGroupAccesses || [], publicAccess: metadata.publicAccess, externalAccess: metadata.externalAccess, }; diff --git a/src/data/transformations/__tests__/integration/helpers.ts b/src/data/transformations/__tests__/integration/helpers.ts index 069eea02..1e25eb55 100644 --- a/src/data/transformations/__tests__/integration/helpers.ts +++ b/src/data/transformations/__tests__/integration/helpers.ts @@ -101,6 +101,36 @@ export async function sync({ id: "Db5532sXKX1", })); + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKXT", + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + externalAccess: false, + }, + })); + + local.get("/sharing", async () => ({ + meta: { + allowPublicAccess: true, + allowExternalAccess: false, + }, + object: { + id: "Db5532sXKX1", + externalAccess: false, + publicAccess: "rw------", + user: { id: "H4atNsEuKxP" }, + userGroupAccesses: [], + userAccesses: [], + }, + })); + const addMetadataToDb = async (schema: Schema, request: Request) => { schema.db.metadata.insert(JSON.parse(request.requestBody)); diff --git a/src/domain/metadata/entities/MetadataEntities.ts b/src/domain/metadata/entities/MetadataEntities.ts index 40487678..26cd6cff 100644 --- a/src/domain/metadata/entities/MetadataEntities.ts +++ b/src/domain/metadata/entities/MetadataEntities.ts @@ -5065,6 +5065,7 @@ export type MetadataEntities = { categoryOptionCombos: CategoryOptionCombo[]; categoryOptionGroups: CategoryOptionGroup[]; categoryOptionGroupSets: CategoryOptionGroupSet[]; + constants: Constant[]; charts: Chart[]; dashboards: Dashboard[]; dataApprovalLevels: DataApprovalLevel[]; diff --git a/src/models/dhis/factory.ts b/src/models/dhis/factory.ts index fc51a947..f66f48b8 100644 --- a/src/models/dhis/factory.ts +++ b/src/models/dhis/factory.ts @@ -13,6 +13,7 @@ export const metadataModels = [ metadataClasses.CategoryOptionComboModel, metadataClasses.CategoryOptionGroupModel, metadataClasses.CategoryOptionGroupSetModel, + metadataClasses.ConstantsModel, metadataClasses.DashboardModel, metadataClasses.DataElementModel, metadataClasses.DataElementGroupModel, diff --git a/src/models/dhis/metadata.ts b/src/models/dhis/metadata.ts index f5c5f605..2099a8c1 100644 --- a/src/models/dhis/metadata.ts +++ b/src/models/dhis/metadata.ts @@ -243,6 +243,11 @@ export class DataEntryFormModel extends D2Model { protected static collectionName = "dataEntryForms" as const; } +export class ConstantsModel extends D2Model { + protected static metadataType = "constants"; + protected static collectionName = "constants" as const; +} + export class DataSetModel extends D2Model { protected static metadataType = "dataSet"; protected static collectionName = "dataSets" as const; diff --git a/src/presentation/react/core/components/sync-wizard/common/SummaryStep.tsx b/src/presentation/react/core/components/sync-wizard/common/SummaryStep.tsx index 025f64ba..a8cc288e 100644 --- a/src/presentation/react/core/components/sync-wizard/common/SummaryStep.tsx +++ b/src/presentation/react/core/components/sync-wizard/common/SummaryStep.tsx @@ -217,6 +217,12 @@ export const SummaryStepContent = (props: SummaryStepContentProps) => { {_.keys(metadata).map(metadataType => { + //@ts-ignore + const modelByMetadataType = api.models[metadataType]; + if (!modelByMetadataType) { + console.warn(`Metadata type "${metadataType}" not supported in d2-api`); + return null; + } const itemsByType = metadata[metadataType as keyof MetadataEntities] || []; const items = itemsByType.filter(({ id }) => !syncRule.excludedIds.includes(id)); @@ -225,8 +231,7 @@ export const SummaryStepContent = (props: SummaryStepContentProps) => { items.length > 0 && (
    {items.map(({ id, name }) => (