@solidstarters/solid-core 1.2.122 → 1.2.123

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 (94) hide show
  1. package/dist/controllers/authentication.controller.d.ts +3 -1
  2. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  3. package/dist/controllers/setting.controller.d.ts +6 -3
  4. package/dist/controllers/setting.controller.d.ts.map +1 -1
  5. package/dist/controllers/setting.controller.js +32 -5
  6. package/dist/controllers/setting.controller.js.map +1 -1
  7. package/dist/controllers/user-activity-history.controller.d.ts +43 -0
  8. package/dist/controllers/user-activity-history.controller.d.ts.map +1 -0
  9. package/dist/controllers/user-activity-history.controller.js +179 -0
  10. package/dist/controllers/user-activity-history.controller.js.map +1 -0
  11. package/dist/controllers/user.controller.d.ts +2 -0
  12. package/dist/controllers/user.controller.d.ts.map +1 -1
  13. package/dist/controllers/user.controller.js +19 -0
  14. package/dist/controllers/user.controller.js.map +1 -1
  15. package/dist/dtos/create-setting.dto.d.ts +3 -0
  16. package/dist/dtos/create-setting.dto.d.ts.map +1 -1
  17. package/dist/dtos/create-setting.dto.js +19 -1
  18. package/dist/dtos/create-setting.dto.js.map +1 -1
  19. package/dist/dtos/create-user-activity-history.dto.d.ts +8 -0
  20. package/dist/dtos/create-user-activity-history.dto.d.ts.map +1 -0
  21. package/dist/dtos/create-user-activity-history.dto.js +54 -0
  22. package/dist/dtos/create-user-activity-history.dto.js.map +1 -0
  23. package/dist/dtos/update-setting.dto.d.ts +3 -0
  24. package/dist/dtos/update-setting.dto.d.ts.map +1 -1
  25. package/dist/dtos/update-setting.dto.js +19 -1
  26. package/dist/dtos/update-setting.dto.js.map +1 -1
  27. package/dist/dtos/update-user-activity-history.dto.d.ts +9 -0
  28. package/dist/dtos/update-user-activity-history.dto.d.ts.map +1 -0
  29. package/dist/dtos/update-user-activity-history.dto.js +57 -0
  30. package/dist/dtos/update-user-activity-history.dto.js.map +1 -0
  31. package/dist/dtos/update-user-profile.dto.d.ts +7 -0
  32. package/dist/dtos/update-user-profile.dto.d.ts.map +1 -0
  33. package/dist/dtos/update-user-profile.dto.js +41 -0
  34. package/dist/dtos/update-user-profile.dto.js.map +1 -0
  35. package/dist/dtos/update-user.dto.d.ts.map +1 -1
  36. package/dist/dtos/update-user.dto.js +1 -16
  37. package/dist/dtos/update-user.dto.js.map +1 -1
  38. package/dist/entities/setting.entity.d.ts +3 -0
  39. package/dist/entities/setting.entity.d.ts.map +1 -1
  40. package/dist/entities/setting.entity.js +11 -1
  41. package/dist/entities/setting.entity.js.map +1 -1
  42. package/dist/entities/user-activity-history.entity.d.ts +9 -0
  43. package/dist/entities/user-activity-history.entity.d.ts.map +1 -0
  44. package/dist/entities/user-activity-history.entity.js +46 -0
  45. package/dist/entities/user-activity-history.entity.js.map +1 -0
  46. package/dist/guards/authentication.guard.d.ts +3 -1
  47. package/dist/guards/authentication.guard.d.ts.map +1 -1
  48. package/dist/guards/authentication.guard.js +11 -2
  49. package/dist/guards/authentication.guard.js.map +1 -1
  50. package/dist/index.d.ts +4 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +4 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/seeders/seed-data/solid-core-metadata.json +325 -0
  55. package/dist/services/authentication.service.d.ts +8 -2
  56. package/dist/services/authentication.service.d.ts.map +1 -1
  57. package/dist/services/authentication.service.js +26 -2
  58. package/dist/services/authentication.service.js.map +1 -1
  59. package/dist/services/request-context.service.d.ts +2 -0
  60. package/dist/services/request-context.service.d.ts.map +1 -1
  61. package/dist/services/request-context.service.js +6 -0
  62. package/dist/services/request-context.service.js.map +1 -1
  63. package/dist/services/setting.service.d.ts +11 -3
  64. package/dist/services/setting.service.d.ts.map +1 -1
  65. package/dist/services/setting.service.js +86 -60
  66. package/dist/services/setting.service.js.map +1 -1
  67. package/dist/services/user-activity-history.service.d.ts +26 -0
  68. package/dist/services/user-activity-history.service.d.ts.map +1 -0
  69. package/dist/services/user-activity-history.service.js +69 -0
  70. package/dist/services/user-activity-history.service.js.map +1 -0
  71. package/dist/solid-core.module.d.ts.map +1 -1
  72. package/dist/solid-core.module.js +8 -1
  73. package/dist/solid-core.module.js.map +1 -1
  74. package/dist/tsconfig.tsbuildinfo +1 -1
  75. package/package.json +1 -1
  76. package/src/controllers/setting.controller.ts +32 -4
  77. package/src/controllers/user-activity-history.controller.ts +93 -0
  78. package/src/controllers/user.controller.ts +12 -1
  79. package/src/dtos/create-setting.dto.ts +13 -1
  80. package/src/dtos/create-user-activity-history.dto.ts +30 -0
  81. package/src/dtos/update-setting.dto.ts +13 -1
  82. package/src/dtos/update-user-activity-history.dto.ts +32 -0
  83. package/src/dtos/update-user-profile.dto.ts +19 -0
  84. package/src/dtos/update-user.dto.ts +13 -13
  85. package/src/entities/setting.entity.ts +7 -1
  86. package/src/entities/user-activity-history.entity.ts +21 -0
  87. package/src/guards/authentication.guard.ts +12 -1
  88. package/src/index.ts +7 -0
  89. package/src/seeders/seed-data/solid-core-metadata.json +325 -0
  90. package/src/services/authentication.service.ts +45 -12
  91. package/src/services/request-context.service.ts +8 -0
  92. package/src/services/setting.service.ts +103 -71
  93. package/src/services/user-activity-history.service.ts +49 -0
  94. package/src/solid-core.module.ts +8 -1
@@ -9,11 +9,12 @@ import { CRUDService } from 'src/services/crud.service';
9
9
  import { FileService } from 'src/services/file.service';
10
10
  import { ModelMetadataService } from 'src/services/model-metadata.service';
11
11
  import { ModuleMetadataService } from 'src/services/module-metadata.service';
12
-
13
-
14
12
  import commonConfig from 'src/config/common.config';
15
13
  import { iamConfig } from 'src/config/iam.config';
16
14
  import { Setting } from '../entities/setting.entity';
15
+ import { RequestContextService } from './request-context.service';
16
+ import { User } from 'src/entities/user.entity';
17
+ import { CreateSettingDto } from 'src/dtos/create-setting.dto';
17
18
 
18
19
  @Injectable()
19
20
  export class SettingService extends CRUDService<Setting> {
@@ -31,8 +32,9 @@ export class SettingService extends CRUDService<Setting> {
31
32
  readonly entityManager: EntityManager,
32
33
  @InjectRepository(Setting, 'default')
33
34
  readonly repo: Repository<Setting>,
34
- readonly moduleRef: ModuleRef
35
-
35
+ readonly moduleRef: ModuleRef,
36
+ private readonly requestContextService: RequestContextService,
37
+ @InjectRepository(User) private readonly userRepository: Repository<User>,
36
38
  ) {
37
39
  super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'setting', 'solid-core', moduleRef
38
40
  );
@@ -47,22 +49,24 @@ export class SettingService extends CRUDService<Setting> {
47
49
  iamGoogleOAuthEnabled: false,
48
50
  authPagesLayout: "center",
49
51
  authPagesTheme: "light",
50
- appLogo: "",
51
- companylogo: "",
52
- favicon: "",
52
+ appLogo: null,
53
+ companylogo: null,
54
+ favicon: null,
53
55
  appLogoPosition: "in_form_view",
54
56
  showAuthContent: false,
55
57
  appTitle: process.env.SOLID_APP_NAME || "Solid App",
56
58
  appSubtitle: process.env.SOLID_APP_SUBTITLE || "Lorem Ipsum",
57
59
  appDescription: process.env.SOLID_APP_DESCRIPTION || "lorem ipsum",
58
60
  showLegalLinks: false,
59
- appTnc: "",
60
- appPrivacyPolicy: "",
61
+ appTnc: null,
62
+ appPrivacyPolicy: null,
61
63
  defaultRole: this.iamConfiguration.defaultRole,
62
64
  shouldQueueEmails: this.commonConfiguration.shouldQueueEmails,
63
65
  shouldQueueSms: this.commonConfiguration.shouldQueueSms,
64
66
  enableDarkMode: true,
65
- copyright : ""
67
+ copyright: null,
68
+ enableUsername: true,
69
+ enabledNotification: true
66
70
  };
67
71
 
68
72
  const existingSettings = await this.repo.find();
@@ -131,23 +135,25 @@ export class SettingService extends CRUDService<Setting> {
131
135
  iamGoogleOAuthEnabled: false,
132
136
  authPagesLayout: "center",
133
137
  authPagesTheme: "light",
134
- appLogo: "",
135
- companylogo: "",
136
- favicon: "",
138
+ appLogo: null,
139
+ companylogo: null,
140
+ favicon: null,
137
141
  appLogoPosition: "in_form_view", //in_form_view | in_image_view
138
142
  showAuthContent: false,
139
143
  appTitle: process.env.SOLID_APP_NAME || "Solid App",
140
- appSubtitle: "",
141
- appDescription: "",
144
+ appSubtitle: null,
145
+ appDescription: null,
142
146
  showLegalLinks: false,
143
- appTnc: "",
144
- appPrivacyPolicy: "",
147
+ appTnc: null,
148
+ appPrivacyPolicy: null,
145
149
  defaultRole: this.iamConfiguration.defaultRole,
146
150
  shouldQueueEmails: this.commonConfiguration.shouldQueueEmails,
147
151
  shouldQueueSms: this.commonConfiguration.shouldQueueSms,
148
152
  enableDarkMode: true,
149
- copyright : "",
150
- forceChangePasswordOnFirstLogin:true
153
+ copyright: null,
154
+ forceChangePasswordOnFirstLogin: true,
155
+ enableUsername: true,
156
+ enabledNotification: true
151
157
  };
152
158
  }
153
159
 
@@ -155,7 +161,7 @@ export class SettingService extends CRUDService<Setting> {
155
161
  try {
156
162
  const settingsArray: Setting[] = await this.repo.find();
157
163
  const settingEntry = settingsArray.find(setting => setting.key === settingKey);
158
-
164
+
159
165
  if (settingEntry && settingEntry.value !== null && settingEntry.value !== undefined) {
160
166
  const value = settingEntry.value;
161
167
 
@@ -181,65 +187,84 @@ export class SettingService extends CRUDService<Setting> {
181
187
  }
182
188
  }
183
189
 
184
- async updateSettings(settings: Record<string, any> = {}, files: Array<Express.Multer.File> = []): Promise<Setting[]> {
190
+ async updateSettings(
191
+ settings: CreateSettingDto[] = [],
192
+ uploadedFiles: Array<Express.Multer.File> = []
193
+ ): Promise<Setting[]> {
194
+ const activeUser = this.requestContextService.getActiveUser();
195
+ const userId = activeUser?.sub;
196
+
185
197
  const existingSettings = await this.repo.find();
186
- const existingKeys = new Set(existingSettings.map(s => s.key));
187
198
 
188
199
  const settingsToUpdate: Setting[] = [];
189
200
  const settingsToCreate: Setting[] = [];
190
201
 
191
- if (files && files.length > 0) {
192
- for (const file of files) {
193
- const key = file.fieldname;
194
- const relativePath = `${file.filename}-${file.originalname}`;
195
- const fileStoragePath = `${this.configService.get('app-builder.fileStorageDir')}/${relativePath}`;
202
+ let user: User | null = null;
203
+ const hasUserSettings = settings.some(dto => dto.type === 'user');
204
+ if (hasUserSettings && userId) {
205
+ user = await this.userRepository.findOne({ where: { id: userId } });
206
+ }
207
+
208
+ // Handle uploaded files
209
+ if (uploadedFiles?.length) {
210
+ for (const file of uploadedFiles) {
211
+ const settingKey = file.fieldname;
212
+ const relativeFileName = `${file.filename}-${file.originalname}`;
213
+ const storagePath = `${this.configService.get('app-builder.fileStorageDir')}/${relativeFileName}`;
196
214
  const baseUrl = process.env.BASE_URL || '';
197
- const fullUrl = `${baseUrl}/${fileStoragePath}`;
198
-
199
- await this.fileService.copyFile(file.path, fileStoragePath);
215
+ const fileUrl = `${baseUrl}/${storagePath}`;
216
+
217
+ await this.fileService.copyFile(file.path, storagePath);
200
218
  await this.fileService.deleteFile(file.path);
201
219
 
202
- if (existingKeys.has(key)) {
203
- const existingSetting = existingSettings.find(s => s.key === key);
204
- if (existingSetting) {
205
- existingSetting.value = fullUrl;
206
- settingsToUpdate.push(existingSetting);
207
- }
220
+ const matchedDto = settings.find(dto => dto.key === settingKey);
221
+ const settingType = matchedDto?.type ?? 'system';
222
+
223
+ const existingSetting = existingSettings.find(s => s.key === settingKey);
224
+ if (existingSetting) {
225
+ existingSetting.value = fileUrl;
226
+ existingSetting.type = settingType;
227
+ settingsToUpdate.push(existingSetting);
208
228
  } else {
209
229
  const newSetting = new Setting();
210
- newSetting.key = key;
211
- newSetting.value = fullUrl;
230
+ newSetting.key = settingKey;
231
+ newSetting.value = fileUrl;
232
+ newSetting.type = settingType;
233
+
234
+ if (settingType === 'user' && user) {
235
+ newSetting.user = user;
236
+ }
237
+
212
238
  settingsToCreate.push(newSetting);
213
239
  }
214
240
  }
215
241
  }
216
242
 
217
- let parsedSettings: Record<string, any>;
218
- try {
219
- parsedSettings = typeof settings === 'string' ? JSON.parse(settings) : settings;
220
- } catch (error) {
221
- parsedSettings = {};
222
- }
223
-
224
- for (const [key, value] of Object.entries(parsedSettings)) {
225
- if (files && files.some(f => f.fieldname === key)) {
226
- continue;
243
+ // Handle non-file settings
244
+ for (const settingDto of settings) {
245
+ if (uploadedFiles?.some(file => file.fieldname === settingDto.key)) {
246
+ continue; // skip if already handled via file
227
247
  }
228
248
 
229
- const stringValue = typeof value === 'boolean' ? value.toString() :
230
- Array.isArray(value) ? value.join(',') :
231
- value === null || value === undefined ? '' : String(value);
249
+ const key = settingDto.key;
250
+ const value = settingDto.value ?? '';
251
+ const settingType = settingDto.type ?? 'system';
232
252
 
233
- if (existingKeys.has(key)) {
234
- const existingSetting = existingSettings.find(s => s.key === key);
235
- if (existingSetting) {
236
- existingSetting.value = stringValue;
237
- settingsToUpdate.push(existingSetting);
238
- }
253
+ const existingSetting = existingSettings.find(s => s.key === key);
254
+ if (existingSetting) {
255
+ existingSetting.value = value;
256
+ existingSetting.type = settingType;
257
+ settingsToUpdate.push(existingSetting);
239
258
  } else {
240
259
  const newSetting = new Setting();
241
260
  newSetting.key = key;
242
- newSetting.value = stringValue;
261
+ newSetting.value = value;
262
+ newSetting.type = settingType;
263
+
264
+ if (settingType === 'user' && user) {
265
+ newSetting.user = user;
266
+ }
267
+
243
268
  settingsToCreate.push(newSetting);
244
269
  }
245
270
  }
@@ -255,29 +280,36 @@ export class SettingService extends CRUDService<Setting> {
255
280
  return [...settingsToUpdate, ...settingsToCreate];
256
281
  }
257
282
 
258
- async getAllSettings(): Promise<Record<string, any>> {
259
- const settingsArray = await this.repo.find();
260
- const settingsMap: Record<string, any> = {};
283
+ async getAllSettings(): Promise<{ system: Record<string, any>, user: Record<string, any> }> {
284
+ const settingsArray = await this.repo.find({ relations: ['user'] });
285
+
286
+ const system: Record<string, any> = {};
287
+ const user: Record<string, any> = {};
261
288
 
262
289
  for (const setting of settingsArray) {
263
290
  if (setting.key && setting.value !== undefined && setting.value !== null) {
264
291
  const value = setting.value;
292
+ let parsedValue: any;
265
293
 
266
294
  if (value === 'true' || value === 'false') {
267
- settingsMap[setting.key] = value === 'true';
268
- }
269
- else if (!isNaN(Number(value)) && value.trim() !== '') {
270
- settingsMap[setting.key] = Number(value);
271
- }
272
- else if (value.includes(',')) {
273
- settingsMap[setting.key] = value.split(',').map(item => item.trim());
295
+ parsedValue = value === 'true';
296
+ } else if (!isNaN(Number(value)) && value.trim() !== '') {
297
+ parsedValue = Number(value);
298
+ } else if (value.includes(',')) {
299
+ parsedValue = value.split(',').map(item => item.trim());
300
+ } else {
301
+ parsedValue = value;
274
302
  }
275
- else {
276
- settingsMap[setting.key] = value;
303
+
304
+ if (setting.type === 'user') {
305
+ user[setting.key] = parsedValue;
306
+ } else {
307
+ system[setting.key] = parsedValue;
277
308
  }
278
309
  }
279
310
  }
280
311
 
281
- return settingsMap;
312
+ return { system, user };
282
313
  }
314
+
283
315
  }
@@ -0,0 +1,49 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
3
+ import { DiscoveryService, ModuleRef } from "@nestjs/core";
4
+ import { EntityManager, Repository } 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
+
13
+
14
+ import { UserActivityHistory } from '../entities/user-activity-history.entity';
15
+ import { RequestContextService } from './request-context.service';
16
+ import { User } from 'src/entities/user.entity';
17
+
18
+ @Injectable()
19
+ export class UserActivityHistoryService extends CRUDService<UserActivityHistory> {
20
+ constructor(
21
+ readonly modelMetadataService: ModelMetadataService,
22
+ readonly moduleMetadataService: ModuleMetadataService,
23
+ readonly configService: ConfigService,
24
+ readonly fileService: FileService,
25
+ readonly discoveryService: DiscoveryService,
26
+ readonly crudHelperService: CrudHelperService,
27
+ @InjectEntityManager()
28
+ readonly entityManager: EntityManager,
29
+ @InjectRepository(UserActivityHistory, 'default')
30
+ readonly repo: Repository<UserActivityHistory>,
31
+ readonly moduleRef: ModuleRef,
32
+ readonly requestContextService: RequestContextService,
33
+
34
+ ) {
35
+ super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'userActivityHistory', 'solid-core', moduleRef);
36
+ }
37
+ async logEvent(event: 'login' | 'logout' | 'tokenRefreshed', user: User) {
38
+ const ip = this.requestContextService.getIp();
39
+ const userAgent = this.requestContextService.getUserAgent();
40
+
41
+ await this.repo.save({
42
+ user,
43
+ event,
44
+ ipAddress: ip,
45
+ userAgent,
46
+ });
47
+ }
48
+
49
+ }
@@ -188,6 +188,9 @@ import { SystemFieldsSeederService } from './seeders/system-fields-seeder.servic
188
188
  import { ModelMetadataHelperService } from './helpers/model-metadata-helper.service';
189
189
  import { GenerateCodePublisher } from './jobs/database/generate-code-publisher.service';
190
190
  import { GenerateCodeSubscriber } from './jobs/database/generate-code-subscriber.service';
191
+ import { UserActivityHistory } from './entities/user-activity-history.entity';
192
+ import { UserActivityHistoryService } from './services/user-activity-history.service';
193
+ import { UserActivityHistoryController } from './controllers/user-activity-history.controller';
191
194
 
192
195
 
193
196
  @Global()
@@ -244,6 +247,7 @@ import { GenerateCodeSubscriber } from './jobs/database/generate-code-subscriber
244
247
  HttpModule,
245
248
  ConfigModule,
246
249
  ClsModule,
250
+ TypeOrmModule.forFeature([UserActivityHistory]),
247
251
  ],
248
252
  controllers: [
249
253
  ModuleMetadataController,
@@ -280,6 +284,7 @@ import { GenerateCodeSubscriber } from './jobs/database/generate-code-subscriber
280
284
  ExportTransactionController,
281
285
  ImportTransactionController,
282
286
  ImportTransactionErrorLogController,
287
+ UserActivityHistoryController,
283
288
  ],
284
289
  providers: [
285
290
  {
@@ -400,6 +405,7 @@ import { GenerateCodeSubscriber } from './jobs/database/generate-code-subscriber
400
405
  ImportTransactionErrorLogService,
401
406
  CreatedByUpdatedBySubscriber,
402
407
  SystemFieldsSeederService,
408
+ UserActivityHistoryService,
403
409
 
404
410
  ],
405
411
  exports: [
@@ -430,7 +436,8 @@ import { GenerateCodeSubscriber } from './jobs/database/generate-code-subscriber
430
436
  RefreshModuleCommand,
431
437
  RequestContextService,
432
438
  SecurityRuleRepository,
433
- FieldRepository
439
+ FieldRepository,
440
+ UserActivityHistoryService
434
441
  ],
435
442
  })
436
443
  export class SolidCoreModule { }