@solidstarters/solid-core 1.2.174 → 1.2.175

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 (50) hide show
  1. package/dev-grooming-docs/ozzy-prompts.txt +13 -0
  2. package/dist/config/iam.config.js +2 -2
  3. package/dist/config/iam.config.js.map +1 -1
  4. package/dist/constants/chatter-message.constants.d.ts +11 -0
  5. package/dist/constants/chatter-message.constants.d.ts.map +1 -0
  6. package/dist/constants/chatter-message.constants.js +14 -0
  7. package/dist/constants/chatter-message.constants.js.map +1 -0
  8. package/dist/controllers/authentication.controller.d.ts +1 -2
  9. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  10. package/dist/controllers/chatter-message-details.controller.d.ts +0 -16
  11. package/dist/controllers/chatter-message-details.controller.d.ts.map +1 -1
  12. package/dist/controllers/chatter-message-details.controller.js +0 -109
  13. package/dist/controllers/chatter-message-details.controller.js.map +1 -1
  14. package/dist/controllers/chatter-message.controller.d.ts +10 -13
  15. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  16. package/dist/controllers/chatter-message.controller.js +19 -88
  17. package/dist/controllers/chatter-message.controller.js.map +1 -1
  18. package/dist/entities/chatter-message-details.entity.d.ts +1 -0
  19. package/dist/entities/chatter-message-details.entity.d.ts.map +1 -1
  20. package/dist/entities/chatter-message-details.entity.js +5 -1
  21. package/dist/entities/chatter-message-details.entity.js.map +1 -1
  22. package/dist/entities/chatter-message.entity.d.ts +4 -0
  23. package/dist/entities/chatter-message.entity.d.ts.map +1 -1
  24. package/dist/entities/chatter-message.entity.js +14 -1
  25. package/dist/entities/chatter-message.entity.js.map +1 -1
  26. package/dist/seeders/seed-data/solid-core-metadata.json +39 -1
  27. package/dist/services/authentication.service.d.ts +2 -3
  28. package/dist/services/authentication.service.d.ts.map +1 -1
  29. package/dist/services/authentication.service.js +4 -4
  30. package/dist/services/authentication.service.js.map +1 -1
  31. package/dist/services/chatter-message.service.d.ts +16 -3
  32. package/dist/services/chatter-message.service.d.ts.map +1 -1
  33. package/dist/services/chatter-message.service.js +120 -25
  34. package/dist/services/chatter-message.service.js.map +1 -1
  35. package/dist/services/refresh-token-ids-storage.service.d.ts +2 -1
  36. package/dist/services/refresh-token-ids-storage.service.d.ts.map +1 -1
  37. package/dist/services/refresh-token-ids-storage.service.js +6 -7
  38. package/dist/services/refresh-token-ids-storage.service.js.map +1 -1
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +1 -1
  41. package/src/config/iam.config.ts +2 -2
  42. package/src/constants/chatter-message.constants.ts +11 -0
  43. package/src/controllers/chatter-message-details.controller.ts +44 -44
  44. package/src/controllers/chatter-message.controller.ts +58 -38
  45. package/src/entities/chatter-message-details.entity.ts +3 -0
  46. package/src/entities/chatter-message.entity.ts +9 -2
  47. package/src/seeders/seed-data/solid-core-metadata.json +39 -1
  48. package/src/services/authentication.service.ts +9 -4
  49. package/src/services/chatter-message.service.ts +143 -24
  50. package/src/services/refresh-token-ids-storage.service.ts +11 -7
@@ -19,6 +19,10 @@ import { RequestContextService } from './request-context.service';
19
19
  import { ChatterMessageRepository } from 'src/repository/chatter-message.repository';
20
20
  import { lowerFirst } from 'src/helpers/string.helper';
21
21
  import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
22
+ import { ChatterMessageDetailsRepository } from 'src/repository/chatter-message-details.repository';
23
+ import { FieldMetadata } from 'src/entities/field-metadata.entity';
24
+ import { CHATTER_MESSAGE_TYPE, CHATTER_MESSAGE_SUBTYPE } from 'src/constants/chatter-message.constants';
25
+ import { classify } from '@angular-devkit/core/src/utils/strings';
22
26
  @Injectable()
23
27
  export class ChatterMessageService extends CRUDService<ChatterMessage> {
24
28
  constructor(
@@ -32,8 +36,10 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
32
36
  readonly entityManager: EntityManager,
33
37
  // @InjectRepository(ChatterMessage, 'default')
34
38
  readonly repo: ChatterMessageRepository,
35
- @InjectRepository(ChatterMessageDetails, 'default')
36
- readonly chatterMessageDetailsRepo: Repository<ChatterMessageDetails>,
39
+ // @InjectRepository(ChatterMessageDetailsRepository, 'default')
40
+ readonly chatterMessageDetailsRepo: ChatterMessageDetailsRepository,
41
+ @InjectRepository(FieldMetadata, 'default')
42
+ readonly fieldMetadataRepo: Repository<FieldMetadata>,
37
43
  readonly moduleRef: ModuleRef,
38
44
  @InjectRepository(ModelMetadata)
39
45
  private readonly modelMetadataRepo: Repository<ModelMetadata>,
@@ -45,8 +51,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
45
51
 
46
52
  async postMessage(postDto: PostChatterMessageDto, files: Express.Multer.File[] = []) {
47
53
  const chatterMessage = new ChatterMessage();
48
- chatterMessage.messageType = 'custom';
49
- chatterMessage.messageSubType = postDto.messageSubType || 'post_message';
54
+ chatterMessage.messageType = CHATTER_MESSAGE_TYPE.CUSTOM;
55
+ chatterMessage.messageSubType = postDto.messageSubType || CHATTER_MESSAGE_SUBTYPE.CUSTOM;
50
56
  chatterMessage.messageBody = postDto.messageBody;
51
57
  chatterMessage.coModelEntityId = postDto.coModelEntityId;
52
58
  chatterMessage.coModelName = postDto.coModelName;
@@ -97,7 +103,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
97
103
  },
98
104
  relations: {
99
105
  fields: true,
100
- module: true
106
+ module: true,
107
+ userKeyField: true
101
108
  }
102
109
  });
103
110
 
@@ -114,11 +121,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
114
121
  const activeUser = this.requestContextService.getActiveUser();
115
122
 
116
123
  const chatterMessage = new ChatterMessage();
117
- chatterMessage.messageType = 'audit';
118
- chatterMessage.messageSubType = 'insert';
124
+ chatterMessage.messageType = CHATTER_MESSAGE_TYPE.AUDIT;
125
+ chatterMessage.messageSubType = CHATTER_MESSAGE_SUBTYPE.AUDIT_INSERT;
119
126
  chatterMessage.coModelEntityId = entity.id;
120
- chatterMessage.coModelName = model.singularName;
121
- chatterMessage.messageBody = `New ${model.displayName} created`;
127
+ chatterMessage.coModelName = model?.singularName;
128
+ chatterMessage.modelDisplayName = model?.displayName;
129
+ chatterMessage.modelUserKey = entity[model?.userKeyField?.name];
130
+ chatterMessage.messageBody = `New ${model?.displayName} created`;
122
131
 
123
132
  if (activeUser) {
124
133
  const userId = activeUser?.sub;
@@ -135,6 +144,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
135
144
  const messageDetail = new ChatterMessageDetails();
136
145
  messageDetail.chatterMessage = savedMessage;
137
146
  messageDetail.fieldName = field.name;
147
+ messageDetail.fieldDisplayName = field.displayName;
138
148
  messageDetail.oldValue = null;
139
149
  messageDetail.oldValueDisplay = null;
140
150
  messageDetail.newValue = this.formatFieldValue(field, fieldValue);
@@ -154,7 +164,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
154
164
  },
155
165
  relations: {
156
166
  fields: true,
157
- module: true
167
+ module: true,
168
+ userKeyField: true
158
169
  }
159
170
  });
160
171
 
@@ -228,11 +239,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
228
239
  const activeUser = this.requestContextService.getActiveUser();
229
240
 
230
241
  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`;
242
+ chatterMessage.messageType = CHATTER_MESSAGE_TYPE.AUDIT;
243
+ chatterMessage.messageSubType = CHATTER_MESSAGE_SUBTYPE.AUDIT_UPDATE;
244
+ chatterMessage.coModelEntityId = entity?.id;
245
+ chatterMessage.coModelName = model?.singularName;
246
+ chatterMessage.modelDisplayName = model.displayName;
247
+ chatterMessage.modelUserKey = entity[model?.userKeyField?.name];
248
+ chatterMessage.messageBody = `${model?.displayName} updated`;
236
249
 
237
250
  if (activeUser) {
238
251
  const userId = activeUser?.sub;
@@ -247,6 +260,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
247
260
  const messageDetail = new ChatterMessageDetails();
248
261
  messageDetail.chatterMessage = savedMessage;
249
262
  messageDetail.fieldName = field.name;
263
+ messageDetail.fieldDisplayName = field.displayName;
250
264
  messageDetail.oldValue = this.formatFieldValue(field, oldValue);
251
265
  messageDetail.newValue = this.formatFieldValue(field, newValue);
252
266
  messageDetail.oldValueDisplay = this.formatFieldValueDisplay(field, oldValue);
@@ -262,7 +276,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
262
276
  },
263
277
  relations: {
264
278
  fields: true,
265
- module: true
279
+ module: true,
280
+ userKeyField: true
266
281
  }
267
282
  });
268
283
 
@@ -271,11 +286,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
271
286
  }
272
287
 
273
288
  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`;
289
+ chatterMessage.messageType = CHATTER_MESSAGE_TYPE.AUDIT;
290
+ chatterMessage.messageSubType = CHATTER_MESSAGE_SUBTYPE.AUDIT_DELETE;
291
+ chatterMessage.coModelEntityId = databaseEntity?.id;
292
+ chatterMessage.coModelName = model?.singularName;
293
+ chatterMessage.modelDisplayName = model?.displayName;
294
+ chatterMessage.modelUserKey = entity[model?.userKeyField?.name];
295
+ chatterMessage.messageBody = `${model?.displayName} deleted`;
279
296
 
280
297
  const activeUser = this.requestContextService.getActiveUser();
281
298
 
@@ -302,7 +319,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
302
319
  if (field.relationType === "many-to-one") {
303
320
  return value.id;
304
321
  }
305
- if (field.relationType === 'manyToMany') {
322
+ if (field.relationType === 'many-to-many') {
306
323
  return value.map(item => item.id).join(', ');
307
324
  }
308
325
  }
@@ -324,7 +341,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
324
341
  if (field.relationType === "many-to-one") {
325
342
  return value.name;
326
343
  }
327
- if (field.relationType === 'many-toMany') {
344
+ if (field.relationType === 'many-to-many') {
328
345
  return value.map(item => item.name).join(', ');
329
346
  }
330
347
  }
@@ -383,7 +400,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
383
400
  return newId !== oldId;
384
401
  }
385
402
 
386
- if (field.relationType === 'many-to-many' || field.relationType === 'manyToMany') {
403
+ if (field.relationType === 'many-to-many') {
387
404
  const newIds = this.extractRelationIds(newValue);
388
405
  const oldIds = this.extractRelationIds(oldValue);
389
406
 
@@ -469,4 +486,106 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
469
486
 
470
487
  return populatedEntity;
471
488
  }
489
+
490
+ async getChatterMessages(
491
+ entityId: number,
492
+ entityName: string,
493
+ query: any
494
+ ) {
495
+ const { limit = 25, offset = 0, sort, populate = [] } = query;
496
+
497
+ const model = await this.modelMetadataRepo.findOne({
498
+ where: {
499
+ singularName: entityName
500
+ },
501
+ });
502
+ const oneToManyFields = await this.fieldMetadataRepo.find({
503
+ where: {
504
+ model: { id: model.id },
505
+ type: 'relation',
506
+ relationType: 'one-to-many'
507
+ }
508
+ });
509
+
510
+ const relatedEntitiesMap = new Map<string, number[]>();
511
+
512
+ for (const field of oneToManyFields) {
513
+ const coModelName = field.relationCoModelSingularName;
514
+ const coModelFieldName = field.relationCoModelFieldName;
515
+
516
+ const coModel = await this.modelMetadataRepo.findOne({
517
+ where: { singularName: coModelName }
518
+ });
519
+
520
+ if (coModel) {
521
+ const relatedEntityRepository = this.entityManager.getRepository(classify(coModelName));
522
+
523
+ const relatedEntities = await relatedEntityRepository.find({
524
+ where: { [coModelFieldName]: { id: entityId } }
525
+ });
526
+
527
+ const relatedIds = relatedEntities.map((entity: any) => entity.id);
528
+ relatedEntitiesMap.set(field.name, relatedIds);
529
+ }
530
+ }
531
+
532
+ const qb = this.repo.createQueryBuilder('entity');
533
+
534
+ const orConditions: string[] = [];
535
+ const parameters: any = {};
536
+
537
+ orConditions.push('(entity.coModelName = :entityName AND entity.coModelEntityId = :entityId)');
538
+ parameters.entityName = entityName;
539
+ parameters.entityId = entityId;
540
+
541
+ let paramIndex = 0;
542
+ for (const [fieldName, relatedIds] of relatedEntitiesMap.entries()) {
543
+ if (relatedIds.length > 0) {
544
+ const field = oneToManyFields.find(f => f.name === fieldName);
545
+ if (field) {
546
+ const coModelName = field.relationCoModelSingularName;
547
+ const idsParamName = `relatedIds${paramIndex}`;
548
+ orConditions.push(`(entity.coModelName = :coModelName${paramIndex} AND entity.coModelEntityId IN (:...${idsParamName}))`);
549
+ parameters[`coModelName${paramIndex}`] = coModelName;
550
+ parameters[idsParamName] = relatedIds;
551
+ paramIndex++;
552
+ }
553
+ }
554
+ }
555
+
556
+ qb.where(orConditions.join(' OR '), parameters);
557
+
558
+ const relations = ['chatterMessageDetails', 'user'];
559
+ if (populate && populate.length > 0) {
560
+ const normalizedPopulate = this.crudHelperService.normalize(populate);
561
+ relations.push(...normalizedPopulate.filter(rel => !relations.includes(rel)));
562
+ }
563
+
564
+ relations.forEach(relation => {
565
+ qb.leftJoinAndSelect(`entity.${relation}`, relation);
566
+ });
567
+
568
+ qb.orderBy('entity.createdAt', 'DESC');
569
+
570
+ qb.skip(offset).take(limit);
571
+
572
+ const [entities, count] = await qb.getManyAndCount();
573
+
574
+ const currentPage = Math.floor(offset / limit) + 1;
575
+ const totalPages = Math.ceil(count / limit);
576
+ const nextPage = currentPage < totalPages ? currentPage + 1 : null;
577
+ const prevPage = currentPage > 1 ? currentPage - 1 : null;
578
+
579
+ return {
580
+ meta: {
581
+ totalRecords: count,
582
+ currentPage: currentPage,
583
+ nextPage: nextPage,
584
+ prevPage: prevPage,
585
+ totalPages: totalPages,
586
+ perPage: +limit,
587
+ },
588
+ records: entities
589
+ };
590
+ }
472
591
  }
@@ -28,13 +28,13 @@ export class RefreshTokenIdsStorageService {
28
28
  private readonly authenticationService: AuthenticationService
29
29
  ) { }
30
30
 
31
- async insert(userId: number, refreshToken: string): Promise<void> {
31
+ async insert(userId: number, refreshToken: string, previousRefreshToken?: string): Promise<void> {
32
32
  // TODO: save a refresh token object with this shape {"currentRefreshToken": "", "previousRefreshToken": ""}
33
33
  // Save a refresh token object with the shape: { currentRefreshToken: string, previousRefreshToken: string }
34
34
  const existing = (await this.cacheManager.get(this.getKey(userId))) as { currentRefreshToken?: string, previousRefreshToken?: string } | undefined;
35
35
  const refreshTokenState = {
36
36
  currentRefreshToken: refreshToken,
37
- previousRefreshToken: "",
37
+ previousRefreshToken: previousRefreshToken ?? "",
38
38
  };
39
39
  await this.cacheManager.set(this.getKey(userId), refreshTokenState);
40
40
  }
@@ -84,14 +84,14 @@ export class RefreshTokenIdsStorageService {
84
84
  // Scenario 1: Token matches currentRefreshToken
85
85
  valid = true;
86
86
  // Rotate tokens: move current to previous, set new current (simulate generation)
87
- newRefreshToken = await this.authenticationService.generateRefreshToken(user); // Replace with real token generation logic
87
+ newRefreshToken = await this.authenticationService.generateRefreshToken(user, refreshTokenState.currentRefreshToken); // Replace with real token generation logic
88
88
 
89
89
 
90
90
  // updated cache state
91
- await this.cacheManager.set(this.getKey(user.id), {
92
- currentRefreshToken: newRefreshToken,
93
- previousRefreshToken: refreshTokenState.currentRefreshToken,
94
- });
91
+ // await this.cacheManager.set(this.getKey(user.id), {
92
+ // currentRefreshToken: newRefreshToken,
93
+ // previousRefreshToken: refreshTokenState.currentRefreshToken,
94
+ // });
95
95
 
96
96
  // Optionally, set a timeout to clear previousRefreshToken after X minutes
97
97
  setTimeout(async () => {
@@ -125,4 +125,8 @@ export class RefreshTokenIdsStorageService {
125
125
  private getKey(userId: number): string {
126
126
  return `user-${userId}`;
127
127
  }
128
+
129
+ getCurrentRefreshTokenState(userId: number): Promise<any> {
130
+ return this.cacheManager.get(this.getKey(userId));
131
+ }
128
132
  }