@solidxai/core 0.1.6-beta.23 → 0.1.6-beta.25
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.
- package/dist/entities/mq-message-queue.entity.d.ts.map +1 -1
- package/dist/entities/mq-message-queue.entity.js.map +1 -1
- package/dist/helpers/bootstrap.helper.js +1 -1
- package/dist/helpers/bootstrap.helper.js.map +1 -1
- package/dist/helpers/cors.helper.d.ts.map +1 -1
- package/dist/helpers/cors.helper.js +4 -1
- package/dist/helpers/cors.helper.js.map +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/jobs/chatter-queue-options.js +1 -1
- package/dist/jobs/chatter-queue-options.js.map +1 -1
- package/dist/jobs/chatter-queue-publisher.service.d.ts +9 -9
- package/dist/jobs/chatter-queue-publisher.service.d.ts.map +1 -1
- package/dist/jobs/chatter-queue-publisher.service.js +5 -5
- package/dist/jobs/chatter-queue-publisher.service.js.map +1 -1
- package/dist/jobs/chatter-queue-subscriber.service.d.ts +4 -4
- package/dist/jobs/chatter-queue-subscriber.service.d.ts.map +1 -1
- package/dist/jobs/chatter-queue-subscriber.service.js +11 -11
- package/dist/jobs/chatter-queue-subscriber.service.js.map +1 -1
- package/dist/jobs/computed-field-evaluation-queue-options.d.ts +1 -0
- package/dist/jobs/computed-field-evaluation-queue-options.d.ts.map +1 -1
- package/dist/jobs/computed-field-evaluation-queue-options.js +1 -0
- package/dist/jobs/computed-field-evaluation-queue-options.js.map +1 -1
- package/dist/jobs/database/chatter-queue-options-database.d.ts +8 -0
- package/dist/jobs/database/chatter-queue-options-database.d.ts.map +1 -0
- package/dist/jobs/database/chatter-queue-options-database.js +10 -0
- package/dist/jobs/database/chatter-queue-options-database.js.map +1 -0
- package/dist/jobs/database/chatter-queue-publisher-database.service.d.ts +12 -0
- package/dist/jobs/database/chatter-queue-publisher-database.service.d.ts.map +1 -0
- package/dist/jobs/database/chatter-queue-publisher-database.service.js +39 -0
- package/dist/jobs/database/chatter-queue-publisher-database.service.js.map +1 -0
- package/dist/jobs/database/chatter-queue-subscriber-database.service.d.ts +19 -0
- package/dist/jobs/database/chatter-queue-subscriber-database.service.d.ts.map +1 -0
- package/dist/jobs/database/chatter-queue-subscriber-database.service.js +62 -0
- package/dist/jobs/database/chatter-queue-subscriber-database.service.js.map +1 -0
- package/dist/services/chatter-message.service.d.ts +4 -4
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +33 -9
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/queues/rabbitmq-publisher.service.d.ts +1 -0
- package/dist/services/queues/rabbitmq-publisher.service.d.ts.map +1 -1
- package/dist/services/queues/rabbitmq-publisher.service.js +6 -1
- package/dist/services/queues/rabbitmq-publisher.service.js.map +1 -1
- package/dist/services/queues/rabbitmq-subscriber.service.d.ts +1 -0
- package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
- package/dist/services/queues/rabbitmq-subscriber.service.js +15 -4
- package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
- package/dist/services/request-context.service.d.ts +2 -1
- package/dist/services/request-context.service.d.ts.map +1 -1
- package/dist/services/request-context.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +8 -0
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/audit.subscriber.d.ts +8 -3
- package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
- package/dist/subscribers/audit.subscriber.js +54 -52
- package/dist/subscribers/audit.subscriber.js.map +1 -1
- package/dist/subscribers/created-by-updated-by.subscriber.d.ts +0 -1
- package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
- package/dist/subscribers/created-by-updated-by.subscriber.js +3 -13
- package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
- package/package.json +1 -1
- package/src/entities/mq-message-queue.entity.ts +8 -8
- package/src/helpers/bootstrap.helper.ts +1 -1
- package/src/helpers/cors.helper.ts +5 -1
- package/src/interfaces.ts +1 -0
- package/src/jobs/chatter-queue-options.ts +1 -1
- package/src/jobs/chatter-queue-publisher.service.ts +11 -11
- package/src/jobs/chatter-queue-subscriber.service.ts +13 -8
- package/src/jobs/computed-field-evaluation-queue-options.ts +1 -0
- package/src/jobs/database/chatter-queue-options-database.ts +9 -0
- package/src/jobs/database/chatter-queue-publisher-database.service.ts +24 -0
- package/src/jobs/database/chatter-queue-subscriber-database.service.ts +53 -0
- package/src/services/chatter-message.service.ts +41 -9
- package/src/services/queues/rabbitmq-publisher.service.ts +8 -2
- package/src/services/queues/rabbitmq-subscriber.service.ts +16 -5
- package/src/services/request-context.service.ts +2 -1
- package/src/solid-core.module.ts +8 -2
- package/src/subscribers/audit.subscriber.ts +59 -224
- package/src/subscribers/created-by-updated-by.subscriber.ts +22 -16
- package/logs_load_testing +0 -49
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { CommonEntity } from "src/entities/common.entity"
|
|
2
|
-
import {Entity, Column, OneToMany} from "typeorm";
|
|
2
|
+
import { Entity, Column, OneToMany } from "typeorm";
|
|
3
3
|
import { MqMessage } from 'src/entities/mq-message.entity'
|
|
4
4
|
@Entity("ss_mq_message_queue")
|
|
5
|
-
export class MqMessageQueue extends CommonEntity{
|
|
6
|
-
@Column({ type: "varchar", unique: true })
|
|
7
|
-
name: string;
|
|
5
|
+
export class MqMessageQueue extends CommonEntity {
|
|
6
|
+
@Column({ type: "varchar", unique: true })
|
|
7
|
+
name: string;
|
|
8
8
|
|
|
9
|
-
@Column({ type: "varchar", nullable: true })
|
|
10
|
-
description: string;
|
|
9
|
+
@Column({ type: "varchar", nullable: true })
|
|
10
|
+
description: string;
|
|
11
11
|
|
|
12
|
-
@OneToMany(() => MqMessage, mqMessage => mqMessage.mqMessageQueue, { cascade: true })
|
|
13
|
-
mqMessages: MqMessage[];
|
|
12
|
+
@OneToMany(() => MqMessage, mqMessage => mqMessage.mqMessageQueue, { cascade: true })
|
|
13
|
+
mqMessages: MqMessage[];
|
|
14
14
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { log } from 'console';
|
|
1
2
|
import { CorsOptions } from 'cors';
|
|
2
3
|
|
|
3
4
|
/** Build CorsOptions from env; supports wildcards like https://*.example.com */
|
|
4
5
|
export function buildDefaultCorsOptions(): CorsOptions {
|
|
5
6
|
const rawOrigins = process.env.SECURITY_CORS_ORIGINS ?? '*';
|
|
7
|
+
log(`CORS allowed origins: ${rawOrigins}`);
|
|
6
8
|
|
|
7
9
|
const allowed = rawOrigins.split(',').map(s => s.trim()).filter(Boolean);
|
|
8
10
|
|
|
@@ -18,6 +20,8 @@ export function buildDefaultCorsOptions(): CorsOptions {
|
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
const matchers = allowed.map(patternToRegex);
|
|
23
|
+
log(`CORS regexes: ${matchers.map(r => r.toString()).join(', ')}`);
|
|
24
|
+
|
|
21
25
|
const isAllowed = (origin: string) =>
|
|
22
26
|
matchers.length > 0 && matchers.some(rx => rx.test(origin));
|
|
23
27
|
|
|
@@ -25,7 +29,7 @@ export function buildDefaultCorsOptions(): CorsOptions {
|
|
|
25
29
|
origin: (origin, cb) => {
|
|
26
30
|
if (!origin) return cb(null, true); // allow no-origin (CLI/mobile/internal)
|
|
27
31
|
if (isAllowed(origin)) return cb(null, true);
|
|
28
|
-
return cb(new Error(`Origin ${origin} not allowed by CORS`), false);
|
|
32
|
+
return cb(new Error(`Origin ${origin} not allowed by CORS. Allowed origins: ${allowed.join(', ')}`), false);
|
|
29
33
|
},
|
|
30
34
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
|
31
35
|
allowedHeaders: ['Content-Type', 'Authorization'],
|
package/src/interfaces.ts
CHANGED
|
@@ -7,21 +7,21 @@ import { MqMessageService } from '../services/mq-message.service';
|
|
|
7
7
|
import { QueuesModuleOptions } from "../interfaces";
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
export type
|
|
10
|
+
export type AuditEventType = 'insert' | 'update' | 'delete';
|
|
11
11
|
|
|
12
|
-
export interface
|
|
13
|
-
eventType:
|
|
14
|
-
|
|
15
|
-
entityId: string
|
|
16
|
-
occurredAt: string;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
userId?:
|
|
12
|
+
export interface AuditQueuePayload {
|
|
13
|
+
eventType: AuditEventType;
|
|
14
|
+
modelName: string; // TypeORM entity class name (e.g. 'Order')
|
|
15
|
+
entityId: string | number | null;
|
|
16
|
+
occurredAt: string; // ISO timestamp, captured at event time
|
|
17
|
+
after?: any; // entity state after operation (insert/update)
|
|
18
|
+
before?: any; // entity state before operation (update/delete)
|
|
19
|
+
updatedColumnNames?: string[]; // propertyNames of changed columns (update only)
|
|
20
|
+
userId?: number | null; // active user captured at event time
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
@Injectable()
|
|
24
|
-
export class
|
|
24
|
+
export class ChatterQueuePublisherRabbitmq extends RabbitMqPublisher<AuditQueuePayload> {
|
|
25
25
|
constructor(
|
|
26
26
|
protected readonly mqMessageService: MqMessageService,
|
|
27
27
|
protected readonly mqMessageQueueService: MqMessageQueueService,
|
|
@@ -6,12 +6,12 @@ import { MqMessageService } from '../services/mq-message.service';
|
|
|
6
6
|
import { MqMessageQueueService } from '../services/mq-message-queue.service';
|
|
7
7
|
import { QueuesModuleOptions } from "../interfaces";
|
|
8
8
|
import chatterQueueOptions from './chatter-queue-options';
|
|
9
|
-
import {
|
|
9
|
+
import { AuditQueuePayload } from './chatter-queue-publisher.service';
|
|
10
10
|
import { ChatterMessageService } from 'src/services/chatter-message.service';
|
|
11
11
|
|
|
12
12
|
@Injectable()
|
|
13
|
-
export class
|
|
14
|
-
private readonly
|
|
13
|
+
export class ChatterQueueSubscriberRabbitmq extends RabbitMqSubscriber<AuditQueuePayload> {
|
|
14
|
+
private readonly chatterLogger = new Logger(ChatterQueueSubscriberRabbitmq.name);
|
|
15
15
|
|
|
16
16
|
constructor(
|
|
17
17
|
readonly mqMessageService: MqMessageService,
|
|
@@ -27,19 +27,24 @@ export class ChatterQueueSubscriber extends RabbitMqSubscriber<any> {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async subscribe(message: QueueMessage<
|
|
30
|
+
async subscribe(message: QueueMessage<AuditQueuePayload>) {
|
|
31
31
|
const p = message.payload;
|
|
32
|
-
this.
|
|
32
|
+
this.chatterLogger.debug(`Audit event ${p.eventType} ${p.modelName}#${p.entityId}`);
|
|
33
33
|
|
|
34
34
|
switch (p.eventType) {
|
|
35
35
|
case 'insert':
|
|
36
|
-
await this.chatterMessageService.postAuditMessageOnInsert(p.after,
|
|
36
|
+
await this.chatterMessageService.postAuditMessageOnInsert(p.after, p.modelName);
|
|
37
37
|
break;
|
|
38
38
|
case 'update':
|
|
39
|
-
await this.chatterMessageService.postAuditMessageOnUpdate(
|
|
39
|
+
await this.chatterMessageService.postAuditMessageOnUpdate(
|
|
40
|
+
p.after,
|
|
41
|
+
p.modelName,
|
|
42
|
+
p.before,
|
|
43
|
+
(p.updatedColumnNames ?? []).map(n => ({ propertyName: n })),
|
|
44
|
+
);
|
|
40
45
|
break;
|
|
41
46
|
case 'delete':
|
|
42
|
-
await this.chatterMessageService.postAuditMessageOnDelete(p.
|
|
47
|
+
await this.chatterMessageService.postAuditMessageOnDelete(p.modelName, p.before);
|
|
43
48
|
break;
|
|
44
49
|
}
|
|
45
50
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { DatabasePublisher } from 'src/services/queues/database-publisher.service';
|
|
4
|
+
import { MqMessageQueueService } from '../../services/mq-message-queue.service';
|
|
5
|
+
import { MqMessageService } from '../../services/mq-message.service';
|
|
6
|
+
import { QueuesModuleOptions } from "../../interfaces";
|
|
7
|
+
import { AuditQueuePayload } from '../chatter-queue-publisher.service';
|
|
8
|
+
import chatterQueueOptionsDatabase from './chatter-queue-options-database';
|
|
9
|
+
|
|
10
|
+
@Injectable()
|
|
11
|
+
export class ChatterQueuePublisherDatabase extends DatabasePublisher<AuditQueuePayload> {
|
|
12
|
+
constructor(
|
|
13
|
+
protected readonly mqMessageService: MqMessageService,
|
|
14
|
+
protected readonly mqMessageQueueService: MqMessageQueueService,
|
|
15
|
+
) {
|
|
16
|
+
super(mqMessageService, mqMessageQueueService);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
options(): QueuesModuleOptions {
|
|
20
|
+
return {
|
|
21
|
+
...chatterQueueOptionsDatabase
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { DatabaseSubscriber } from 'src/services/queues/database-subscriber.service';
|
|
4
|
+
import { QueueMessage } from 'src/interfaces/mq';
|
|
5
|
+
import { MqMessageService } from '../../services/mq-message.service';
|
|
6
|
+
import { MqMessageQueueService } from '../../services/mq-message-queue.service';
|
|
7
|
+
import { QueuesModuleOptions } from "../../interfaces";
|
|
8
|
+
import { PollerService } from 'src/services/poller.service';
|
|
9
|
+
import { AuditQueuePayload } from '../chatter-queue-publisher.service';
|
|
10
|
+
import { ChatterMessageService } from 'src/services/chatter-message.service';
|
|
11
|
+
import chatterQueueOptionsDatabase from './chatter-queue-options-database';
|
|
12
|
+
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class ChatterQueueSubscriberDatabase extends DatabaseSubscriber<AuditQueuePayload> {
|
|
15
|
+
private readonly chatterLogger = new Logger(ChatterQueueSubscriberDatabase.name);
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
readonly mqMessageService: MqMessageService,
|
|
19
|
+
readonly mqMessageQueueService: MqMessageQueueService,
|
|
20
|
+
readonly poller: PollerService,
|
|
21
|
+
private readonly chatterMessageService: ChatterMessageService,
|
|
22
|
+
) {
|
|
23
|
+
super(mqMessageService, mqMessageQueueService, poller);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
options(): QueuesModuleOptions {
|
|
27
|
+
return {
|
|
28
|
+
...chatterQueueOptionsDatabase
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async subscribe(message: QueueMessage<AuditQueuePayload>) {
|
|
33
|
+
const p = message.payload;
|
|
34
|
+
this.chatterLogger.debug(`Audit event ${p.eventType} ${p.modelName}#${p.entityId}`);
|
|
35
|
+
|
|
36
|
+
switch (p.eventType) {
|
|
37
|
+
case 'insert':
|
|
38
|
+
await this.chatterMessageService.postAuditMessageOnInsert(p.after, p.modelName);
|
|
39
|
+
break;
|
|
40
|
+
case 'update':
|
|
41
|
+
await this.chatterMessageService.postAuditMessageOnUpdate(
|
|
42
|
+
p.after,
|
|
43
|
+
p.modelName,
|
|
44
|
+
p.before,
|
|
45
|
+
(p.updatedColumnNames ?? []).map(n => ({ propertyName: n })),
|
|
46
|
+
);
|
|
47
|
+
break;
|
|
48
|
+
case 'delete':
|
|
49
|
+
await this.chatterMessageService.postAuditMessageOnDelete(p.modelName, p.before);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -90,13 +90,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
90
90
|
return savedMessage;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
async postAuditMessageOnInsert(entity: any,
|
|
93
|
+
async postAuditMessageOnInsert(entity: any, modelName: string, messageQueue: boolean = false) {
|
|
94
94
|
if (!entity) {
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
const model = await this.modelMetadataRepo.findOne({
|
|
98
98
|
where: {
|
|
99
|
-
singularName: lowerFirst(
|
|
99
|
+
singularName: lowerFirst(modelName)
|
|
100
100
|
},
|
|
101
101
|
relations: {
|
|
102
102
|
fields: true,
|
|
@@ -152,13 +152,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
async postAuditMessageOnUpdate(entity: any,
|
|
155
|
+
async postAuditMessageOnUpdate(entity: any, modelName: string, databaseEntity: any, updatedColumns: any[] = [], messageQueue: boolean = false) {
|
|
156
156
|
if (!databaseEntity || !entity) {
|
|
157
157
|
return;
|
|
158
158
|
}
|
|
159
159
|
const model = await this.modelMetadataRepo.findOne({
|
|
160
160
|
where: {
|
|
161
|
-
singularName: lowerFirst(
|
|
161
|
+
singularName: lowerFirst(modelName)
|
|
162
162
|
},
|
|
163
163
|
relations: {
|
|
164
164
|
fields: true,
|
|
@@ -204,6 +204,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
204
204
|
|
|
205
205
|
const changedRelationFields = [];
|
|
206
206
|
if (potentialRelationFields.length > 0) {
|
|
207
|
+
const metadata = this.entityManager.connection.entityMetadatas.find(m => m.name === modelName);
|
|
207
208
|
const populatedOldEntity = await this.populateRelationFields(databaseEntity, potentialRelationFields, metadata);
|
|
208
209
|
|
|
209
210
|
for (const field of potentialRelationFields) {
|
|
@@ -268,13 +269,12 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
async postAuditMessageOnDelete(
|
|
272
|
+
async postAuditMessageOnDelete(modelName: string, databaseEntity: any, messageQueue: boolean = false) {
|
|
272
273
|
const model = await this.modelMetadataRepo.findOne({
|
|
273
274
|
where: {
|
|
274
|
-
singularName: lowerFirst(
|
|
275
|
+
singularName: lowerFirst(modelName)
|
|
275
276
|
},
|
|
276
277
|
relations: {
|
|
277
|
-
fields: true,
|
|
278
278
|
module: true,
|
|
279
279
|
userKeyField: true
|
|
280
280
|
}
|
|
@@ -284,13 +284,29 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
284
284
|
return;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName);
|
|
288
|
+
|
|
289
|
+
const auditFields = modelFields.filter(field =>
|
|
290
|
+
field.enableAuditTracking &&
|
|
291
|
+
!['mediaSingle', 'mediaMultiple', 'richText', 'json'].includes(field.type) &&
|
|
292
|
+
!(field.type === 'relation' && field.relationType === 'one-to-many')
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
// Populate relation fields so display values (e.g. names) are resolvable.
|
|
296
|
+
// The related entities themselves still exist in the DB after a delete.
|
|
297
|
+
const relationFields = auditFields.filter(field => field.type === 'relation');
|
|
298
|
+
const entityMetadata = this.entityManager.connection.entityMetadatas.find(m => m.name === modelName);
|
|
299
|
+
const populatedEntity = relationFields.length > 0 && entityMetadata
|
|
300
|
+
? await this.populateRelationFields(databaseEntity, relationFields, entityMetadata)
|
|
301
|
+
: { ...databaseEntity };
|
|
302
|
+
|
|
287
303
|
const chatterMessage = new ChatterMessage();
|
|
288
304
|
chatterMessage.messageType = CHATTER_MESSAGE_TYPE.AUDIT;
|
|
289
305
|
chatterMessage.messageSubType = CHATTER_MESSAGE_SUBTYPE.AUDIT_DELETE;
|
|
290
306
|
chatterMessage.coModelEntityId = databaseEntity?.id;
|
|
291
307
|
chatterMessage.coModelName = model?.singularName;
|
|
292
308
|
chatterMessage.modelDisplayName = model?.displayName;
|
|
293
|
-
chatterMessage.modelUserKey =
|
|
309
|
+
chatterMessage.modelUserKey = databaseEntity[model?.userKeyField?.name];
|
|
294
310
|
chatterMessage.messageBody = `${model?.displayName} deleted`;
|
|
295
311
|
|
|
296
312
|
const activeUser = this.requestContextService.getActiveUser();
|
|
@@ -302,7 +318,23 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
302
318
|
chatterMessage.user = null;
|
|
303
319
|
}
|
|
304
320
|
|
|
305
|
-
await this.repo.save(chatterMessage);
|
|
321
|
+
const savedMessage = await this.repo.save(chatterMessage);
|
|
322
|
+
|
|
323
|
+
for (const field of auditFields) {
|
|
324
|
+
const fieldValue = populatedEntity[field.name];
|
|
325
|
+
if (fieldValue !== undefined && fieldValue !== null && fieldValue !== '') {
|
|
326
|
+
const messageDetail = new ChatterMessageDetails();
|
|
327
|
+
messageDetail.chatterMessage = savedMessage;
|
|
328
|
+
messageDetail.fieldName = field.name;
|
|
329
|
+
messageDetail.fieldDisplayName = field.displayName;
|
|
330
|
+
messageDetail.fieldType = field.type;
|
|
331
|
+
messageDetail.oldValue = this.formatFieldValue(field, fieldValue);
|
|
332
|
+
messageDetail.oldValueDisplay = await this.formatFieldValueDisplay(field, fieldValue);
|
|
333
|
+
messageDetail.newValue = null;
|
|
334
|
+
messageDetail.newValueDisplay = null;
|
|
335
|
+
await this.chatterMessageDetailsRepo.save(messageDetail);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
306
338
|
}
|
|
307
339
|
|
|
308
340
|
private formatFieldValue(field: any, value: any): string {
|
|
@@ -34,6 +34,10 @@ export abstract class RabbitMqPublisher<T> implements OnModuleDestroy, QueuePubl
|
|
|
34
34
|
|
|
35
35
|
abstract options(): QueuesModuleOptions;
|
|
36
36
|
|
|
37
|
+
protected shouldPersistToDatabase(): boolean {
|
|
38
|
+
return this.options().persistToDatabase ?? true;
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
private async ensureConnectionAndChannel(): Promise<amqp.Channel> {
|
|
38
42
|
if (this.channel) {
|
|
39
43
|
return this.channel;
|
|
@@ -170,7 +174,9 @@ export abstract class RabbitMqPublisher<T> implements OnModuleDestroy, QueuePubl
|
|
|
170
174
|
message.messageId = uuidv4();
|
|
171
175
|
|
|
172
176
|
// Save the message to the DB so that we can then change its status in the subscriber...
|
|
173
|
-
|
|
177
|
+
if (this.shouldPersistToDatabase()) {
|
|
178
|
+
await this.persistToDatabase(namespacedQueueName, message);
|
|
179
|
+
}
|
|
174
180
|
|
|
175
181
|
// wait for the channel to confirm
|
|
176
182
|
try {
|
|
@@ -199,7 +205,7 @@ export abstract class RabbitMqPublisher<T> implements OnModuleDestroy, QueuePubl
|
|
|
199
205
|
|
|
200
206
|
private async persistToDatabase(queueName: string, message: QueueMessage<T>) {
|
|
201
207
|
|
|
202
|
-
//
|
|
208
|
+
// make an entry in the relevant database table, generate a unique id earlier.
|
|
203
209
|
try {
|
|
204
210
|
// 1. resolve the queue first
|
|
205
211
|
const mqMessageQueue = await this.mqMessageQueueService.resolveQueue(queueName);
|
|
@@ -56,6 +56,10 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
56
56
|
|
|
57
57
|
abstract options(): QueuesModuleOptions;
|
|
58
58
|
|
|
59
|
+
protected shouldPersistToDatabase(): boolean {
|
|
60
|
+
return this.options().persistToDatabase ?? true;
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
async establishConnection(): Promise<amqp.Connection> {
|
|
60
64
|
|
|
61
65
|
const url = new URL(this.url);
|
|
@@ -236,7 +240,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
236
240
|
this.logger.error(`Error processing message on queue ${queueName}: ${errorMessage}`, (error as Error)?.stack);
|
|
237
241
|
|
|
238
242
|
if (message.currentRetry < message.retryCount) {
|
|
239
|
-
|
|
243
|
+
if (this.shouldPersistToDatabase()) {
|
|
244
|
+
await this.updateStatusInDatabase('retrying', message);
|
|
245
|
+
}
|
|
240
246
|
|
|
241
247
|
message.currentRetry++;
|
|
242
248
|
const retryQueue = `${queueName}.retry`;
|
|
@@ -254,8 +260,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
254
260
|
this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms on queue ${queueName}`);
|
|
255
261
|
return;
|
|
256
262
|
}
|
|
257
|
-
|
|
258
|
-
|
|
263
|
+
if (this.shouldPersistToDatabase()) {
|
|
264
|
+
await this.updateStatusInDatabase('failed', message, errorMessage, '');
|
|
265
|
+
}
|
|
259
266
|
channel.ack(rawMessage);
|
|
260
267
|
await this.publishToFailedQueue(queueName, Buffer.from(JSON.stringify(message)), channel, error);
|
|
261
268
|
this.logger.error(`Message failed after ${message.retryCount} attempts on queue ${queueName}: ${errorMessage}`);
|
|
@@ -355,7 +362,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
355
362
|
* Abstract method for message processing logic.
|
|
356
363
|
*/
|
|
357
364
|
protected async processMessage(message: QueueMessage<T>, rawMessage, channel, queueName: string): Promise<void> {
|
|
358
|
-
|
|
365
|
+
if (this.shouldPersistToDatabase()) {
|
|
366
|
+
await this.updateStatusInDatabase('started', message);
|
|
367
|
+
}
|
|
359
368
|
|
|
360
369
|
// Capture the results of handling the task.
|
|
361
370
|
const result = await this.subscribeWithTimeout(message, queueName);
|
|
@@ -364,7 +373,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
364
373
|
channel.ack(rawMessage);
|
|
365
374
|
|
|
366
375
|
// Persist success output and timing.
|
|
367
|
-
|
|
376
|
+
if (this.shouldPersistToDatabase()) {
|
|
377
|
+
await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');
|
|
378
|
+
}
|
|
368
379
|
|
|
369
380
|
}
|
|
370
381
|
|
|
@@ -2,6 +2,7 @@ import { Injectable } from "@nestjs/common";
|
|
|
2
2
|
import { ClsService } from "nestjs-cls";
|
|
3
3
|
import { REQUEST_USER_KEY } from "src/constants";
|
|
4
4
|
import { BasicFilterDto } from "src/dtos/basic-filters.dto";
|
|
5
|
+
import { ActiveUserData } from "src/interfaces/active-user-data.interface";
|
|
5
6
|
|
|
6
7
|
@Injectable()
|
|
7
8
|
export class RequestContextService {
|
|
@@ -9,7 +10,7 @@ export class RequestContextService {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
// This method i.e getActiveUser() will fetch the user from the request object in the context
|
|
12
|
-
getActiveUser() {
|
|
13
|
+
getActiveUser(): ActiveUserData | undefined {
|
|
13
14
|
return this.cls.get(REQUEST_USER_KEY);
|
|
14
15
|
}
|
|
15
16
|
|
package/src/solid-core.module.ts
CHANGED
|
@@ -94,6 +94,10 @@ import { Msg91SmsQueuePublisher } from './jobs/msg91-sms-publisher.service';
|
|
|
94
94
|
import { Msg91SmsQueueSubscriber } from './jobs/msg91-sms-subscriber.service';
|
|
95
95
|
import { SmtpEmailQueuePublisherRabbitmq } from './jobs/smtp-email-publisher.service';
|
|
96
96
|
import { SmtpEmailQueueSubscriberRabbitmq } from './jobs/smtp-email-subscriber.service';
|
|
97
|
+
import { ChatterQueuePublisherRabbitmq } from './jobs/chatter-queue-publisher.service';
|
|
98
|
+
import { ChatterQueueSubscriberRabbitmq } from './jobs/chatter-queue-subscriber.service';
|
|
99
|
+
import { ChatterQueuePublisherDatabase } from './jobs/database/chatter-queue-publisher-database.service';
|
|
100
|
+
import { ChatterQueueSubscriberDatabase } from './jobs/database/chatter-queue-subscriber-database.service';
|
|
97
101
|
import { TestQueuePublisher } from './jobs/test-queue-publisher.service';
|
|
98
102
|
import { TestQueueSubscriber } from './jobs/test-queue-subscriber.service';
|
|
99
103
|
import { UserRegistrationListener } from './listeners/user-registration.listener';
|
|
@@ -595,8 +599,10 @@ import { Entity } from 'typeorm';
|
|
|
595
599
|
TestQueuePublisher,
|
|
596
600
|
TestQueueSubscriber,
|
|
597
601
|
|
|
598
|
-
|
|
599
|
-
|
|
602
|
+
ChatterQueuePublisherRabbitmq,
|
|
603
|
+
ChatterQueueSubscriberRabbitmq,
|
|
604
|
+
ChatterQueuePublisherDatabase,
|
|
605
|
+
ChatterQueueSubscriberDatabase,
|
|
600
606
|
|
|
601
607
|
TestQueuePublisherDatabase,
|
|
602
608
|
TestQueueSubscriberDatabase,
|