diff --git a/api/src/modules/admin-regions/admin-regions.controller.ts b/api/src/modules/admin-regions/admin-regions.controller.ts index 45850e172c..031331bdca 100644 --- a/api/src/modules/admin-regions/admin-regions.controller.ts +++ b/api/src/modules/admin-regions/admin-regions.controller.ts @@ -114,7 +114,7 @@ export class AdminRegionsController { async getTreesForEudr( @Query(ValidationPipe) adminRegionTreeOptions: GetEUDRAdminRegions, - ): Promise { + ): Promise { const results: AdminRegion[] = await this.adminRegionsService.getTrees({ ...adminRegionTreeOptions, withSourcingLocations: true, diff --git a/api/src/modules/geo-regions/dto/get-geo-region.dto.ts b/api/src/modules/geo-regions/dto/get-geo-region.dto.ts new file mode 100644 index 0000000000..4015827381 --- /dev/null +++ b/api/src/modules/geo-regions/dto/get-geo-region.dto.ts @@ -0,0 +1,5 @@ +import { CommonEUDRFiltersDTO } from 'utils/base.query-builder'; + +export class GetEUDRGeoRegions extends CommonEUDRFiltersDTO { + withSourcingLocations!: boolean; +} diff --git a/api/src/modules/geo-regions/geo-region.entity.ts b/api/src/modules/geo-regions/geo-region.entity.ts index 04f873f7e3..7c05a4961f 100644 --- a/api/src/modules/geo-regions/geo-region.entity.ts +++ b/api/src/modules/geo-regions/geo-region.entity.ts @@ -49,6 +49,8 @@ export class GeoRegion extends BaseEntity { @ApiPropertyOptional() theGeom?: JSON; + // TODO: It might be interesting to add a trigger to calculate the value in case it's not provided. We are considering that EUDR will alwaus provide the value + // but not the regular ingestion @Column({ type: 'decimal', nullable: true }) totalArea?: number; diff --git a/api/src/modules/geo-regions/geo-region.repository.ts b/api/src/modules/geo-regions/geo-region.repository.ts index d2ff1049da..d927c1e9d4 100644 --- a/api/src/modules/geo-regions/geo-region.repository.ts +++ b/api/src/modules/geo-regions/geo-region.repository.ts @@ -7,6 +7,11 @@ import { import { GeoRegion } from 'modules/geo-regions/geo-region.entity'; import { LocationGeoRegionDto } from 'modules/geo-regions/dto/location.geo-region.dto'; import { Injectable } from '@nestjs/common'; +import { GetAdminRegionTreeWithOptionsDto } from '../admin-regions/dto/get-admin-region-tree-with-options.dto'; +import { AdminRegion } from '../admin-regions/admin-region.entity'; +import { SourcingLocation } from '../sourcing-locations/sourcing-location.entity'; +import { BaseQueryBuilder } from '../../utils/base.query-builder'; +import { GetEUDRGeoRegions } from './dto/get-geo-region.dto'; @Injectable() export class GeoRegionRepository extends Repository { @@ -128,4 +133,17 @@ export class GeoRegionRepository extends Repository { ], ); } + + async getGeoRegionsFromSourcingLocations( + getGeoRegionsDto: GetEUDRGeoRegions, + ): Promise { + const initialQueryBuilder: SelectQueryBuilder = + this.createQueryBuilder('gr') + .innerJoin(SourcingLocation, 'sl', 'sl.geoRegionId = gr.id') + .distinct(true); + const queryBuilder: SelectQueryBuilder = + BaseQueryBuilder.addFilters(initialQueryBuilder, getGeoRegionsDto); + + return queryBuilder.getMany(); + } } diff --git a/api/src/modules/geo-regions/geo-regions.controller.ts b/api/src/modules/geo-regions/geo-regions.controller.ts index 48937c8e69..e91dd228e4 100644 --- a/api/src/modules/geo-regions/geo-regions.controller.ts +++ b/api/src/modules/geo-regions/geo-regions.controller.ts @@ -6,6 +6,7 @@ import { Param, Patch, Post, + Query, UsePipes, ValidationPipe, } from '@nestjs/common'; @@ -35,6 +36,7 @@ import { import { CreateGeoRegionDto } from 'modules/geo-regions/dto/create.geo-region.dto'; import { UpdateGeoRegionDto } from 'modules/geo-regions/dto/update.geo-region.dto'; import { PaginationMeta } from 'utils/app-base.service'; +import { GetEUDRGeoRegions } from './dto/get-geo-region.dto'; @Controller(`/api/v1/geo-regions`) @ApiTags(geoRegionResource.className) @@ -71,6 +73,32 @@ export class GeoRegionsController { return this.geoRegionsService.serialize(results.data, results.metadata); } + @ApiOperation({ + description: 'Find all EUDR geo regions', + }) + @ApiOkResponse({ + type: GeoRegion, + isArray: true, + }) + @ApiUnauthorizedResponse() + @ApiForbiddenResponse() + @JSONAPIQueryParams({ + availableFilters: geoRegionResource.columnsAllowedAsFilter.map( + (columnName: string) => ({ + name: columnName, + }), + ), + }) + @Get('/eudr') + async findAllEudr( + @Query(ValidationPipe) + dto: GetEUDRGeoRegions, + ): Promise { + const results: GeoRegion[] = + await this.geoRegionsService.getGeoRegionsFromSourcingLocations(dto); + return this.geoRegionsService.serialize(results); + } + @ApiOperation({ description: 'Find geo region by id' }) @ApiOkResponse({ type: GeoRegion }) @ApiNotFoundResponse({ description: 'Geo region not found' }) diff --git a/api/src/modules/geo-regions/geo-regions.module.ts b/api/src/modules/geo-regions/geo-regions.module.ts index 6bcd35a666..4bacd115ec 100644 --- a/api/src/modules/geo-regions/geo-regions.module.ts +++ b/api/src/modules/geo-regions/geo-regions.module.ts @@ -4,9 +4,17 @@ import { GeoRegionsController } from 'modules/geo-regions/geo-regions.controller import { GeoRegionsService } from 'modules/geo-regions/geo-regions.service'; import { GeoRegion } from 'modules/geo-regions/geo-region.entity'; import { GeoRegionRepository } from 'modules/geo-regions/geo-region.repository'; +import { AdminRegionsModule } from 'modules/admin-regions/admin-regions.module'; +import { MaterialsModule } from 'modules/materials/materials.module'; +import { SuppliersModule } from 'modules/suppliers/suppliers.module'; @Module({ - imports: [TypeOrmModule.forFeature([GeoRegion])], + imports: [ + TypeOrmModule.forFeature([GeoRegion]), + AdminRegionsModule, + MaterialsModule, + SuppliersModule, + ], controllers: [GeoRegionsController], providers: [GeoRegionsService, GeoRegionRepository], exports: [GeoRegionsService, GeoRegionRepository], diff --git a/api/src/modules/geo-regions/geo-regions.service.ts b/api/src/modules/geo-regions/geo-regions.service.ts index 624f96ea8b..7f3cc6c403 100644 --- a/api/src/modules/geo-regions/geo-regions.service.ts +++ b/api/src/modules/geo-regions/geo-regions.service.ts @@ -12,6 +12,12 @@ import { GeoRegionRepository } from 'modules/geo-regions/geo-region.repository'; import { CreateGeoRegionDto } from 'modules/geo-regions/dto/create.geo-region.dto'; import { UpdateGeoRegionDto } from 'modules/geo-regions/dto/update.geo-region.dto'; import { LocationGeoRegionDto } from 'modules/geo-regions/dto/location.geo-region.dto'; +import { GetSupplierByType } from '../suppliers/dto/get-supplier-by-type.dto'; +import { Supplier } from '../suppliers/supplier.entity'; +import { AdminRegionsService } from 'modules/admin-regions/admin-regions.service'; +import { MaterialsService } from 'modules/materials/materials.service'; +import { SupplierRepository } from 'modules/suppliers/supplier.repository'; +import { GetEUDRGeoRegions } from './dto/get-geo-region.dto'; @Injectable() export class GeoRegionsService extends AppBaseService< @@ -20,7 +26,11 @@ export class GeoRegionsService extends AppBaseService< UpdateGeoRegionDto, AppInfoDTO > { - constructor(protected readonly geoRegionRepository: GeoRegionRepository) { + constructor( + protected readonly geoRegionRepository: GeoRegionRepository, + private readonly adminRegionService: AdminRegionsService, + private readonly materialsService: MaterialsService, + ) { super( geoRegionRepository, geoRegionResource.name.singular, @@ -87,4 +97,22 @@ export class GeoRegionsService extends AppBaseService< async deleteGeoRegionsCreatedByUser(): Promise { await this.geoRegionRepository.delete({ isCreatedByUser: true }); } + + async getGeoRegionsFromSourcingLocations( + options: GetEUDRGeoRegions, + ): Promise { + if (options.originIds) { + options.originIds = + await this.adminRegionService.getAdminRegionDescendants( + options.originIds, + ); + } + if (options.materialIds) { + options.materialIds = await this.materialsService.getMaterialsDescendants( + options.materialIds, + ); + } + + return this.geoRegionRepository.getGeoRegionsFromSourcingLocations(options); + } } diff --git a/api/src/modules/suppliers/suppliers.service.ts b/api/src/modules/suppliers/suppliers.service.ts index 8f4edc7b5e..359eaea218 100644 --- a/api/src/modules/suppliers/suppliers.service.ts +++ b/api/src/modules/suppliers/suppliers.service.ts @@ -134,18 +134,10 @@ export class SuppliersService extends AppBaseService< await this.supplierRepository.delete({}); } - async getSuppliersByIds(ids: string[]): Promise { - return this.supplierRepository.findByIds(ids); - } - async findTreesWithOptions(depth?: number): Promise { return this.supplierRepository.findTrees({ depth }); } - async findAllUnpaginated(): Promise { - return this.supplierRepository.find({}); - } - /** * * @description Get a tree of Suppliers that are associated with sourcing locations diff --git a/infrastructure/base/modules/aws/eks/thumbprint.sh b/infrastructure/base/modules/aws/eks/thumbprint.sh index 9f565c53ca..10772d9136 100755 --- a/infrastructure/base/modules/aws/eks/thumbprint.sh +++ b/infrastructure/base/modules/aws/eks/thumbprint.sh @@ -1,5 +1,5 @@ #!/bin/bash -THUMBPRINT=$(echo | openssl s_client -servername oidc.eks.${1}.amazonaws.com -showcerts -connect oidc.eks.${1}.amazonaws.com:443 2>&- | tail -r | sed -n '/-----END CERTIFICATE-----/,/-----BEGIN CERTIFICATE-----/p; /-----BEGIN CERTIFICATE-----/q' | tail -r | openssl x509 -fingerprint -noout | sed 's/://g' | awk -F= '{print tolower($2)}') +THUMBPRINT=$(echo | openssl s_client -servername oidc.eks.${1}.amazonaws.com -showcerts -connect oidc.eks.${1}.amazonaws.com:443 2>&- | tac | sed -n '/-----END CERTIFICATE-----/,/-----BEGIN CERTIFICATE-----/p; /-----BEGIN CERTIFICATE-----/q' | tac | openssl x509 -fingerprint -noout | sed 's/://g' | awk -F= '{print tolower($2)}') THUMBPRINT_JSON="{\"thumbprint\": \"${THUMBPRINT}\"}" echo $THUMBPRINT_JSON