Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ids-api): Add legal representative delegation type and return in delegation list. #15837

Merged
merged 23 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ describe('DelegationsController', () => {
)
nationalRegistryApi = app.get(NationalRegistryClientService)
delegationIndexService = app.get(DelegationsIndexService)
delegationIndexService.indexDelegations = jest
.fn()
.mockImplementation(() => Promise.resolve())
factory = new FixtureFactory(app)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,17 @@ export const testCases: Record<string, TestCase> = {
],
},
),
// Returns available delegations for legal representatives
legalRepresentative1: new TestCase(
createClient({
clientId: clientId,
supportedDelegationTypes: [AuthDelegationType.LegalRepresentative],
}),
{
fromLegalRepresentative: [person1, person2],
protectedScopes: [],
expectedFrom: [person1, person2],
expectedTypes: [AuthDelegationType.LegalRepresentative],
},
),
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const customScope2 = 'cu2'
const customScopeOtherDomain = 'cu-od1'
const representativeScope1 = 'pr1'
const representativeScope2 = 'pr2'
const legalRepresentativeScope1 = 'lr1'
const legalRepresentativeScope2 = 'lr2'

export const legalGuardianScopes = [legalGuardianScope1, legalGuardianScope2]
export const procurationHolderScopes = [
Expand All @@ -37,12 +39,17 @@ export const procurationHolderScopes = [
]
export const customScopes = [customScope1, customScope2, customScopeOtherDomain]
export const representativeScopes = [representativeScope1, representativeScope2]
export const legalRepresentativeScopes = [
legalRepresentativeScope1,
legalRepresentativeScope2,
]

export interface ITestCaseOptions {
fromChildren?: string[]
fromCompanies?: string[]
fromCustom?: string[]
fromRepresentative?: string[]
fromLegalRepresentative?: string[]
scopes?: string[]
protectedScopes?: string[]
scopeAccess?: [string, string][]
Expand All @@ -59,6 +66,7 @@ export class TestCase {
fromCompanies: string[]
fromCustom: string[]
fromRepresentative: string[]
fromLegalRepresentative: string[]
scopes: string[]
protectedScopes: string[]
scopeAccess: [string, string][]
Expand All @@ -71,11 +79,13 @@ export class TestCase {
this.fromCompanies = options.fromCompanies ?? []
this.fromCustom = options.fromCustom ?? []
this.fromRepresentative = options.fromRepresentative ?? []
this.fromLegalRepresentative = options.fromLegalRepresentative ?? []
this.scopes = options.scopes ?? [
...legalGuardianScopes,
...procurationHolderScopes,
...customScopes,
...representativeScopes,
...legalRepresentativeScopes,
]
this.protectedScopes = options.protectedScopes ?? []
this.scopeAccess = options.scopeAccess ?? []
Expand Down Expand Up @@ -160,6 +170,9 @@ export class TestCase {
if (representativeScopes.includes(scopeName)) {
result.push(AuthDelegationType.PersonalRepresentative)
}
if (legalRepresentativeScopes.includes(scopeName)) {
result.push(AuthDelegationType.LegalRepresentative)
}
return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { MergedDelegationDTO } from '@island.is/auth-api-lib'
import { RskRelationshipsClient } from '@island.is/clients-rsk-relationships'
import { NationalRegistryClientService } from '@island.is/clients/national-registry-v2'
import { FixtureFactory } from '@island.is/services/auth/testing'
import {
AuthDelegationProvider,
AuthDelegationType,
} from '@island.is/shared/types'
import { createNationalRegistryUser } from '@island.is/testing/fixtures'
import { TestApp, truncate } from '@island.is/testing/nest'

Expand Down Expand Up @@ -86,6 +90,17 @@ describe('DelegationsController', () => {
),
)

await Promise.all(
testCase.fromLegalRepresentative.map((nationalId) =>
factory.createDelegationIndexRecord({
fromNationalId: nationalId,
toNationalId: testCase.user.nationalId,
type: AuthDelegationType.LegalRepresentative,
provider: AuthDelegationProvider.DistrictCommissionersRegistry,
}),
),
)
valurefugl marked this conversation as resolved.
Show resolved Hide resolved

jest
.spyOn(nationalRegistryApi, 'getCustodyChildren')
.mockImplementation(async () => testCase.fromChildren)
Expand Down
8 changes: 1 addition & 7 deletions apps/services/auth/ids-api/test/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@ class MockUserProfile {
meUserProfileControllerFindUserProfile = jest.fn().mockResolvedValue({})
}

class MockDelegationsIndexService {
indexDelegations = jest.fn().mockImplementation(() => Promise.resolve())
}
saevarma marked this conversation as resolved.
Show resolved Hide resolved

interface SetupOptions {
user: User
scopes?: Scopes
Expand Down Expand Up @@ -133,9 +129,7 @@ export const setupWithAuth = async ({
.useValue({
getValue: (feature: Features) =>
!features || features.includes(feature),
})
.overrideProvider(DelegationsIndexService)
.useClass(MockDelegationsIndexService),
}),
hooks: [
useAuth({ auth: user }),
useDatabase({ type: 'postgres', provider: SequelizeConfigService }),
Expand Down
5 changes: 5 additions & 0 deletions apps/services/auth/public-api/test/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
IndividualDto,
NationalRegistryClientService,
} from '@island.is/clients/national-registry-v2'
import { CompanyRegistryClientService } from '@island.is/clients/rsk/company-registry'
valurefugl marked this conversation as resolved.
Show resolved Hide resolved
import { ConfigType } from '@island.is/nest/config'
import { FeatureFlagService } from '@island.is/nest/feature-flags'
import {
Expand Down Expand Up @@ -154,6 +155,10 @@ export const setupWithAuth = async ({
.useValue(createMockEinstaklingurApi(nationalRegistryUser))
.overrideProvider(RskRelationshipsClient)
.useValue(RskProcuringClientMock)
.overrideProvider(CompanyRegistryClientService)
.useValue({
getCompany: jest.fn().mockResolvedValue({}),
})
valurefugl marked this conversation as resolved.
Show resolved Hide resolved
.overrideProvider(DelegationConfig.KEY)
.useValue(delegationConfig)
.overrideProvider(FeatureFlagService)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import faker from 'faker'

import { UserProfileDto } from '@island.is/clients/user-profile'
import { createNationalId } from '@island.is/testing/fixtures'
import { DelegationRecordDTO } from '@island.is/clients/auth/delegation-api'
import { UserProfileDto } from '@island.is/clients/user-profile'
import { Features } from '@island.is/feature-flags'
import type { User } from '@island.is/auth-nest-tools'
import type { ConfigType } from '@island.is/nest/config'
import { createNationalId } from '@island.is/testing/fixtures'

import { UserNotificationsConfig } from '../../../../config'
import { HnippTemplate } from '../dto/hnippTemplate.response'

import type { User } from '@island.is/auth-nest-tools'
import type { ConfigType } from '@island.is/nest/config'

export const mockFullName = 'mockFullName'
export const delegationSubjectId = 'delegation-subject-id'

Expand Down Expand Up @@ -135,20 +136,23 @@ const delegations: Record<string, DelegationRecordDTO[]> = {
fromNationalId: userWithDelegations.nationalId,
toNationalId: userWithNoDelegations.nationalId,
subjectId: null, // test that 3rd party login is not used if subjectId is null
type: null,
valurefugl marked this conversation as resolved.
Show resolved Hide resolved
},
],
[userWithDelegations2.nationalId]: [
{
fromNationalId: userWithDelegations2.nationalId,
toNationalId: userWithDelegations.nationalId,
subjectId: delegationSubjectId,
type: null,
},
],
[userWithSendToDelegationsFeatureFlagDisabled.nationalId]: [
{
fromNationalId: userWithSendToDelegationsFeatureFlagDisabled.nationalId,
toNationalId: userWithNoDelegations.nationalId,
subjectId: faker.datatype.uuid(),
type: null,
},
],
}
Expand Down
9 changes: 8 additions & 1 deletion libs/api/domains/auth/src/lib/models/delegation.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import {
registerEnumType,
} from '@nestjs/graphql'

import { Identity } from '@island.is/api/domains/identity'
import {
AuthDelegationProvider,
AuthDelegationType,
} from '@island.is/clients/auth/delegation-api'
import { Identity } from '@island.is/api/domains/identity'

import { DelegationScope } from './delegationScope.model'

Expand All @@ -32,6 +32,8 @@ const exhaustiveCheck = (param: never) => {
return PersonalRepresentativeDelegation
case AuthDelegationType.Custom:
return CustomDelegation
case AuthDelegationType.LegalRepresentative:
return LegalRepresentativeDelegation
default:
exhaustiveCheck(delegation.type)
}
Expand Down Expand Up @@ -83,6 +85,11 @@ export class CustomDelegation extends Delegation {
domainName?: string
}

@ObjectType('AuthLegalRepresentativeDelegation', {
implements: Delegation,
})
export class LegalRepresentativeDelegation extends Delegation {}
saevarma marked this conversation as resolved.
Show resolved Hide resolved

@ObjectType('AuthMergedDelegation')
export class MergedDelegation {
@Field(() => [AuthDelegationType])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module.exports = {
up(queryInterface) {
return queryInterface.sequelize.query(`
BEGIN;
INSERT INTO delegation_provider
(id, name, description)
VALUES
('syslumenn', 'Sýslumenn', 'Provider for district commissioners registry');

INSERT INTO delegation_type
(id, provider, name, description)
VALUES
('LegalRepresentative', 'syslumenn', 'Legal Representative', 'Legal Representative delegation type');

INSERT INTO api_scope_delegation_types
(api_scope_name, delegation_type)
VALUES
('@island.is/documents', 'LegalRepresentative');

INSERT INTO client_delegation_types
(client_id, delegation_type)
VALUES
('@island.is/web', 'LegalRepresentative');

COMMIT;
`)
},

down(queryInterface) {
return queryInterface.sequelize.query(`
BEGIN;
DELETE FROM client_delegation_types
WHERE client_id = '@island.is/web' AND delegation_type = 'LegalRepresentative';

DELETE FROM api_scope_delegation_types
WHERE api_scope_name = '@island.is/documents' AND delegation_type = 'LegalRepresentative';

DELETE FROM delegation_type
WHERE id = 'LegalRepresentative';

DELETE FROM delegation_provider
WHERE id = 'syslumenn';

COMMIT;
`)
},
}
13 changes: 13 additions & 0 deletions libs/auth-api-lib/src/lib/delegations/delegation-dto.mapper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { AuthDelegationType } from '@island.is/shared/types'

import { DelegationRecordDTO } from './dto/delegation-index.dto'
import { DelegationDTO } from './dto/delegation.dto'
import { MergedDelegationDTO } from './dto/merged-delegation.dto'

Expand All @@ -13,4 +16,14 @@ export class DelegationDTOMapper {
scopes: dto.scopes,
}
}

public static recordToMergedDelegationDTO(
dto: DelegationRecordDTO,
): MergedDelegationDTO {
return {
fromNationalId: dto.fromNationalId,
toNationalId: dto.toNationalId,
types: [dto.type as AuthDelegationType],
valurefugl marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Loading
Loading