From 6f4ab1cf9d1289594d66d4f8e98cb4e3c77a6d92 Mon Sep 17 00:00:00 2001 From: Haukur Ingi Date: Wed, 18 Sep 2024 13:17:10 +0000 Subject: [PATCH 1/6] support adding constituancies for parliamentary collection --- .../src/lib/dto/addLists.input.ts | 14 +++ .../src/lib/guards/userAccess.guard.ts | 4 + .../src/lib/signatureCollection.resolver.ts | 12 +++ .../src/lib/signatureCollection.service.ts | 12 +++ .../src/clientConfig.json | 17 ++++ .../src/lib/signature-collection.service.ts | 94 +++++++++++++++++-- .../src/lib/signature-collection.types.ts | 8 ++ 7 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts diff --git a/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts b/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts new file mode 100644 index 000000000000..f33663d089b5 --- /dev/null +++ b/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts @@ -0,0 +1,14 @@ +import { IsArray, IsString } from 'class-validator' +import { Field, InputType } from '@nestjs/graphql' +import { SignatureCollectionIdInput } from './collectionId.input' + +@InputType() +export class SignatureCollectionAddListsInput extends SignatureCollectionIdInput { + @Field() + @IsString() + candidateId!: string + + @Field(() => [String], { nullable: false, defaultValue: [] }) + @IsArray() + areaIds?: string[] +} diff --git a/libs/api/domains/signature-collection/src/lib/guards/userAccess.guard.ts b/libs/api/domains/signature-collection/src/lib/guards/userAccess.guard.ts index 9f90138ae2cb..b3fbfa65c404 100644 --- a/libs/api/domains/signature-collection/src/lib/guards/userAccess.guard.ts +++ b/libs/api/domains/signature-collection/src/lib/guards/userAccess.guard.ts @@ -6,6 +6,7 @@ import { UserAccess, } from '../decorators/acessRequirement.decorator' import { SignatureCollectionService } from '../signatureCollection.service' +import { AuthDelegationType } from '@island.is/shared/types' @Injectable() export class UserAccessGuard implements CanActivate { @@ -34,6 +35,9 @@ export class UserAccessGuard implements CanActivate { return false } const isDelegatedUser = !!user?.actor?.nationalId + const isProcurationHolder = user?.delegationType?.some( + (delegation) => delegation === AuthDelegationType.ProcurationHolder, + ) // IsOwner needs signee const signee = await this.signatureCollectionService.signee(user) request.body = { ...request.body, signee } diff --git a/libs/api/domains/signature-collection/src/lib/signatureCollection.resolver.ts b/libs/api/domains/signature-collection/src/lib/signatureCollection.resolver.ts index c42a6dca9688..2b5b5a9c26f1 100644 --- a/libs/api/domains/signature-collection/src/lib/signatureCollection.resolver.ts +++ b/libs/api/domains/signature-collection/src/lib/signatureCollection.resolver.ts @@ -30,6 +30,7 @@ import { CurrentSignee } from './decorators/signee.decorator' import { ApiScope } from '@island.is/auth/scopes' import { SignatureCollectionCancelListsInput } from './dto/cencelLists.input' import { SignatureCollectionIdInput } from './dto/collectionId.input' +import { SignatureCollectionAddListsInput } from './dto/addLists.input' @UseGuards(IdsUserGuard, ScopesGuard, UserAccessGuard) @Resolver() @Audit({ namespace: '@island.is/api/signature-collection' }) @@ -146,4 +147,15 @@ export class SignatureCollectionResolver { ): Promise { return this.signatureCollectionService.cancel(input, user) } + + @Scopes(ApiScope.signatureCollection) + @AccessRequirement(OwnerAccess.RestrictActor) + @Mutation(() => SignatureCollectionSuccess) + @Audit() + async signatureCollectionAddAreas( + @CurrentUser() user: User, + @Args('input') input: SignatureCollectionAddListsInput, + ): Promise { + return this.signatureCollectionService.add(input, user) + } } diff --git a/libs/api/domains/signature-collection/src/lib/signatureCollection.service.ts b/libs/api/domains/signature-collection/src/lib/signatureCollection.service.ts index 69235ab49c01..6478b66b7981 100644 --- a/libs/api/domains/signature-collection/src/lib/signatureCollection.service.ts +++ b/libs/api/domains/signature-collection/src/lib/signatureCollection.service.ts @@ -14,6 +14,8 @@ import { import { User } from '@island.is/auth-nest-tools' import { SignatureCollectionCancelListsInput } from './dto/cencelLists.input' import { SignatureCollectionIdInput } from './dto/collectionId.input' +import { SignatureCollectionAddListsInput } from './dto/addLists.input' +import { SignatureCollectionOwnerInput } from './dto/owner.input' @Injectable() export class SignatureCollectionService { @@ -118,4 +120,14 @@ export class SignatureCollectionService { ): Promise { return await this.signatureCollectionClientService.removeLists(input, user) } + + async add( + input: SignatureCollectionAddListsInput, + user: User, + ): Promise { + return await this.signatureCollectionClientService.createParliamentaryLists( + { ...input, areas: input.areaIds?.map((area) => ({ areaId: area })) }, + user, + ) + } } diff --git a/libs/clients/signature-collection/src/clientConfig.json b/libs/clients/signature-collection/src/clientConfig.json index 975e79e8f925..950fffcdf18a 100644 --- a/libs/clients/signature-collection/src/clientConfig.json +++ b/libs/clients/signature-collection/src/clientConfig.json @@ -493,6 +493,7 @@ "/Frambod/{ID}/RemoveFrambodUser": { "post": { "tags": ["Frambod"], + "summary": "GAMALT. Nota DELETE /Frambod/{ID}.", "parameters": [ { "name": "ID", @@ -522,6 +523,7 @@ "/Frambod/{ID}/RemoveFrambodAdmin": { "post": { "tags": ["Frambod"], + "summary": "GAMALT. Nota DELETE /Admin/Frambod/{ID}.", "parameters": [ { "name": "ID", @@ -551,6 +553,7 @@ "/Frambod/{ID}/AddUmbod": { "post": { "tags": ["Frambod"], + "summary": "Ath. þarfnast skoðunar", "parameters": [ { "name": "ID", @@ -587,6 +590,7 @@ "/Frambod/{ID}/RemoveUmbod/{Kennitala}": { "get": { "tags": ["Frambod"], + "summary": "Ath. þarfnast skoðunar", "parameters": [ { "name": "ID", @@ -816,6 +820,7 @@ "/Medmaelalistar/AddListar": { "post": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Nota POST /Frambod til að stofna framboð.\r\nNota POST /Medmaelalistar til að bæta listum við þegar stofnað framboð.", "requestBody": { "content": { "application/json": { @@ -849,6 +854,7 @@ "/Medmaelalistar/AddListarAdmin": { "post": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Nota POST /Admin/Frambod til að stofna framboð.", "requestBody": { "content": { "application/json": { @@ -1033,6 +1039,7 @@ "/Medmaelalistar/{ID}/AddMedmaeli": { "post": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Nota POST /Medmaelalistar/{ID}/Medmaeli til að bæta við meðmæli.", "parameters": [ { "name": "ID", @@ -1063,6 +1070,7 @@ "/Medmaelalistar/{ID}/AddMedmaeliBulk": { "post": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Fyrir framboð: Nota POST /Medmaelalistar/{ID}/Medmaeli/Bulk til að bæta við skriflegum meðmælum.\r\nFyrir admin: Nota POST /Admin/Medmaelalistar/{ID}/Medmaeli/Bulk til að bæta við skriflegum meðmælum.", "parameters": [ { "name": "ID", @@ -1103,6 +1111,7 @@ "/Medmaelalistar/{ID}/ExtendTime": { "patch": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Nota PATCH /Admin/Medmaelalistar/{ID}/ExtendTime til að framlengja meðmælalista.", "parameters": [ { "name": "ID", @@ -1140,6 +1149,7 @@ "/Medmaelalistar/{ID}/ToggleList": { "patch": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Nota PATCH /Admin/Medmaelalistar/{ID}/ToggleList.", "parameters": [ { "name": "ID", @@ -1172,6 +1182,7 @@ "/Medmaelalistar/{ID}/Compare": { "post": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Nota POST /Admin/Medmaelalistar/{ID}/Compare.", "parameters": [ { "name": "ID", @@ -1212,6 +1223,7 @@ "/Medmaelalistar/{ID}/RemoveMedmaelalistiUser": { "post": { "tags": ["Medmaelalistar"], + "summary": "GAMALT. Fyrir framboð: Nota DELETE /Medmaelalistar/{ID}.\r\nFyrir admin: Nota DELETE /Admin/Medmaelalistar/{ID}.", "parameters": [ { "name": "ID", @@ -1474,6 +1486,7 @@ "/Medmaelasofnun/{ID}/EinsInfoAdmin/{Kennitala}": { "get": { "tags": ["Medmaelasofnun"], + "summary": "GAMALT. Nota GET /Admin/Medmaelasofnun/{ID}/EinsInfo/{Kennitala}.", "parameters": [ { "name": "ID", @@ -1511,6 +1524,7 @@ "/Medmaelasofnun/{ID}/ToggleSofnun": { "post": { "tags": ["Medmaelasofnun"], + "summary": "GAMALT. Nota PATCH /Admin/Medmaelasofnun/{ID}/ToggleSofnun.", "parameters": [ { "name": "ID", @@ -1541,6 +1555,7 @@ "/Medmaelasofnun/{ID}/Compare": { "post": { "tags": ["Medmaelasofnun"], + "summary": "GAMALT. Nota POST /Admin/Medmaelasofnun/{ID}/Compare.", "parameters": [ { "name": "ID", @@ -1618,6 +1633,7 @@ "/Medmaeli/{ID}/RemoveMedmaeliUser": { "post": { "tags": ["Medmaeli"], + "summary": "GAMALT. Nota DELETE /Medmaeli/{ID}", "parameters": [ { "name": "ID", @@ -1647,6 +1663,7 @@ "/Medmaeli/{ID}/RemoveMedmaeliAdmin": { "post": { "tags": ["Medmaeli"], + "summary": "GAMALT. Nota DELETE Admin/Medmaeli/{ID}", "parameters": [ { "name": "ID", diff --git a/libs/clients/signature-collection/src/lib/signature-collection.service.ts b/libs/clients/signature-collection/src/lib/signature-collection.service.ts index c182467a626b..b809fd361431 100644 --- a/libs/clients/signature-collection/src/lib/signature-collection.service.ts +++ b/libs/clients/signature-collection/src/lib/signature-collection.service.ts @@ -13,9 +13,16 @@ import { CanCreateInput, CanSignInput, CreateParliamentaryCandidacyInput, + AddListsInput, } from './signature-collection.types' import { Collection } from './types/collection.dto' -import { List, SignedList, mapList, mapListBase } from './types/list.dto' +import { + List, + SignedList, + getSlug, + mapList, + mapListBase, +} from './types/list.dto' import { Signature, mapSignature } from './types/signature.dto' import { Signee } from './types/user.dto' import { Success, mapReasons } from './types/success.dto' @@ -179,7 +186,85 @@ export class SignatureCollectionClientService { })), }, }) - return { slug: 'frambodWowee' } + return { + slug: getSlug( + candidacy.id ?? '', + candidacy.medmaelasofnun?.kosningTegund ?? '', + ), + } + } + + async createParliamentaryLists( + { collectionId, candidateId, areas }: AddListsInput, + auth: User, + ): Promise { + const { + id, + isActive, + isPresidential, + areas: collectionAreas, + } = await this.currentCollection() + + // check if collectionId is current collection and current collection is open + if (collectionId !== id.toString() || !isActive) { + throw new Error('Collection is not open') + } + // check if user is already owner of lists + + const { canCreate, canCreateInfo, name } = await this.getSignee(auth) + console.log('canCreate', canCreate) + console.log('canCreateInfo', canCreateInfo) + if (!canCreate) { + // allow parliamentary owners to add more areas to their collection + if ( + !isPresidential && + !( + canCreateInfo?.length === 1 && + canCreateInfo[0] === ReasonKey.AlreadyOwner + ) + ) { + return { success: false, reasons: canCreateInfo } + } + } + + const filteredAreas = areas + ? collectionAreas.filter((area) => + areas.flatMap((a) => a.areaId).includes(area.id), + ) + : collectionAreas + + console.log(areas) + console.log(filteredAreas) + + const promises = filteredAreas.map((area) => + this.getApiWithAuth(this.listsApi, auth).medmaelalistarPost({ + medmaelalistarRequestDTO: { + frambodID: parseInt(candidateId), + medmaelalisti: { + svaediID: parseInt(area.id), + listiNafn: `${name} - ${area.name}`, + }, + }, + }), + ) + const lists = await Promise.all(promises) + + // const lists = await this.getApiWithAuth( + // this.listsApi, + // auth, + // ).medmaelalistarPost({ + // medmaelalistarRequestDTO: { + // frambodID: parseInt(id), + // medmaelalisti: filteredAreas.map((area) => ({ + // svaediID: parseInt(area.id), + // listiNafn: `${name} - ${area.name}`, + // })), + // }, + // }) + if (filteredAreas.length !== lists.length) { + throw new Error('Not all lists created') + } + return { success: true } } async signList(listId: string, auth: User): Promise { @@ -252,10 +337,7 @@ export class SignatureCollectionClientService { listsToRemove.map( async (list) => - await this.getApiWithAuth( - this.listsApi, - auth, - ).medmaelalistarIDRemoveMedmaelalistiUserPost({ + await this.getApiWithAuth(this.listsApi, auth).medmaelalistarIDDelete({ iD: parseInt(list.id), }), ) diff --git a/libs/clients/signature-collection/src/lib/signature-collection.types.ts b/libs/clients/signature-collection/src/lib/signature-collection.types.ts index 660719c75e9a..0a0b2ae5401a 100644 --- a/libs/clients/signature-collection/src/lib/signature-collection.types.ts +++ b/libs/clients/signature-collection/src/lib/signature-collection.types.ts @@ -30,6 +30,14 @@ export interface CreateListInput { owner: OwnerInput areas?: AreaInput[] } + +// Should replace CreateListInput once refactored to new ÞÍ endpoints +export interface AddListsInput { + collectionId: string + candidateId: string + areas?: AreaInput[] +} + export interface CreateParliamentaryCandidacyInput extends CreateListInput { agents: AgentInput[] } From 12055479b33100cdad2b59ce4fd85d7c046656f1 Mon Sep 17 00:00:00 2001 From: Haukur Ingi Date: Wed, 18 Sep 2024 13:24:07 +0000 Subject: [PATCH 2/6] remove debug --- .../src/lib/signature-collection.service.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/libs/clients/signature-collection/src/lib/signature-collection.service.ts b/libs/clients/signature-collection/src/lib/signature-collection.service.ts index b809fd361431..91edd215cd6b 100644 --- a/libs/clients/signature-collection/src/lib/signature-collection.service.ts +++ b/libs/clients/signature-collection/src/lib/signature-collection.service.ts @@ -212,8 +212,6 @@ export class SignatureCollectionClientService { // check if user is already owner of lists const { canCreate, canCreateInfo, name } = await this.getSignee(auth) - console.log('canCreate', canCreate) - console.log('canCreateInfo', canCreateInfo) if (!canCreate) { // allow parliamentary owners to add more areas to their collection if ( @@ -233,9 +231,6 @@ export class SignatureCollectionClientService { ) : collectionAreas - console.log(areas) - console.log(filteredAreas) - const promises = filteredAreas.map((area) => this.getApiWithAuth(this.listsApi, auth).medmaelalistarPost({ medmaelalistarRequestDTO: { @@ -249,18 +244,6 @@ export class SignatureCollectionClientService { ) const lists = await Promise.all(promises) - // const lists = await this.getApiWithAuth( - // this.listsApi, - // auth, - // ).medmaelalistarPost({ - // medmaelalistarRequestDTO: { - // frambodID: parseInt(id), - // medmaelalisti: filteredAreas.map((area) => ({ - // svaediID: parseInt(area.id), - // listiNafn: `${name} - ${area.name}`, - // })), - // }, - // }) if (filteredAreas.length !== lists.length) { throw new Error('Not all lists created') } From 42f2ee917e3f81566836ea3ba8c933a81d119c77 Mon Sep 17 00:00:00 2001 From: Haukur Ingi Date: Wed, 18 Sep 2024 13:26:19 +0000 Subject: [PATCH 3/6] set nullable to false --- .../domains/signature-collection/src/lib/dto/addLists.input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts b/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts index f33663d089b5..23bcd902de1a 100644 --- a/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts +++ b/libs/api/domains/signature-collection/src/lib/dto/addLists.input.ts @@ -8,7 +8,7 @@ export class SignatureCollectionAddListsInput extends SignatureCollectionIdInput @IsString() candidateId!: string - @Field(() => [String], { nullable: false, defaultValue: [] }) + @Field(() => [String], { nullable: true, defaultValue: [] }) @IsArray() areaIds?: string[] } From 7e5327e8522a8c86d801833f8959cd5b336357d6 Mon Sep 17 00:00:00 2001 From: Haukur Ingi Date: Wed, 18 Sep 2024 13:57:04 +0000 Subject: [PATCH 4/6] await all list removals --- .../src/lib/signature-collection.service.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/clients/signature-collection/src/lib/signature-collection.service.ts b/libs/clients/signature-collection/src/lib/signature-collection.service.ts index 91edd215cd6b..778b566f713c 100644 --- a/libs/clients/signature-collection/src/lib/signature-collection.service.ts +++ b/libs/clients/signature-collection/src/lib/signature-collection.service.ts @@ -318,11 +318,12 @@ export class SignatureCollectionClientService { return { success: false, reasons: [ReasonKey.NoListToRemove] } } - listsToRemove.map( - async (list) => - await this.getApiWithAuth(this.listsApi, auth).medmaelalistarIDDelete({ + await Promise.all( + listsToRemove.map((list) => + this.getApiWithAuth(this.listsApi, auth).medmaelalistarIDDelete({ iD: parseInt(list.id), }), + ), ) return { success: true } } From 25b4f3882987f3c103abe72a9f81b93dfd036a07 Mon Sep 17 00:00:00 2001 From: Haukur Ingi Date: Wed, 18 Sep 2024 14:02:41 +0000 Subject: [PATCH 5/6] update client --- .../src/clientConfig.json | 12 ++++++---- .../src/lib/signature-collection.service.ts | 24 +++++++++---------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/libs/clients/signature-collection/src/clientConfig.json b/libs/clients/signature-collection/src/clientConfig.json index 950fffcdf18a..edf7e250b0cd 100644 --- a/libs/clients/signature-collection/src/clientConfig.json +++ b/libs/clients/signature-collection/src/clientConfig.json @@ -804,7 +804,10 @@ "description": "OK", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/MedmaelalistiDTO" } + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/MedmaelalistiDTO" } + } } } }, @@ -1977,8 +1980,9 @@ "type": "object", "properties": { "frambodID": { "type": "integer", "format": "int32" }, - "medmaelalisti": { - "$ref": "#/components/schemas/FrambodListarRequestDTO" + "medmaelalistar": { + "type": "array", + "items": { "$ref": "#/components/schemas/FrambodListarRequestDTO" } } }, "additionalProperties": false @@ -2112,7 +2116,7 @@ "$ref": "#/components/schemas/MedmaelasofnunExtendedDTO" } }, - "sveitastjornakosningar": { + "sveitarstjornarkosningar": { "type": "array", "items": { "$ref": "#/components/schemas/MedmaelasofnunExtendedDTO" diff --git a/libs/clients/signature-collection/src/lib/signature-collection.service.ts b/libs/clients/signature-collection/src/lib/signature-collection.service.ts index 778b566f713c..bdb16c174992 100644 --- a/libs/clients/signature-collection/src/lib/signature-collection.service.ts +++ b/libs/clients/signature-collection/src/lib/signature-collection.service.ts @@ -231,18 +231,18 @@ export class SignatureCollectionClientService { ) : collectionAreas - const promises = filteredAreas.map((area) => - this.getApiWithAuth(this.listsApi, auth).medmaelalistarPost({ - medmaelalistarRequestDTO: { - frambodID: parseInt(candidateId), - medmaelalisti: { - svaediID: parseInt(area.id), - listiNafn: `${name} - ${area.name}`, - }, - }, - }), - ) - const lists = await Promise.all(promises) + const lists = await this.getApiWithAuth( + this.listsApi, + auth, + ).medmaelalistarPost({ + medmaelalistarRequestDTO: { + frambodID: parseInt(candidateId), + medmaelalistar: filteredAreas.map((area) => ({ + svaediId: parseInt(area.id), + listiNafn: `${name} - ${area.name}`, + })), + }, + }) if (filteredAreas.length !== lists.length) { throw new Error('Not all lists created') From bccd370362cf4630afd653846a1f151e812c8ef0 Mon Sep 17 00:00:00 2001 From: albinagu <47886428+albinagu@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:34:14 +0000 Subject: [PATCH 6/6] Update libs/clients/signature-collection/src/lib/signature-collection.service.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../src/lib/signature-collection.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/clients/signature-collection/src/lib/signature-collection.service.ts b/libs/clients/signature-collection/src/lib/signature-collection.service.ts index bdb16c174992..04cd1a23e53b 100644 --- a/libs/clients/signature-collection/src/lib/signature-collection.service.ts +++ b/libs/clients/signature-collection/src/lib/signature-collection.service.ts @@ -238,7 +238,7 @@ export class SignatureCollectionClientService { medmaelalistarRequestDTO: { frambodID: parseInt(candidateId), medmaelalistar: filteredAreas.map((area) => ({ - svaediId: parseInt(area.id), + svaediID: parseInt(area.id), listiNafn: `${name} - ${area.name}`, })), },