@solidstarters/solid-core 1.2.165 → 1.2.168

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 (80) hide show
  1. package/dist/config/iam.config.d.ts +2 -0
  2. package/dist/config/iam.config.d.ts.map +1 -1
  3. package/dist/config/iam.config.js +1 -0
  4. package/dist/config/iam.config.js.map +1 -1
  5. package/dist/decorators/error-codes-provider.decorator.d.ts +4 -0
  6. package/dist/decorators/error-codes-provider.decorator.d.ts.map +1 -0
  7. package/dist/decorators/error-codes-provider.decorator.js +12 -0
  8. package/dist/decorators/error-codes-provider.decorator.js.map +1 -0
  9. package/dist/dtos/post-chatter-message.dto.js.map +1 -1
  10. package/dist/entities/chatter-message.entity.js.map +1 -1
  11. package/dist/entities/security-rule.entity.js +0 -1
  12. package/dist/entities/security-rule.entity.js.map +1 -1
  13. package/dist/filters/http-exception.filter.d.ts +3 -2
  14. package/dist/filters/http-exception.filter.d.ts.map +1 -1
  15. package/dist/filters/http-exception.filter.js +23 -16
  16. package/dist/filters/http-exception.filter.js.map +1 -1
  17. package/dist/helpers/error-mapper.service.d.ts +12 -2
  18. package/dist/helpers/error-mapper.service.d.ts.map +1 -1
  19. package/dist/helpers/error-mapper.service.js +85 -72
  20. package/dist/helpers/error-mapper.service.js.map +1 -1
  21. package/dist/helpers/security.helper.d.ts +4 -2
  22. package/dist/helpers/security.helper.d.ts.map +1 -1
  23. package/dist/helpers/security.helper.js +38 -23
  24. package/dist/helpers/security.helper.js.map +1 -1
  25. package/dist/helpers/solid-core-error-codes-provider.service.d.ts +7 -0
  26. package/dist/helpers/solid-core-error-codes-provider.service.d.ts.map +1 -0
  27. package/dist/helpers/solid-core-error-codes-provider.service.js +67 -0
  28. package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -0
  29. package/dist/helpers/solid-registry.d.ts +5 -1
  30. package/dist/helpers/solid-registry.d.ts.map +1 -1
  31. package/dist/helpers/solid-registry.js +16 -0
  32. package/dist/helpers/solid-registry.js.map +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +1 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/interfaces.d.ts +16 -0
  38. package/dist/interfaces.d.ts.map +1 -1
  39. package/dist/interfaces.js.map +1 -1
  40. package/dist/repository/security-rule.repository.js +2 -2
  41. package/dist/repository/security-rule.repository.js.map +1 -1
  42. package/dist/seeders/seed-data/solid-core-metadata.json +2 -2
  43. package/dist/services/authentication.service.js +5 -4
  44. package/dist/services/authentication.service.js.map +1 -1
  45. package/dist/services/chatter-message.service.d.ts.map +1 -1
  46. package/dist/services/chatter-message.service.js.map +1 -1
  47. package/dist/services/model-metadata.service.js +1 -1
  48. package/dist/services/model-metadata.service.js.map +1 -1
  49. package/dist/services/setting.service.d.ts.map +1 -1
  50. package/dist/services/setting.service.js +2 -1
  51. package/dist/services/setting.service.js.map +1 -1
  52. package/dist/services/solid-introspect.service.d.ts +1 -0
  53. package/dist/services/solid-introspect.service.d.ts.map +1 -1
  54. package/dist/services/solid-introspect.service.js +14 -0
  55. package/dist/services/solid-introspect.service.js.map +1 -1
  56. package/dist/solid-core.module.d.ts.map +1 -1
  57. package/dist/solid-core.module.js +2 -0
  58. package/dist/solid-core.module.js.map +1 -1
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +1 -1
  61. package/src/config/iam.config.ts +1 -0
  62. package/src/decorators/error-codes-provider.decorator.ts +9 -0
  63. package/src/dtos/post-chatter-message.dto.ts +1 -1
  64. package/src/entities/chatter-message.entity.ts +3 -3
  65. package/src/entities/security-rule.entity.ts +1 -1
  66. package/src/filters/http-exception.filter.ts +48 -23
  67. package/src/helpers/error-mapper.service.ts +117 -176
  68. package/src/helpers/security.helper.ts +95 -30
  69. package/src/helpers/solid-core-error-codes-provider.service.ts +63 -0
  70. package/src/helpers/solid-registry.ts +20 -1
  71. package/src/index.ts +1 -0
  72. package/src/interfaces.ts +36 -0
  73. package/src/repository/security-rule.repository.ts +2 -2
  74. package/src/seeders/seed-data/solid-core-metadata.json +2 -2
  75. package/src/services/authentication.service.ts +6 -6
  76. package/src/services/chatter-message.service.ts +373 -374
  77. package/src/services/model-metadata.service.ts +1 -1
  78. package/src/services/setting.service.ts +2 -1
  79. package/src/services/solid-introspect.service.ts +22 -0
  80. package/src/solid-core.module.ts +2 -0
@@ -1,6 +1,6 @@
1
1
  import { Injectable } from '@nestjs/common';
2
2
  import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
3
- import { DiscoveryService, ModuleRef } from "@nestjs/core";
3
+ import { DiscoveryService, ModuleRef } from "@nestjs/core";
4
4
  import { EntityManager, Repository, EntityMetadata } from 'typeorm';
5
5
 
6
6
  import { CRUDService } from 'src/services/crud.service';
@@ -10,7 +10,6 @@ import { ConfigService } from '@nestjs/config';
10
10
  import { FileService } from 'src/services/file.service';
11
11
  import { CrudHelperService } from 'src/services/crud-helper.service';
12
12
  import { PostChatterMessageDto } from 'src/dtos/post-chatter-message.dto';
13
- import { SolidRequestContextDto } from 'src/dtos/solid-request-context.dto';
14
13
  import { ChatterMessage } from '../entities/chatter-message.entity';
15
14
  import { getMediaStorageProvider } from './mediaStorageProviders';
16
15
  import { MediaStorageProviderType } from '../dtos/create-media-storage-provider-metadata.dto';
@@ -21,453 +20,453 @@ import { ChatterMessageRepository } from 'src/repository/chatter-message.reposit
21
20
  import { lowerFirst } from 'src/helpers/string.helper';
22
21
  import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
23
22
  @Injectable()
24
- export class ChatterMessageService extends CRUDService<ChatterMessage>{
25
- constructor(
26
- readonly modelMetadataService: ModelMetadataService,
27
- readonly moduleMetadataService: ModuleMetadataService,
28
- readonly configService: ConfigService,
29
- readonly fileService: FileService,
30
- readonly discoveryService: DiscoveryService,
31
- readonly crudHelperService: CrudHelperService,
32
- @InjectEntityManager()
33
- readonly entityManager: EntityManager,
34
- // @InjectRepository(ChatterMessage, 'default')
35
- readonly repo: ChatterMessageRepository,
36
- @InjectRepository(ChatterMessageDetails, 'default')
37
- readonly chatterMessageDetailsRepo: Repository<ChatterMessageDetails>,
38
- readonly moduleRef: ModuleRef,
39
- @InjectRepository(ModelMetadata)
40
- private readonly modelMetadataRepo: Repository<ModelMetadata>,
41
- readonly requestContextService: RequestContextService,
42
- private readonly modelMetadataHelperService: ModelMetadataHelperService,
43
- ) {
44
- super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService,entityManager, repo, 'chatterMessage', 'solid-core', moduleRef);
45
- }
46
-
47
- async postMessage(postDto: PostChatterMessageDto, files: Express.Multer.File[] = []) {
48
- const chatterMessage = new ChatterMessage();
49
- chatterMessage.messageType = 'custom';
50
- chatterMessage.messageSubType = postDto.messageSubType || 'post_message';
51
- chatterMessage.messageBody = postDto.messageBody;
52
- chatterMessage.coModelEntityId = postDto.coModelEntityId;
53
- chatterMessage.coModelName = postDto.coModelName;
54
-
55
- const activeUser = this.requestContextService.getActiveUser();
56
-
57
- if (activeUser) {
58
- const userId = activeUser?.sub;
59
- chatterMessage.user = { id: userId } as any;
60
- } else {
61
- chatterMessage.user = null;
62
- }
23
+ export class ChatterMessageService extends CRUDService<ChatterMessage> {
24
+ constructor(
25
+ readonly modelMetadataService: ModelMetadataService,
26
+ readonly moduleMetadataService: ModuleMetadataService,
27
+ readonly configService: ConfigService,
28
+ readonly fileService: FileService,
29
+ readonly discoveryService: DiscoveryService,
30
+ readonly crudHelperService: CrudHelperService,
31
+ @InjectEntityManager()
32
+ readonly entityManager: EntityManager,
33
+ // @InjectRepository(ChatterMessage, 'default')
34
+ readonly repo: ChatterMessageRepository,
35
+ @InjectRepository(ChatterMessageDetails, 'default')
36
+ readonly chatterMessageDetailsRepo: Repository<ChatterMessageDetails>,
37
+ readonly moduleRef: ModuleRef,
38
+ @InjectRepository(ModelMetadata)
39
+ private readonly modelMetadataRepo: Repository<ModelMetadata>,
40
+ readonly requestContextService: RequestContextService,
41
+ private readonly modelMetadataHelperService: ModelMetadataHelperService,
42
+ ) {
43
+ super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'chatterMessage', 'solid-core', moduleRef);
44
+ }
45
+
46
+ async postMessage(postDto: PostChatterMessageDto, files: Express.Multer.File[] = []) {
47
+ const chatterMessage = new ChatterMessage();
48
+ chatterMessage.messageType = 'custom';
49
+ chatterMessage.messageSubType = postDto.messageSubType || 'post_message';
50
+ chatterMessage.messageBody = postDto.messageBody;
51
+ chatterMessage.coModelEntityId = postDto.coModelEntityId;
52
+ chatterMessage.coModelName = postDto.coModelName;
53
+
54
+ const activeUser = this.requestContextService.getActiveUser();
55
+
56
+ if (activeUser) {
57
+ const userId = activeUser?.sub;
58
+ chatterMessage.user = { id: userId } as any;
59
+ } else {
60
+ chatterMessage.user = null;
61
+ }
63
62
 
64
- const savedMessage = await this.repo.save(chatterMessage);
63
+ const savedMessage = await this.repo.save(chatterMessage);
64
+
65
+ if (files && files.length > 0) {
66
+ const model = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
67
+ fields: {
68
+ model: true,
69
+ mediaStorageProvider: true,
70
+ },
71
+ module: true,
72
+ });
73
+
74
+ const mediaFields = model.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
75
+
76
+ for (const mediaField of mediaFields) {
77
+ const media = files.filter(multerFile => multerFile.fieldname === mediaField.name);
78
+ if (media.length > 0) {
79
+ const storageProviderMetadata = mediaField.mediaStorageProvider;
80
+ const storageProviderType = storageProviderMetadata.type as MediaStorageProviderType;
81
+ const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);
82
+ await storageProvider.store(media, savedMessage, mediaField);
83
+ }
84
+ }
85
+ }
65
86
 
66
- if (files && files.length > 0) {
67
- const model = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
68
- fields: {
69
- model: true,
70
- mediaStorageProvider: true,
71
- },
72
- module: true,
73
- });
87
+ return savedMessage;
88
+ }
74
89
 
75
- const mediaFields = model.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
90
+ async postAuditMessageOnInsert(entity: any, metadata: EntityMetadata, messageQueue: boolean = false) {
91
+ if (!entity) {
92
+ return;
93
+ }
94
+ const model = await this.modelMetadataRepo.findOne({
95
+ where: {
96
+ singularName: lowerFirst(metadata.name)
97
+ },
98
+ relations: {
99
+ fields: true,
100
+ module: true
101
+ }
102
+ });
76
103
 
77
- for (const mediaField of mediaFields) {
78
- const media = files.filter(multerFile => multerFile.fieldname === mediaField.name);
79
- if (media.length > 0) {
80
- const storageProviderMetadata = mediaField.mediaStorageProvider;
81
- const storageProviderType = storageProviderMetadata.type as MediaStorageProviderType;
82
- const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);
83
- await storageProvider.store(media, savedMessage, mediaField);
104
+ if (!model || !model.enableAuditTracking) {
105
+ return;
84
106
  }
85
- }
86
- }
87
107
 
88
- return savedMessage;
89
- }
108
+ const auditFields = model.fields.filter(field =>
109
+ field.enableAuditTracking &&
110
+ !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&
111
+ !(field.type === 'relation' && field.relationType === 'one-to-many')
112
+ );
90
113
 
91
- async postAuditMessageOnInsert(entity: any, metadata: EntityMetadata, messageQueue: boolean = false) {
92
- if(!entity){
93
- return;
94
- }
95
- const model = await this.modelMetadataRepo.findOne({
96
- where: {
97
- singularName: lowerFirst(metadata.name)
98
- },
99
- relations: {
100
- fields: true,
101
- module: true
102
- }
103
- });
104
-
105
- if (!model || !model.enableAuditTracking) {
106
- return;
107
- }
114
+ const activeUser = this.requestContextService.getActiveUser();
108
115
 
109
- const auditFields = model.fields.filter(field =>
110
- field.enableAuditTracking &&
111
- !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&
112
- !(field.type === 'relation' && field.relationType === 'one-to-many')
113
- );
114
-
115
- const activeUser = this.requestContextService.getActiveUser();
116
-
117
- const chatterMessage = new ChatterMessage();
118
- chatterMessage.messageType = 'audit';
119
- chatterMessage.messageSubType = 'insert';
120
- chatterMessage.coModelEntityId = entity.id;
121
- chatterMessage.coModelName = model.singularName;
122
- chatterMessage.messageBody = `New ${model.displayName} created`;
123
-
124
- if (activeUser) {
125
- const userId = activeUser?.sub;
126
- chatterMessage.user = { id: userId } as any;
127
- } else {
128
- chatterMessage.user = null;
129
- }
116
+ const chatterMessage = new ChatterMessage();
117
+ chatterMessage.messageType = 'audit';
118
+ chatterMessage.messageSubType = 'insert';
119
+ chatterMessage.coModelEntityId = entity.id;
120
+ chatterMessage.coModelName = model.singularName;
121
+ chatterMessage.messageBody = `New ${model.displayName} created`;
130
122
 
131
- const savedMessage = await this.repo.save(chatterMessage);
123
+ if (activeUser) {
124
+ const userId = activeUser?.sub;
125
+ chatterMessage.user = { id: userId } as any;
126
+ } else {
127
+ chatterMessage.user = null;
128
+ }
132
129
 
133
- for (const field of auditFields) {
134
- const fieldValue = entity[field.name];
135
- if (fieldValue !== undefined && fieldValue !== null && fieldValue !== '') {
136
- const messageDetail = new ChatterMessageDetails();
137
- messageDetail.chatterMessage = savedMessage;
138
- messageDetail.fieldName = field.name;
139
- messageDetail.oldValue = null;
140
- messageDetail.oldValueDisplay = null;
141
- messageDetail.newValue = this.formatFieldValue(field, fieldValue);
142
- messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, fieldValue);
143
- await this.chatterMessageDetailsRepo.save(messageDetail);
130
+ const savedMessage = await this.repo.save(chatterMessage);
131
+
132
+ for (const field of auditFields) {
133
+ const fieldValue = entity[field.name];
134
+ if (fieldValue !== undefined && fieldValue !== null && fieldValue !== '') {
135
+ const messageDetail = new ChatterMessageDetails();
136
+ messageDetail.chatterMessage = savedMessage;
137
+ messageDetail.fieldName = field.name;
138
+ messageDetail.oldValue = null;
139
+ messageDetail.oldValueDisplay = null;
140
+ messageDetail.newValue = this.formatFieldValue(field, fieldValue);
141
+ messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, fieldValue);
142
+ await this.chatterMessageDetailsRepo.save(messageDetail);
143
+ }
144
144
  }
145
145
  }
146
- }
147
146
 
148
- async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEntity: any, updatedColumns: any[] = [], messageQueue: boolean = false) {
149
- if(!databaseEntity || !entity){
150
- return;
151
- }
152
- const model = await this.modelMetadataRepo.findOne({
153
- where: {
154
- singularName: lowerFirst(metadata.name)
155
- },
156
- relations: {
157
- fields: true,
158
- module: true
159
- }
160
- });
161
-
162
- if (!model || !model.enableAuditTracking) {
163
- return;
164
- }
165
-
166
- const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName)
167
-
168
- const auditFields = modelFields.filter(field =>
169
- field.enableAuditTracking &&
170
- !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&
171
- !(field.type === 'relation' && field.relationType === 'one-to-many')
172
- );
173
-
174
- const updatedFieldNames = new Set(updatedColumns.map(col => col.propertyName));
175
-
176
- const allNonRelationFields = auditFields.filter(field => field.type !== 'relation');
177
- const allRelationFields = auditFields.filter(field => field.type === 'relation');
178
-
179
- let potentialNonRelationFields = [];
180
-
181
- if (updatedColumns.length > 0) {
182
- potentialNonRelationFields = allNonRelationFields.filter(field =>
183
- updatedFieldNames.has(field.name)
147
+ async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEntity: any, updatedColumns: any[] = [], messageQueue: boolean = false) {
148
+ if (!databaseEntity || !entity) {
149
+ return;
150
+ }
151
+ const model = await this.modelMetadataRepo.findOne({
152
+ where: {
153
+ singularName: lowerFirst(metadata.name)
154
+ },
155
+ relations: {
156
+ fields: true,
157
+ module: true
158
+ }
159
+ });
160
+
161
+ if (!model || !model.enableAuditTracking) {
162
+ return;
163
+ }
164
+
165
+ const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName)
166
+
167
+ const auditFields = modelFields.filter(field =>
168
+ field.enableAuditTracking &&
169
+ !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&
170
+ !(field.type === 'relation' && field.relationType === 'one-to-many')
184
171
  );
185
- } else {
186
- potentialNonRelationFields = allNonRelationFields;
187
- }
188
172
 
189
- const potentialRelationFields = allRelationFields;
173
+ const updatedFieldNames = new Set(updatedColumns.map(col => col.propertyName));
190
174
 
191
- const changedNonRelationFields = potentialNonRelationFields.filter(field => {
192
- const newValue = entity[field.name];
193
- const oldValue = databaseEntity[field.name];
194
- return this.hasValueChanged(newValue, oldValue);
195
- });
175
+ const allNonRelationFields = auditFields.filter(field => field.type !== 'relation');
176
+ const allRelationFields = auditFields.filter(field => field.type === 'relation');
196
177
 
197
- const changedRelationFields = [];
198
- if (potentialRelationFields.length > 0) {
199
- const populatedOldEntity = await this.populateRelationFields(databaseEntity, potentialRelationFields, metadata);
178
+ let potentialNonRelationFields = [];
200
179
 
201
- for (const field of potentialRelationFields) {
180
+ if (updatedColumns.length > 0) {
181
+ potentialNonRelationFields = allNonRelationFields.filter(field =>
182
+ updatedFieldNames.has(field.name)
183
+ );
184
+ } else {
185
+ potentialNonRelationFields = allNonRelationFields;
186
+ }
187
+
188
+ const potentialRelationFields = allRelationFields;
189
+
190
+ const changedNonRelationFields = potentialNonRelationFields.filter(field => {
202
191
  const newValue = entity[field.name];
203
- const oldValue = populatedOldEntity[field.name];
204
-
205
- if (this.hasRelationValueChanged(field, newValue, oldValue)) {
206
- changedRelationFields.push({
207
- field,
208
- newValue,
209
- oldValue
210
- });
192
+ const oldValue = databaseEntity[field.name];
193
+ return this.hasValueChanged(newValue, oldValue);
194
+ });
195
+
196
+ const changedRelationFields = [];
197
+ if (potentialRelationFields.length > 0) {
198
+ const populatedOldEntity = await this.populateRelationFields(databaseEntity, potentialRelationFields, metadata);
199
+
200
+ for (const field of potentialRelationFields) {
201
+ const newValue = entity[field.name];
202
+ const oldValue = populatedOldEntity[field.name];
203
+
204
+ if (this.hasRelationValueChanged(field, newValue, oldValue)) {
205
+ changedRelationFields.push({
206
+ field,
207
+ newValue,
208
+ oldValue
209
+ });
210
+ }
211
211
  }
212
212
  }
213
- }
214
213
 
215
214
 
216
- const allChangedFields = [
217
- ...changedNonRelationFields.map(field => ({
218
- field,
219
- newValue: entity[field.name],
220
- oldValue: databaseEntity[field.name]
221
- })),
222
- ...changedRelationFields
223
- ];
224
-
225
- if (allChangedFields.length === 0) {
226
- return;
227
- }
215
+ const allChangedFields = [
216
+ ...changedNonRelationFields.map(field => ({
217
+ field,
218
+ newValue: entity[field.name],
219
+ oldValue: databaseEntity[field.name]
220
+ })),
221
+ ...changedRelationFields
222
+ ];
228
223
 
229
- const activeUser = this.requestContextService.getActiveUser();
230
-
231
- const chatterMessage = new ChatterMessage();
232
- chatterMessage.messageType = 'audit';
233
- chatterMessage.messageSubType = 'update';
234
- chatterMessage.coModelEntityId = entity.id;
235
- chatterMessage.coModelName = model.singularName;
236
- chatterMessage.messageBody = `${model.displayName} updated`;
237
-
238
- if (activeUser) {
239
- const userId = activeUser?.sub;
240
- chatterMessage.user = { id: userId } as any;
241
- } else {
242
- chatterMessage.user = null;
243
- }
224
+ if (allChangedFields.length === 0) {
225
+ return;
226
+ }
244
227
 
245
- const savedMessage = await this.repo.save(chatterMessage);
246
-
247
- for (const { field, newValue, oldValue } of allChangedFields) {
248
- const messageDetail = new ChatterMessageDetails();
249
- messageDetail.chatterMessage = savedMessage;
250
- messageDetail.fieldName = field.name;
251
- messageDetail.oldValue = this.formatFieldValue(field, oldValue);
252
- messageDetail.newValue = this.formatFieldValue(field, newValue);
253
- messageDetail.oldValueDisplay = this.formatFieldValueDisplay(field, oldValue);
254
- messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, newValue);
255
- await this.chatterMessageDetailsRepo.save(messageDetail);
256
- }
257
- }
228
+ const activeUser = this.requestContextService.getActiveUser();
258
229
 
259
- async postAuditMessageOnDelete(entity: any, metadata: EntityMetadata, databaseEntity: any, messageQueue: boolean = false) {
260
- const model = await this.modelMetadataRepo.findOne({
261
- where: {
262
- singularName: lowerFirst(metadata.name)
263
- },
264
- relations: {
265
- fields: true,
266
- module: true
230
+ const chatterMessage = new ChatterMessage();
231
+ chatterMessage.messageType = 'audit';
232
+ chatterMessage.messageSubType = 'update';
233
+ chatterMessage.coModelEntityId = entity.id;
234
+ chatterMessage.coModelName = model.singularName;
235
+ chatterMessage.messageBody = `${model.displayName} updated`;
236
+
237
+ if (activeUser) {
238
+ const userId = activeUser?.sub;
239
+ chatterMessage.user = { id: userId } as any;
240
+ } else {
241
+ chatterMessage.user = null;
267
242
  }
268
- });
269
243
 
270
- if (!model || !model.enableAuditTracking) {
271
- return;
272
- }
244
+ const savedMessage = await this.repo.save(chatterMessage);
273
245
 
274
- const chatterMessage = new ChatterMessage();
275
- chatterMessage.messageType = 'audit';
276
- chatterMessage.messageSubType = 'delete';
277
- chatterMessage.coModelEntityId = databaseEntity.id;
278
- chatterMessage.coModelName = model.singularName;
279
- chatterMessage.messageBody = `${model.displayName} deleted`;
280
-
281
- const activeUser = this.requestContextService.getActiveUser();
282
-
283
- if (activeUser) {
284
- const userId = activeUser?.sub;
285
- chatterMessage.user = { id: userId } as any;
286
- } else {
287
- chatterMessage.user = null;
246
+ for (const { field, newValue, oldValue } of allChangedFields) {
247
+ const messageDetail = new ChatterMessageDetails();
248
+ messageDetail.chatterMessage = savedMessage;
249
+ messageDetail.fieldName = field.name;
250
+ messageDetail.oldValue = this.formatFieldValue(field, oldValue);
251
+ messageDetail.newValue = this.formatFieldValue(field, newValue);
252
+ messageDetail.oldValueDisplay = this.formatFieldValueDisplay(field, oldValue);
253
+ messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, newValue);
254
+ await this.chatterMessageDetailsRepo.save(messageDetail);
255
+ }
288
256
  }
289
257
 
290
- await this.repo.save(chatterMessage);
291
- }
258
+ async postAuditMessageOnDelete(entity: any, metadata: EntityMetadata, databaseEntity: any, messageQueue: boolean = false) {
259
+ const model = await this.modelMetadataRepo.findOne({
260
+ where: {
261
+ singularName: lowerFirst(metadata.name)
262
+ },
263
+ relations: {
264
+ fields: true,
265
+ module: true
266
+ }
267
+ });
292
268
 
293
- private formatFieldValue(field: any, value: any): string {
294
- if (value === null || value === undefined) {
295
- return '';
296
- }
269
+ if (!model || !model.enableAuditTracking) {
270
+ return;
271
+ }
272
+
273
+ const chatterMessage = new ChatterMessage();
274
+ chatterMessage.messageType = 'audit';
275
+ chatterMessage.messageSubType = 'delete';
276
+ chatterMessage.coModelEntityId = databaseEntity.id;
277
+ chatterMessage.coModelName = model.singularName;
278
+ chatterMessage.messageBody = `${model.displayName} deleted`;
279
+
280
+ const activeUser = this.requestContextService.getActiveUser();
297
281
 
298
- if (field.type === 'selectionStatic' || field.type === 'selectionDynamic') {
299
- return `${value}`;
282
+ if (activeUser) {
283
+ const userId = activeUser?.sub;
284
+ chatterMessage.user = { id: userId } as any;
285
+ } else {
286
+ chatterMessage.user = null;
287
+ }
288
+
289
+ await this.repo.save(chatterMessage);
300
290
  }
301
291
 
302
- if (field.type === 'relation') {
303
- if (field.relationType === "many-to-one") {
304
- return value.id;
292
+ private formatFieldValue(field: any, value: any): string {
293
+ if (value === null || value === undefined) {
294
+ return '';
305
295
  }
306
- if (field.relationType === 'manyToMany') {
307
- return value.map(item => item.id).join(', ');
296
+
297
+ if (field.type === 'selectionStatic' || field.type === 'selectionDynamic') {
298
+ return `${value}`;
308
299
  }
309
- }
310
300
 
301
+ if (field.type === 'relation') {
302
+ if (field.relationType === "many-to-one") {
303
+ return value.id;
304
+ }
305
+ if (field.relationType === 'manyToMany') {
306
+ return value.map(item => item.id).join(', ');
307
+ }
308
+ }
311
309
 
312
- return value.toString();
313
- }
314
310
 
315
- private formatFieldValueDisplay(field: any, value: any): string {
316
- if (value === null || value === undefined) {
317
- return '';
311
+ return value.toString();
318
312
  }
319
313
 
320
- if (field.type === 'selectionStatic' || field.type === 'selectionDynamic') {
321
- return `${value}`;
322
- }
314
+ private formatFieldValueDisplay(field: any, value: any): string {
315
+ if (value === null || value === undefined) {
316
+ return '';
317
+ }
323
318
 
324
- if (field.type === 'relation') {
325
- if (field.relationType === "many-to-one") {
326
- return value.name;
319
+ if (field.type === 'selectionStatic' || field.type === 'selectionDynamic') {
320
+ return `${value}`;
327
321
  }
328
- if (field.relationType === 'many-toMany') {
329
- return value.map(item => item.name).join(', ');
322
+
323
+ if (field.type === 'relation') {
324
+ if (field.relationType === "many-to-one") {
325
+ return value.name;
326
+ }
327
+ if (field.relationType === 'many-toMany') {
328
+ return value.map(item => item.name).join(', ');
329
+ }
330
330
  }
331
+
332
+
333
+ return value.toString();
331
334
  }
332
335
 
336
+ private hasValueChanged(newValue: any, oldValue: any): boolean {
337
+ if (newValue === oldValue) {
338
+ return false;
339
+ }
333
340
 
334
- return value.toString();
335
- }
341
+ if (newValue === null && oldValue === null) {
342
+ return false;
343
+ }
336
344
 
337
- private hasValueChanged(newValue: any, oldValue: any): boolean {
338
- if (newValue === oldValue) {
339
- return false;
340
- }
345
+ if (newValue === undefined && oldValue === undefined) {
346
+ return false;
347
+ }
341
348
 
342
- if (newValue === null && oldValue === null) {
343
- return false;
344
- }
349
+ if (newValue && oldValue && typeof newValue === 'object' && typeof oldValue === 'object') {
350
+ if (newValue.id !== undefined && oldValue.id !== undefined) {
351
+ return newValue.id !== oldValue.id;
352
+ }
353
+
354
+ if (Array.isArray(newValue) && Array.isArray(oldValue)) {
355
+ if (newValue.length !== oldValue.length) {
356
+ return true;
357
+ }
358
+ const newIds = newValue.map(item => item.id || item).sort();
359
+ const oldIds = oldValue.map(item => item.id || item).sort();
360
+ return JSON.stringify(newIds) !== JSON.stringify(oldIds);
361
+ }
362
+ }
345
363
 
346
- if (newValue === undefined && oldValue === undefined) {
347
- return false;
364
+ if (Array.isArray(newValue) && Array.isArray(oldValue)) {
365
+ return JSON.stringify(newValue) !== JSON.stringify(oldValue);
366
+ }
367
+
368
+ return true;
348
369
  }
349
370
 
350
- if (newValue && oldValue && typeof newValue === 'object' && typeof oldValue === 'object') {
351
- if (newValue.id !== undefined && oldValue.id !== undefined) {
352
- return newValue.id !== oldValue.id;
371
+ private hasRelationValueChanged(field: any, newValue: any, oldValue: any): boolean {
372
+ if (newValue === oldValue) {
373
+ return false;
353
374
  }
354
-
355
- if (Array.isArray(newValue) && Array.isArray(oldValue)) {
356
- if (newValue.length !== oldValue.length) {
375
+
376
+ if ((newValue === null || newValue === undefined) && (oldValue === null || oldValue === undefined)) {
377
+ return false;
378
+ }
379
+
380
+ if (field.relationType === 'many-to-one') {
381
+ const newId = this.extractRelationId(newValue);
382
+ const oldId = this.extractRelationId(oldValue);
383
+ return newId !== oldId;
384
+ }
385
+
386
+ if (field.relationType === 'many-to-many' || field.relationType === 'manyToMany') {
387
+ const newIds = this.extractRelationIds(newValue);
388
+ const oldIds = this.extractRelationIds(oldValue);
389
+
390
+ if (newIds.length !== oldIds.length) {
357
391
  return true;
358
392
  }
359
- const newIds = newValue.map(item => item.id || item).sort();
360
- const oldIds = oldValue.map(item => item.id || item).sort();
393
+
394
+ newIds.sort();
395
+ oldIds.sort();
396
+
361
397
  return JSON.stringify(newIds) !== JSON.stringify(oldIds);
362
398
  }
363
- }
364
399
 
365
- if (Array.isArray(newValue) && Array.isArray(oldValue)) {
366
- return JSON.stringify(newValue) !== JSON.stringify(oldValue);
400
+ return this.hasValueChanged(newValue, oldValue);
367
401
  }
368
402
 
369
- return true;
370
- }
403
+ private extractRelationId(value: any): any {
404
+ if (value === null || value === undefined) {
405
+ return null;
406
+ }
371
407
 
372
- private hasRelationValueChanged(field: any, newValue: any, oldValue: any): boolean {
373
- if (newValue === oldValue) {
374
- return false;
375
- }
376
-
377
- if ((newValue === null || newValue === undefined) && (oldValue === null || oldValue === undefined)) {
378
- return false;
379
- }
408
+ if (typeof value === 'string' || typeof value === 'number') {
409
+ return value;
410
+ }
380
411
 
381
- if (field.relationType === 'many-to-one') {
382
- const newId = this.extractRelationId(newValue);
383
- const oldId = this.extractRelationId(oldValue);
384
- return newId !== oldId;
385
- }
412
+ if (typeof value === 'object' && value.id !== undefined) {
413
+ return value.id;
414
+ }
386
415
 
387
- if (field.relationType === 'many-to-many' || field.relationType === 'manyToMany') {
388
- const newIds = this.extractRelationIds(newValue);
389
- const oldIds = this.extractRelationIds(oldValue);
390
-
391
- if (newIds.length !== oldIds.length) {
392
- return true;
393
- }
394
-
395
- newIds.sort();
396
- oldIds.sort();
397
-
398
- return JSON.stringify(newIds) !== JSON.stringify(oldIds);
416
+ return null;
399
417
  }
400
418
 
401
- return this.hasValueChanged(newValue, oldValue);
402
- }
419
+ private extractRelationIds(value: any): any[] {
420
+ if (!Array.isArray(value)) {
421
+ const id = this.extractRelationId(value);
422
+ return id !== null ? [id] : [];
423
+ }
403
424
 
404
- private extractRelationId(value: any): any {
405
- if (value === null || value === undefined) {
406
- return null;
407
- }
408
-
409
- if (typeof value === 'string' || typeof value === 'number') {
410
- return value;
425
+ return value.map(item => this.extractRelationId(item)).filter(id => id !== null);
411
426
  }
412
-
413
- if (typeof value === 'object' && value.id !== undefined) {
414
- return value.id;
415
- }
416
-
417
- return null;
418
- }
419
427
 
420
- private extractRelationIds(value: any): any[] {
421
- if (!Array.isArray(value)) {
422
- const id = this.extractRelationId(value);
423
- return id !== null ? [id] : [];
424
- }
425
-
426
- return value.map(item => this.extractRelationId(item)).filter(id => id !== null);
427
- }
428
+ private async populateRelationFields(databaseEntity: any, relationFields: any[], metadata: EntityMetadata): Promise<any> {
429
+ const populatedEntity = { ...databaseEntity };
428
430
 
429
- private async populateRelationFields(databaseEntity: any, relationFields: any[], metadata: EntityMetadata): Promise<any> {
430
- const populatedEntity = { ...databaseEntity };
431
-
432
- for (const field of relationFields) {
433
- const relationValue = databaseEntity[field.name];
434
-
435
- if (relationValue === null || relationValue === undefined) {
436
- populatedEntity[field.name] = relationValue;
437
- continue;
438
- }
431
+ for (const field of relationFields) {
432
+ const relationValue = databaseEntity[field.name];
439
433
 
440
- const relationMetadata = metadata.relations.find(rel => rel.propertyName === field.name);
441
- if (!relationMetadata) {
442
- populatedEntity[field.name] = relationValue;
443
- continue;
444
- }
434
+ if (relationValue === null || relationValue === undefined) {
435
+ populatedEntity[field.name] = relationValue;
436
+ continue;
437
+ }
445
438
 
446
- const targetEntity = relationMetadata.inverseEntityMetadata || relationMetadata.type;
447
-
448
- if (field.relationType === 'many-to-one') {
449
- const relationId = this.extractRelationId(relationValue);
450
- if (relationId) {
451
- const relatedEntity = await this.entityManager.findOne(targetEntity as any, {
452
- where: { id: relationId }
453
- });
454
- populatedEntity[field.name] = relatedEntity;
455
- } else {
456
- populatedEntity[field.name] = relationValue;
439
+ const relationMetadata = metadata.relations.find(rel => rel.propertyName === field.name);
440
+ if (!relationMetadata) {
441
+ populatedEntity[field.name] = relationValue;
442
+ continue;
457
443
  }
458
- } else if (field.relationType === 'many-to-many' || field.relationType === 'manyToMany') {
459
- const relationIds = this.extractRelationIds(relationValue);
460
- if (relationIds.length > 0) {
461
- const relatedEntities = await this.entityManager.findByIds(targetEntity as any, relationIds);
462
- populatedEntity[field.name] = relatedEntities;
444
+
445
+ const targetEntity = relationMetadata.inverseEntityMetadata || relationMetadata.type;
446
+
447
+ if (field.relationType === 'many-to-one') {
448
+ const relationId = this.extractRelationId(relationValue);
449
+ if (relationId) {
450
+ const relatedEntity = await this.entityManager.findOne(targetEntity as any, {
451
+ where: { id: relationId }
452
+ });
453
+ populatedEntity[field.name] = relatedEntity;
454
+ } else {
455
+ populatedEntity[field.name] = relationValue;
456
+ }
457
+ } else if (field.relationType === 'many-to-many' || field.relationType === 'manyToMany') {
458
+ const relationIds = this.extractRelationIds(relationValue);
459
+ if (relationIds.length > 0) {
460
+ const relatedEntities = await this.entityManager.findByIds(targetEntity as any, relationIds);
461
+ populatedEntity[field.name] = relatedEntities;
462
+ } else {
463
+ populatedEntity[field.name] = relationValue;
464
+ }
463
465
  } else {
464
- populatedEntity[field.name] = relationValue;
466
+ populatedEntity[field.name] = relationValue;
465
467
  }
466
- } else {
467
- populatedEntity[field.name] = relationValue;
468
468
  }
469
+
470
+ return populatedEntity;
469
471
  }
470
-
471
- return populatedEntity;
472
- }
473
472
  }