@sphereon/ssi-sdk.data-store 0.30.1-unstable.4 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +77 -77
  3. package/dist/contact/ContactStore.d.ts.map +1 -1
  4. package/dist/digitalCredential/DigitalCredentialStore.d.ts.map +1 -1
  5. package/dist/eventLogger/EventLoggerStore.d.ts.map +1 -1
  6. package/dist/issuanceBranding/IssuanceBrandingStore.d.ts.map +1 -1
  7. package/dist/migrations/internal-migrations-ormconfig.d.ts.map +1 -1
  8. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js +33 -33
  9. package/dist/migrations/postgres/1708797018115-CreateMachineStateStore.js +16 -16
  10. package/dist/migrations/postgres/1715761125001-CreateContacts.js +33 -33
  11. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +12 -12
  12. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js +32 -32
  13. package/dist/migrations/sqlite/1708796002272-CreateMachineStateStore.js +15 -15
  14. package/dist/migrations/sqlite/1710438363002-CreateContacts.js +13 -13
  15. package/dist/migrations/sqlite/1715761125002-CreateContacts.js +32 -32
  16. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +9 -9
  17. package/dist/presentationDefinition/PDStore.d.ts.map +1 -1
  18. package/dist/utils/SortingUtils.d.ts.map +1 -1
  19. package/dist/utils/contact/MappingUtils.d.ts.map +1 -1
  20. package/dist/utils/digitalCredential/MappingUtils.d.ts.map +1 -1
  21. package/dist/utils/digitalCredential/MappingUtils.js +4 -4
  22. package/dist/utils/digitalCredential/MappingUtils.js.map +1 -1
  23. package/dist/utils/presentationDefinition/MappingUtils.js +2 -2
  24. package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -1
  25. package/package.json +8 -8
  26. package/src/__tests__/contact.entities.test.ts +2642 -2642
  27. package/src/__tests__/contact.store.test.ts +2649 -2649
  28. package/src/__tests__/digitalCredential.entities.test.ts +274 -274
  29. package/src/__tests__/digitalCredential.store.test.ts +330 -330
  30. package/src/__tests__/eventLogger.entities.test.ts +76 -76
  31. package/src/__tests__/eventLogger.store.test.ts +130 -130
  32. package/src/__tests__/issuanceBranding.entities.test.ts +846 -846
  33. package/src/__tests__/issuanceBranding.store.test.ts +1886 -1886
  34. package/src/__tests__/machineState.entities.test.ts +53 -53
  35. package/src/__tests__/machineState.store.test.ts +176 -176
  36. package/src/__tests__/pd-manager.entities.test.ts +73 -73
  37. package/src/__tests__/pd-manager.store.test.ts +193 -193
  38. package/src/contact/AbstractContactStore.ts +71 -71
  39. package/src/contact/ContactStore.ts +768 -768
  40. package/src/digitalCredential/AbstractDigitalCredentialStore.ts +21 -21
  41. package/src/digitalCredential/DigitalCredentialStore.ts +189 -189
  42. package/src/entities/contact/BaseContactEntity.ts +51 -51
  43. package/src/entities/contact/ConnectionEntity.ts +35 -35
  44. package/src/entities/contact/ContactMetadataItemEntity.ts +51 -51
  45. package/src/entities/contact/CorrelationIdentifierEntity.ts +43 -43
  46. package/src/entities/contact/DidAuthConfigEntity.ts +20 -20
  47. package/src/entities/contact/ElectronicAddressEntity.ts +70 -70
  48. package/src/entities/contact/IdentityEntity.ts +107 -107
  49. package/src/entities/contact/IdentityMetadataItemEntity.ts +48 -48
  50. package/src/entities/contact/NaturalPersonEntity.ts +44 -44
  51. package/src/entities/contact/OpenIdConfigEntity.ts +32 -32
  52. package/src/entities/contact/OrganizationEntity.ts +35 -35
  53. package/src/entities/contact/PartyEntity.ts +117 -117
  54. package/src/entities/contact/PartyRelationshipEntity.ts +68 -68
  55. package/src/entities/contact/PartyTypeEntity.ts +63 -63
  56. package/src/entities/contact/PhysicalAddressEntity.ts +95 -95
  57. package/src/entities/digitalCredential/DigitalCredentialEntity.ts +98 -98
  58. package/src/entities/eventLogger/AuditEventEntity.ts +92 -92
  59. package/src/entities/issuanceBranding/BackgroundAttributesEntity.ts +42 -42
  60. package/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts +87 -87
  61. package/src/entities/issuanceBranding/CredentialBrandingEntity.ts +79 -79
  62. package/src/entities/issuanceBranding/CredentialLocaleBrandingEntity.ts +33 -33
  63. package/src/entities/issuanceBranding/ImageAttributesEntity.ts +57 -57
  64. package/src/entities/issuanceBranding/ImageDimensionsEntity.ts +22 -22
  65. package/src/entities/issuanceBranding/IssuerBrandingEntity.ts +73 -73
  66. package/src/entities/issuanceBranding/IssuerLocaleBrandingEntity.ts +33 -33
  67. package/src/entities/issuanceBranding/TextAttributesEntity.ts +31 -31
  68. package/src/entities/machineState/MachineStateInfoEntity.ts +59 -59
  69. package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +44 -44
  70. package/src/entities/statusList2021/StatusList2021Entity.ts +96 -96
  71. package/src/entities/statusList2021/StatusList2021EntryEntity.ts +29 -29
  72. package/src/eventLogger/AbstractEventLoggerStore.ts +7 -7
  73. package/src/eventLogger/EventLoggerStore.ts +62 -62
  74. package/src/index.ts +160 -160
  75. package/src/issuanceBranding/IssuanceBrandingStore.ts +559 -559
  76. package/src/machineState/IAbstractMachineStateStore.ts +65 -65
  77. package/src/machineState/MachineStateStore.ts +149 -149
  78. package/src/migrations/generic/1-CreateContacts.ts +66 -66
  79. package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -66
  80. package/src/migrations/generic/2-CreateIssuanceBranding.ts +64 -64
  81. package/src/migrations/generic/3-CreateContacts.ts +66 -66
  82. package/src/migrations/generic/4-CreateStatusList.ts +54 -54
  83. package/src/migrations/generic/5-CreateAuditEvents.ts +66 -66
  84. package/src/migrations/generic/6-CreateDigitalCredential.ts +66 -66
  85. package/src/migrations/generic/7-CreateMachineStateStore.ts +66 -66
  86. package/src/migrations/generic/8-CreateContacts.ts +66 -66
  87. package/src/migrations/generic/9-CreateContacts.ts +66 -66
  88. package/src/migrations/generic/index.ts +43 -43
  89. package/src/migrations/index.ts +10 -10
  90. package/src/migrations/postgres/1659463079428-CreateContacts.ts +63 -63
  91. package/src/migrations/postgres/1685628974232-CreateIssuanceBranding.ts +85 -85
  92. package/src/migrations/postgres/1690925872592-CreateContacts.ts +158 -158
  93. package/src/migrations/postgres/1693866470001-CreateStatusList.ts +24 -24
  94. package/src/migrations/postgres/1701634812183-CreateAuditEvents.ts +33 -33
  95. package/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts +61 -61
  96. package/src/migrations/postgres/1708797018115-CreateMachineStateStore.ts +29 -29
  97. package/src/migrations/postgres/1710438363001-CreateContacts.ts +63 -63
  98. package/src/migrations/postgres/1715761125001-CreateContacts.ts +60 -60
  99. package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -25
  100. package/src/migrations/sqlite/1659463069549-CreateContacts.ts +110 -110
  101. package/src/migrations/sqlite/1685628973231-CreateIssuanceBranding.ts +119 -119
  102. package/src/migrations/sqlite/1690925872693-CreateContacts.ts +228 -228
  103. package/src/migrations/sqlite/1693866470000-CreateStatusList.ts +24 -24
  104. package/src/migrations/sqlite/1701634819487-CreateAuditEvents.ts +15 -15
  105. package/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts +46 -46
  106. package/src/migrations/sqlite/1708796002272-CreateMachineStateStore.ts +28 -28
  107. package/src/migrations/sqlite/1710438363002-CreateContacts.ts +83 -83
  108. package/src/migrations/sqlite/1715761125002-CreateContacts.ts +59 -59
  109. package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -24
  110. package/src/presentationDefinition/AbstractPDStore.ts +20 -20
  111. package/src/presentationDefinition/PDStore.ts +185 -185
  112. package/src/statusList/IStatusListStore.ts +44 -44
  113. package/src/statusList/StatusListStore.ts +236 -236
  114. package/src/types/contact/IAbstractContactStore.ts +161 -161
  115. package/src/types/contact/contact.ts +295 -295
  116. package/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts +42 -42
  117. package/src/types/digitalCredential/digitalCredential.ts +102 -102
  118. package/src/types/eventLogger/IAbstractEventLoggerStore.ts +12 -12
  119. package/src/types/eventLogger/eventLogger.ts +3 -3
  120. package/src/types/index.ts +14 -14
  121. package/src/types/machineState/IAbstractMachineStateStore.ts +68 -68
  122. package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -25
  123. package/src/types/presentationDefinition/presentationDefinition.ts +17 -17
  124. package/src/utils/SortingUtils.ts +16 -16
  125. package/src/utils/contact/MappingUtils.ts +506 -506
  126. package/src/utils/digitalCredential/MappingUtils.ts +160 -160
  127. package/src/utils/hasher.ts +19 -19
  128. package/src/utils/presentationDefinition/MappingUtils.ts +52 -52
  129. package/dist/entities/contact/IMetadataEntity.d.ts +0 -8
  130. package/dist/entities/contact/IMetadataEntity.d.ts.map +0 -1
  131. package/dist/entities/contact/IMetadataEntity.js +0 -2
  132. package/dist/entities/contact/IMetadataEntity.js.map +0 -1
  133. package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts +0 -7
  134. package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts.map +0 -1
  135. package/dist/migrations/generic/8-CreatePresentationDefinitions.js +0 -78
  136. package/dist/migrations/generic/8-CreatePresentationDefinitions.js.map +0 -1
@@ -1,559 +1,559 @@
1
- import Debug from 'debug'
2
- import { DataSource, DeleteResult, In, Not, Repository } from 'typeorm'
3
- import { OrPromise } from '@sphereon/ssi-types'
4
- import { BackgroundAttributesEntity } from '../entities/issuanceBranding/BackgroundAttributesEntity'
5
- import { ImageAttributesEntity } from '../entities/issuanceBranding/ImageAttributesEntity'
6
- import { ImageDimensionsEntity } from '../entities/issuanceBranding/ImageDimensionsEntity'
7
- import { IssuerBrandingEntity, issuerBrandingEntityFrom } from '../entities/issuanceBranding/IssuerBrandingEntity'
8
- import { CredentialBrandingEntity, credentialBrandingEntityFrom } from '../entities/issuanceBranding/CredentialBrandingEntity'
9
- import { CredentialLocaleBrandingEntity, credentialLocaleBrandingEntityFrom } from '../entities/issuanceBranding/CredentialLocaleBrandingEntity'
10
- import { IssuerLocaleBrandingEntity, issuerLocaleBrandingEntityFrom } from '../entities/issuanceBranding/IssuerLocaleBrandingEntity'
11
- import { BaseLocaleBrandingEntity } from '../entities/issuanceBranding/BaseLocaleBrandingEntity'
12
- import { TextAttributesEntity } from '../entities/issuanceBranding/TextAttributesEntity'
13
- import { AbstractIssuanceBrandingStore } from './AbstractIssuanceBrandingStore'
14
- import {
15
- IAddCredentialBrandingArgs,
16
- IAddCredentialLocaleBrandingArgs,
17
- IAddIssuerBrandingArgs,
18
- IAddIssuerLocaleBrandingArgs,
19
- IBasicCredentialLocaleBranding,
20
- IBasicIssuerLocaleBranding,
21
- ICredentialBranding,
22
- IPartialCredentialBranding,
23
- ICredentialLocaleBranding,
24
- ICredentialLocaleBrandingFilter,
25
- IGetCredentialBrandingArgs,
26
- IGetCredentialLocaleBrandingArgs,
27
- IGetIssuerBrandingArgs,
28
- IGetIssuerLocaleBrandingArgs,
29
- IIssuerBranding,
30
- IIssuerBrandingFilter,
31
- IIssuerLocaleBranding,
32
- IIssuerLocaleBrandingFilter,
33
- ILocaleBranding,
34
- IRemoveCredentialBrandingArgs,
35
- IRemoveCredentialLocaleBrandingArgs,
36
- IRemoveIssuerBrandingArgs,
37
- IRemoveIssuerLocaleBrandingArgs,
38
- IUpdateCredentialBrandingArgs,
39
- IUpdateCredentialLocaleBrandingArgs,
40
- IUpdateIssuerBrandingArgs,
41
- IUpdateIssuerLocaleBrandingArgs,
42
- ICredentialBrandingFilter,
43
- } from '../types'
44
-
45
- const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:issuance-branding-store')
46
-
47
- export class IssuanceBrandingStore extends AbstractIssuanceBrandingStore {
48
- private readonly dbConnection: OrPromise<DataSource>
49
-
50
- constructor(dbConnection: OrPromise<DataSource>) {
51
- super()
52
- this.dbConnection = dbConnection
53
- }
54
-
55
- public addCredentialBranding = async (args: IAddCredentialBrandingArgs): Promise<ICredentialBranding> => {
56
- const { localeBranding, vcHash } = args
57
- const repository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
58
- const result: CredentialBrandingEntity | null = await repository.findOne({
59
- where: [{ vcHash }],
60
- })
61
-
62
- if (result) {
63
- return Promise.reject(Error(`Credential branding already present for vc with hash: ${vcHash}`))
64
- }
65
-
66
- if (await this.hasDuplicateLocales(localeBranding)) {
67
- return Promise.reject(Error(`Credential branding contains duplicate locales`))
68
- }
69
-
70
- const credentialBrandingEntity: CredentialBrandingEntity = credentialBrandingEntityFrom(args)
71
- debug('Adding credential branding', credentialBrandingEntity)
72
- const createdResult: CredentialBrandingEntity = await repository.save(credentialBrandingEntity)
73
-
74
- return this.credentialBrandingFrom(createdResult)
75
- }
76
-
77
- public getCredentialBranding = async (args?: IGetCredentialBrandingArgs): Promise<Array<ICredentialBranding>> => {
78
- const { filter } = args ?? {}
79
- if (filter) {
80
- filter.forEach((filter: IPartialCredentialBranding): void => {
81
- if (filter.localeBranding && 'locale' in filter.localeBranding && filter.localeBranding.locale === undefined) {
82
- filter.localeBranding.locale = ''
83
- }
84
- })
85
- }
86
-
87
- debug('Getting credential branding', args)
88
- const result: Array<CredentialBrandingEntity> = await (await this.dbConnection).getRepository(CredentialBrandingEntity).find({
89
- ...(filter && { where: filter }),
90
- })
91
-
92
- return result.map((credentialBranding: CredentialBrandingEntity) => this.credentialBrandingFrom(credentialBranding))
93
- }
94
-
95
- public removeCredentialBranding = async (args: IRemoveCredentialBrandingArgs): Promise<void> => {
96
- const { filter } = args
97
- const repository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
98
- const credentialBranding: Array<CredentialBrandingEntity> = await repository.find({
99
- where: filter,
100
- })
101
-
102
- debug('Removing credential locale branding', args)
103
- const localeBrandingDeletions: Array<Array<Promise<void>>> = credentialBranding.map((credentialBranding: CredentialBrandingEntity) =>
104
- credentialBranding.localeBranding.map(
105
- async (localeBranding: CredentialLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
106
- ),
107
- )
108
- await Promise.all(localeBrandingDeletions)
109
-
110
- debug('Removing credential branding', args)
111
- const credentialBrandingDeletions: Array<Promise<DeleteResult>> = filter.map(
112
- async (filter: ICredentialBrandingFilter): Promise<DeleteResult> => await repository.delete(filter),
113
- )
114
- await Promise.all(credentialBrandingDeletions)
115
- }
116
-
117
- public updateCredentialBranding = async (args: IUpdateCredentialBrandingArgs): Promise<ICredentialBranding> => {
118
- const { credentialBranding } = args
119
- const repository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
120
- const credentialBrandingEntity: CredentialBrandingEntity | null = await repository.findOne({
121
- where: { id: credentialBranding.id },
122
- })
123
-
124
- if (!credentialBrandingEntity) {
125
- return Promise.reject(Error(`No credential branding found for id: ${credentialBranding.id}`))
126
- }
127
-
128
- const branding: Omit<ICredentialBranding, 'createdAt' | 'lastUpdatedAt'> = {
129
- ...credentialBranding,
130
- localeBranding: credentialBrandingEntity.localeBranding,
131
- }
132
-
133
- debug('Updating credential branding', branding)
134
- const result: CredentialBrandingEntity = await repository.save(branding, { transaction: true })
135
-
136
- return this.credentialBrandingFrom(result)
137
- }
138
-
139
- public addCredentialLocaleBranding = async (args: IAddCredentialLocaleBrandingArgs): Promise<ICredentialBranding> => {
140
- const { credentialBrandingId, localeBranding } = args
141
- const credentialBrandingRepository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
142
- const credentialBranding: CredentialBrandingEntity | null = await credentialBrandingRepository.findOne({
143
- where: { id: credentialBrandingId },
144
- })
145
-
146
- if (!credentialBranding) {
147
- return Promise.reject(Error(`No credential branding found for id: ${credentialBrandingId}`))
148
- }
149
-
150
- const locales: Array<CredentialLocaleBrandingEntity> | null = await (await this.dbConnection).getRepository(CredentialLocaleBrandingEntity).find({
151
- where: {
152
- credentialBranding: {
153
- id: credentialBrandingId,
154
- },
155
- locale: In(localeBranding.map((localeBranding: IBasicCredentialLocaleBranding) => localeBranding.locale)),
156
- },
157
- })
158
-
159
- if (locales && locales.length > 0) {
160
- return Promise.reject(
161
- Error(
162
- `Credential branding already contains locales: ${locales?.map(
163
- (credentialLocaleBrandingEntity: CredentialLocaleBrandingEntity) => credentialLocaleBrandingEntity.locale,
164
- )}`,
165
- ),
166
- )
167
- }
168
-
169
- const credentialLocaleBrandingRepository: Repository<CredentialLocaleBrandingEntity> = (await this.dbConnection).getRepository(
170
- CredentialLocaleBrandingEntity,
171
- )
172
- const addCredentialLocaleBranding: Array<Promise<void>> = localeBranding.map(
173
- async (localeBranding: IBasicCredentialLocaleBranding): Promise<void> => {
174
- const credentialLocaleBrandingEntity: CredentialLocaleBrandingEntity = credentialLocaleBrandingEntityFrom(localeBranding)
175
- debug('Adding credential locale branding', credentialLocaleBrandingEntity)
176
- credentialLocaleBrandingEntity.credentialBranding = credentialBranding
177
- await credentialLocaleBrandingRepository.save(credentialLocaleBrandingEntity, { transaction: true })
178
- },
179
- )
180
-
181
- await Promise.all(addCredentialLocaleBranding)
182
-
183
- const result: CredentialBrandingEntity | null = await credentialBrandingRepository.findOne({
184
- where: { id: credentialBrandingId },
185
- })
186
-
187
- if (!result) {
188
- return Promise.reject(Error('Unable to get updated credential branding'))
189
- }
190
-
191
- return this.credentialBrandingFrom(result)
192
- }
193
-
194
- public getCredentialLocaleBranding = async (args?: IGetCredentialLocaleBrandingArgs): Promise<Array<ICredentialLocaleBranding>> => {
195
- const { filter } = args ?? {}
196
- if (filter) {
197
- filter.forEach((filter: ICredentialLocaleBrandingFilter): void => {
198
- if ('locale' in filter && filter.locale === undefined) {
199
- filter.locale = ''
200
- }
201
- })
202
- }
203
-
204
- debug('Getting credential locale branding', args)
205
- const credentialBrandingLocale: Array<CredentialLocaleBrandingEntity> | null = await (await this.dbConnection)
206
- .getRepository(CredentialLocaleBrandingEntity)
207
- .find({
208
- ...(filter && { where: filter }),
209
- })
210
-
211
- return credentialBrandingLocale
212
- ? credentialBrandingLocale.map(
213
- (credentialLocaleBranding: CredentialLocaleBrandingEntity) =>
214
- this.localeBrandingFrom(credentialLocaleBranding) as ICredentialLocaleBranding,
215
- )
216
- : []
217
- }
218
-
219
- public removeCredentialLocaleBranding = async (args: IRemoveCredentialLocaleBrandingArgs): Promise<void> => {
220
- const { filter } = args
221
- const credentialLocaleBranding: Array<CredentialLocaleBrandingEntity> = await (await this.dbConnection)
222
- .getRepository(CredentialLocaleBrandingEntity)
223
- .find({
224
- where: filter,
225
- })
226
-
227
- debug('Removing credential locale branding', args)
228
- const localeBrandingDeletions: Array<Promise<void>> = credentialLocaleBranding.map(
229
- async (localeBranding: CredentialLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
230
- )
231
- await Promise.all(localeBrandingDeletions)
232
- }
233
-
234
- public updateCredentialLocaleBranding = async (args: IUpdateCredentialLocaleBrandingArgs): Promise<ICredentialLocaleBranding> => {
235
- const { localeBranding } = args
236
- const repository: Repository<CredentialLocaleBrandingEntity> = (await this.dbConnection).getRepository(CredentialLocaleBrandingEntity)
237
- const result: CredentialLocaleBrandingEntity | null = await repository.findOne({
238
- where: { id: localeBranding.id },
239
- })
240
-
241
- if (!result) {
242
- return Promise.reject(Error(`No credential locale branding found for id: ${localeBranding.id}`))
243
- }
244
-
245
- const locales: Array<CredentialLocaleBrandingEntity> | null = await repository.find({
246
- where: {
247
- credentialBranding: {
248
- id: result.credentialBrandingId,
249
- },
250
- id: Not(In([localeBranding.id])),
251
- locale: localeBranding.locale,
252
- },
253
- })
254
-
255
- if (locales && locales.length > 0) {
256
- return Promise.reject(Error(`Credential branding: ${result.credentialBrandingId} already contains locale: ${localeBranding.locale}`))
257
- }
258
-
259
- debug('Updating credential locale branding', localeBranding)
260
- const updatedResult: CredentialLocaleBrandingEntity = await repository.save(localeBranding, { transaction: true })
261
-
262
- return this.localeBrandingFrom(updatedResult) as ICredentialLocaleBranding
263
- }
264
-
265
- public addIssuerBranding = async (args: IAddIssuerBrandingArgs): Promise<IIssuerBranding> => {
266
- const { localeBranding, issuerCorrelationId } = args
267
- const repository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
268
- const result: IssuerBrandingEntity | null = await repository.findOne({
269
- where: [{ issuerCorrelationId }],
270
- })
271
-
272
- if (result) {
273
- return Promise.reject(Error(`Issuer branding already present for issuer with correlation id: ${issuerCorrelationId}`))
274
- }
275
-
276
- if (await this.hasDuplicateLocales(localeBranding)) {
277
- return Promise.reject(Error(`Issuer branding contains duplicate locales`))
278
- }
279
-
280
- const issuerBrandingEntity: IssuerBrandingEntity = issuerBrandingEntityFrom(args)
281
- debug('Adding issuer branding', issuerBrandingEntity)
282
- const createdResult: IssuerBrandingEntity = await repository.save(issuerBrandingEntity)
283
-
284
- return this.issuerBrandingFrom(createdResult)
285
- }
286
-
287
- public getIssuerBranding = async (args?: IGetIssuerBrandingArgs): Promise<Array<IIssuerBranding>> => {
288
- const { filter } = args ?? {}
289
- if (filter) {
290
- filter.forEach((filter: IIssuerBrandingFilter): void => {
291
- if (filter.localeBranding && 'locale' in filter.localeBranding && filter.localeBranding.locale === undefined) {
292
- filter.localeBranding.locale = ''
293
- }
294
- })
295
- }
296
-
297
- debug('Getting issuer branding', args)
298
- const result: Array<IssuerBrandingEntity> = await (await this.dbConnection).getRepository(IssuerBrandingEntity).find({
299
- ...(filter && { where: filter }),
300
- })
301
-
302
- return result.map((issuerBranding: IssuerBrandingEntity) => this.issuerBrandingFrom(issuerBranding))
303
- }
304
-
305
- public removeIssuerBranding = async (args: IRemoveIssuerBrandingArgs): Promise<void> => {
306
- const { filter } = args
307
- const repository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
308
- const issuerBranding: Array<IssuerBrandingEntity> = await repository.find({
309
- where: filter,
310
- })
311
-
312
- debug('Removing issuer locale branding', args)
313
- const localeBrandingDeletions: Array<Array<Promise<void>>> = issuerBranding.map((issuerBranding: IssuerBrandingEntity) =>
314
- issuerBranding.localeBranding.map(
315
- async (localeBranding: IssuerLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
316
- ),
317
- )
318
- await Promise.all(localeBrandingDeletions)
319
-
320
- debug('Removing issuer branding', args)
321
- const issuerBrandingDeletions: Array<Promise<DeleteResult>> = filter.map(
322
- async (filter: IIssuerBrandingFilter): Promise<DeleteResult> => await repository.delete(filter),
323
- )
324
- await Promise.all(issuerBrandingDeletions)
325
- }
326
-
327
- public updateIssuerBranding = async (args: IUpdateIssuerBrandingArgs): Promise<IIssuerBranding> => {
328
- const { issuerBranding } = args
329
- const repository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
330
- const issuerBrandingEntity: IssuerBrandingEntity | null = await repository.findOne({
331
- where: { id: issuerBranding.id },
332
- })
333
-
334
- if (!issuerBrandingEntity) {
335
- return Promise.reject(Error(`No issuer branding found for id: ${issuerBranding.id}`))
336
- }
337
-
338
- const branding: Omit<IIssuerBranding, 'createdAt' | 'lastUpdatedAt'> = {
339
- ...issuerBranding,
340
- localeBranding: issuerBrandingEntity.localeBranding,
341
- }
342
-
343
- debug('Updating issuer branding', branding)
344
- const result: IssuerBrandingEntity = await repository.save(branding, { transaction: true })
345
-
346
- return this.issuerBrandingFrom(result)
347
- }
348
-
349
- public addIssuerLocaleBranding = async (args: IAddIssuerLocaleBrandingArgs): Promise<IIssuerBranding> => {
350
- const { localeBranding, issuerBrandingId } = args
351
- const issuerBrandingRepository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
352
- const issuerBranding: IssuerBrandingEntity | null = await issuerBrandingRepository.findOne({
353
- where: { id: issuerBrandingId },
354
- })
355
-
356
- if (!issuerBranding) {
357
- return Promise.reject(Error(`No issuer branding found for id: ${issuerBrandingId}`))
358
- }
359
-
360
- const locales: Array<IssuerLocaleBrandingEntity> | null = await (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity).find({
361
- where: {
362
- issuerBranding: {
363
- id: issuerBrandingId,
364
- },
365
- locale: In(localeBranding.map((localeBranding: IBasicIssuerLocaleBranding) => localeBranding.locale)),
366
- },
367
- })
368
-
369
- if (locales && locales.length > 0) {
370
- return Promise.reject(
371
- Error(
372
- `Issuer branding already contains locales: ${locales?.map(
373
- (issuerLocaleBrandingEntity: IssuerLocaleBrandingEntity) => issuerLocaleBrandingEntity.locale,
374
- )}`,
375
- ),
376
- )
377
- }
378
-
379
- const issuerLocaleBrandingRepository: Repository<IssuerLocaleBrandingEntity> = (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity)
380
- const addIssuerLocaleBranding: Array<Promise<void>> = localeBranding.map(async (localeBranding: IBasicIssuerLocaleBranding): Promise<void> => {
381
- const issuerLocaleBrandingEntity: IssuerLocaleBrandingEntity = issuerLocaleBrandingEntityFrom(localeBranding)
382
- debug('Adding issuer locale branding', issuerLocaleBrandingEntity)
383
- issuerLocaleBrandingEntity.issuerBranding = issuerBranding
384
- await issuerLocaleBrandingRepository.save(issuerLocaleBrandingEntity, { transaction: true })
385
- })
386
-
387
- await Promise.all(addIssuerLocaleBranding)
388
-
389
- const result: IssuerBrandingEntity | null = await issuerBrandingRepository.findOne({
390
- where: { id: issuerBrandingId },
391
- })
392
-
393
- if (!result) {
394
- return Promise.reject(Error('Unable to get updated issuer branding'))
395
- }
396
-
397
- return this.issuerBrandingFrom(result)
398
- }
399
-
400
- public getIssuerLocaleBranding = async (args?: IGetIssuerLocaleBrandingArgs): Promise<Array<IIssuerLocaleBranding>> => {
401
- const { filter } = args ?? {}
402
- if (filter) {
403
- filter.forEach((filter: IIssuerLocaleBrandingFilter): void => {
404
- if ('locale' in filter && filter.locale === undefined) {
405
- filter.locale = ''
406
- }
407
- })
408
- }
409
-
410
- debug('Getting issuer locale branding', args)
411
- const issuerLocaleBranding: Array<IssuerLocaleBrandingEntity> | null = await (await this.dbConnection)
412
- .getRepository(IssuerLocaleBrandingEntity)
413
- .find({
414
- ...(filter && { where: filter }),
415
- })
416
-
417
- return issuerLocaleBranding
418
- ? issuerLocaleBranding.map(
419
- (issuerLocaleBranding: IssuerLocaleBrandingEntity) => this.localeBrandingFrom(issuerLocaleBranding) as IIssuerLocaleBranding,
420
- )
421
- : []
422
- }
423
-
424
- public removeIssuerLocaleBranding = async (args: IRemoveIssuerLocaleBrandingArgs): Promise<void> => {
425
- const { filter } = args
426
- const issuerLocaleBranding: Array<IssuerLocaleBrandingEntity> = await (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity).find({
427
- where: filter,
428
- })
429
-
430
- debug('Removing credential locale branding', args)
431
- const localeBrandingDeletions: Array<Promise<void>> = issuerLocaleBranding.map(
432
- async (localeBranding: IssuerLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
433
- )
434
- await Promise.all(localeBrandingDeletions)
435
- }
436
-
437
- public updateIssuerLocaleBranding = async (args: IUpdateIssuerLocaleBrandingArgs): Promise<IIssuerLocaleBranding> => {
438
- const { localeBranding } = args
439
- const repository: Repository<IssuerLocaleBrandingEntity> = (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity)
440
- const result: IssuerLocaleBrandingEntity | null = await repository.findOne({
441
- where: { id: localeBranding.id },
442
- })
443
-
444
- if (!result) {
445
- return Promise.reject(Error(`No issuer locale branding found for id: ${localeBranding.id}`))
446
- }
447
-
448
- const locales: Array<IssuerLocaleBrandingEntity> | null = await repository.find({
449
- where: {
450
- issuerBranding: {
451
- id: result.issuerBrandingId,
452
- },
453
- id: Not(In([localeBranding.id])),
454
- locale: localeBranding.locale,
455
- },
456
- })
457
-
458
- if (locales && locales.length > 0) {
459
- return Promise.reject(Error(`Issuer branding: ${result.issuerBrandingId} already contains locale: ${localeBranding.locale}`))
460
- }
461
-
462
- debug('Updating issuer locale branding', localeBranding)
463
- const updatedResult: IssuerLocaleBrandingEntity = await repository.save(localeBranding, { transaction: true })
464
-
465
- return this.localeBrandingFrom(updatedResult) as IIssuerLocaleBranding
466
- }
467
-
468
- private credentialBrandingFrom = (credentialBranding: CredentialBrandingEntity): ICredentialBranding => {
469
- const result: ICredentialBranding = {
470
- ...credentialBranding,
471
- localeBranding: credentialBranding.localeBranding.map((localeBranding: BaseLocaleBrandingEntity) => this.localeBrandingFrom(localeBranding)),
472
- }
473
-
474
- return this.replaceNullWithUndefined(result)
475
- }
476
-
477
- private issuerBrandingFrom = (issuerBranding: IssuerBrandingEntity): IIssuerBranding => {
478
- const result: IIssuerBranding = {
479
- ...issuerBranding,
480
- localeBranding: issuerBranding.localeBranding.map((localeBranding: BaseLocaleBrandingEntity) => this.localeBrandingFrom(localeBranding)),
481
- }
482
-
483
- return this.replaceNullWithUndefined(result)
484
- }
485
-
486
- private localeBrandingFrom = (localeBranding: BaseLocaleBrandingEntity): ILocaleBranding => {
487
- const result: ILocaleBranding = {
488
- ...localeBranding,
489
- locale: localeBranding.locale === '' ? undefined : localeBranding.locale,
490
- }
491
-
492
- return this.replaceNullWithUndefined(result)
493
- }
494
-
495
- private replaceNullWithUndefined(obj: any): any {
496
- if (obj === null) {
497
- return undefined
498
- }
499
-
500
- if (typeof obj !== 'object' || obj instanceof Date) {
501
- return obj
502
- }
503
-
504
- if (Array.isArray(obj)) {
505
- return obj.map((value: any) => this.replaceNullWithUndefined(value))
506
- }
507
-
508
- const result: any = {}
509
- for (const key in obj) {
510
- if (obj.hasOwnProperty(key)) {
511
- result[key] = this.replaceNullWithUndefined(obj[key])
512
- }
513
- }
514
- return result
515
- }
516
-
517
- private hasDuplicateLocales = async (localeBranding: Array<IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding>): Promise<boolean> => {
518
- let seen: Set<string | undefined> = new Set()
519
- return localeBranding.some((localeBranding: IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding): boolean => {
520
- return seen.size === seen.add(localeBranding.locale).size
521
- })
522
- }
523
-
524
- private removeLocaleBranding = async (localeBranding: BaseLocaleBrandingEntity): Promise<void> => {
525
- debug('Removing credential locale branding', localeBranding)
526
- // Delete background image dimensions
527
- if (localeBranding.background?.image?.dimensions) {
528
- await (await this.dbConnection).getRepository(ImageDimensionsEntity).delete({ id: localeBranding.background?.image?.dimensions?.id })
529
- }
530
-
531
- // Delete background image
532
- if (localeBranding.background?.image) {
533
- await (await this.dbConnection).getRepository(ImageAttributesEntity).delete({ id: localeBranding.background?.image?.id })
534
- }
535
-
536
- // Delete background
537
- if (localeBranding.background) {
538
- await (await this.dbConnection).getRepository(BackgroundAttributesEntity).delete({ id: localeBranding.background?.id })
539
- }
540
-
541
- // Delete logo image dimensions
542
- if (localeBranding.logo?.dimensions) {
543
- await (await this.dbConnection).getRepository(ImageDimensionsEntity).delete({ id: localeBranding.logo?.dimensions?.id })
544
- }
545
-
546
- // Delete logo
547
- if (localeBranding.logo) {
548
- await (await this.dbConnection).getRepository(ImageAttributesEntity).delete({ id: localeBranding.logo?.id })
549
- }
550
-
551
- // Delete text
552
- if (localeBranding.text) {
553
- await (await this.dbConnection).getRepository(TextAttributesEntity).delete({ id: localeBranding.text?.id })
554
- }
555
-
556
- // Delete locale branding
557
- await (await this.dbConnection).getRepository(CredentialLocaleBrandingEntity).delete({ id: localeBranding.id })
558
- }
559
- }
1
+ import Debug from 'debug'
2
+ import { DataSource, DeleteResult, In, Not, Repository } from 'typeorm'
3
+ import { OrPromise } from '@sphereon/ssi-types'
4
+ import { BackgroundAttributesEntity } from '../entities/issuanceBranding/BackgroundAttributesEntity'
5
+ import { ImageAttributesEntity } from '../entities/issuanceBranding/ImageAttributesEntity'
6
+ import { ImageDimensionsEntity } from '../entities/issuanceBranding/ImageDimensionsEntity'
7
+ import { IssuerBrandingEntity, issuerBrandingEntityFrom } from '../entities/issuanceBranding/IssuerBrandingEntity'
8
+ import { CredentialBrandingEntity, credentialBrandingEntityFrom } from '../entities/issuanceBranding/CredentialBrandingEntity'
9
+ import { CredentialLocaleBrandingEntity, credentialLocaleBrandingEntityFrom } from '../entities/issuanceBranding/CredentialLocaleBrandingEntity'
10
+ import { IssuerLocaleBrandingEntity, issuerLocaleBrandingEntityFrom } from '../entities/issuanceBranding/IssuerLocaleBrandingEntity'
11
+ import { BaseLocaleBrandingEntity } from '../entities/issuanceBranding/BaseLocaleBrandingEntity'
12
+ import { TextAttributesEntity } from '../entities/issuanceBranding/TextAttributesEntity'
13
+ import { AbstractIssuanceBrandingStore } from './AbstractIssuanceBrandingStore'
14
+ import {
15
+ IAddCredentialBrandingArgs,
16
+ IAddCredentialLocaleBrandingArgs,
17
+ IAddIssuerBrandingArgs,
18
+ IAddIssuerLocaleBrandingArgs,
19
+ IBasicCredentialLocaleBranding,
20
+ IBasicIssuerLocaleBranding,
21
+ ICredentialBranding,
22
+ IPartialCredentialBranding,
23
+ ICredentialLocaleBranding,
24
+ ICredentialLocaleBrandingFilter,
25
+ IGetCredentialBrandingArgs,
26
+ IGetCredentialLocaleBrandingArgs,
27
+ IGetIssuerBrandingArgs,
28
+ IGetIssuerLocaleBrandingArgs,
29
+ IIssuerBranding,
30
+ IIssuerBrandingFilter,
31
+ IIssuerLocaleBranding,
32
+ IIssuerLocaleBrandingFilter,
33
+ ILocaleBranding,
34
+ IRemoveCredentialBrandingArgs,
35
+ IRemoveCredentialLocaleBrandingArgs,
36
+ IRemoveIssuerBrandingArgs,
37
+ IRemoveIssuerLocaleBrandingArgs,
38
+ IUpdateCredentialBrandingArgs,
39
+ IUpdateCredentialLocaleBrandingArgs,
40
+ IUpdateIssuerBrandingArgs,
41
+ IUpdateIssuerLocaleBrandingArgs,
42
+ ICredentialBrandingFilter,
43
+ } from '../types'
44
+
45
+ const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:issuance-branding-store')
46
+
47
+ export class IssuanceBrandingStore extends AbstractIssuanceBrandingStore {
48
+ private readonly dbConnection: OrPromise<DataSource>
49
+
50
+ constructor(dbConnection: OrPromise<DataSource>) {
51
+ super()
52
+ this.dbConnection = dbConnection
53
+ }
54
+
55
+ public addCredentialBranding = async (args: IAddCredentialBrandingArgs): Promise<ICredentialBranding> => {
56
+ const { localeBranding, vcHash } = args
57
+ const repository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
58
+ const result: CredentialBrandingEntity | null = await repository.findOne({
59
+ where: [{ vcHash }],
60
+ })
61
+
62
+ if (result) {
63
+ return Promise.reject(Error(`Credential branding already present for vc with hash: ${vcHash}`))
64
+ }
65
+
66
+ if (await this.hasDuplicateLocales(localeBranding)) {
67
+ return Promise.reject(Error(`Credential branding contains duplicate locales`))
68
+ }
69
+
70
+ const credentialBrandingEntity: CredentialBrandingEntity = credentialBrandingEntityFrom(args)
71
+ debug('Adding credential branding', credentialBrandingEntity)
72
+ const createdResult: CredentialBrandingEntity = await repository.save(credentialBrandingEntity)
73
+
74
+ return this.credentialBrandingFrom(createdResult)
75
+ }
76
+
77
+ public getCredentialBranding = async (args?: IGetCredentialBrandingArgs): Promise<Array<ICredentialBranding>> => {
78
+ const { filter } = args ?? {}
79
+ if (filter) {
80
+ filter.forEach((filter: IPartialCredentialBranding): void => {
81
+ if (filter.localeBranding && 'locale' in filter.localeBranding && filter.localeBranding.locale === undefined) {
82
+ filter.localeBranding.locale = ''
83
+ }
84
+ })
85
+ }
86
+
87
+ debug('Getting credential branding', args)
88
+ const result: Array<CredentialBrandingEntity> = await (await this.dbConnection).getRepository(CredentialBrandingEntity).find({
89
+ ...(filter && { where: filter }),
90
+ })
91
+
92
+ return result.map((credentialBranding: CredentialBrandingEntity) => this.credentialBrandingFrom(credentialBranding))
93
+ }
94
+
95
+ public removeCredentialBranding = async (args: IRemoveCredentialBrandingArgs): Promise<void> => {
96
+ const { filter } = args
97
+ const repository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
98
+ const credentialBranding: Array<CredentialBrandingEntity> = await repository.find({
99
+ where: filter,
100
+ })
101
+
102
+ debug('Removing credential locale branding', args)
103
+ const localeBrandingDeletions: Array<Array<Promise<void>>> = credentialBranding.map((credentialBranding: CredentialBrandingEntity) =>
104
+ credentialBranding.localeBranding.map(
105
+ async (localeBranding: CredentialLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
106
+ ),
107
+ )
108
+ await Promise.all(localeBrandingDeletions)
109
+
110
+ debug('Removing credential branding', args)
111
+ const credentialBrandingDeletions: Array<Promise<DeleteResult>> = filter.map(
112
+ async (filter: ICredentialBrandingFilter): Promise<DeleteResult> => await repository.delete(filter),
113
+ )
114
+ await Promise.all(credentialBrandingDeletions)
115
+ }
116
+
117
+ public updateCredentialBranding = async (args: IUpdateCredentialBrandingArgs): Promise<ICredentialBranding> => {
118
+ const { credentialBranding } = args
119
+ const repository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
120
+ const credentialBrandingEntity: CredentialBrandingEntity | null = await repository.findOne({
121
+ where: { id: credentialBranding.id },
122
+ })
123
+
124
+ if (!credentialBrandingEntity) {
125
+ return Promise.reject(Error(`No credential branding found for id: ${credentialBranding.id}`))
126
+ }
127
+
128
+ const branding: Omit<ICredentialBranding, 'createdAt' | 'lastUpdatedAt'> = {
129
+ ...credentialBranding,
130
+ localeBranding: credentialBrandingEntity.localeBranding,
131
+ }
132
+
133
+ debug('Updating credential branding', branding)
134
+ const result: CredentialBrandingEntity = await repository.save(branding, { transaction: true })
135
+
136
+ return this.credentialBrandingFrom(result)
137
+ }
138
+
139
+ public addCredentialLocaleBranding = async (args: IAddCredentialLocaleBrandingArgs): Promise<ICredentialBranding> => {
140
+ const { credentialBrandingId, localeBranding } = args
141
+ const credentialBrandingRepository: Repository<CredentialBrandingEntity> = (await this.dbConnection).getRepository(CredentialBrandingEntity)
142
+ const credentialBranding: CredentialBrandingEntity | null = await credentialBrandingRepository.findOne({
143
+ where: { id: credentialBrandingId },
144
+ })
145
+
146
+ if (!credentialBranding) {
147
+ return Promise.reject(Error(`No credential branding found for id: ${credentialBrandingId}`))
148
+ }
149
+
150
+ const locales: Array<CredentialLocaleBrandingEntity> | null = await (await this.dbConnection).getRepository(CredentialLocaleBrandingEntity).find({
151
+ where: {
152
+ credentialBranding: {
153
+ id: credentialBrandingId,
154
+ },
155
+ locale: In(localeBranding.map((localeBranding: IBasicCredentialLocaleBranding) => localeBranding.locale)),
156
+ },
157
+ })
158
+
159
+ if (locales && locales.length > 0) {
160
+ return Promise.reject(
161
+ Error(
162
+ `Credential branding already contains locales: ${locales?.map(
163
+ (credentialLocaleBrandingEntity: CredentialLocaleBrandingEntity) => credentialLocaleBrandingEntity.locale,
164
+ )}`,
165
+ ),
166
+ )
167
+ }
168
+
169
+ const credentialLocaleBrandingRepository: Repository<CredentialLocaleBrandingEntity> = (await this.dbConnection).getRepository(
170
+ CredentialLocaleBrandingEntity,
171
+ )
172
+ const addCredentialLocaleBranding: Array<Promise<void>> = localeBranding.map(
173
+ async (localeBranding: IBasicCredentialLocaleBranding): Promise<void> => {
174
+ const credentialLocaleBrandingEntity: CredentialLocaleBrandingEntity = credentialLocaleBrandingEntityFrom(localeBranding)
175
+ debug('Adding credential locale branding', credentialLocaleBrandingEntity)
176
+ credentialLocaleBrandingEntity.credentialBranding = credentialBranding
177
+ await credentialLocaleBrandingRepository.save(credentialLocaleBrandingEntity, { transaction: true })
178
+ },
179
+ )
180
+
181
+ await Promise.all(addCredentialLocaleBranding)
182
+
183
+ const result: CredentialBrandingEntity | null = await credentialBrandingRepository.findOne({
184
+ where: { id: credentialBrandingId },
185
+ })
186
+
187
+ if (!result) {
188
+ return Promise.reject(Error('Unable to get updated credential branding'))
189
+ }
190
+
191
+ return this.credentialBrandingFrom(result)
192
+ }
193
+
194
+ public getCredentialLocaleBranding = async (args?: IGetCredentialLocaleBrandingArgs): Promise<Array<ICredentialLocaleBranding>> => {
195
+ const { filter } = args ?? {}
196
+ if (filter) {
197
+ filter.forEach((filter: ICredentialLocaleBrandingFilter): void => {
198
+ if ('locale' in filter && filter.locale === undefined) {
199
+ filter.locale = ''
200
+ }
201
+ })
202
+ }
203
+
204
+ debug('Getting credential locale branding', args)
205
+ const credentialBrandingLocale: Array<CredentialLocaleBrandingEntity> | null = await (await this.dbConnection)
206
+ .getRepository(CredentialLocaleBrandingEntity)
207
+ .find({
208
+ ...(filter && { where: filter }),
209
+ })
210
+
211
+ return credentialBrandingLocale
212
+ ? credentialBrandingLocale.map(
213
+ (credentialLocaleBranding: CredentialLocaleBrandingEntity) =>
214
+ this.localeBrandingFrom(credentialLocaleBranding) as ICredentialLocaleBranding,
215
+ )
216
+ : []
217
+ }
218
+
219
+ public removeCredentialLocaleBranding = async (args: IRemoveCredentialLocaleBrandingArgs): Promise<void> => {
220
+ const { filter } = args
221
+ const credentialLocaleBranding: Array<CredentialLocaleBrandingEntity> = await (await this.dbConnection)
222
+ .getRepository(CredentialLocaleBrandingEntity)
223
+ .find({
224
+ where: filter,
225
+ })
226
+
227
+ debug('Removing credential locale branding', args)
228
+ const localeBrandingDeletions: Array<Promise<void>> = credentialLocaleBranding.map(
229
+ async (localeBranding: CredentialLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
230
+ )
231
+ await Promise.all(localeBrandingDeletions)
232
+ }
233
+
234
+ public updateCredentialLocaleBranding = async (args: IUpdateCredentialLocaleBrandingArgs): Promise<ICredentialLocaleBranding> => {
235
+ const { localeBranding } = args
236
+ const repository: Repository<CredentialLocaleBrandingEntity> = (await this.dbConnection).getRepository(CredentialLocaleBrandingEntity)
237
+ const result: CredentialLocaleBrandingEntity | null = await repository.findOne({
238
+ where: { id: localeBranding.id },
239
+ })
240
+
241
+ if (!result) {
242
+ return Promise.reject(Error(`No credential locale branding found for id: ${localeBranding.id}`))
243
+ }
244
+
245
+ const locales: Array<CredentialLocaleBrandingEntity> | null = await repository.find({
246
+ where: {
247
+ credentialBranding: {
248
+ id: result.credentialBrandingId,
249
+ },
250
+ id: Not(In([localeBranding.id])),
251
+ locale: localeBranding.locale,
252
+ },
253
+ })
254
+
255
+ if (locales && locales.length > 0) {
256
+ return Promise.reject(Error(`Credential branding: ${result.credentialBrandingId} already contains locale: ${localeBranding.locale}`))
257
+ }
258
+
259
+ debug('Updating credential locale branding', localeBranding)
260
+ const updatedResult: CredentialLocaleBrandingEntity = await repository.save(localeBranding, { transaction: true })
261
+
262
+ return this.localeBrandingFrom(updatedResult) as ICredentialLocaleBranding
263
+ }
264
+
265
+ public addIssuerBranding = async (args: IAddIssuerBrandingArgs): Promise<IIssuerBranding> => {
266
+ const { localeBranding, issuerCorrelationId } = args
267
+ const repository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
268
+ const result: IssuerBrandingEntity | null = await repository.findOne({
269
+ where: [{ issuerCorrelationId }],
270
+ })
271
+
272
+ if (result) {
273
+ return Promise.reject(Error(`Issuer branding already present for issuer with correlation id: ${issuerCorrelationId}`))
274
+ }
275
+
276
+ if (await this.hasDuplicateLocales(localeBranding)) {
277
+ return Promise.reject(Error(`Issuer branding contains duplicate locales`))
278
+ }
279
+
280
+ const issuerBrandingEntity: IssuerBrandingEntity = issuerBrandingEntityFrom(args)
281
+ debug('Adding issuer branding', issuerBrandingEntity)
282
+ const createdResult: IssuerBrandingEntity = await repository.save(issuerBrandingEntity)
283
+
284
+ return this.issuerBrandingFrom(createdResult)
285
+ }
286
+
287
+ public getIssuerBranding = async (args?: IGetIssuerBrandingArgs): Promise<Array<IIssuerBranding>> => {
288
+ const { filter } = args ?? {}
289
+ if (filter) {
290
+ filter.forEach((filter: IIssuerBrandingFilter): void => {
291
+ if (filter.localeBranding && 'locale' in filter.localeBranding && filter.localeBranding.locale === undefined) {
292
+ filter.localeBranding.locale = ''
293
+ }
294
+ })
295
+ }
296
+
297
+ debug('Getting issuer branding', args)
298
+ const result: Array<IssuerBrandingEntity> = await (await this.dbConnection).getRepository(IssuerBrandingEntity).find({
299
+ ...(filter && { where: filter }),
300
+ })
301
+
302
+ return result.map((issuerBranding: IssuerBrandingEntity) => this.issuerBrandingFrom(issuerBranding))
303
+ }
304
+
305
+ public removeIssuerBranding = async (args: IRemoveIssuerBrandingArgs): Promise<void> => {
306
+ const { filter } = args
307
+ const repository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
308
+ const issuerBranding: Array<IssuerBrandingEntity> = await repository.find({
309
+ where: filter,
310
+ })
311
+
312
+ debug('Removing issuer locale branding', args)
313
+ const localeBrandingDeletions: Array<Array<Promise<void>>> = issuerBranding.map((issuerBranding: IssuerBrandingEntity) =>
314
+ issuerBranding.localeBranding.map(
315
+ async (localeBranding: IssuerLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
316
+ ),
317
+ )
318
+ await Promise.all(localeBrandingDeletions)
319
+
320
+ debug('Removing issuer branding', args)
321
+ const issuerBrandingDeletions: Array<Promise<DeleteResult>> = filter.map(
322
+ async (filter: IIssuerBrandingFilter): Promise<DeleteResult> => await repository.delete(filter),
323
+ )
324
+ await Promise.all(issuerBrandingDeletions)
325
+ }
326
+
327
+ public updateIssuerBranding = async (args: IUpdateIssuerBrandingArgs): Promise<IIssuerBranding> => {
328
+ const { issuerBranding } = args
329
+ const repository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
330
+ const issuerBrandingEntity: IssuerBrandingEntity | null = await repository.findOne({
331
+ where: { id: issuerBranding.id },
332
+ })
333
+
334
+ if (!issuerBrandingEntity) {
335
+ return Promise.reject(Error(`No issuer branding found for id: ${issuerBranding.id}`))
336
+ }
337
+
338
+ const branding: Omit<IIssuerBranding, 'createdAt' | 'lastUpdatedAt'> = {
339
+ ...issuerBranding,
340
+ localeBranding: issuerBrandingEntity.localeBranding,
341
+ }
342
+
343
+ debug('Updating issuer branding', branding)
344
+ const result: IssuerBrandingEntity = await repository.save(branding, { transaction: true })
345
+
346
+ return this.issuerBrandingFrom(result)
347
+ }
348
+
349
+ public addIssuerLocaleBranding = async (args: IAddIssuerLocaleBrandingArgs): Promise<IIssuerBranding> => {
350
+ const { localeBranding, issuerBrandingId } = args
351
+ const issuerBrandingRepository: Repository<IssuerBrandingEntity> = (await this.dbConnection).getRepository(IssuerBrandingEntity)
352
+ const issuerBranding: IssuerBrandingEntity | null = await issuerBrandingRepository.findOne({
353
+ where: { id: issuerBrandingId },
354
+ })
355
+
356
+ if (!issuerBranding) {
357
+ return Promise.reject(Error(`No issuer branding found for id: ${issuerBrandingId}`))
358
+ }
359
+
360
+ const locales: Array<IssuerLocaleBrandingEntity> | null = await (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity).find({
361
+ where: {
362
+ issuerBranding: {
363
+ id: issuerBrandingId,
364
+ },
365
+ locale: In(localeBranding.map((localeBranding: IBasicIssuerLocaleBranding) => localeBranding.locale)),
366
+ },
367
+ })
368
+
369
+ if (locales && locales.length > 0) {
370
+ return Promise.reject(
371
+ Error(
372
+ `Issuer branding already contains locales: ${locales?.map(
373
+ (issuerLocaleBrandingEntity: IssuerLocaleBrandingEntity) => issuerLocaleBrandingEntity.locale,
374
+ )}`,
375
+ ),
376
+ )
377
+ }
378
+
379
+ const issuerLocaleBrandingRepository: Repository<IssuerLocaleBrandingEntity> = (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity)
380
+ const addIssuerLocaleBranding: Array<Promise<void>> = localeBranding.map(async (localeBranding: IBasicIssuerLocaleBranding): Promise<void> => {
381
+ const issuerLocaleBrandingEntity: IssuerLocaleBrandingEntity = issuerLocaleBrandingEntityFrom(localeBranding)
382
+ debug('Adding issuer locale branding', issuerLocaleBrandingEntity)
383
+ issuerLocaleBrandingEntity.issuerBranding = issuerBranding
384
+ await issuerLocaleBrandingRepository.save(issuerLocaleBrandingEntity, { transaction: true })
385
+ })
386
+
387
+ await Promise.all(addIssuerLocaleBranding)
388
+
389
+ const result: IssuerBrandingEntity | null = await issuerBrandingRepository.findOne({
390
+ where: { id: issuerBrandingId },
391
+ })
392
+
393
+ if (!result) {
394
+ return Promise.reject(Error('Unable to get updated issuer branding'))
395
+ }
396
+
397
+ return this.issuerBrandingFrom(result)
398
+ }
399
+
400
+ public getIssuerLocaleBranding = async (args?: IGetIssuerLocaleBrandingArgs): Promise<Array<IIssuerLocaleBranding>> => {
401
+ const { filter } = args ?? {}
402
+ if (filter) {
403
+ filter.forEach((filter: IIssuerLocaleBrandingFilter): void => {
404
+ if ('locale' in filter && filter.locale === undefined) {
405
+ filter.locale = ''
406
+ }
407
+ })
408
+ }
409
+
410
+ debug('Getting issuer locale branding', args)
411
+ const issuerLocaleBranding: Array<IssuerLocaleBrandingEntity> | null = await (await this.dbConnection)
412
+ .getRepository(IssuerLocaleBrandingEntity)
413
+ .find({
414
+ ...(filter && { where: filter }),
415
+ })
416
+
417
+ return issuerLocaleBranding
418
+ ? issuerLocaleBranding.map(
419
+ (issuerLocaleBranding: IssuerLocaleBrandingEntity) => this.localeBrandingFrom(issuerLocaleBranding) as IIssuerLocaleBranding,
420
+ )
421
+ : []
422
+ }
423
+
424
+ public removeIssuerLocaleBranding = async (args: IRemoveIssuerLocaleBrandingArgs): Promise<void> => {
425
+ const { filter } = args
426
+ const issuerLocaleBranding: Array<IssuerLocaleBrandingEntity> = await (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity).find({
427
+ where: filter,
428
+ })
429
+
430
+ debug('Removing credential locale branding', args)
431
+ const localeBrandingDeletions: Array<Promise<void>> = issuerLocaleBranding.map(
432
+ async (localeBranding: IssuerLocaleBrandingEntity): Promise<void> => this.removeLocaleBranding(localeBranding),
433
+ )
434
+ await Promise.all(localeBrandingDeletions)
435
+ }
436
+
437
+ public updateIssuerLocaleBranding = async (args: IUpdateIssuerLocaleBrandingArgs): Promise<IIssuerLocaleBranding> => {
438
+ const { localeBranding } = args
439
+ const repository: Repository<IssuerLocaleBrandingEntity> = (await this.dbConnection).getRepository(IssuerLocaleBrandingEntity)
440
+ const result: IssuerLocaleBrandingEntity | null = await repository.findOne({
441
+ where: { id: localeBranding.id },
442
+ })
443
+
444
+ if (!result) {
445
+ return Promise.reject(Error(`No issuer locale branding found for id: ${localeBranding.id}`))
446
+ }
447
+
448
+ const locales: Array<IssuerLocaleBrandingEntity> | null = await repository.find({
449
+ where: {
450
+ issuerBranding: {
451
+ id: result.issuerBrandingId,
452
+ },
453
+ id: Not(In([localeBranding.id])),
454
+ locale: localeBranding.locale,
455
+ },
456
+ })
457
+
458
+ if (locales && locales.length > 0) {
459
+ return Promise.reject(Error(`Issuer branding: ${result.issuerBrandingId} already contains locale: ${localeBranding.locale}`))
460
+ }
461
+
462
+ debug('Updating issuer locale branding', localeBranding)
463
+ const updatedResult: IssuerLocaleBrandingEntity = await repository.save(localeBranding, { transaction: true })
464
+
465
+ return this.localeBrandingFrom(updatedResult) as IIssuerLocaleBranding
466
+ }
467
+
468
+ private credentialBrandingFrom = (credentialBranding: CredentialBrandingEntity): ICredentialBranding => {
469
+ const result: ICredentialBranding = {
470
+ ...credentialBranding,
471
+ localeBranding: credentialBranding.localeBranding.map((localeBranding: BaseLocaleBrandingEntity) => this.localeBrandingFrom(localeBranding)),
472
+ }
473
+
474
+ return this.replaceNullWithUndefined(result)
475
+ }
476
+
477
+ private issuerBrandingFrom = (issuerBranding: IssuerBrandingEntity): IIssuerBranding => {
478
+ const result: IIssuerBranding = {
479
+ ...issuerBranding,
480
+ localeBranding: issuerBranding.localeBranding.map((localeBranding: BaseLocaleBrandingEntity) => this.localeBrandingFrom(localeBranding)),
481
+ }
482
+
483
+ return this.replaceNullWithUndefined(result)
484
+ }
485
+
486
+ private localeBrandingFrom = (localeBranding: BaseLocaleBrandingEntity): ILocaleBranding => {
487
+ const result: ILocaleBranding = {
488
+ ...localeBranding,
489
+ locale: localeBranding.locale === '' ? undefined : localeBranding.locale,
490
+ }
491
+
492
+ return this.replaceNullWithUndefined(result)
493
+ }
494
+
495
+ private replaceNullWithUndefined(obj: any): any {
496
+ if (obj === null) {
497
+ return undefined
498
+ }
499
+
500
+ if (typeof obj !== 'object' || obj instanceof Date) {
501
+ return obj
502
+ }
503
+
504
+ if (Array.isArray(obj)) {
505
+ return obj.map((value: any) => this.replaceNullWithUndefined(value))
506
+ }
507
+
508
+ const result: any = {}
509
+ for (const key in obj) {
510
+ if (obj.hasOwnProperty(key)) {
511
+ result[key] = this.replaceNullWithUndefined(obj[key])
512
+ }
513
+ }
514
+ return result
515
+ }
516
+
517
+ private hasDuplicateLocales = async (localeBranding: Array<IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding>): Promise<boolean> => {
518
+ let seen: Set<string | undefined> = new Set()
519
+ return localeBranding.some((localeBranding: IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding): boolean => {
520
+ return seen.size === seen.add(localeBranding.locale).size
521
+ })
522
+ }
523
+
524
+ private removeLocaleBranding = async (localeBranding: BaseLocaleBrandingEntity): Promise<void> => {
525
+ debug('Removing credential locale branding', localeBranding)
526
+ // Delete background image dimensions
527
+ if (localeBranding.background?.image?.dimensions) {
528
+ await (await this.dbConnection).getRepository(ImageDimensionsEntity).delete({ id: localeBranding.background?.image?.dimensions?.id })
529
+ }
530
+
531
+ // Delete background image
532
+ if (localeBranding.background?.image) {
533
+ await (await this.dbConnection).getRepository(ImageAttributesEntity).delete({ id: localeBranding.background?.image?.id })
534
+ }
535
+
536
+ // Delete background
537
+ if (localeBranding.background) {
538
+ await (await this.dbConnection).getRepository(BackgroundAttributesEntity).delete({ id: localeBranding.background?.id })
539
+ }
540
+
541
+ // Delete logo image dimensions
542
+ if (localeBranding.logo?.dimensions) {
543
+ await (await this.dbConnection).getRepository(ImageDimensionsEntity).delete({ id: localeBranding.logo?.dimensions?.id })
544
+ }
545
+
546
+ // Delete logo
547
+ if (localeBranding.logo) {
548
+ await (await this.dbConnection).getRepository(ImageAttributesEntity).delete({ id: localeBranding.logo?.id })
549
+ }
550
+
551
+ // Delete text
552
+ if (localeBranding.text) {
553
+ await (await this.dbConnection).getRepository(TextAttributesEntity).delete({ id: localeBranding.text?.id })
554
+ }
555
+
556
+ // Delete locale branding
557
+ await (await this.dbConnection).getRepository(CredentialLocaleBrandingEntity).delete({ id: localeBranding.id })
558
+ }
559
+ }