@solidstarters/solid-core 1.2.158 → 1.2.159

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 (71) hide show
  1. package/dist/factories/whatsapp.factory.d.ts.map +1 -1
  2. package/dist/factories/whatsapp.factory.js +1 -1
  3. package/dist/factories/whatsapp.factory.js.map +1 -1
  4. package/dist/helpers/index.d.ts +2 -0
  5. package/dist/helpers/index.d.ts.map +1 -0
  6. package/dist/helpers/index.js +13 -0
  7. package/dist/helpers/index.js.map +1 -0
  8. package/dist/helpers/model-metadata-helper.service.d.ts +5 -1
  9. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  10. package/dist/helpers/model-metadata-helper.service.js +32 -2
  11. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  12. package/dist/helpers/string.helper.d.ts +2 -0
  13. package/dist/helpers/string.helper.d.ts.map +1 -0
  14. package/dist/helpers/string.helper.js +10 -0
  15. package/dist/helpers/string.helper.js.map +1 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  21. package/dist/repository/security-rule.repository.js +16 -9
  22. package/dist/repository/security-rule.repository.js.map +1 -1
  23. package/dist/repository/user.repository.d.ts +12 -0
  24. package/dist/repository/user.repository.d.ts.map +1 -0
  25. package/dist/repository/user.repository.js +34 -0
  26. package/dist/repository/user.repository.js.map +1 -0
  27. package/dist/seeders/module-metadata-seeder.service.d.ts +12 -12
  28. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  29. package/dist/seeders/module-metadata-seeder.service.js +31 -13
  30. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  31. package/dist/seeders/seed-data/solid-core-metadata.json +40 -6
  32. package/dist/services/chatter-message.service.d.ts +8 -2
  33. package/dist/services/chatter-message.service.d.ts.map +1 -1
  34. package/dist/services/chatter-message.service.js +155 -30
  35. package/dist/services/chatter-message.service.js.map +1 -1
  36. package/dist/services/crud-helper.service.d.ts +7 -3
  37. package/dist/services/crud-helper.service.d.ts.map +1 -1
  38. package/dist/services/crud-helper.service.js +17 -5
  39. package/dist/services/crud-helper.service.js.map +1 -1
  40. package/dist/services/user.service.d.ts +3 -2
  41. package/dist/services/user.service.d.ts.map +1 -1
  42. package/dist/services/user.service.js +2 -2
  43. package/dist/services/user.service.js.map +1 -1
  44. package/dist/services/view-metadata.service.d.ts +3 -1
  45. package/dist/services/view-metadata.service.d.ts.map +1 -1
  46. package/dist/services/view-metadata.service.js +5 -2
  47. package/dist/services/view-metadata.service.js.map +1 -1
  48. package/dist/solid-core.module.d.ts.map +1 -1
  49. package/dist/solid-core.module.js +2 -0
  50. package/dist/solid-core.module.js.map +1 -1
  51. package/dist/subscribers/audit.subscriber.d.ts +3 -1
  52. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  53. package/dist/subscribers/audit.subscriber.js +10 -5
  54. package/dist/subscribers/audit.subscriber.js.map +1 -1
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +1 -1
  57. package/src/factories/whatsapp.factory.ts +2 -1
  58. package/src/helpers/index.ts +9 -0
  59. package/src/helpers/model-metadata-helper.service.ts +30 -2
  60. package/src/helpers/string.helper.ts +4 -0
  61. package/src/index.ts +1 -0
  62. package/src/repository/security-rule.repository.ts +25 -12
  63. package/src/repository/user.repository.ts +17 -0
  64. package/src/seeders/module-metadata-seeder.service.ts +34 -15
  65. package/src/seeders/seed-data/solid-core-metadata.json +40 -6
  66. package/src/services/chatter-message.service.ts +185 -35
  67. package/src/services/crud-helper.service.ts +24 -6
  68. package/src/services/user.service.ts +3 -2
  69. package/src/services/view-metadata.service.ts +3 -1
  70. package/src/solid-core.module.ts +3 -0
  71. package/src/subscribers/audit.subscriber.ts +9 -3
@@ -18,6 +18,8 @@ import { ChatterMessageDetails } from '../entities/chatter-message-details.entit
18
18
  import { ModelMetadata } from 'src/entities/model-metadata.entity';
19
19
  import { RequestContextService } from './request-context.service';
20
20
  import { ChatterMessageRepository } from 'src/repository/chatter-message.repository';
21
+ import { lowerFirst } from 'src/helpers/string.helper';
22
+ import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
21
23
  @Injectable()
22
24
  export class ChatterMessageService extends CRUDService<ChatterMessage>{
23
25
  constructor(
@@ -36,7 +38,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage>{
36
38
  readonly moduleRef: ModuleRef,
37
39
  @InjectRepository(ModelMetadata)
38
40
  private readonly modelMetadataRepo: Repository<ModelMetadata>,
39
- readonly requestContextService: RequestContextService
41
+ readonly requestContextService: RequestContextService,
42
+ private readonly modelMetadataHelperService: ModelMetadataHelperService,
40
43
  ) {
41
44
  super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService,entityManager, repo, 'chatterMessage', 'solid-core', moduleRef);
42
45
  }
@@ -91,7 +94,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage>{
91
94
  }
92
95
  const model = await this.modelMetadataRepo.findOne({
93
96
  where: {
94
- displayName: metadata.name
97
+ singularName: lowerFirst(metadata.name)
95
98
  },
96
99
  relations: {
97
100
  fields: true,
@@ -142,13 +145,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage>{
142
145
  }
143
146
  }
144
147
 
145
- async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEntity: any, messageQueue: boolean = false) {
148
+ async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEntity: any, updatedColumns: any[] = [], messageQueue: boolean = false) {
146
149
  if(!databaseEntity || !entity){
147
150
  return;
148
151
  }
149
152
  const model = await this.modelMetadataRepo.findOne({
150
153
  where: {
151
- displayName: metadata.name
154
+ singularName: lowerFirst(metadata.name)
152
155
  },
153
156
  relations: {
154
157
  fields: true,
@@ -159,34 +162,70 @@ async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEn
159
162
  if (!model || !model.enableAuditTracking) {
160
163
  return;
161
164
  }
165
+
166
+ const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName)
162
167
 
163
- const auditFields = model.fields.filter(field =>
168
+ const auditFields = modelFields.filter(field =>
164
169
  field.enableAuditTracking &&
165
170
  !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&
166
171
  !(field.type === 'relation' && field.relationType === 'one-to-many')
167
172
  );
168
173
 
169
- const relationFields = auditFields.filter(field =>
170
- field.type === 'relation'
171
- );
172
- if (relationFields.length > 0) {
173
- const populatedEntity = await this.entityManager.findOne(metadata.target, {
174
- where: { id: databaseEntity.id },
175
- relations: relationFields.map(field => field.name)
176
- });
177
- if (populatedEntity) {
178
- databaseEntity = populatedEntity;
179
- }
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)
184
+ );
185
+ } else {
186
+ potentialNonRelationFields = allNonRelationFields;
180
187
  }
181
- const changedFields = auditFields.filter(field => {
188
+
189
+ const potentialRelationFields = allRelationFields;
190
+
191
+ const changedNonRelationFields = potentialNonRelationFields.filter(field => {
182
192
  const newValue = entity[field.name];
183
193
  const oldValue = databaseEntity[field.name];
184
194
  return this.hasValueChanged(newValue, oldValue);
185
195
  });
196
+
197
+ const changedRelationFields = [];
198
+ if (potentialRelationFields.length > 0) {
199
+ const populatedOldEntity = await this.populateRelationFields(databaseEntity, potentialRelationFields, metadata);
200
+
201
+ for (const field of potentialRelationFields) {
202
+ 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
+ });
211
+ }
212
+ }
213
+ }
214
+
215
+
216
+ const allChangedFields = [
217
+ ...changedNonRelationFields.map(field => ({
218
+ field,
219
+ newValue: entity[field.name],
220
+ oldValue: databaseEntity[field.name]
221
+ })),
222
+ ...changedRelationFields
223
+ ];
186
224
 
187
- if (changedFields.length === 0) {
225
+ if (allChangedFields.length === 0) {
188
226
  return;
189
227
  }
228
+
190
229
  const activeUser = this.requestContextService.getActiveUser();
191
230
 
192
231
  const chatterMessage = new ChatterMessage();
@@ -205,14 +244,14 @@ async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEn
205
244
 
206
245
  const savedMessage = await this.repo.save(chatterMessage);
207
246
 
208
- for (const field of changedFields) {
247
+ for (const { field, newValue, oldValue } of allChangedFields) {
209
248
  const messageDetail = new ChatterMessageDetails();
210
249
  messageDetail.chatterMessage = savedMessage;
211
250
  messageDetail.fieldName = field.name;
212
- messageDetail.oldValue = this.formatFieldValue(field, databaseEntity[field.name]);
213
- messageDetail.newValue = this.formatFieldValue(field, entity[field.name]);
214
- messageDetail.oldValueDisplay = this.formatFieldValueDisplay(field, databaseEntity[field.name]);
215
- messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, entity[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);
216
255
  await this.chatterMessageDetailsRepo.save(messageDetail);
217
256
  }
218
257
  }
@@ -220,7 +259,7 @@ async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEn
220
259
  async postAuditMessageOnDelete(entity: any, metadata: EntityMetadata, databaseEntity: any, messageQueue: boolean = false) {
221
260
  const model = await this.modelMetadataRepo.findOne({
222
261
  where: {
223
- displayName: metadata.name
262
+ singularName: lowerFirst(metadata.name)
224
263
  },
225
264
  relations: {
226
265
  fields: true,
@@ -296,28 +335,139 @@ private formatFieldValueDisplay(field: any, value: any): string {
296
335
  }
297
336
 
298
337
  private hasValueChanged(newValue: any, oldValue: any): boolean {
299
- if (
300
- (newValue === null || newValue === undefined) &&
301
- (oldValue === null || oldValue === undefined)
302
- ) {
338
+ if (newValue === oldValue) {
303
339
  return false;
304
340
  }
305
341
 
306
- if (newValue === oldValue) {
342
+ if (newValue === null && oldValue === null) {
307
343
  return false;
308
344
  }
309
345
 
310
- if (Array.isArray(newValue) && Array.isArray(oldValue)) {
311
- return JSON.stringify(newValue) !== JSON.stringify(oldValue);
346
+ if (newValue === undefined && oldValue === undefined) {
347
+ return false;
348
+ }
349
+
350
+ if (newValue && oldValue && typeof newValue === 'object' && typeof oldValue === 'object') {
351
+ if (newValue.id !== undefined && oldValue.id !== undefined) {
352
+ return newValue.id !== oldValue.id;
353
+ }
354
+
355
+ if (Array.isArray(newValue) && Array.isArray(oldValue)) {
356
+ if (newValue.length !== oldValue.length) {
357
+ return true;
358
+ }
359
+ const newIds = newValue.map(item => item.id || item).sort();
360
+ const oldIds = oldValue.map(item => item.id || item).sort();
361
+ return JSON.stringify(newIds) !== JSON.stringify(oldIds);
362
+ }
312
363
  }
313
364
 
314
- if (
315
- typeof newValue === 'object' && newValue !== null &&
316
- typeof oldValue === 'object' && oldValue !== null
317
- ) {
365
+ if (Array.isArray(newValue) && Array.isArray(oldValue)) {
318
366
  return JSON.stringify(newValue) !== JSON.stringify(oldValue);
319
367
  }
320
368
 
321
369
  return true;
322
370
  }
371
+
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
+ }
380
+
381
+ if (field.relationType === 'many-to-one') {
382
+ const newId = this.extractRelationId(newValue);
383
+ const oldId = this.extractRelationId(oldValue);
384
+ return newId !== oldId;
385
+ }
386
+
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);
399
+ }
400
+
401
+ return this.hasValueChanged(newValue, oldValue);
402
+ }
403
+
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;
411
+ }
412
+
413
+ if (typeof value === 'object' && value.id !== undefined) {
414
+ return value.id;
415
+ }
416
+
417
+ return null;
418
+ }
419
+
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
+
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
+ }
439
+
440
+ const relationMetadata = metadata.relations.find(rel => rel.propertyName === field.name);
441
+ if (!relationMetadata) {
442
+ populatedEntity[field.name] = relationValue;
443
+ continue;
444
+ }
445
+
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;
457
+ }
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;
463
+ } else {
464
+ populatedEntity[field.name] = relationValue;
465
+ }
466
+ } else {
467
+ populatedEntity[field.name] = relationValue;
468
+ }
469
+ }
470
+
471
+ return populatedEntity;
472
+ }
323
473
  }
@@ -6,6 +6,10 @@ import { SolidRegistry } from "src/helpers/solid-registry";
6
6
  import { Logger } from "@nestjs/common";
7
7
  import { ERROR_MESSAGES } from "src/constants/error-messages";
8
8
 
9
+ export enum FilterCombinator {
10
+ AND = '$and',
11
+ OR = '$or'
12
+ }
9
13
 
10
14
  export class CrudHelperService {
11
15
  constructor(
@@ -24,7 +28,7 @@ export class CrudHelperService {
24
28
  return orderOptions;
25
29
  }
26
30
 
27
- private applyFilters(qb: WhereExpressionBuilder, filters: any, alias: string = 'entity', selectQb: SelectQueryBuilder<any>) {
31
+ applyFilters(qb: WhereExpressionBuilder, filters: any, alias: string = 'entity', selectQb: SelectQueryBuilder<any>) {
28
32
  const normalizedFilters = this.normalizeObjectKeys(filters);
29
33
  if (normalizedFilters.$and) {
30
34
  normalizedFilters.$and.forEach((andFilter: any) => {
@@ -157,8 +161,16 @@ export class CrudHelperService {
157
161
  private hasJoins(queryBuilder: SelectQueryBuilder<any>): boolean {
158
162
  return queryBuilder.expressionMap.joinAttributes.length > 0;
159
163
  }
160
-
161
- buildFilterQuery(qb: SelectQueryBuilder<any>, basicFilterDto: BasicFilterDto, entityAlias: string, internationalisation?: boolean, draftPublishWorkflow?: boolean,moduleRef?:any): SelectQueryBuilder<any> { // TODO : Check how to pass a type to SelectQueryBuilder instead of any
164
+
165
+ buildFilterQuery(
166
+ qb: SelectQueryBuilder<any>,
167
+ basicFilterDto: BasicFilterDto,
168
+ entityAlias: string,
169
+ internationalisation?: boolean,
170
+ draftPublishWorkflow?: boolean,
171
+ moduleRef?: any,
172
+ filterCombinator: FilterCombinator = FilterCombinator.AND
173
+ ): SelectQueryBuilder<any> { // TODO : Check how to pass a type to SelectQueryBuilder instead of any
162
174
  let { limit, offset, showSoftDeleted, filters } = basicFilterDto;
163
175
  const { fields, sort, groupBy, populate = [], populateMedia = [], locale, status } = basicFilterDto;
164
176
 
@@ -184,9 +196,15 @@ export class CrudHelperService {
184
196
  }
185
197
 
186
198
  if (filters) {
187
- qb.andWhere(new Brackets(whereQb => {
188
- this.applyFilters(whereQb, filters, entityAlias, qb);
189
- }));
199
+ if (filterCombinator === FilterCombinator.AND) {
200
+ qb.andWhere(new Brackets(whereQb => {
201
+ this.applyFilters(whereQb, filters, entityAlias, qb);
202
+ }));
203
+ } else if (filterCombinator === FilterCombinator.OR) {
204
+ qb.orWhere(new Brackets(whereQb => {
205
+ this.applyFilters(whereQb, filters, entityAlias, qb);
206
+ }));
207
+ }
190
208
  }
191
209
 
192
210
  let finalLocale = locale
@@ -16,6 +16,7 @@ import { User } from '../entities/user.entity';
16
16
  import { ActiveUserData } from '../interfaces/active-user-data.interface';
17
17
  import { iamConfig } from 'src/config/iam.config';
18
18
  import { ERROR_MESSAGES } from 'src/constants/error-messages';
19
+ import { UserRepository } from 'src/repository/user.repository';
19
20
 
20
21
  @Injectable()
21
22
  export class UserService extends CRUDService<User> {
@@ -28,8 +29,8 @@ export class UserService extends CRUDService<User> {
28
29
  readonly crudHelperService: CrudHelperService,
29
30
  @InjectEntityManager()
30
31
  readonly entityManager: EntityManager,
31
- @InjectRepository(User, 'default')
32
- readonly repo: Repository<User>,
32
+ // @InjectRepository(User, 'default')
33
+ readonly repo: UserRepository,
33
34
  @InjectRepository(RoleMetadata)
34
35
  private readonly roleRepository: Repository<RoleMetadata>,
35
36
  readonly moduleRef: ModuleRef,
@@ -21,6 +21,7 @@ import { ActionMetadataService } from './action-metadata.service';
21
21
  import { SolidIntrospectService } from './solid-introspect.service';
22
22
  import { UserViewMetadataService } from './user-view-metadata.service';
23
23
  import { ViewMetadataRepository } from 'src/repository/view-metadata.repository';
24
+ import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
24
25
 
25
26
  @Injectable()
26
27
  export class ViewMetadataService extends CRUDService<ViewMetadata> {
@@ -42,6 +43,7 @@ export class ViewMetadataService extends CRUDService<ViewMetadata> {
42
43
  private readonly fieldMetadataRepo: Repository<FieldMetadata>,
43
44
  @InjectRepository(ModelMetadata)
44
45
  private readonly modelMetadataRepo: Repository<ModelMetadata>,
46
+ private readonly modelMetadataHelperService: ModelMetadataHelperService,
45
47
  readonly moduleRef: ModuleRef
46
48
  ) {
47
49
  super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'viewMetadata', 'solid-core', moduleRef);
@@ -172,7 +174,7 @@ export class ViewMetadataService extends CRUDService<ViewMetadata> {
172
174
  }
173
175
 
174
176
  // 5. Create an easy to use map of field metadata, rather than sending an array of fields it becomes easier to use in the frontend.
175
- const fields = await this.loadFieldHierarchy(modelName);
177
+ const fields = await this.modelMetadataHelperService.loadFieldHierarchy(modelName);
176
178
  const fieldsMap = new Map<string, FieldMetadata>();
177
179
  for (let i = 0; i < fields.length; i++) {
178
180
  const field = fields[i];
@@ -283,6 +283,7 @@ import { Three60WhatsappQueueSubscriberDatabase } from './jobs/database/three60-
283
283
  import { Three60WhatsappService } from './services/whatsapp/Three60WhatsappService';
284
284
  import { ThrottlerStorageRedisService } from '@nest-lab/throttler-storage-redis/src/throttler-storage-redis.service';
285
285
  import { isRedisConfigured } from './helpers/environment.helper';
286
+ import { UserRepository } from './repository/user.repository';
286
287
 
287
288
 
288
289
  @Global()
@@ -546,6 +547,7 @@ import { isRedisConfigured } from './helpers/environment.helper';
546
547
  RoleMetadataService,
547
548
  PermissionMetadataSeederService,
548
549
  UserService,
550
+ UserRepository,
549
551
  SettingService,
550
552
  ConcatComputedFieldProvider,
551
553
  FileStorageProvider,
@@ -615,6 +617,7 @@ import { isRedisConfigured } from './helpers/environment.helper';
615
617
  MailFactory,
616
618
  ChatterMessageRepository,
617
619
  ChatterMessageDetailsRepository,
620
+
618
621
  ],
619
622
  exports: [
620
623
  ModuleMetadataService,
@@ -3,6 +3,9 @@ import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
3
3
  import { DataSource, EntityMetadata, EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, Repository, UpdateEvent } from 'typeorm';
4
4
  import { ModelMetadata } from '../entities/model-metadata.entity';
5
5
  import { ChatterMessageService } from '../services/chatter-message.service';
6
+ import { lowerFirst } from 'src/helpers/string.helper';
7
+ import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
8
+
6
9
  @Injectable()
7
10
  @EventSubscriber()
8
11
  export class AuditSubscriber implements EntitySubscriberInterface {
@@ -13,6 +16,7 @@ export class AuditSubscriber implements EntitySubscriberInterface {
13
16
  private readonly chatterMessageService: ChatterMessageService,
14
17
  @InjectRepository(ModelMetadata)
15
18
  private readonly modelMetadataRepo: Repository<ModelMetadata>,
19
+ private readonly modelMetadataHelperService : ModelMetadataHelperService,
16
20
  ) {
17
21
  this.dataSource.subscribers.push(this);
18
22
  }
@@ -20,7 +24,7 @@ export class AuditSubscriber implements EntitySubscriberInterface {
20
24
  private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<boolean> {
21
25
  const model = await this.modelMetadataRepo.findOne({
22
26
  where: {
23
- displayName: metadata.name
27
+ singularName: lowerFirst(metadata.name)
24
28
  },
25
29
  relations: {
26
30
  fields: true,
@@ -32,7 +36,9 @@ export class AuditSubscriber implements EntitySubscriberInterface {
32
36
  return false;
33
37
  }
34
38
 
35
- const auditFields = model.fields.filter(field =>
39
+ const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName)
40
+
41
+ const auditFields = modelFields.filter(field =>
36
42
  field.enableAuditTracking &&
37
43
  !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&
38
44
  !(field.type === 'relation' && field.relationType === 'one-to-many')
@@ -56,7 +62,7 @@ export class AuditSubscriber implements EntitySubscriberInterface {
56
62
 
57
63
  async afterUpdate(event: UpdateEvent<any>) {
58
64
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
59
- await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity);
65
+ await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, event.updatedColumns || []);
60
66
  }
61
67
  }
62
68