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(license-service): update license service #15204

Merged
merged 85 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
5f0e007
feat:updat emodels
thorkellmani Jun 11, 2024
b0bd894
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 11, 2024
84f8b09
feat/bunch
thorkellmani Jun 12, 2024
959c1fa
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 13, 2024
ff1bb57
feat: updates
thorkellmani Jun 18, 2024
1ac46db
feat: add and remove
thorkellmani Jun 18, 2024
3066d37
chore: stash merge
thorkellmani Jun 20, 2024
b0abee0
feat: more stuff
thorkellmani Jun 20, 2024
726e7db
fix: license type
thorkellmani Jun 20, 2024
eee35a1
feat: license overivew works
thorkellmani Jun 21, 2024
9e2300e
chore:revert
thorkellmani Jun 21, 2024
b2f7363
chore: revert messages
thorkellmani Jun 21, 2024
553c1bc
chore: console
thorkellmani Jun 21, 2024
caf4447
chore: revert
thorkellmani Jun 21, 2024
0b7fe69
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 21, 2024
00ed428
chore: nx format:write update dirty files
andes-it Jun 21, 2024
8e1519a
fix: passports
thorkellmani Jun 24, 2024
c934636
chore: start details
thorkellmani Jun 24, 2024
5387007
chore: nx format:write update dirty files
andes-it Jun 24, 2024
5108eb6
feat: update details
thorkellmani Jun 25, 2024
7a438b0
Merge remote-tracking branch 'refs/remotes/origin/feat/update-license…
thorkellmani Jun 25, 2024
32f39fc
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 25, 2024
250073f
fix: enum
thorkellmani Jun 25, 2024
aee18d0
fix: date format
thorkellmani Jun 25, 2024
98de224
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 26, 2024
e71e7a4
fix: type import
thorkellmani Jun 26, 2024
0a7d9bb
Merge remote-tracking branch 'refs/remotes/origin/feat/update-license…
thorkellmani Jun 26, 2024
1a86227
chore:small fixes
thorkellmani Jun 26, 2024
464b050
chore:rename-liceinse-service
thorkellmani Jun 26, 2024
39b6609
chore: remove original license service
thorkellmani Jun 26, 2024
5d97c1d
chore: add unchanged license service
thorkellmani Jun 26, 2024
4ab3093
chore: add mocks back
thorkellmani Jun 26, 2024
f835e34
chore: add to resolver
thorkellmani Jun 26, 2024
ced1ba4
chore:renmae license
thorkellmani Jun 26, 2024
abba81d
chore: readd licens service
thorkellmani Jun 26, 2024
431a326
fix: license-v2
thorkellmani Jun 26, 2024
845c5b9
fix: readd ls-v1
thorkellmani Jun 26, 2024
6f08e5c
feat: rename
thorkellmani Jun 27, 2024
8d0bd02
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 27, 2024
abf7b9b
chore: nx format:write update dirty files
andes-it Jun 27, 2024
1f9cd1d
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 27, 2024
2053f92
fix: passport display
thorkellmani Jun 27, 2024
73c0e65
Merge branch 'main' into feat/update-license-service
thorkellmani Jun 27, 2024
48919e7
Merge remote-tracking branch 'refs/remotes/origin/feat/update-license…
thorkellmani Jun 27, 2024
23b3b6f
chore: codeowners
thorkellmani Jun 28, 2024
3865524
chore: move datafields
thorkellmani Jun 28, 2024
ea28e0d
fix: html semantics
thorkellmani Jun 28, 2024
0e33190
fix:pkpass display
thorkellmani Jun 28, 2024
7e7fd0b
chore:console log
thorkellmani Jun 28, 2024
7ee74da
chore: use types
thorkellmani Jun 28, 2024
ee57f94
feat: remove v2 and merge in v1
thorkellmani Jun 28, 2024
f644109
chore:import
thorkellmani Jun 28, 2024
27c29ca
fix: expires
thorkellmani Jul 1, 2024
1b6a5c2
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 1, 2024
2ea9391
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 5, 2024
2df58b9
fix:navigation
thorkellmani Jul 5, 2024
2f40e87
fix: mapping
thorkellmani Jul 5, 2024
448a9f4
chore: import
thorkellmani Jul 5, 2024
0aceda1
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 8, 2024
55c96c2
fix: time format
thorkellmani Jul 8, 2024
2fa2114
fix:fix
thorkellmani Jul 8, 2024
b172814
chore: clean up types
thorkellmani Jul 9, 2024
d35f9c8
fix: async
thorkellmani Jul 9, 2024
0fd08aa
fix: messages
thorkellmani Jul 10, 2024
48fa9bd
fix: update display slightly
thorkellmani Jul 10, 2024
e05d4eb
fix: mcoks
thorkellmani Jul 10, 2024
cd57061
chore: deprecate model
thorkellmani Jul 10, 2024
326ba14
chore: import clean up
thorkellmani Jul 10, 2024
07d12e8
fix: update mapping
thorkellmani Jul 10, 2024
25cb249
chore: import clean up
thorkellmani Jul 10, 2024
8b25f30
fix: reimport reaect
thorkellmani Jul 10, 2024
e1f7113
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 10, 2024
e5a47ee
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 10, 2024
e709bab
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 10, 2024
dbad808
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 10, 2024
57b31f8
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 11, 2024
f17cf23
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 11, 2024
881b09e
Merge branch 'main' into feat/update-license-service
thorkellmani Jul 11, 2024
3c53d29
Merge branch 'main' into feat/update-license-service
thorkellmani Aug 12, 2024
8b50893
chore: use tag map
thorkellmani Aug 12, 2024
9e1c392
chore: coderabbit improvements
thorkellmani Aug 12, 2024
fcc370f
fix: const issues
thorkellmani Aug 12, 2024
8b94bfa
Merge branch 'main' into feat/update-license-service
thorkellmani Aug 12, 2024
781a01e
chore: concising
thorkellmani Aug 14, 2024
b2a324d
Merge branch 'main' into feat/update-license-service
kodiakhq[bot] Aug 14, 2024
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ codemagic.yaml
/libs/api/domains/assets/ @island-is/hugsmidjan
/libs/api/domains/hms-loans/ @island-is/hugsmidjan
/libs/api/domains/license-service/ @island-is/hugsmidjan @island-is/aranja
/libs/api/domains/license-service-v2/ @island-is/hugsmidjan @island-is/aranja
/libs/api/domains/work-machines/ @island-is/hugsmidjan @island-is/origo
/libs/api/domains/national-registry/ @island-is/hugsmidjan
/libs/api/domains/notifications/ @island-is/hugsmidjan
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
} from '@island.is/api/domains/communications'
import { IdentityModule } from '@island.is/api/domains/identity'
import { LicenseServiceModule } from '@island.is/api/domains/license-service'
import { LicenseServiceModuleV2 } from '@island.is/api/domains/license-service-v2'
import { OfficialJournalOfIcelandModule } from '@island.is/api/domains/official-journal-of-iceland'
import { OfficialJournalOfIcelandApplicationModule } from '@island.is/api/domains/official-journal-of-iceland-application'
import { MortgageCertificateModule } from '@island.is/api/domains/mortgage-certificate'
Expand Down Expand Up @@ -233,6 +234,7 @@ const environment = getConfig
baseApiUrl: environment.applicationSystem.baseApiUrl!,
}),
LicenseServiceModule,
LicenseServiceModuleV2,
DirectorateOfLabourModule,
FileUploadModule,
DocumentModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,7 @@ const NotificationMenu = ({
isVisible={sideMenuOpen}
hideOnClickOutside={true}
hideOnEsc={true}
modalLabel={formatMessage({
id: 'service.portal:notification-button-aria',
defaultMessage: 'Valmynd fyrir tilkynningar',
})}
modalLabel={formatMessage(m.notificationButtonAria)}
removeOnClose={true}
preventBodyScroll={false}
onVisibilityChange={(visibility: boolean) => {
Expand Down
6 changes: 1 addition & 5 deletions apps/service-portal/src/components/Sidemenu/Sidemenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,7 @@ const Sidemenu = ({
isVisible={sideMenuOpen}
hideOnClickOutside={true}
hideOnEsc={true}
modalLabel={formatMessage({
id: 'service.portal:menu-button-aria',
description: 'Lýsing á notendavalmynd fyrir skjálesara',
defaultMessage: 'Valmynd fyrir yfirlit',
})}
modalLabel={formatMessage(m.menuButtonAria)}
removeOnClose={true}
preventBodyScroll={false}
onVisibilityChange={(visibility: boolean) => {
Expand Down
10 changes: 10 additions & 0 deletions libs/api/domains/license-service-v2/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": ["../../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"rules": {},
"overrides": [
{ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": {} },
{ "files": ["*.ts", "*.tsx"], "rules": {} },
{ "files": ["*.js", "*.jsx"], "rules": {} }
]
}
73 changes: 73 additions & 0 deletions libs/api/domains/license-service-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# API Domains License Service

A layer that provides a single point of entry for all of a users licenses.

### Licenses

The license service returns a generic license that consists of the following parts.

- License type: A license type comes from an exhaustive list of types.
- e.g. DriversLicense, FirearmLicense, MachineLicense etc...
- Provider: What issuer provides the license.
- e.g National police commissioner
- Fetch: A status object containing all relevant info about the fetch itself.
- Payload: The actual payload, i.e. the license itself. Might be empty if the user doesn't have a license!

**Currently accepted licenses include**:

- Driving License
- Firearm License
- Machine License
- ADR License
- Disability License

### Usage

The Api and Xroad services need to be running

- Api
`Yarn start api`
- XRoad
`./scripts/run-xroad-proxy.sh`

### Mocking

Mocks are available if switched on.
When a new license is added, don't forget to mock it!

### Adding a new license

1. Generate an external client that fetches the data from a 3rd party
2. Create a client folder in `/license-service/client/` folder
- Each individual client is a module, so it can be injected into the license service easily. What you need then is:
- A service that provides the license data.
- A mapper that transforms and raw specific license data into a generic form.
- A configuration definition for the service. - All secrets should be kept in the AWS parameter store. Do not use environment files!
- (optional) Type definitions if required
- Finally, the module definitions, that provides the everything for injection and exports the service.
3. Add the new license to the relevant types, e.g. `GenericLicenseTypeType``
4. Inject the new internal client into the LicenseService!
- For digital licenses, you also need to provide the config to the CONFIG_PROVIDER factory function if pkpass is available (so it can retrieve the `passTemplateId` from it)
- Don't forget to add the new license to the `AVAILABLE_LICENSES` object if it's supposed to be displayed.

### Digital Licenses

The license service offers a service to create a digital license for each applicable license. To do this, it creates a _Pk pass_

The license service currently uses the [SmartSolution API](https://smartsolutions.gitbook.io/smart-solutions-drivers-license/) to generate a pk pass for all applicable licenses, which is the used to provide a digitized license.

To be able to generate a digital license, some conditions need to be met for each license.

- **Drivers License**

- User has a result when RLS API is called
- The result has a non-null `mynd` in the result
- The date of the image is 1997-08-15 or newer

- **Firearm License**

- The license must not be expired

- **Adr License**

- The license must not be expired
17 changes: 17 additions & 0 deletions libs/api/domains/license-service-v2/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-disable */
export default {
displayName: 'api-domains-license-service-v2',
preset: './jest.preset.js',
rootDir: '../../../..',
roots: [__dirname],
globals: {},
transform: {
'^.+\\.[tj]sx?$': [
'ts-jest',
{ tsconfig: `${__dirname}/tsconfig.spec.json` },
],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '<rootDir>/coverage/libs/api/domains/license-service-v2',
testEnvironment: 'node',
}
33 changes: 33 additions & 0 deletions libs/api/domains/license-service-v2/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "api-domains-license-service-v2",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/api/domains/license-service-v2/src",
"projectType": "library",
"targets": {
"lint": {
"executor": "@nx/linter:eslint",
"options": {
"lintFilePatterns": [
"libs/api/domains/license-service-v2/**/*.{ts,tsx,js,jsx}"
]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/libs/api/domains/license-service-v2"
],
"options": {
"jestConfig": "libs/api/domains/license-service-v2/jest.config.ts",
"passWithNoTests": true
}
},
"extract-strings": {
"executor": "nx:run-commands",
"options": {
"command": "yarn ts-node -P libs/localization/tsconfig.lib.json libs/localization/scripts/extract 'libs/api/domains/license-service-v2/src/lib/messages.ts'"
}
}
},
"tags": ["lib:api", "scope:api"]
}
1 change: 1 addition & 0 deletions libs/api/domains/license-service-v2/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/licenseService.module'
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'

@ObjectType('LicenseServiceV2CreateBarcodeResult')
export class CreateBarcodeResult {
@Field({
description: 'Barcode token',
})
token!: string

@Field(() => Int, {
description: 'Barcode expire time in seconds',
})
expiresIn!: number
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Field, InputType } from '@nestjs/graphql'
import { GenericLicenseType } from '../licenceService.type'

@InputType('LicenseServiceV2GeneratePkPassInput')
export class GeneratePkPassInput {
@Field(() => GenericLicenseType)
licenseType!: GenericLicenseType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'
import {
GenericLicenseType,
GenericUserLicensePkPassStatus,
GenericUserLicenseStatus,
} from '../licenceService.type'
import { GenericLicenseProvider } from './GenericLicenseProvider.dto'

registerEnumType(GenericLicenseType, {
name: 'LicenseServiceV2GenericLicenseType',
description: 'Exhaustive list of license types',
})

registerEnumType(GenericUserLicenseStatus, {
name: 'LicenseServiceV2GenericUserLicenseStatus',
description: 'Possible license statuses for user',
})

registerEnumType(GenericUserLicensePkPassStatus, {
name: 'LicenseServiceV2GenericUserLicensePkPassStatus',
description: 'Possible license pkpass statuses',
})

@ObjectType('LicenseServiceV2GenericLicense')
export class GenericLicense {
@Field(() => GenericLicenseType, {
description: 'Type of license from an exhaustive list',
})
type!: GenericLicenseType

@Field(() => GenericLicenseProvider, {
description: 'Provider of the license',
})
provider!: GenericLicenseProvider

@Field({ description: 'Does the license support pkpass?' })
pkpass!: boolean

@Field({ description: 'Does the license support verification of pkpass?' })
pkpassVerify!: boolean

@Field({
nullable: true,
deprecationReason: 'Unclear if this is used',
description:
'How long the data about the license should be treated as fresh',
})
timeout?: number

@Field(() => GenericUserLicenseStatus, { description: 'Status of license' })
status!: GenericUserLicenseStatus

@Field(() => GenericUserLicensePkPassStatus, {
description: 'Status of pkpass availablity of license',
})
pkpassStatus!: GenericUserLicensePkPassStatus
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Field, ObjectType } from '@nestjs/graphql'
import { LicenseError } from './GenericLicenseError.dto'
import { GenericUserLicense } from './GenericUserLicense.dto'

@ObjectType('LicenseServiceV2GenericLicensesCollection')
export class LicenseCollection {
@Field(() => [GenericUserLicense], { nullable: true })
licenses!: Array<GenericUserLicense>

@Field(() => [LicenseError], { nullable: true })
errors?: Array<LicenseError>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'
import { GenericLicenseDataFieldType } from '../licenceService.type'
import { GenericUserLicenseMetaLinks } from './GenericUserLicenseMetaLinks.dto'
import { GenericUserLicenseMetaTag } from './GenericUserLicenseMetaTag.dto'

registerEnumType(GenericLicenseDataFieldType, {
name: 'LicenseServiceV2GenericLicenseDataFieldType',
description: 'Possible types of data fields',
})

@ObjectType('LicenseServiceV2GenericLicenseDataField')
export class GenericLicenseDataField {
@Field(() => GenericLicenseDataFieldType, {
description: 'Type of data field',
})
type!: GenericLicenseDataFieldType

@Field({ nullable: true, description: 'Name of data field' })
name?: string

@Field({ nullable: true, description: 'Label of data field' })
label?: string

@Field({
nullable: true,
description: 'Display value of data field category',
})
description?: string

@Field({ nullable: true, description: 'Value of data field' })
value?: string

@Field(() => GenericUserLicenseMetaTag, { nullable: true })
tag?: GenericUserLicenseMetaTag

@Field(() => GenericUserLicenseMetaLinks, {
nullable: true,
description: 'External meta link',
})
link?: GenericUserLicenseMetaLinks

@Field({
nullable: true,
description: 'Hide from service portal',
defaultValue: false,
})
hideFromServicePortal?: boolean

@Field(() => [GenericLicenseDataField], {
nullable: true,
description: 'Name of data field',
})
fields?: GenericLicenseDataField[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'
import { GenericLicenseType } from '../licenceService.type'
import { GenericLicenseProvider } from './GenericLicenseProvider.dto'

@ObjectType('LicenseServiceV2GenericUserLicenseError')
export class LicenseError {
@Field(() => GenericLicenseType)
type!: GenericLicenseType

@Field(() => GenericLicenseProvider, { nullable: true })
provider?: GenericLicenseProvider

@Field(() => Int, { nullable: true })
errorCode?: number

@Field({ nullable: true })
errorMessage?: string

@Field({ nullable: true })
extraData?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'
import { GenericUserLicenseFetchStatus } from '../licenceService.type'

registerEnumType(GenericUserLicenseFetchStatus, {
name: 'LicenseServiceV2GenericUserLicenseFetchStatus',
description: 'Possible license fetch statuses',
})

@ObjectType('LicenseServiceV2GenericLicenseFetch')
export class GenericLicenseFetch {
@Field(() => GenericUserLicenseFetchStatus, {
description: 'Status of license fetch',
})
status!: GenericUserLicenseFetchStatus

@Field({ description: 'Datetime of last update of fetch status' })
updated!: string
}
Loading
Loading