Skip to content

Commit

Permalink
feat(ids-api): Add legal representative delegation type and return in…
Browse files Browse the repository at this point in the history
… delegation list. (#15837)

* Add legal representative delegation type and return in delegation list.

* Remove directive.

* Add type to domain model.

* Fix mocks.

* Fix import.

* Fix index service mocking.

* Add missing mock for company registry.

* Testing.

* Revert test change. Add try/catch for index.

* Fix name and import.

* Make types required on delegation dto.

* Type fixes.

* Reuse constant.

* Callback for rejected promise.

* Combine imports.

* Remove mock.

* Refactor name lookup.

* Fix export.

* Remove unused import.

* Move function to class member.

* Move index mocking to the shared setup function.

---------

Co-authored-by: Sævar Már Atlason <saevar.m.atlason@gmail.com>
Co-authored-by: Valur Einarsson <valure@live.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored and jonnigs committed Sep 12, 2024
1 parent 98f6e1f commit df40024
Show file tree
Hide file tree
Showing 21 changed files with 274 additions and 41 deletions.
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,
}),
),
)

jest
.spyOn(nationalRegistryApi, 'getCustodyChildren')
.mockImplementation(async () => testCase.fromChildren)
Expand Down
14 changes: 7 additions & 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())
}

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 All @@ -149,6 +143,12 @@ export const setupWithAuth = async ({
const apiScopeModel = app.get<typeof ApiScope>(getModelToken(ApiScope))
await apiScopeModel.bulkCreate(Object.values(scopes).map(createApiScope))

// Mock delegation indexing
const delegationIndexService = app.get(DelegationsIndexService)
delegationIndexService.indexDelegations = jest
.fn()
.mockImplementation(() => Promise.resolve())

return app
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import faker from 'faker'

import {
AuthDelegationType,
DelegationRecordDTO,
} from '@island.is/clients/auth/delegation-api'
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 { 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 @@ -160,20 +164,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: AuthDelegationType.ProcurationHolder,
},
],
[userWithDelegations2.nationalId]: [
{
fromNationalId: userWithDelegations2.nationalId,
toNationalId: userWithDelegations.nationalId,
subjectId: delegationSubjectId,
type: AuthDelegationType.ProcurationHolder,
},
],
[userWithSendToDelegationsFeatureFlagDisabled.nationalId]: [
{
fromNationalId: userWithSendToDelegationsFeatureFlagDisabled.nationalId,
toNationalId: userWithNoDelegations.nationalId,
subjectId: faker.datatype.uuid(),
type: AuthDelegationType.ProcurationHolder,
},
],
}
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 {}

@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;
`)
},
}
1 change: 1 addition & 0 deletions libs/auth-api-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export * from './lib/delegations/models/delegation-type.model'
export * from './lib/delegations/models/delegation-provider.model'
export * from './lib/delegations/DelegationConfig'
export * from './lib/delegations/utils/scopes'
export * from './lib/delegations/constants/names'

// Resources module
export * from './lib/resources/resources.module'
Expand Down
1 change: 1 addition & 0 deletions libs/auth-api-lib/src/lib/delegations/constants/names.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const UNKNOWN_NAME = 'Óþekkt nafn'
11 changes: 11 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,4 @@
import { DelegationRecordDTO } from './dto/delegation-index.dto'
import { DelegationDTO } from './dto/delegation.dto'
import { MergedDelegationDTO } from './dto/merged-delegation.dto'

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

public static recordToMergedDelegationDTO(
dto: DelegationRecordDTO,
): MergedDelegationDTO {
return {
fromNationalId: dto.fromNationalId,
toNationalId: dto.toNationalId,
types: [dto.type],
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { isDefined } from '@island.is/shared/utils'
import { ApiScopeDelegationType } from '../resources/models/api-scope-delegation-type.model'
import { ApiScopeUserAccess } from '../resources/models/api-scope-user-access.model'
import { ApiScope } from '../resources/models/api-scope.model'
import { UNKNOWN_NAME } from './constants/names'
import { ApiScopeInfo } from './delegations-incoming.service'
import { DelegationDTO } from './dto/delegation.dto'
import { MergedDelegationDTO } from './dto/merged-delegation.dto'
Expand All @@ -30,8 +31,6 @@ import { DelegationValidity } from './types/delegationValidity'
import { partitionWithIndex } from './utils/partitionWithIndex'
import { getScopeValidityWhereClause } from './utils/scopes'

export const UNKNOWN_NAME = 'Óþekkt nafn'

type FindAllValidIncomingOptions = {
nationalId: string
domainName?: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ import { isDefined } from '@island.is/shared/utils'

import { PersonalRepresentativeDTO } from '../personal-representative/dto/personal-representative.dto'
import { PersonalRepresentativeService } from '../personal-representative/services/personalRepresentative.service'
import { UNKNOWN_NAME } from './constants/names'
import { ApiScopeInfo } from './delegations-incoming.service'
import { DelegationDTO } from './dto/delegation.dto'
import { partitionWithIndex } from './utils/partitionWithIndex'

export const UNKNOWN_NAME = 'Óþekkt nafn'

type FindAllIncomingOptions = {
nationalId: string
clientAllowedApiScopes?: ApiScopeInfo[]
Expand Down
Loading

0 comments on commit df40024

Please sign in to comment.