@solidstarters/solid-core 1.2.57 → 1.2.58
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/controllers/chatter-message-details.controller.d.ts +41 -0
- package/dist/controllers/chatter-message-details.controller.d.ts.map +1 -0
- package/dist/controllers/chatter-message-details.controller.js +179 -0
- package/dist/controllers/chatter-message-details.controller.js.map +1 -0
- package/dist/controllers/chatter-message.controller.d.ts +44 -0
- package/dist/controllers/chatter-message.controller.d.ts.map +1 -0
- package/dist/controllers/chatter-message.controller.js +199 -0
- package/dist/controllers/chatter-message.controller.js.map +1 -0
- package/dist/dtos/create-chatter-message-details.dto.d.ts +10 -0
- package/dist/dtos/create-chatter-message-details.dto.d.ts.map +1 -0
- package/dist/dtos/create-chatter-message-details.dto.js +66 -0
- package/dist/dtos/create-chatter-message-details.dto.js.map +1 -0
- package/dist/dtos/create-chatter-message.dto.d.ts +10 -0
- package/dist/dtos/create-chatter-message.dto.d.ts.map +1 -0
- package/dist/dtos/create-chatter-message.dto.js +65 -0
- package/dist/dtos/create-chatter-message.dto.js.map +1 -0
- package/dist/dtos/create-field-metadata.dto.d.ts +1 -0
- package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-field-metadata.dto.js +6 -1
- package/dist/dtos/create-field-metadata.dto.js.map +1 -1
- package/dist/dtos/post-chatter-message.dto.d.ts +7 -0
- package/dist/dtos/post-chatter-message.dto.d.ts.map +1 -0
- package/dist/dtos/post-chatter-message.dto.js +41 -0
- package/dist/dtos/post-chatter-message.dto.js.map +1 -0
- package/dist/dtos/update-chatter-message-details.dto.d.ts +11 -0
- package/dist/dtos/update-chatter-message-details.dto.d.ts.map +1 -0
- package/dist/dtos/update-chatter-message-details.dto.js +70 -0
- package/dist/dtos/update-chatter-message-details.dto.js.map +1 -0
- package/dist/dtos/update-chatter-message.dto.d.ts +11 -0
- package/dist/dtos/update-chatter-message.dto.d.ts.map +1 -0
- package/dist/dtos/update-chatter-message.dto.js +74 -0
- package/dist/dtos/update-chatter-message.dto.js.map +1 -0
- package/dist/entities/chatter-message-details.entity.d.ts +11 -0
- package/dist/entities/chatter-message-details.entity.d.ts.map +1 -0
- package/dist/entities/chatter-message-details.entity.js +52 -0
- package/dist/entities/chatter-message-details.entity.js.map +1 -0
- package/dist/entities/chatter-message.entity.d.ts +11 -0
- package/dist/entities/chatter-message.entity.d.ts.map +1 -0
- package/dist/entities/chatter-message.entity.js +53 -0
- package/dist/entities/chatter-message.entity.js.map +1 -0
- package/dist/entities/field-metadata.entity.d.ts +1 -0
- package/dist/entities/field-metadata.entity.d.ts.map +1 -1
- package/dist/entities/field-metadata.entity.js +5 -1
- package/dist/entities/field-metadata.entity.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +517 -1
- package/dist/services/chatter-message-details.service.d.ts +24 -0
- package/dist/services/chatter-message-details.service.d.ts.map +1 -0
- package/dist/services/chatter-message-details.service.js +59 -0
- package/dist/services/chatter-message-details.service.js.map +1 -0
- package/dist/services/chatter-message.service.d.ts +37 -0
- package/dist/services/chatter-message.service.d.ts.map +1 -0
- package/dist/services/chatter-message.service.js +279 -0
- package/dist/services/chatter-message.service.js.map +1 -0
- package/dist/services/crud.service.d.ts +3 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +43 -3
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/user-context.service.d.ts +10 -0
- package/dist/services/user-context.service.d.ts.map +1 -0
- package/dist/services/user-context.service.js +42 -0
- package/dist/services/user-context.service.js.map +1 -0
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +18 -2
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/audit.subscriber.d.ts +17 -0
- package/dist/subscribers/audit.subscriber.d.ts.map +1 -0
- package/dist/subscribers/audit.subscriber.js +83 -0
- package/dist/subscribers/audit.subscriber.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/controllers/chatter-message-details.controller.ts +92 -0
- package/src/controllers/chatter-message.controller.ts +105 -0
- package/src/dtos/create-chatter-message-details.dto.ts +40 -0
- package/src/dtos/create-chatter-message.dto.ts +34 -0
- package/src/dtos/create-field-metadata.dto.ts +4 -0
- package/src/dtos/post-chatter-message.dto.ts +19 -0
- package/src/dtos/update-chatter-message-details.dto.ts +43 -0
- package/src/dtos/update-chatter-message.dto.ts +41 -0
- package/src/entities/chatter-message-details.entity.ts +25 -0
- package/src/entities/chatter-message.entity.ts +22 -0
- package/src/entities/field-metadata.entity.ts +3 -0
- package/src/index.ts +10 -2
- package/src/seeders/seed-data/solid-core-metadata.json +518 -2
- package/src/services/chatter-message-details.service.ts +34 -0
- package/src/services/chatter-message.service.ts +301 -0
- package/src/services/crud.service.ts +10 -2
- package/src/services/user-context.service.ts +31 -0
- package/src/solid-core.module.ts +18 -3
- package/src/subscribers/audit.subscriber.ts +73 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
|
|
3
|
+
import { DiscoveryService, ModuleRef } from "@nestjs/core";
|
|
4
|
+
import { EntityManager, Repository, EntityMetadata } from 'typeorm';
|
|
5
|
+
|
|
6
|
+
import { CRUDService } from 'src/services/crud.service';
|
|
7
|
+
import { ModelMetadataService } from 'src/services/model-metadata.service';
|
|
8
|
+
import { ModuleMetadataService } from 'src/services/module-metadata.service';
|
|
9
|
+
import { ConfigService } from '@nestjs/config';
|
|
10
|
+
import { FileService } from 'src/services/file.service';
|
|
11
|
+
import { CrudHelperService } from 'src/services/crud-helper.service';
|
|
12
|
+
import { PostChatterMessageDto } from 'src/dtos/post-chatter-message.dto';
|
|
13
|
+
import { SolidRequestContextDto } from 'src/dtos/solid-request-context.dto';
|
|
14
|
+
import { ChatterMessage } from '../entities/chatter-message.entity';
|
|
15
|
+
import { getMediaStorageProvider } from './mediaStorageProviders';
|
|
16
|
+
import { MediaStorageProviderType } from '../dtos/create-media-storage-provider-metadata.dto';
|
|
17
|
+
import { ChatterMessageDetails } from '../entities/chatter-message-details.entity';
|
|
18
|
+
import { ModelMetadata } from 'src/entities/model-metadata.entity';
|
|
19
|
+
import { UserContextService } from './user-context.service';
|
|
20
|
+
@Injectable()
|
|
21
|
+
export class ChatterMessageService extends CRUDService<ChatterMessage>{
|
|
22
|
+
constructor(
|
|
23
|
+
readonly modelMetadataService: ModelMetadataService,
|
|
24
|
+
readonly moduleMetadataService: ModuleMetadataService,
|
|
25
|
+
readonly configService: ConfigService,
|
|
26
|
+
readonly fileService: FileService,
|
|
27
|
+
readonly discoveryService: DiscoveryService,
|
|
28
|
+
readonly crudHelperService: CrudHelperService,
|
|
29
|
+
@InjectEntityManager()
|
|
30
|
+
readonly entityManager: EntityManager,
|
|
31
|
+
@InjectRepository(ChatterMessage, 'default')
|
|
32
|
+
readonly repo: Repository<ChatterMessage>,
|
|
33
|
+
@InjectRepository(ChatterMessageDetails, 'default')
|
|
34
|
+
readonly chatterMessageDetailsRepo: Repository<ChatterMessageDetails>,
|
|
35
|
+
readonly moduleRef: ModuleRef,
|
|
36
|
+
@InjectRepository(ModelMetadata)
|
|
37
|
+
private readonly modelMetadataRepo: Repository<ModelMetadata>,
|
|
38
|
+
readonly userContextService: UserContextService
|
|
39
|
+
) {
|
|
40
|
+
super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService,entityManager, repo, 'chatterMessage', 'solid-core', moduleRef, userContextService);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async postMessage(postDto: PostChatterMessageDto, solidRequestContext: SolidRequestContextDto, files: Express.Multer.File[] = []) {
|
|
44
|
+
const chatterMessage = new ChatterMessage();
|
|
45
|
+
chatterMessage.messageType = 'custom';
|
|
46
|
+
chatterMessage.messageSubType = postDto.messageSubType || 'general';
|
|
47
|
+
chatterMessage.messageBody = postDto.messageBody;
|
|
48
|
+
chatterMessage.coModelEntityId = postDto.coModelEntityId;
|
|
49
|
+
chatterMessage.coModelName = postDto.coModelName;
|
|
50
|
+
|
|
51
|
+
const userId = typeof solidRequestContext.activeUser === 'object'
|
|
52
|
+
? solidRequestContext.activeUser.sub
|
|
53
|
+
: solidRequestContext.activeUser;
|
|
54
|
+
|
|
55
|
+
chatterMessage.user = { id: userId } as any;
|
|
56
|
+
|
|
57
|
+
const savedMessage = await this.repo.save(chatterMessage);
|
|
58
|
+
|
|
59
|
+
if (files && files.length > 0) {
|
|
60
|
+
const model = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
|
|
61
|
+
fields: {
|
|
62
|
+
model: true,
|
|
63
|
+
mediaStorageProvider: true,
|
|
64
|
+
},
|
|
65
|
+
module: true,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const mediaFields = model.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
|
|
69
|
+
|
|
70
|
+
for (const mediaField of mediaFields) {
|
|
71
|
+
const media = files.filter(multerFile => multerFile.fieldname === mediaField.name);
|
|
72
|
+
if (media.length > 0) {
|
|
73
|
+
const storageProviderMetadata = mediaField.mediaStorageProvider;
|
|
74
|
+
const storageProviderType = storageProviderMetadata.type as MediaStorageProviderType;
|
|
75
|
+
const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);
|
|
76
|
+
await storageProvider.store(media, savedMessage, mediaField);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return savedMessage;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async postAuditMessageOnInsert(entity: any, metadata: EntityMetadata, activeUser: any, messageQueue: boolean = false) {
|
|
85
|
+
const model = await this.modelMetadataRepo.findOne({
|
|
86
|
+
where: {
|
|
87
|
+
displayName: metadata.name
|
|
88
|
+
},
|
|
89
|
+
relations: {
|
|
90
|
+
fields: true,
|
|
91
|
+
module: true
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (!model || !model.enableAuditTracking) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const auditFields = model.fields.filter(field =>
|
|
100
|
+
field.enableAuditTracking &&
|
|
101
|
+
!['oneToMany', 'mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const chatterMessage = new ChatterMessage();
|
|
105
|
+
chatterMessage.messageType = 'audit';
|
|
106
|
+
chatterMessage.messageSubType = 'insert';
|
|
107
|
+
chatterMessage.coModelEntityId = entity.id;
|
|
108
|
+
chatterMessage.coModelName = model.singularName;
|
|
109
|
+
chatterMessage.messageBody = `New ${model.displayName} created`;
|
|
110
|
+
|
|
111
|
+
if (activeUser) {
|
|
112
|
+
const userId = typeof activeUser === 'object' ? activeUser.sub : activeUser;
|
|
113
|
+
chatterMessage.user = { id: userId } as any;
|
|
114
|
+
} else {
|
|
115
|
+
chatterMessage.user = null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const savedMessage = await this.repo.save(chatterMessage);
|
|
119
|
+
|
|
120
|
+
for (const field of auditFields) {
|
|
121
|
+
const fieldValue = entity[field.name];
|
|
122
|
+
if (fieldValue !== undefined && fieldValue !== null) {
|
|
123
|
+
const messageDetail = new ChatterMessageDetails();
|
|
124
|
+
messageDetail.chatterMessage = savedMessage;
|
|
125
|
+
messageDetail.fieldName = field.name;
|
|
126
|
+
messageDetail.oldValue = null;
|
|
127
|
+
messageDetail.oldValueDisplay = null;
|
|
128
|
+
messageDetail.newValue = this.formatFieldValue(field, fieldValue);
|
|
129
|
+
messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, fieldValue);
|
|
130
|
+
await this.chatterMessageDetailsRepo.save(messageDetail);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEntity: any, activeUser: any, messageQueue: boolean = false) {
|
|
136
|
+
const model = await this.modelMetadataRepo.findOne({
|
|
137
|
+
where: {
|
|
138
|
+
displayName: metadata.name
|
|
139
|
+
},
|
|
140
|
+
relations: {
|
|
141
|
+
fields: true,
|
|
142
|
+
module: true
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (!model || !model.enableAuditTracking) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const auditFields = model.fields.filter(field =>
|
|
151
|
+
field.enableAuditTracking &&
|
|
152
|
+
!['oneToMany', 'mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const relationFields = auditFields.filter(field =>
|
|
156
|
+
field.type === 'relation'
|
|
157
|
+
);
|
|
158
|
+
if (relationFields.length > 0) {
|
|
159
|
+
const populatedEntity = await this.entityManager.findOne(metadata.target, {
|
|
160
|
+
where: { id: databaseEntity.id },
|
|
161
|
+
relations: relationFields.map(field => field.name)
|
|
162
|
+
});
|
|
163
|
+
if (populatedEntity) {
|
|
164
|
+
databaseEntity = populatedEntity;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const changedFields = auditFields.filter(field => {
|
|
169
|
+
const newValue = entity[field.name];
|
|
170
|
+
const oldValue = databaseEntity[field.name];
|
|
171
|
+
return this.hasValueChanged(newValue, oldValue);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (changedFields.length === 0) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const chatterMessage = new ChatterMessage();
|
|
179
|
+
chatterMessage.messageType = 'audit';
|
|
180
|
+
chatterMessage.messageSubType = 'update';
|
|
181
|
+
chatterMessage.coModelEntityId = entity.id;
|
|
182
|
+
chatterMessage.coModelName = model.singularName;
|
|
183
|
+
chatterMessage.messageBody = `${model.displayName} updated`;
|
|
184
|
+
|
|
185
|
+
if (activeUser) {
|
|
186
|
+
const userId = typeof activeUser === 'object' ? activeUser.sub : activeUser;
|
|
187
|
+
chatterMessage.user = { id: userId } as any;
|
|
188
|
+
} else {
|
|
189
|
+
chatterMessage.user = null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const savedMessage = await this.repo.save(chatterMessage);
|
|
193
|
+
|
|
194
|
+
for (const field of changedFields) {
|
|
195
|
+
const messageDetail = new ChatterMessageDetails();
|
|
196
|
+
messageDetail.chatterMessage = savedMessage;
|
|
197
|
+
messageDetail.fieldName = field.name;
|
|
198
|
+
messageDetail.oldValue = this.formatFieldValue(field, databaseEntity[field.name]);
|
|
199
|
+
messageDetail.newValue = this.formatFieldValue(field, entity[field.name]);
|
|
200
|
+
messageDetail.oldValueDisplay = this.formatFieldValueDisplay(field, databaseEntity[field.name]);
|
|
201
|
+
messageDetail.newValueDisplay = this.formatFieldValueDisplay(field, entity[field.name]);
|
|
202
|
+
await this.chatterMessageDetailsRepo.save(messageDetail);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async postAuditMessageOnDelete(entity: any, metadata: EntityMetadata, databaseEntity: any, activeUser: any, messageQueue: boolean = false) {
|
|
207
|
+
const model = await this.modelMetadataRepo.findOne({
|
|
208
|
+
where: {
|
|
209
|
+
displayName: metadata.name
|
|
210
|
+
},
|
|
211
|
+
relations: {
|
|
212
|
+
fields: true,
|
|
213
|
+
module: true
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (!model || !model.enableAuditTracking) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const chatterMessage = new ChatterMessage();
|
|
222
|
+
chatterMessage.messageType = 'audit';
|
|
223
|
+
chatterMessage.messageSubType = 'delete';
|
|
224
|
+
chatterMessage.coModelEntityId = databaseEntity.id;
|
|
225
|
+
chatterMessage.coModelName = model.singularName;
|
|
226
|
+
chatterMessage.messageBody = `${model.displayName} deleted`;
|
|
227
|
+
|
|
228
|
+
if (activeUser) {
|
|
229
|
+
const userId = typeof activeUser === 'object' ? activeUser.sub : activeUser;
|
|
230
|
+
chatterMessage.user = { id: userId } as any;
|
|
231
|
+
} else {
|
|
232
|
+
chatterMessage.user = null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
await this.repo.save(chatterMessage);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private formatFieldValue(field: any, value: any): string {
|
|
239
|
+
if (value === null || value === undefined) {
|
|
240
|
+
return '';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (field.type === 'selectionStatic' || field.type === 'selectionDynamic') {
|
|
244
|
+
return `${value}`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (field.type === 'relation') {
|
|
248
|
+
if (field.relationType === "many-to-one") {
|
|
249
|
+
return value.id;
|
|
250
|
+
}
|
|
251
|
+
if (field.relationType === 'manyToMany') {
|
|
252
|
+
return value.map(item => item.id).join(', ');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
return value.toString();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private formatFieldValueDisplay(field: any, value: any): string {
|
|
261
|
+
if (value === null || value === undefined) {
|
|
262
|
+
return '';
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (field.type === 'selectionStatic' || field.type === 'selectionDynamic') {
|
|
266
|
+
return `${value}`;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (field.type === 'relation') {
|
|
270
|
+
if (field.relationType === "many-to-one") {
|
|
271
|
+
return value.name;
|
|
272
|
+
}
|
|
273
|
+
if (field.relationType === 'many-toMany') {
|
|
274
|
+
return value.map(item => item.name).join(', ');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
return value.toString();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private hasValueChanged(newValue: any, oldValue: any): boolean {
|
|
283
|
+
if (newValue === oldValue) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (newValue === null && oldValue === null) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (newValue === undefined && oldValue === undefined) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (Array.isArray(newValue) && Array.isArray(oldValue)) {
|
|
296
|
+
return JSON.stringify(newValue) !== JSON.stringify(oldValue);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
@@ -34,7 +34,8 @@ import { FileService } from "./file.service";
|
|
|
34
34
|
import { getMediaStorageProvider } from "./mediaStorageProviders";
|
|
35
35
|
import { ModelMetadataService } from "./model-metadata.service";
|
|
36
36
|
import { ModuleMetadataService } from "./module-metadata.service";
|
|
37
|
-
|
|
37
|
+
import { UserContextService } from "./user-context.service";
|
|
38
|
+
import { Optional } from "@nestjs/common";
|
|
38
39
|
const DEFAULT_LIMIT = 10;
|
|
39
40
|
const DEFAULT_OFFSET = 0;
|
|
40
41
|
export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDto, so we get the proper types in our service
|
|
@@ -50,7 +51,8 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
50
51
|
readonly repo: Repository<T>,
|
|
51
52
|
readonly modelName: string,
|
|
52
53
|
readonly moduleName: string,
|
|
53
|
-
readonly moduleRef: ModuleRef
|
|
54
|
+
readonly moduleRef: ModuleRef,
|
|
55
|
+
@Optional() readonly userContextService?: UserContextService
|
|
54
56
|
//We can just have the Model Entity here
|
|
55
57
|
) { }
|
|
56
58
|
|
|
@@ -66,6 +68,9 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
66
68
|
// Check wheather user has create permission for model
|
|
67
69
|
if (solidRequestContext.activeUser) {
|
|
68
70
|
const hasPermission = this.crudHelperService.hasCreatePermissionOnModel(solidRequestContext.activeUser, model.singularName);
|
|
71
|
+
if (this.userContextService) {
|
|
72
|
+
this.userContextService.setUser(solidRequestContext.activeUser);
|
|
73
|
+
}
|
|
69
74
|
if (!hasPermission) {
|
|
70
75
|
throw new BadRequestException('Forbidden');
|
|
71
76
|
}
|
|
@@ -160,6 +165,9 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
160
165
|
// Check wheather user has update permission for model
|
|
161
166
|
if (solidRequestContext.activeUser) {
|
|
162
167
|
const hasPermission = this.crudHelperService.hasUpdatePermissionOnModel(solidRequestContext.activeUser, model.singularName);
|
|
168
|
+
if (this.userContextService) {
|
|
169
|
+
this.userContextService.setUser(solidRequestContext.activeUser);
|
|
170
|
+
}
|
|
163
171
|
if (!hasPermission) {
|
|
164
172
|
throw new BadRequestException('Forbidden');
|
|
165
173
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
import { ActiveUserData } from '../interfaces/active-user-data.interface';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class UserContextService {
|
|
6
|
+
private readonly logger = new Logger(UserContextService.name);
|
|
7
|
+
private static currentUser: any = null;
|
|
8
|
+
|
|
9
|
+
setUser(user: any) {
|
|
10
|
+
this.logger.debug(`Setting user: ${JSON.stringify(user)}`);
|
|
11
|
+
UserContextService.currentUser = user;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getUser() {
|
|
15
|
+
return UserContextService.currentUser;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
runWithUser<T>(user: any, callback: () => T): T {
|
|
19
|
+
const previousUser = this.getUser();
|
|
20
|
+
try {
|
|
21
|
+
this.setUser(user);
|
|
22
|
+
return callback();
|
|
23
|
+
} finally {
|
|
24
|
+
this.setUser(previousUser);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getCurrentUser(): ActiveUserData | null {
|
|
29
|
+
return this.getUser();
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/solid-core.module.ts
CHANGED
|
@@ -154,7 +154,14 @@ import { RequestContextService } from './services/request-context.service';
|
|
|
154
154
|
import { SecurityRuleRepository } from './repository/security-rule.repository';
|
|
155
155
|
import { SecurityRuleSubscriber } from './subscribers/security-rule.subscriber';
|
|
156
156
|
import { ListOfValuesController } from './controllers/list-of-values.controller';
|
|
157
|
-
|
|
157
|
+
import { ChatterMessage } from './entities/chatter-message.entity';
|
|
158
|
+
import { ChatterMessageService } from './services/chatter-message.service';
|
|
159
|
+
import { ChatterMessageController } from './controllers/chatter-message.controller';
|
|
160
|
+
import { ChatterMessageDetails } from './entities/chatter-message-details.entity';
|
|
161
|
+
import { ChatterMessageDetailsService } from './services/chatter-message-details.service';
|
|
162
|
+
import { ChatterMessageDetailsController } from './controllers/chatter-message-details.controller';
|
|
163
|
+
import { AuditSubscriber } from './subscribers/audit.subscriber';
|
|
164
|
+
import { UserContextService } from './services/user-context.service';
|
|
158
165
|
|
|
159
166
|
@Global()
|
|
160
167
|
@Module({
|
|
@@ -203,6 +210,8 @@ import { ListOfValuesController } from './controllers/list-of-values.controller'
|
|
|
203
210
|
TypeOrmModule.forFeature([SecurityRule]),
|
|
204
211
|
TypeOrmModule.forFeature([SavedFilters]),
|
|
205
212
|
TypeOrmModule.forFeature([ListOfValues]),
|
|
213
|
+
TypeOrmModule.forFeature([ChatterMessage]),
|
|
214
|
+
TypeOrmModule.forFeature([ChatterMessageDetails]),
|
|
206
215
|
// TypeOrmModule.forFeature([User]),
|
|
207
216
|
],
|
|
208
217
|
controllers: [
|
|
@@ -232,7 +241,9 @@ import { ListOfValuesController } from './controllers/list-of-values.controller'
|
|
|
232
241
|
UserViewMetadataController,
|
|
233
242
|
SecurityRuleController,
|
|
234
243
|
SavedFiltersController,
|
|
235
|
-
ListOfValuesController
|
|
244
|
+
ListOfValuesController,
|
|
245
|
+
ChatterMessageController,
|
|
246
|
+
ChatterMessageDetailsController
|
|
236
247
|
],
|
|
237
248
|
providers: [
|
|
238
249
|
{
|
|
@@ -333,7 +344,11 @@ import { ListOfValuesController } from './controllers/list-of-values.controller'
|
|
|
333
344
|
SecurityRuleRepository,
|
|
334
345
|
SecurityRuleSubscriber,
|
|
335
346
|
RequestContextService,
|
|
336
|
-
SavedFiltersService
|
|
347
|
+
SavedFiltersService,
|
|
348
|
+
ChatterMessageService,
|
|
349
|
+
ChatterMessageDetailsService,
|
|
350
|
+
AuditSubscriber,
|
|
351
|
+
UserContextService,
|
|
337
352
|
],
|
|
338
353
|
exports: [
|
|
339
354
|
ModuleMetadataService,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Connection, EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, UpdateEvent } from 'typeorm';
|
|
2
|
+
import { ChatterMessageService } from '../services/chatter-message.service';
|
|
3
|
+
import { EntityMetadata } from 'typeorm';
|
|
4
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
5
|
+
import { ModelMetadata } from '../entities/model-metadata.entity';
|
|
6
|
+
import { Repository } from 'typeorm';
|
|
7
|
+
import { Injectable } from '@nestjs/common';
|
|
8
|
+
import { UserContextService } from '../services/user-context.service';
|
|
9
|
+
@Injectable()
|
|
10
|
+
@EventSubscriber()
|
|
11
|
+
export class AuditSubscriber implements EntitySubscriberInterface {
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly connection: Connection,
|
|
15
|
+
private readonly chatterMessageService: ChatterMessageService,
|
|
16
|
+
@InjectRepository(ModelMetadata)
|
|
17
|
+
private readonly modelMetadataRepo: Repository<ModelMetadata>,
|
|
18
|
+
private readonly userContextService: UserContextService
|
|
19
|
+
) {
|
|
20
|
+
connection.subscribers.push(this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<boolean> {
|
|
24
|
+
const model = await this.modelMetadataRepo.findOne({
|
|
25
|
+
where: {
|
|
26
|
+
displayName: metadata.name
|
|
27
|
+
},
|
|
28
|
+
relations: {
|
|
29
|
+
fields: true,
|
|
30
|
+
module: true
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!model || !model.enableAuditTracking) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const auditFields = model.fields.filter(field =>
|
|
39
|
+
field.enableAuditTracking &&
|
|
40
|
+
!['oneToMany', 'mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (auditFields.length === 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return auditFields.some(field => {
|
|
48
|
+
const fieldValue = entity[field.name];
|
|
49
|
+
return fieldValue !== undefined && fieldValue !== null;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async afterInsert(event: InsertEvent<any>) {
|
|
54
|
+
if (await this.shouldTrackAudit(event.entity, event.metadata)) {
|
|
55
|
+
const activeUser = this.userContextService.getUser();
|
|
56
|
+
await this.chatterMessageService.postAuditMessageOnInsert(event.entity, event.metadata, activeUser);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async afterUpdate(event: UpdateEvent<any>) {
|
|
61
|
+
if (await this.shouldTrackAudit(event.entity, event.metadata)) {
|
|
62
|
+
const activeUser = this.userContextService.getUser();
|
|
63
|
+
await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, activeUser);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async afterRemove(event: RemoveEvent<any>) {
|
|
68
|
+
if (await this.shouldTrackAudit(event.entity, event.metadata)) {
|
|
69
|
+
const activeUser = this.userContextService.getUser();
|
|
70
|
+
await this.chatterMessageService.postAuditMessageOnDelete(event.entity, event.metadata, event.databaseEntity, activeUser);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|