From ef211b6aabc9d6a5f243a98a8edd072b3f88661e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafn=20=C3=81rnason?= Date: Wed, 18 Sep 2024 13:34:33 +0000 Subject: [PATCH 01/12] feat(endorsement-system): Endorsement count column index logic (#15880) * endorsement count db and logic * model documentation * idx test * dto and disabling interceptor * dto cleanup * reinstate intercept * revert tests cleanup * fix test * cleanup * cleanup * cleanup * codegen cleanup * chore: nx format:write update dirty files * query cleanup * cleanup * removed reduntant comments * removed reduntant comments * chore: nx format:write update dirty files * cleanup * removed reduntant comments --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../20240904000001-endorsement-count.js | 30 ++++++++ .../endorsement/endorsement.service.ts | 72 +++++++++++++++---- .../dto/endorsementList.dto.ts | 13 ++-- .../endorsementList/endorsementList.model.ts | 11 +++ .../endorsementList.service.ts | 33 +-------- 5 files changed, 109 insertions(+), 50 deletions(-) create mode 100644 apps/services/endorsements/api/migrations/20240904000001-endorsement-count.js diff --git a/apps/services/endorsements/api/migrations/20240904000001-endorsement-count.js b/apps/services/endorsements/api/migrations/20240904000001-endorsement-count.js new file mode 100644 index 000000000000..98b67c2fdf1c --- /dev/null +++ b/apps/services/endorsements/api/migrations/20240904000001-endorsement-count.js @@ -0,0 +1,30 @@ +module.exports = { + up: async (queryInterface, Sequelize) => { + // Add the 'endorsement_count' column to 'endorsement_list' table + await queryInterface.addColumn('endorsement_list', 'endorsement_count', { + type: Sequelize.INTEGER, + allowNull: false, + defaultValue: 0, + }) + + // Add composite index on 'endorsement_count' and 'counter' + await queryInterface.addIndex( + 'endorsement_list', + ['endorsement_count', 'counter'], + { + name: 'idx_endorsement_count_counter', + }, + ) + }, + + down: async (queryInterface, Sequelize) => { + // Remove the composite index on 'endorsement_count' and 'counter' + await queryInterface.removeIndex( + 'endorsement_list', + 'idx_endorsement_count_counter', + ) + + // Remove the 'endorsement_count' column from 'endorsement_list' table + await queryInterface.removeColumn('endorsement_list', 'endorsement_count') + }, +} diff --git a/apps/services/endorsements/api/src/app/modules/endorsement/endorsement.service.ts b/apps/services/endorsements/api/src/app/modules/endorsement/endorsement.service.ts index d6dc2d6a2376..cafdd41e718a 100644 --- a/apps/services/endorsements/api/src/app/modules/endorsement/endorsement.service.ts +++ b/apps/services/endorsements/api/src/app/modules/endorsement/endorsement.service.ts @@ -58,6 +58,50 @@ export class EndorsementService { private readonly awsService: AwsService, ) {} + async onModuleInit() { + this.logger.info( + 'Updating endorsement counts for all lists onModuleInit...', + ) + try { + await this.updateCountsForAllLists() + } catch (error) { + this.logger.error( + 'Error updating endorsement counts for all lists', + error, + ) + } + } + + async updateCountsForAllLists(): Promise { + const allLists = await this.endorsementListModel.findAll() + for (const list of allLists) { + await this.updateEndorsementCountOnList(list.id) + } + this.logger.info('All endorsement counts have been updated.') + } + + async updateEndorsementCountOnList(listId: string): Promise { + const count = await this.endorsementModel.count({ + where: { endorsementListId: listId }, + }) + const [affectedRows, updatedList] = await this.endorsementListModel.update( + { endorsementCount: count }, + { + where: { id: listId }, + returning: true, + }, + ) + if (affectedRows > 0 && updatedList[0].endorsementCount === count) { + this.logger.info( + `Successfully updated endorsement count for list "${listId}" to ${count}`, + ) + } else { + this.logger.warn( + `Failed to update endorsement count for list "${listId}". The count was not updated correctly.`, + ) + } + } + async findEndorsements({ listId }: FindEndorsementsInput, query: any) { this.logger.info(`Finding endorsements by list id "${listId}"`) @@ -111,7 +155,6 @@ export class EndorsementService { return { hasEndorsed: true } } - // FIXME: Find a way to combine with create bulk endorsements async createEndorsementOnList({ endorsementList, nationalId, @@ -136,20 +179,20 @@ export class EndorsementService { }, } - return this.endorsementModel.create(endorsement).catch((error) => { - // map meaningful sequelize errors to custom errors, else return error - switch (error.constructor) { - case UniqueConstraintError: { - this.logger.warn('Endorsement already exists in list') - throw new MethodNotAllowedException([ - 'Endorsement already exists in list', - ]) - } - default: { - throw error - } + try { + const createdEndorsement = await this.endorsementModel.create(endorsement) + await this.updateEndorsementCountOnList(endorsementList.id) + return createdEndorsement + } catch (error) { + if (error instanceof UniqueConstraintError) { + this.logger.warn('Endorsement already exists in list') + throw new MethodNotAllowedException([ + 'Endorsement already exists in list', + ]) + } else { + throw error } - }) + } } async deleteFromListByNationalId({ @@ -182,5 +225,6 @@ export class EndorsementService { ) throw new NotFoundException(["This endorsement doesn't exist"]) } + await this.updateEndorsementCountOnList(endorsementList.id) } } diff --git a/apps/services/endorsements/api/src/app/modules/endorsementList/dto/endorsementList.dto.ts b/apps/services/endorsements/api/src/app/modules/endorsementList/dto/endorsementList.dto.ts index d48a18638142..62b11bce6178 100644 --- a/apps/services/endorsements/api/src/app/modules/endorsementList/dto/endorsementList.dto.ts +++ b/apps/services/endorsements/api/src/app/modules/endorsementList/dto/endorsementList.dto.ts @@ -40,17 +40,20 @@ export class EndorsementListDto { @IsObject() meta = {} - @ApiProperty({ type: Date }) + @ApiProperty({ type: Date, default: new Date() }) // default today @Type(() => Date) @IsDate() - closedDate!: Date + openedDate!: Date - @ApiProperty({ type: Date }) + @ApiProperty({ + type: Date, + default: new Date(new Date().setMonth(new Date().getMonth() + 1)), + }) // default month from today @Type(() => Date) @IsDate() - openedDate!: Date + closedDate!: Date - @ApiProperty({ type: Boolean }) + @ApiProperty({ type: Boolean, default: false }) @IsBoolean() adminLock!: boolean } diff --git a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts index b67a6c26c42d..82b4c591cea8 100644 --- a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts +++ b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts @@ -118,4 +118,15 @@ export class EndorsementList extends Model { }) @UpdatedAt readonly modified!: Date + + @ApiProperty({ + type: Number, + description: 'The number of endorsements in the list', + }) + @Column({ + type: DataType.INTEGER, + allowNull: false, + defaultValue: 0, + }) + endorsementCount!: number } diff --git a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts index 36a942766817..dfddba4a6e73 100644 --- a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts +++ b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts @@ -3,10 +3,9 @@ import { Injectable, NotFoundException, BadRequestException, - ForbiddenException, } from '@nestjs/common' import { InjectModel } from '@nestjs/sequelize' -import { col, Op, Sequelize } from 'sequelize' +import { Op } from 'sequelize' import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' import { EndorsementList } from './endorsementList.model' @@ -74,7 +73,6 @@ export class EndorsementListService { } } - // generic reusable query with pagination defaults async findListsGenericQuery(query: any, where: any = {}) { this.logger.info(`Finding endorsement lists`) return await paginate({ @@ -83,28 +81,8 @@ export class EndorsementListService { after: query.after, before: query.before, primaryKeyField: 'counter', - orderOption: [ - ['endorsementCounter', 'DESC'], - ['counter', 'DESC'], - ], + orderOption: [['endorsementCount', 'DESC']], where: where, - attributes: { - include: [ - [ - Sequelize.fn('COUNT', Sequelize.col('endorsements.id')), - 'endorsementCounter', - ], - ], - }, - include: [ - { - model: Endorsement, - required: false, // Required false for left outer join so that counts come for 0 as well - duplicating: false, - attributes: [], - }, - ], - group: ['EndorsementList.id'], }) } @@ -127,8 +105,6 @@ export class EndorsementListService { } async findSingleList(listId: string, user?: User, check?: boolean) { - // Check variable needed since finAll function in Endorsement controller uses this function twice - // on the second call it passes nationalID of user but does not go throught the get list pipe const isAdmin = user && check ? this.hasAdminScope(user) : false this.logger.info(`Finding single endorsement lists by id "${listId}"`) const result = await this.endorsementListModel.findOne({ @@ -259,7 +235,6 @@ export class EndorsementListService { this.logger.info(`Creating endorsement list: ${list.title}`) const endorsementList = await this.endorsementListModel.create({ ...list }) - console.log('process.env.NODE_ENV', process.env.NODE_ENV) if (process.env.NODE_ENV === 'production') { await this.emailCreated(endorsementList) } @@ -267,7 +242,6 @@ export class EndorsementListService { return endorsementList } - // generic get open lists async findOpenListsTaggedGeneralPetition(query: any) { const dateOb = new Date() try { @@ -305,9 +279,6 @@ export class EndorsementListService { } async getOwnerInfo(listId: string, owner?: string) { - // Is used by both unauthenticated users, authenticated users and admin - // Admin needs to access locked lists and can not use the EndorsementListById pipe - // Since the endpoint is not authenticated this.logger.info(`Finding single endorsement lists by id "${listId}"`) if (!owner) { const endorsementList = await this.endorsementListModel.findOne({ From c9a363ea058c78bd5601285e2600506c482bfb5b Mon Sep 17 00:00:00 2001 From: mannipje <135017126+mannipje@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:44:51 +0000 Subject: [PATCH 02/12] feat(web): Add default header for utlendingastofnun organization (#16054) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../components/Organization/Wrapper/OrganizationWrapper.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx b/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx index 3267be6545ae..904fcbad9d2a 100644 --- a/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx +++ b/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx @@ -297,7 +297,9 @@ export const OrganizationHeader: React.FC< /> ) case 'utlendingastofnun': - return ( + return n('usingDefaultHeader', false) ? ( + + ) : ( Date: Wed, 18 Sep 2024 13:55:29 +0000 Subject: [PATCH 03/12] fix(regulations-admin): Disclaimer button (#16055) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/components/EditBasics.tsx | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx b/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx index b6f79ed5fec0..6cf202cbdd87 100644 --- a/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx +++ b/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx @@ -188,16 +188,30 @@ export const EditBasics = () => { setIsModalVisible(true)} - variant="text" - size="small" + message={ + - Uppfæra - + {updateText} + + + + } /> From ab53cdcf8b74a822b88f180f8a62edfafde7134d Mon Sep 17 00:00:00 2001 From: jonarnarbriem <107482569+jonarnarbriem@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:08:18 +0000 Subject: [PATCH 04/12] chore(ids-auth-api): Change handling of alsoForDelegatedUser in createScope helper (#16046) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- ...53226-set-also-for-delegated-user-false.js | 23 +++++++++++++++++++ .../seeders/data/helpers/createScope.ts | 7 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 libs/auth-api-lib/seeders/20240917153226-set-also-for-delegated-user-false.js diff --git a/libs/auth-api-lib/seeders/20240917153226-set-also-for-delegated-user-false.js b/libs/auth-api-lib/seeders/20240917153226-set-also-for-delegated-user-false.js new file mode 100644 index 000000000000..03879f2dbbee --- /dev/null +++ b/libs/auth-api-lib/seeders/20240917153226-set-also-for-delegated-user-false.js @@ -0,0 +1,23 @@ +module.exports = { + up(queryInterface) { + return queryInterface.sequelize.query(` + BEGIN; + UPDATE api_scope + SET also_for_delegated_user = false + WHERE name = '@island.is/signature-collection' + + COMMIT; + `) + }, + + down(queryInterface) { + return queryInterface.sequelize.query(` + BEGIN; + UPDATE api_scope + SET also_for_delegated_user = true + WHERE name = '@island.is/signature-collection' + + COMMIT; + `) + }, +} diff --git a/libs/auth-api-lib/seeders/data/helpers/createScope.ts b/libs/auth-api-lib/seeders/data/helpers/createScope.ts index db4b9994ace1..a5ee6f424363 100644 --- a/libs/auth-api-lib/seeders/data/helpers/createScope.ts +++ b/libs/auth-api-lib/seeders/data/helpers/createScope.ts @@ -47,6 +47,11 @@ interface ScopeOptions { * Configures which claims the scope requires. Defaults to `nationalId`. */ claims?: Array + + /** + * Should this scope be added to the actor claim object in the access token. Defaults to false. + */ + alsoForDelegatedUser?: boolean } const getScopeFields = (options: ScopeOptions): DbScope => ({ @@ -55,7 +60,7 @@ const getScopeFields = (options: ScopeOptions): DbScope => ({ description: options.description, grant_to_legal_guardians: options.delegation?.legalGuardians === true, grant_to_procuring_holders: options.delegation?.procuringHolders === true, - also_for_delegated_user: options.delegation?.custom === true, + also_for_delegated_user: options.alsoForDelegatedUser ?? false, is_access_controlled: options.accessControlled ?? false, // The scope name should be prefixed with the organisation domain, eg `@island.is/some-scope:name`. From e3c7d87294e1246ffc529c7ae3ff9e7abaaac815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 14:41:04 +0000 Subject: [PATCH 05/12] Better types --- .../api/src/app/modules/backend/backend.service.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts index ba82a1cb9745..97d11974c577 100644 --- a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts +++ b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts @@ -16,6 +16,8 @@ import { } from '../case' import { CaseListEntry } from '../case-list' import { Defendant, DeleteDefendantResponse } from '../defendant' +import { CreateCivilClaimantInput } from '../defendant/dto/createCivilClaimant.input' +import { UpdateCivilClaimantInput } from '../defendant/dto/updateCivilClaimant.input' import { CivilClaimant } from '../defendant/models/civilClaimant.model' import { DeleteCivilClaimantResponse } from '../defendant/models/deleteCivilClaimant.response' import { CreateEventLogInput } from '../event-log' @@ -333,7 +335,7 @@ export class BackendService extends DataSource<{ req: Request }> { createCivilClaimant( caseId: string, - createCivilClaimant: unknown, + createCivilClaimant: CreateCivilClaimantInput, ): Promise { return this.post(`case/${caseId}/civilClaimant`, createCivilClaimant) } @@ -341,7 +343,7 @@ export class BackendService extends DataSource<{ req: Request }> { updateCivilClaimant( caseId: string, civilClaimantId: string, - updateCivilClaimant: unknown, + updateCivilClaimant: UpdateCivilClaimantInput, ): Promise { return this.patch( `case/${caseId}/civilClaimant/${civilClaimantId}`, From 2b95efccdf5564774817c3c802147e021ed332e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 14:43:45 +0000 Subject: [PATCH 06/12] Revert better types --- .../api/src/app/modules/backend/backend.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts index 97d11974c577..02697264e27f 100644 --- a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts +++ b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts @@ -335,7 +335,7 @@ export class BackendService extends DataSource<{ req: Request }> { createCivilClaimant( caseId: string, - createCivilClaimant: CreateCivilClaimantInput, + createCivilClaimant: unknown, ): Promise { return this.post(`case/${caseId}/civilClaimant`, createCivilClaimant) } @@ -343,7 +343,7 @@ export class BackendService extends DataSource<{ req: Request }> { updateCivilClaimant( caseId: string, civilClaimantId: string, - updateCivilClaimant: UpdateCivilClaimantInput, + updateCivilClaimant: unknown, ): Promise { return this.patch( `case/${caseId}/civilClaimant/${civilClaimantId}`, From b3f0be60a9da0bbeef03a0aff5ab59306d5081e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 14:56:29 +0000 Subject: [PATCH 07/12] Remove unused imports --- .../api/src/app/modules/backend/backend.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts index 02697264e27f..ba82a1cb9745 100644 --- a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts +++ b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts @@ -16,8 +16,6 @@ import { } from '../case' import { CaseListEntry } from '../case-list' import { Defendant, DeleteDefendantResponse } from '../defendant' -import { CreateCivilClaimantInput } from '../defendant/dto/createCivilClaimant.input' -import { UpdateCivilClaimantInput } from '../defendant/dto/updateCivilClaimant.input' import { CivilClaimant } from '../defendant/models/civilClaimant.model' import { DeleteCivilClaimantResponse } from '../defendant/models/deleteCivilClaimant.response' import { CreateEventLogInput } from '../event-log' From 7c09f211b3a9a0b56e27c32b1307c903f7364eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 14:58:42 +0000 Subject: [PATCH 08/12] Fix imports --- .../api/src/app/modules/backend/backend.service.ts | 9 ++++++--- .../api/src/app/modules/defendant/index.ts | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts index ba82a1cb9745..238f4b51de76 100644 --- a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts +++ b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts @@ -15,9 +15,12 @@ import { SignatureConfirmationResponse, } from '../case' import { CaseListEntry } from '../case-list' -import { Defendant, DeleteDefendantResponse } from '../defendant' -import { CivilClaimant } from '../defendant/models/civilClaimant.model' -import { DeleteCivilClaimantResponse } from '../defendant/models/deleteCivilClaimant.response' +import { + CivilClaimant, + Defendant, + DeleteCivilClaimantResponse, + DeleteDefendantResponse, +} from '../defendant' import { CreateEventLogInput } from '../event-log' import { CaseFile, diff --git a/apps/judicial-system/api/src/app/modules/defendant/index.ts b/apps/judicial-system/api/src/app/modules/defendant/index.ts index b6c4df49e25e..0811956a0ca8 100644 --- a/apps/judicial-system/api/src/app/modules/defendant/index.ts +++ b/apps/judicial-system/api/src/app/modules/defendant/index.ts @@ -1,2 +1,4 @@ export { Defendant } from './models/defendant.model' export { DeleteDefendantResponse } from './models/delete.response' +export { CivilClaimant } from './models/civilClaimant.model' +export { DeleteCivilClaimantResponse } from './models/deleteCivilClaimant.response' From e1b7050759deff832ef8d47cbada88de3c1e6fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 15:01:11 +0000 Subject: [PATCH 09/12] Fix imports --- .../api/src/app/modules/case/models/case.model.ts | 3 +-- .../backend/src/app/modules/case/case.service.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/case/models/case.model.ts b/apps/judicial-system/api/src/app/modules/case/models/case.model.ts index 80f811efa64b..a4e9e9778078 100644 --- a/apps/judicial-system/api/src/app/modules/case/models/case.model.ts +++ b/apps/judicial-system/api/src/app/modules/case/models/case.model.ts @@ -26,8 +26,7 @@ import { UserRole, } from '@island.is/judicial-system/types' -import { Defendant } from '../../defendant' -import { CivilClaimant } from '../../defendant/models/civilClaimant.model' +import { CivilClaimant, Defendant } from '../../defendant' import { EventLog } from '../../event-log' import { CaseFile } from '../../file' import { IndictmentCount } from '../../indictment-count' diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index c565c46de435..7f2df6274973 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -395,6 +395,7 @@ export const caseListInclude: Includeable[] = [ export const listOrder: OrderItem[] = [ [{ model: Defendant, as: 'defendants' }, 'created', 'ASC'], + [{ model: CivilClaimant, as: 'civilClaimants' }, 'created', 'ASC'], [{ model: DateLog, as: 'dateLogs' }, 'created', 'DESC'], ] From e660f329354705df02b1077e72ea6d04b8d0c6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnlaugur=20Gu=C3=B0mundsson?= <34029342+GunnlaugurG@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:01:52 +0000 Subject: [PATCH 10/12] feat(auth-admin): Delegation domain name changes (#16013) * created new admin module for paper delegations and get route * field resolver DelegationAdminModel * lookup for delegations with detailed view * Cleanup and rest and graphql for DeleteDelegation * small cleanup * chore: nx format:write update dirty files * move delegationAdmin service to admin-api from delegation-api * chore: nx format:write update dirty files * fix config value * chore: charts update dirty files * fix api build issues * fix pr comments * delegation reference id added * removed unwanted char * added comment for reference id * add unique constraint to reference_id in delegations table * allow null value in delegation.domain_namne * simplifying the migration script * fix model with simplification * remove double identifier for reference id --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- ...35625-delegation-allow-null-domain_name.js | 45 +++++++++++++++++++ .../admin/delegation-admin-custom.service.ts | 2 +- .../delegations-outgoing.service.ts | 11 ++--- .../lib/delegations/delegations.service.ts | 4 +- .../delegations/models/delegation.model.ts | 12 +++-- .../resources/delegation-resources.service.ts | 9 ++-- 6 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 libs/auth-api-lib/migrations/20240915135625-delegation-allow-null-domain_name.js diff --git a/libs/auth-api-lib/migrations/20240915135625-delegation-allow-null-domain_name.js b/libs/auth-api-lib/migrations/20240915135625-delegation-allow-null-domain_name.js new file mode 100644 index 000000000000..3465ab1090f0 --- /dev/null +++ b/libs/auth-api-lib/migrations/20240915135625-delegation-allow-null-domain_name.js @@ -0,0 +1,45 @@ +'use strict' + +module.exports = { + async up(queryInterface) { + return queryInterface.sequelize.query(` + BEGIN; + + -- 1. Drop the existing unique constraint on (domain_name, from_national_id, to_national_id) + ALTER TABLE delegation + DROP CONSTRAINT IF EXISTS unique_domain_from_to; + + -- 2. Alter the domain_name column to allow NULL and remove the default value + ALTER TABLE delegation + ALTER COLUMN domain_name DROP DEFAULT, + ALTER COLUMN domain_name DROP NOT NULL; + + -- 3. Create a new unique index to enforce uniqueness where NULL is treated as a value + CREATE UNIQUE INDEX unique_domain_from_to_index + ON delegation (COALESCE(domain_name, 'NULL'), from_national_id, to_national_id); + + COMMIT; + `) + }, + + async down(queryInterface) { + return queryInterface.sequelize.query(` + BEGIN; + + -- 1. Drop the unique index created with COALESCE + DROP INDEX IF EXISTS unique_domain_from_to_index; + + -- 2. Alter the domain_name column to make it NOT NULL again and add the default value + ALTER TABLE delegation + ALTER COLUMN domain_name SET DEFAULT '@island.is', + ALTER COLUMN domain_name SET NOT NULL; + + -- 3. Recreate the original unique constraint on (domain_name, from_national_id, to_national_id) + ALTER TABLE delegation ADD CONSTRAINT unique_domain_from_to + UNIQUE (domain_name, from_national_id, to_national_id); + + COMMIT; + + `) + }, +} diff --git a/libs/auth-api-lib/src/lib/delegations/admin/delegation-admin-custom.service.ts b/libs/auth-api-lib/src/lib/delegations/admin/delegation-admin-custom.service.ts index fd07334a8a1f..2a55384d2623 100644 --- a/libs/auth-api-lib/src/lib/delegations/admin/delegation-admin-custom.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/admin/delegation-admin-custom.service.ts @@ -106,7 +106,7 @@ export class DelegationAdminCustomService { const userScopes = await this.delegationResourceService.findScopes( user, - delegation.domainName, + delegation.domainName ?? null, ) await this.sequelize.transaction(async (transaction) => { diff --git a/libs/auth-api-lib/src/lib/delegations/delegations-outgoing.service.ts b/libs/auth-api-lib/src/lib/delegations/delegations-outgoing.service.ts index 2086a3a55ee8..ab615439e5fb 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegations-outgoing.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegations-outgoing.service.ts @@ -11,10 +11,7 @@ import { isUuid, uuid } from 'uuidv4' import { User } from '@island.is/auth-nest-tools' import { NoContentException } from '@island.is/nest/problem' -import { - NotificationsApi, - UserSystemNotificationModule, -} from '../user-notification' +import { NotificationsApi } from '../user-notification' import { ApiScope } from '../resources/models/api-scope.model' import { DelegationScopeService } from './delegation-scope.service' @@ -345,7 +342,7 @@ export class DelegationsOutgoingService { if ( !(await this.delegationResourceService.validateScopeAccess( user, - currentDelegation.domainName, + currentDelegation.domainName ?? null, DelegationDirection.OUTGOING, [ ...(patchedDelegation.updateScopes ?? []).map((scope) => scope.name), @@ -406,7 +403,7 @@ export class DelegationsOutgoingService { const userScopes = await this.delegationResourceService.findScopes( user, - delegation.domainName, + delegation.domainName ?? null, ) await this.delegationScopeService.delete( delegationId, @@ -460,7 +457,7 @@ export class DelegationsOutgoingService { // Verify and filter scopes. const userScopes = await this.delegationResourceService.findScopeNames( user, - delegation.domainName, + delegation.domainName ?? null, direction, ) if (!userScopes.length) { diff --git a/libs/auth-api-lib/src/lib/delegations/delegations.service.ts b/libs/auth-api-lib/src/lib/delegations/delegations.service.ts index e19a0cfb370a..593cbb1b6e79 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegations.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegations.service.ts @@ -136,7 +136,7 @@ export class DelegationsService { const allowedScopes = await this.delegationResourcesService.findScopeNames( user, - delegation.domainName, + delegation.domainName ?? null, direction, ) // If the user doesn't have any allowed scope in the delegation domain we return null @@ -156,6 +156,7 @@ export class DelegationsService { * if direction is incoming is then all delegation scopes will be deleted else only user scopes * @param user User object of the authenticated user. * @param id Id of the delegation to delete + * @param direction Direction of the delegation: incoming or outgoing * @returns */ async delete( @@ -199,6 +200,7 @@ export class DelegationsService { /** * Deprecated: Use DelegationsIncomingService instead for incoming delegations. */ + /***** Incoming Delegations *****/ /** diff --git a/libs/auth-api-lib/src/lib/delegations/models/delegation.model.ts b/libs/auth-api-lib/src/lib/delegations/models/delegation.model.ts index 063ec5bbb448..fcb192dc7010 100644 --- a/libs/auth-api-lib/src/lib/delegations/models/delegation.model.ts +++ b/libs/auth-api-lib/src/lib/delegations/models/delegation.model.ts @@ -16,7 +16,6 @@ import { Table, UpdatedAt, } from 'sequelize-typescript' -import { DEFAULT_DOMAIN } from '../../types' import { DelegationDTO } from '../dto/delegation.dto' import { DelegationScope } from './delegation-scope.model' import { Domain } from '../../resources/models/domain.model' @@ -29,6 +28,12 @@ import { @Table({ tableName: 'delegation', timestamps: false, + indexes: [ + { + unique: true, + fields: ['domain_name', 'from_national_id', 'to_national_id'], + }, + ], }) export class Delegation extends Model< InferAttributes, @@ -74,11 +79,10 @@ export class Delegation extends Model< @Column({ type: DataType.STRING, - allowNull: false, - defaultValue: DEFAULT_DOMAIN, + allowNull: true, }) @ForeignKey(() => Domain) - domainName!: CreationOptional + domainName?: string /** * ReferenceId is a field for storing a reference to the zendesk ticket id diff --git a/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts b/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts index 3d55ad687b89..3f5b80d434dd 100644 --- a/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts +++ b/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts @@ -25,6 +25,7 @@ import { mapToScopeTree } from './utils/scope-tree.mapper' import type { Attributes, WhereOptions } from 'sequelize' import type { ConfigType } from '@island.is/nest/config' + type DelegationConfigType = ConfigType type ScopeRule = DelegationConfigType['customScopeRules'] extends Array< infer ScopeRule @@ -135,7 +136,7 @@ export class DelegationResourcesService { async findScopes( user: User, - domainName: string, + domainName: string | null, language?: string, direction?: DelegationDirection, ): Promise { @@ -166,7 +167,7 @@ export class DelegationResourcesService { async findScopeNames( user: User, - domainName: string, + domainName: string | null, direction?: DelegationDirection, ) { const scopes = await this.findScopesInternal({ @@ -180,7 +181,7 @@ export class DelegationResourcesService { async validateScopeAccess( user: User, - domainName: string, + domainName: string | null, direction: DelegationDirection, scopesToCheck: Array, ): Promise { @@ -236,7 +237,7 @@ export class DelegationResourcesService { attributes, }: { user: User - domainName: string + domainName: string | null language?: string direction?: DelegationDirection attributes?: Array> From 3abd5207e82994166818afd6f822dd876ca896c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 15:04:34 +0000 Subject: [PATCH 11/12] Fix imports --- .../backend/src/app/modules/case/case.service.ts | 3 +-- .../judicial-system/backend/src/app/modules/defendant/index.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index 7f2df6274973..d60f67175c3a 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -55,8 +55,7 @@ import { } from '../../formatters' import { AwsS3Service } from '../aws-s3' import { CourtService } from '../court' -import { Defendant, DefendantService } from '../defendant' -import { CivilClaimant } from '../defendant/models/civilClaimant.model' +import { CivilClaimant, Defendant, DefendantService } from '../defendant' import { EventService } from '../event' import { EventLog, EventLogService } from '../event-log' import { CaseFile, FileService } from '../file' diff --git a/apps/judicial-system/backend/src/app/modules/defendant/index.ts b/apps/judicial-system/backend/src/app/modules/defendant/index.ts index ee604a0d6779..3839cdb96469 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/index.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/index.ts @@ -1,2 +1,3 @@ export { Defendant } from './models/defendant.model' export { DefendantService } from './defendant.service' +export { CivilClaimant } from './models/civilClaimant.model' From 8a21663d5229626b1511debf1c6ef69ef4008d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 18 Sep 2024 15:05:09 +0000 Subject: [PATCH 12/12] Fix imports --- .../backend/src/app/modules/case/models/case.model.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts b/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts index 3a163ee3a339..96f58bc55d26 100644 --- a/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts +++ b/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts @@ -37,8 +37,7 @@ import { UserRole, } from '@island.is/judicial-system/types' -import { Defendant } from '../../defendant' -import { CivilClaimant } from '../../defendant/models/civilClaimant.model' +import { CivilClaimant, Defendant } from '../../defendant' import { EventLog } from '../../event-log' import { CaseFile } from '../../file' import { IndictmentCount } from '../../indictment-count'