From 3abab91c78770fd4198913286a451cf81865dcef Mon Sep 17 00:00:00 2001 From: yulia-bel Date: Thu, 5 Oct 2023 13:37:06 +0200 Subject: [PATCH] Update cost surfaces piece exporter + format fixes --- .../cost-surface/cost-surface.service.ts | 12 +++--- .../project-cost-surface.controller.ts | 3 +- .../project-cost-surfaces.piece-exporter.ts | 26 +++++++------ .../test/integration/cloning/fixtures.ts | 12 +++--- ...ct-cost-surface.piece-exporter.e2e-spec.ts | 37 ++++++++++--------- ...ct-cost-surface.piece-importer.e2e-spec.ts | 26 ++++++------- .../cost-surface/cleanup.fixtures.ts | 9 ++++- 7 files changed, 67 insertions(+), 58 deletions(-) diff --git a/api/apps/api/src/modules/cost-surface/cost-surface.service.ts b/api/apps/api/src/modules/cost-surface/cost-surface.service.ts index 4e31a0ba6a..fafbe7dad3 100644 --- a/api/apps/api/src/modules/cost-surface/cost-surface.service.ts +++ b/api/apps/api/src/modules/cost-surface/cost-surface.service.ts @@ -4,7 +4,10 @@ import { CostSurface } from '@marxan-api/modules/cost-surface/cost-surface.api.e import { Repository } from 'typeorm'; import { ProjectAclService } from '@marxan-api/modules/access-control/projects-acl/project-acl.service'; import { Either, left, right } from 'fp-ts/lib/Either'; -import { projectNotEditable, projectNotVisible } from "@marxan-api/modules/projects/projects.service"; +import { + projectNotEditable, + projectNotVisible, +} from '@marxan-api/modules/projects/projects.service'; import { UploadCostSurfaceShapefileDto } from '@marxan-api/modules/cost-surface/dto/upload-cost-surface-shapefile.dto'; import { UpdateCostSurfaceDto } from '@marxan-api/modules/cost-surface/dto/update-cost-surface.dto'; import { CostSurfaceCalculationPort } from '@marxan-api/modules/cost-surface/ports/project/cost-surface-calculation.port'; @@ -149,12 +152,7 @@ export class CostSurfaceService { CostRange > > { - if ( - !(await this.projectAclService.canViewProject( - userId, - projectId, - )) - ) { + if (!(await this.projectAclService.canViewProject(userId, projectId))) { return left(projectNotVisible); } const costRange = await this.costSurfaceRepository.findOne({ diff --git a/api/apps/api/src/modules/projects/project-cost-surface.controller.ts b/api/apps/api/src/modules/projects/project-cost-surface.controller.ts index 182a63ca97..eb9b70cee4 100644 --- a/api/apps/api/src/modules/projects/project-cost-surface.controller.ts +++ b/api/apps/api/src/modules/projects/project-cost-surface.controller.ts @@ -133,7 +133,8 @@ export class ProjectCostSurfaceController { @UseGuards(JwtAuthGuard) @ApiParam({ name: 'costSurfaceId', - description: 'The id of the Cost Surface for which to retrieve [min,max] cost range', + description: + 'The id of the Cost Surface for which to retrieve [min,max] cost range', }) @ApiParam({ name: 'projectId', diff --git a/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts b/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts index 5f62748979..95c2ed19e9 100644 --- a/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts +++ b/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts @@ -68,18 +68,22 @@ export class ProjectCostSurfacesPieceExporter implements ExportPieceProcessor { const costSurfacesIds = costSurfaces.map((costSurface) => costSurface.id); let costSurfaceData: CostSurfaceDataSelectResult[] = []; let projectPusMap: Record = {}; - if (costSurfacesIds.length > 0) { - costSurfaceData = await this.geoprocessingEntityManager - .createQueryBuilder() - .select(['cost_surface_id', 'cost', 'projects_pu_id']) - .from('cost_surface_pu_data', 'scpd') - .where('cost_surface_id IN (:...costSurfacesIds)', { - costSurfacesIds, - }) - .execute(); - - projectPusMap = await this.getProjectPusMap(input.resourceId); + + if (!costSurfacesIds) { + const errorMessage = `${ProjectCostSurfacesPieceExporter.name} - Project Cost Surfaces - couldn't find cost surfaces for project ${input.resourceId}`; + this.logger.error(errorMessage); + throw new Error(errorMessage); } + costSurfaceData = await this.geoprocessingEntityManager + .createQueryBuilder() + .select(['cost_surface_id', 'cost', 'projects_pu_id']) + .from('cost_surface_pu_data', 'scpd') + .where('cost_surface_id IN (:...costSurfacesIds)', { + costSurfacesIds, + }) + .execute(); + + projectPusMap = await this.getProjectPusMap(input.resourceId); const fileContent: ProjectCostSurfacesContent = { costSurfaces: costSurfaces.map(({ id, ...costSurface }) => ({ diff --git a/api/apps/geoprocessing/test/integration/cloning/fixtures.ts b/api/apps/geoprocessing/test/integration/cloning/fixtures.ts index 603bea1377..e121d4da71 100644 --- a/api/apps/geoprocessing/test/integration/cloning/fixtures.ts +++ b/api/apps/geoprocessing/test/integration/cloning/fixtures.ts @@ -22,7 +22,7 @@ import { Readable, Transform } from 'stream'; import { DeepPartial, EntityManager, In } from 'typeorm'; import { v4 } from 'uuid'; import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import { CostSurfacePuDataEntity } from "@marxan/cost-surfaces"; +import { CostSurfacePuDataEntity } from '@marxan/cost-surfaces'; export type TestSpecification = { id: string; @@ -604,8 +604,12 @@ export async function GivenCostSurfaces( projectId: string, ) { const costSurface = Array({ - id: v4(), min, max, name, project_id: projectId, - }) + id: v4(), + min, + max, + name, + project_id: projectId, + }); await Promise.all( costSurface.map((values) => @@ -626,14 +630,12 @@ export async function GivenCostSurfaceData( projectId: string, costSurfaceId: string, ): Promise<{ id: string; hash: string; feature_id: string }[]> { - const projectPus = await GivenProjectPus(em, projectId, 10); const insertValues = projectPus.map((pu, index) => ({ id: v4(), costSurfaceId: costSurfaceId, projectsPuId: pu.id, cost: index + 1, - })); const result = await em diff --git a/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts b/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts index bcdb59cf79..4cb26bcfee 100644 --- a/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts +++ b/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts @@ -12,19 +12,19 @@ import { Readable } from 'stream'; import { EntityManager, In } from 'typeorm'; import { v4 } from 'uuid'; import { - DeleteProjectAndOrganization, GivenCostSurfaceData, GivenCostSurfaces, + DeleteProjectAndOrganization, + GivenCostSurfaceData, + GivenCostSurfaces, GivenFeatures, GivenFeaturesData, GivenProjectExists, - readSavedFile -} from "../fixtures"; + readSavedFile, +} from '../fixtures'; import { GeoCloningFilesRepositoryModule } from '@marxan-geoprocessing/modules/cloning-files-repository'; import { FakeLogger } from '@marxan-geoprocessing/utils/__mocks__/fake-logger'; -import { - ProjectCostSurfacesPieceExporter -} from "@marxan-geoprocessing/export/pieces-exporters/project-cost-surfaces.piece-exporter"; -import { CostSurfacePuDataEntity } from "@marxan/cost-surfaces"; -import { ProjectCostSurfacesContent } from "@marxan/cloning/infrastructure/clone-piece-data/project-cost-surfaces"; +import { ProjectCostSurfacesPieceExporter } from '@marxan-geoprocessing/export/pieces-exporters/project-cost-surfaces.piece-exporter'; +import { CostSurfacePuDataEntity } from '@marxan/cost-surfaces'; +import { ProjectCostSurfacesContent } from '@marxan/cloning/infrastructure/clone-piece-data/project-cost-surfaces'; let fixtures: FixtureType; @@ -78,10 +78,11 @@ const getFixtures = async () => { const geoEntityManager: EntityManager = sandbox.get( getEntityManagerToken(geoprocessingConnections.default), ); - const costSurfacesDataRepo = geoEntityManager.getRepository(CostSurfacePuDataEntity); + const costSurfacesDataRepo = geoEntityManager.getRepository( + CostSurfacePuDataEntity, + ); const fileRepository = sandbox.get(CloningFilesRepository); - return { cleanUp: async () => { await DeleteProjectAndOrganization( @@ -90,7 +91,6 @@ const getFixtures = async () => { organizationId, ); await costSurfacesDataRepo.delete({}); - }, GivenAProjectCostSurfacesExportJob: (): ExportJobInput => { return { @@ -114,14 +114,13 @@ const getFixtures = async () => { GivenCostSurfacesForProject: async () => { const costSurface = await GivenCostSurfaces( apiEntityManager, - 1, 10, 'Cost Surface', projectId - ); - - await GivenCostSurfaceData( - geoEntityManager, + 1, + 10, + 'Cost Surface', projectId, - costSurface.id, ); + + await GivenCostSurfaceData(geoEntityManager, projectId, costSurface.id); return costSurface.id; }, GivenTagOnFeature: async (featureId: string, tag: string) => @@ -144,7 +143,9 @@ const getFixtures = async () => { expect(content.costSurfaces).toHaveLength(2); const costSurfacesExported = content.costSurfaces; - const nonDefaultCostSurface = costSurfacesExported.find((costSurface) => costSurface.name === 'Cost Surface') + const nonDefaultCostSurface = costSurfacesExported.find( + (costSurface) => costSurface.name === 'Cost Surface', + ); expect(nonDefaultCostSurface).toBeDefined(); expect(nonDefaultCostSurface?.data).toHaveLength(10); }, diff --git a/api/apps/geoprocessing/test/integration/cloning/piece-importers/project-cost-surface.piece-importer.e2e-spec.ts b/api/apps/geoprocessing/test/integration/cloning/piece-importers/project-cost-surface.piece-importer.e2e-spec.ts index 18cac0a505..23a437fc1e 100644 --- a/api/apps/geoprocessing/test/integration/cloning/piece-importers/project-cost-surface.piece-importer.e2e-spec.ts +++ b/api/apps/geoprocessing/test/integration/cloning/piece-importers/project-cost-surface.piece-importer.e2e-spec.ts @@ -21,18 +21,15 @@ import { v4 } from 'uuid'; import { DeleteProjectAndOrganization, GenerateRandomGeometries, - GivenProjectExists, GivenProjectPus -} from "../fixtures"; + GivenProjectExists, + GivenProjectPus, +} from '../fixtures'; import { GeoCloningFilesRepositoryModule } from '@marxan-geoprocessing/modules/cloning-files-repository'; import { FakeLogger } from '@marxan-geoprocessing/utils/__mocks__/fake-logger'; -import { - ProjectCostSurfacesPieceImporter -} from "@marxan-geoprocessing/import/pieces-importers/project-cost-surfaces.piece-importer"; -import { ProjectCostSurfacesContent } from "@marxan/cloning/infrastructure/clone-piece-data/project-cost-surfaces"; -import { CostSurfacePuDataEntity } from "@marxan/cost-surfaces"; -import { - ProjectCostSurfacesPieceExporter -} from "@marxan-geoprocessing/export/pieces-exporters/project-cost-surfaces.piece-exporter"; +import { ProjectCostSurfacesPieceImporter } from '@marxan-geoprocessing/import/pieces-importers/project-cost-surfaces.piece-importer'; +import { ProjectCostSurfacesContent } from '@marxan/cloning/infrastructure/clone-piece-data/project-cost-surfaces'; +import { CostSurfacePuDataEntity } from '@marxan/cost-surfaces'; +import { ProjectCostSurfacesPieceExporter } from '@marxan-geoprocessing/export/pieces-exporters/project-cost-surfaces.piece-exporter'; let fixtures: FixtureType; @@ -138,8 +135,7 @@ const getFixtures = async () => { }, GivenProject: () => GivenProjectExists(apiEntityManager, projectId, organizationId), - GivenProjectPus: () => - GivenProjectPus(geoEntityManager, projectId, 3), + GivenProjectPus: () => GivenProjectPus(geoEntityManager, projectId, 3), GivenJobInput: (archiveLocation: ArchiveLocation): ImportJobInput => { const relativePath = ClonePieceRelativePathResolver.resolveFor( ClonePiece.ProjectCostSurfaces, @@ -178,7 +174,8 @@ const getFixtures = async () => { ); validProjectCostSurfacesFile = { - costSurfaces: [{ + costSurfaces: [ + { name: 'Cost Surface', min: 1, max: 10, @@ -188,7 +185,8 @@ const getFixtures = async () => { cost: dataIndex * 2, puid: dataIndex + 1, })), - }], + }, + ], }; const exportId = v4(); diff --git a/api/apps/geoprocessing/test/integration/cost-surface/cleanup.fixtures.ts b/api/apps/geoprocessing/test/integration/cost-surface/cleanup.fixtures.ts index c008ce86af..a02e2f121e 100644 --- a/api/apps/geoprocessing/test/integration/cost-surface/cleanup.fixtures.ts +++ b/api/apps/geoprocessing/test/integration/cost-surface/cleanup.fixtures.ts @@ -106,9 +106,14 @@ export const getFixtures = async (app: INestApplication) => { }, cleanup: async () => { - await geoEntityManager.query(`DELETE FROM cost_surface_pu_data WHERE cost_surface_id = $1`, [costSurfaceId]); + await geoEntityManager.query( + `DELETE FROM cost_surface_pu_data WHERE cost_surface_id = $1`, + [costSurfaceId], + ); await geoEntityManager.query(`DELETE FROM projects_pu`); - await apiEntityManager.query(`DELETE FROM cost_surfaces WHERE id = $1`, [costSurfaceId]); + await apiEntityManager.query(`DELETE FROM cost_surfaces WHERE id = $1`, [ + costSurfaceId, + ]); await apiEntityManager.query(`DELETE FROM projects`); await apiEntityManager.query(`DELETE FROM organizations`); },