@solidstarters/solid-core 1.2.157 → 1.2.159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/config/cache.options.js +2 -7
  2. package/dist/config/cache.options.js.map +1 -1
  3. package/dist/constants/error-messages.js +1 -1
  4. package/dist/constants/error-messages.js.map +1 -1
  5. package/dist/controllers/authentication.controller.d.ts +0 -2
  6. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  7. package/dist/controllers/authentication.controller.js +5 -5
  8. package/dist/controllers/authentication.controller.js.map +1 -1
  9. package/dist/factories/whatsapp.factory.d.ts.map +1 -1
  10. package/dist/factories/whatsapp.factory.js +1 -1
  11. package/dist/factories/whatsapp.factory.js.map +1 -1
  12. package/dist/helpers/environment.helper.d.ts +2 -0
  13. package/dist/helpers/environment.helper.d.ts.map +1 -1
  14. package/dist/helpers/environment.helper.js +7 -0
  15. package/dist/helpers/environment.helper.js.map +1 -1
  16. package/dist/helpers/index.d.ts +2 -0
  17. package/dist/helpers/index.d.ts.map +1 -0
  18. package/dist/helpers/index.js +13 -0
  19. package/dist/helpers/index.js.map +1 -0
  20. package/dist/helpers/model-metadata-helper.service.d.ts +5 -1
  21. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  22. package/dist/helpers/model-metadata-helper.service.js +32 -2
  23. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  24. package/dist/helpers/string.helper.d.ts +2 -0
  25. package/dist/helpers/string.helper.d.ts.map +1 -0
  26. package/dist/helpers/string.helper.js +10 -0
  27. package/dist/helpers/string.helper.js.map +1 -0
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  33. package/dist/repository/security-rule.repository.js +16 -9
  34. package/dist/repository/security-rule.repository.js.map +1 -1
  35. package/dist/repository/user.repository.d.ts +12 -0
  36. package/dist/repository/user.repository.d.ts.map +1 -0
  37. package/dist/repository/user.repository.js +34 -0
  38. package/dist/repository/user.repository.js.map +1 -0
  39. package/dist/seeders/module-metadata-seeder.service.d.ts +12 -12
  40. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  41. package/dist/seeders/module-metadata-seeder.service.js +33 -13
  42. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  43. package/dist/seeders/seed-data/solid-core-metadata.json +40 -6
  44. package/dist/services/authentication.service.d.ts +0 -2
  45. package/dist/services/authentication.service.d.ts.map +1 -1
  46. package/dist/services/authentication.service.js +15 -14
  47. package/dist/services/authentication.service.js.map +1 -1
  48. package/dist/services/chatter-message.service.d.ts +8 -2
  49. package/dist/services/chatter-message.service.d.ts.map +1 -1
  50. package/dist/services/chatter-message.service.js +155 -30
  51. package/dist/services/chatter-message.service.js.map +1 -1
  52. package/dist/services/crud-helper.service.d.ts +7 -3
  53. package/dist/services/crud-helper.service.d.ts.map +1 -1
  54. package/dist/services/crud-helper.service.js +17 -5
  55. package/dist/services/crud-helper.service.js.map +1 -1
  56. package/dist/services/list-of-values.service.js.map +1 -1
  57. package/dist/services/user.service.d.ts +3 -2
  58. package/dist/services/user.service.d.ts.map +1 -1
  59. package/dist/services/user.service.js +2 -2
  60. package/dist/services/user.service.js.map +1 -1
  61. package/dist/services/view-metadata.service.d.ts +3 -1
  62. package/dist/services/view-metadata.service.d.ts.map +1 -1
  63. package/dist/services/view-metadata.service.js +5 -2
  64. package/dist/services/view-metadata.service.js.map +1 -1
  65. package/dist/solid-core.module.d.ts.map +1 -1
  66. package/dist/solid-core.module.js +16 -7
  67. package/dist/solid-core.module.js.map +1 -1
  68. package/dist/subscribers/audit.subscriber.d.ts +3 -1
  69. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  70. package/dist/subscribers/audit.subscriber.js +10 -5
  71. package/dist/subscribers/audit.subscriber.js.map +1 -1
  72. package/dist/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +2 -1
  74. package/src/config/cache.options.ts +1 -6
  75. package/src/constants/error-messages.ts +1 -1
  76. package/src/controllers/authentication.controller.ts +5 -5
  77. package/src/factories/whatsapp.factory.ts +2 -1
  78. package/src/helpers/environment.helper.ts +9 -0
  79. package/src/helpers/index.ts +9 -0
  80. package/src/helpers/model-metadata-helper.service.ts +30 -2
  81. package/src/helpers/string.helper.ts +4 -0
  82. package/src/index.ts +1 -0
  83. package/src/repository/security-rule.repository.ts +25 -12
  84. package/src/repository/user.repository.ts +17 -0
  85. package/src/seeders/module-metadata-seeder.service.ts +36 -15
  86. package/src/seeders/seed-data/solid-core-metadata.json +40 -6
  87. package/src/services/authentication.service.ts +20 -14
  88. package/src/services/chatter-message.service.ts +185 -35
  89. package/src/services/crud-helper.service.ts +24 -6
  90. package/src/services/list-of-values.service.ts +1 -1
  91. package/src/services/user.service.ts +3 -2
  92. package/src/services/view-metadata.service.ts +3 -1
  93. package/src/solid-core.module.ts +13 -3
  94. package/src/subscribers/audit.subscriber.ts +9 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.157",
3
+ "version": "1.2.159",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,6 +38,7 @@
38
38
  "@aws-sdk/s3-request-presigner": "^3.828.0",
39
39
  "@elasticemail/elasticemail-client": "^4.0.23",
40
40
  "@hapi/joi": "^17.1.1",
41
+ "@nest-lab/throttler-storage-redis": "^1.1.0",
41
42
  "@nestjs/schedule": "^6.0.0",
42
43
  "@nestjs/throttler": "^6.4.0",
43
44
  "amqplib": "^0.10.4",
@@ -1,7 +1,7 @@
1
1
  import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
2
2
  import { ConfigModule, ConfigService } from '@nestjs/config';
3
3
  import { redisStore } from 'cache-manager-redis-store';
4
- import { isNumber } from 'class-validator';
4
+ import { isRedisConfigured } from 'src/helpers/environment.helper';
5
5
 
6
6
  export const RedisOptions: CacheModuleAsyncOptions = {
7
7
  isGlobal: true,
@@ -29,8 +29,3 @@ async function createRedisStore(configService: ConfigService<Record<string, unkn
29
29
  });
30
30
  }
31
31
 
32
- function isRedisConfigured(configService: ConfigService): boolean {
33
- const host = configService.get<string>('REDIS_HOST');
34
- const port = configService.get<string>('REDIS_PORT');
35
- return host && port && isNumber(parseInt(port));
36
- }
@@ -28,7 +28,7 @@ export const ERROR_MESSAGES = {
28
28
  GOOGLE_OAUTH_PROFILE_FETCH_FAILED: 'Failed to fetch user profile from Google OAuth service',
29
29
  LOGOUT_FAILED: 'Logout failed due to an unexpected error.',
30
30
 
31
- INVALID_CREDENTIALS: 'Invalid username or password specified.',
31
+ INVALID_CREDENTIALS: 'Invalid credentials',
32
32
  LOGIN_FAILED: 'Login Failed',
33
33
  OLD_PASSWORD_INCORRECT: 'You have specified an incorrect old password.',
34
34
  INVALID_NEW_PASSWORD: 'Invalid new password.',
@@ -25,7 +25,7 @@ export class AuthenticationController {
25
25
  constructor(private readonly authService: AuthenticationService) { }
26
26
 
27
27
  @Public()
28
- @SkipThrottle({ login: false }) //Enable the login throttle only
28
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
29
29
  @Post('register')
30
30
  signUp(@Body() signUpDto: SignUpDto) {
31
31
  return this.authService.signUp(signUpDto);
@@ -39,7 +39,7 @@ export class AuthenticationController {
39
39
 
40
40
  @Public()
41
41
  // @UseGuards(LocalAuthGuard)
42
- @SkipThrottle({ login: false }) //Enable the login throttle only
42
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
43
43
  @HttpCode(HttpStatus.OK) // by default @Post does 201, we wanted 200 - hence using @HttpCode(HttpStatus.OK)
44
44
  @Post('authenticate')
45
45
  async signIn(
@@ -62,7 +62,7 @@ export class AuthenticationController {
62
62
  }
63
63
 
64
64
  @Public()
65
- @SkipThrottle({ login: false }) //Enable the login throttle only
65
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
66
66
  @HttpCode(HttpStatus.OK) // changed since the default is 201
67
67
  @Post('refresh-tokens')
68
68
  refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {
@@ -70,14 +70,14 @@ export class AuthenticationController {
70
70
  }
71
71
 
72
72
  @Public()
73
- @SkipThrottle({ login: false }) //Enable the login throttle only
73
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
74
74
  @Post('initiate/forgot-password')
75
75
  initiateForgotPassword(@Body() initiateForgotPasswordDto: InitiateForgotPasswordDto) {
76
76
  return this.authService.initiateForgotPassword(initiateForgotPasswordDto);
77
77
  }
78
78
 
79
79
  @Public()
80
- @SkipThrottle({ login: false }) //Enable the login throttle only
80
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
81
81
  @Post('confirm/forgot-password')
82
82
  confirmForgotPassword(@Body() confirmForgotPasswordDto: ConfirmForgotPasswordDto) {
83
83
  return this.authService.confirmForgotPassword(confirmForgotPasswordDto);
@@ -22,11 +22,12 @@ export class WhatsAppFactory {
22
22
 
23
23
  getWhatsappService(name: string = null): IWhatsAppTransport {
24
24
  // This is the default provider
25
- const whatsappServiceName = this.commonConfiguration.whatsappProvider || name;
25
+ const whatsappServiceName = name || this.commonConfiguration.whatsappProvider;
26
26
  if (!whatsappServiceName) {
27
27
  throw new Error("Unable to resolve whatsapp provider")
28
28
  }
29
29
  const whatsappProviders = this.solidRegistry.getWhatsappProviders();
30
+
30
31
  // Return the instance which matches the whatsappServiceName
31
32
  if (!whatsappProviders.length) {
32
33
  // throw new Error("No mail providers are registered.");
@@ -1,7 +1,16 @@
1
+ import { ConfigService } from "@nestjs/config";
2
+ import { isNumber } from 'class-validator';
3
+
1
4
  export function parseBooleanEnv(key: string, defaultValue: boolean = false): boolean {
2
5
  const value = process.env[key];
3
6
  if (value === undefined) {
4
7
  return defaultValue;
5
8
  }
6
9
  return value.toLowerCase() === 'true';
10
+ }
11
+
12
+ export function isRedisConfigured(configService: ConfigService): boolean {
13
+ const host = configService.get<string>('REDIS_HOST');
14
+ const port = configService.get<string>('REDIS_PORT');
15
+ return host && port && isNumber(parseInt(port));
7
16
  }
@@ -0,0 +1,9 @@
1
+ export function deepFreeze<T>(obj: T): T {
2
+ Object.getOwnPropertyNames(obj).forEach(prop => {
3
+ const value = (obj as any)[prop];
4
+ if (value && typeof value === 'object') {
5
+ deepFreeze(value);
6
+ }
7
+ });
8
+ return Object.freeze(obj);
9
+ }
@@ -2,13 +2,18 @@
2
2
 
3
3
  import { Injectable, Logger } from "@nestjs/common";
4
4
  import { SolidRegistry } from "./solid-registry";
5
- import { In } from "typeorm";
5
+ import { In, Repository } from "typeorm";
6
+ import { InjectRepository } from "@nestjs/typeorm";
7
+ import { ModelMetadata } from "src/entities/model-metadata.entity";
6
8
 
7
9
  @Injectable()
8
10
  export class ModelMetadataHelperService {
9
11
  private readonly logger = new Logger(ModelMetadataHelperService.name);
10
12
 
11
- constructor(private readonly registry: SolidRegistry) {
13
+ constructor(private readonly registry: SolidRegistry,
14
+ @InjectRepository(ModelMetadata)
15
+ private readonly modelMetadataRepo: Repository<ModelMetadata>,
16
+ ) {
12
17
  }
13
18
 
14
19
  getSystemFieldsMetadata(): any[] {
@@ -105,5 +110,28 @@ export class ModelMetadataHelperService {
105
110
  return systemFieldsMetadata;
106
111
  }
107
112
 
113
+ async loadFieldHierarchy(modelName: any) {
114
+ const model = await this.modelMetadataRepo.findOne({
115
+ where: {
116
+ singularName: modelName,
117
+ },
118
+ relations: {
119
+ fields: true,
120
+ parentModel: {
121
+ fields: true,
122
+ }
123
+ }
124
+ });
125
+ const fields = [];
126
+ if (model) {
127
+ // Add the fields of the current model
128
+ fields.push(...model.fields);
108
129
 
130
+ // Add the fields of the parent model
131
+ if (model.parentModel) {
132
+ fields.push(...model.parentModel.fields);
133
+ }
134
+ }
135
+ return fields;
136
+ }
109
137
  }
@@ -0,0 +1,4 @@
1
+ export const lowerFirst = (str: string): string => {
2
+ if (!str) return str;
3
+ return str.charAt(0).toLowerCase() + str.slice(1);
4
+ }
package/src/index.ts CHANGED
@@ -279,6 +279,7 @@ export * from './factories/mail.factory'
279
279
  export * from './repository/solid-base.repository'
280
280
  export * from './repository/security-rule.repository'
281
281
  export * from './repository/field.repository'
282
+ export * from './repository/chatter-message.repository'
282
283
 
283
284
 
284
285
  //softDeleteAwareEventSubscriber.subscriber.ts
@@ -8,8 +8,8 @@ import { RoleMetadata } from 'src/entities/role-metadata.entity';
8
8
  import { SecurityRule } from 'src/entities/security-rule.entity';
9
9
  import { SolidRegistry } from 'src/helpers/solid-registry';
10
10
  import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
11
- import { CrudHelperService } from 'src/services/crud-helper.service';
12
- import { DataSource, Repository, SelectQueryBuilder } from 'typeorm';
11
+ import { CrudHelperService, FilterCombinator } from 'src/services/crud-helper.service';
12
+ import { Brackets, DataSource, Repository, SelectQueryBuilder } from 'typeorm';
13
13
 
14
14
  @Injectable()
15
15
  export class SecurityRuleRepository extends Repository<SecurityRule> {
@@ -26,18 +26,31 @@ export class SecurityRuleRepository extends Repository<SecurityRule> {
26
26
  // Fetch the security rules for the model and roles
27
27
  const securityRules = this.solidRegistry.getSecurityRules(modelSingularName, activeUser.roles);
28
28
 
29
- // Loop through the security rules and add only rules that are json parseable and have a rule
30
- securityRules.forEach((rule: SecurityRule) => {
31
- try {
32
- // Parse the security rule and call the buildFilter method to build the query from the security rule
33
- const parsedRule = JSON.parse(this.resolveSecurityRuleConfig(rule.securityRuleConfig, activeUser)) as SecurityRuleConfig;
29
+ // If no security rules, return the original query builder
30
+ if (!securityRules.length) {
31
+ return qb;
32
+ }
33
+
34
+ // Apply each security rule to the query builder. The rules are combined with OR logic at the top level.
35
+ qb.andWhere(new Brackets((outerQb) => {
36
+ for (const rule of securityRules) {
37
+ try {
38
+ const parsedRule = JSON.parse(
39
+ this.resolveSecurityRuleConfig(rule.securityRuleConfig, activeUser)
40
+ ) as SecurityRuleConfig;
41
+
34
42
  if (parsedRule && parsedRule.filters) {
35
- this.crudHelperService.buildFilterQuery(qb, parsedRule, securityRuleAlias);
43
+ outerQb.orWhere( // combine each rule-group with OR at the outer level
44
+ new Brackets((innerQb) => {
45
+ this.crudHelperService.applyFilters(innerQb, parsedRule.filters, securityRuleAlias, qb); // AND within a rule
46
+ })
47
+ );
48
+ }
49
+ } catch (error) {
50
+ this.logger.warn(`Error parsing security rule: ${rule.securityRuleConfig}`, error);
36
51
  }
37
- } catch (error) {
38
- this.logger.warn(`Error parsing security rule: ${rule.securityRuleConfig}`, error);
39
52
  }
40
- });
53
+ }));
41
54
 
42
55
  return qb;
43
56
  }
@@ -85,7 +98,7 @@ export class SecurityRuleRepository extends Repository<SecurityRule> {
85
98
  },
86
99
  });
87
100
  createDto['role'] = role;
88
- }
101
+ }
89
102
 
90
103
  if (createDto.roleUserKey) {
91
104
  const role = await roleRepository.findOne({
@@ -0,0 +1,17 @@
1
+ import { Injectable } from "@nestjs/common";
2
+ import { User } from "src/entities/user.entity";
3
+ import { RequestContextService } from "src/services/request-context.service";
4
+ import { DataSource } from "typeorm";
5
+ import { SecurityRuleRepository } from "./security-rule.repository";
6
+ import { SolidBaseRepository } from "./solid-base.repository";
7
+
8
+ @Injectable()
9
+ export class UserRepository extends SolidBaseRepository<User> {
10
+ constructor(
11
+ readonly dataSource: DataSource,
12
+ readonly requestContextService: RequestContextService,
13
+ readonly securityRuleRepository: SecurityRuleRepository,
14
+ ) {
15
+ super(User, dataSource, requestContextService, securityRuleRepository);
16
+ }
17
+ }
@@ -41,7 +41,8 @@ import { CreateDashboardDto } from 'src/dtos/create-dashboard.dto';
41
41
  import { DashboardRepository } from 'src/repository/dashboard.repository';
42
42
  // import { CreateScheduledJobDto } from 'src/dtos/create-scheduled-job.dto';
43
43
  import { ScheduledJobRepository } from 'src/repository/scheduled-job.repository';
44
- import { CreateScheduledJobDto } from 'src/dtos/create-scheduled-job.dto';
44
+ import { CreateScheduledJobDto } from 'src/dtos/create-scheduled-job.dto'
45
+ import { deepFreeze } from 'src/helpers';
45
46
 
46
47
  @Injectable()
47
48
  export class ModuleMetadataSeederService {
@@ -128,7 +129,8 @@ export class ModuleMetadataSeederService {
128
129
  for (let i = 0; i < seedDataFiles.length; i++) {
129
130
 
130
131
  // Module, model & field handling.
131
- const overallMetadata = seedDataFiles[i];
132
+ const overallMetadata = deepFreeze(seedDataFiles[i]);
133
+
132
134
  // const fullPath = path.join(process.cwd(), seedDataFile);
133
135
 
134
136
  // For each module metadata seed file provided, read contents, parse & convert to a variable.
@@ -317,14 +319,20 @@ export class ModuleMetadataSeederService {
317
319
  }
318
320
  }
319
321
 
320
- async seedMediaStorageProviders(mediaStorageProviders: any) {
322
+ async seedMediaStorageProviders(_mediaStorageProviders: any) {
323
+ const mediaStorageProviders = structuredClone(_mediaStorageProviders);
324
+ if (!mediaStorageProviders) {
325
+ return;
326
+ }
321
327
  for (let i = 0; i < mediaStorageProviders.length; i++) {
322
328
  const mediaStorageProivder = mediaStorageProviders[i];
323
329
  await this.mediaStorageProviderMetadataService.upsert(mediaStorageProivder);
324
330
  }
325
331
  }
326
332
 
327
- async seedEmailTemplates(emailTemplates: CreateEmailTemplateDto[], moduleMetadata: CreateModuleMetadataDto) {
333
+ async seedEmailTemplates(_emailTemplates: CreateEmailTemplateDto[], _moduleMetadata: CreateModuleMetadataDto) {
334
+ const emailTemplates = structuredClone(_emailTemplates);
335
+ const moduleMetadata = structuredClone(_moduleMetadata);
328
336
  if (!emailTemplates) {
329
337
  return;
330
338
  }
@@ -360,7 +368,9 @@ export class ModuleMetadataSeederService {
360
368
 
361
369
  }
362
370
 
363
- async seedSmsTemplates(smsTemplates: CreateSmsTemplateDto[], moduleMetadata: CreateModuleMetadataDto) {
371
+ async seedSmsTemplates(_smsTemplates: CreateSmsTemplateDto[], _moduleMetadata: CreateModuleMetadataDto) {
372
+ const smsTemplates = structuredClone(_smsTemplates);
373
+ const moduleMetadata = structuredClone(_moduleMetadata);
364
374
  if (!smsTemplates) {
365
375
  return;
366
376
  }
@@ -397,6 +407,7 @@ export class ModuleMetadataSeederService {
397
407
  }
398
408
 
399
409
  async seedMenus(menus: any) {
410
+ // const menus = structuredClone(_menus);
400
411
  if (!menus) {
401
412
  return;
402
413
  }
@@ -434,7 +445,8 @@ export class ModuleMetadataSeederService {
434
445
  }
435
446
  }
436
447
 
437
- async seedActions(actions: any) {
448
+ async seedActions(_actions: any) {
449
+ const actions = structuredClone(_actions);
438
450
  if (!actions) {
439
451
  return;
440
452
  }
@@ -455,7 +467,8 @@ export class ModuleMetadataSeederService {
455
467
  }
456
468
  }
457
469
 
458
- async seedViews(views: any) {
470
+ async seedViews(_views: any) {
471
+ const views = structuredClone(_views);
459
472
  if (!views) {
460
473
  return;
461
474
  }
@@ -478,7 +491,8 @@ export class ModuleMetadataSeederService {
478
491
  }
479
492
  }
480
493
 
481
- async seedUsers(users) {
494
+ async seedUsers(_users) {
495
+ const users = structuredClone(_users);
482
496
  if (!users) {
483
497
  return;
484
498
  }
@@ -499,8 +513,8 @@ export class ModuleMetadataSeederService {
499
513
  }
500
514
  }
501
515
 
502
- async seedModuleModelFields(moduleMetadata: CreateModuleMetadataDto) {
503
-
516
+ async seedModuleModelFields(_moduleMetadata: CreateModuleMetadataDto) {
517
+ const moduleMetadata = structuredClone(_moduleMetadata);
504
518
  // First we create the module.
505
519
  // await this.moduleMetadataService.removeByName(moduleMetadata.name);
506
520
  // const module = await this.moduleMetadataService.create(moduleMetadata);
@@ -561,14 +575,16 @@ export class ModuleMetadataSeederService {
561
575
  }
562
576
  }
563
577
 
564
- async seedSettings(createDto: CreateSettingDto) {
578
+ async seedSettings(_createDto: CreateSettingDto) {
579
+ const createDto = structuredClone(_createDto);
565
580
  const settingsArray: any[] = await this.settingsRepo.find();
566
581
  if (!settingsArray || settingsArray.length === 0) {
567
582
  this.seetingService.create(createDto);
568
583
  }
569
584
  }
570
585
 
571
- async seedSecurityRules(rulesDto: CreateSecurityRuleDto[]) {
586
+ async seedSecurityRules(_rulesDto: CreateSecurityRuleDto[]) {
587
+ const rulesDto = structuredClone(_rulesDto);
572
588
  if (!rulesDto || rulesDto.length === 0) {
573
589
  this.logger.debug(`No security rules found to seed`);
574
590
  return;
@@ -578,17 +594,21 @@ export class ModuleMetadataSeederService {
578
594
  }
579
595
  }
580
596
 
581
- async seedListOfValues(listOfValuesDto: CreateListOfValuesDto[]) {
597
+ async seedListOfValues(_listOfValuesDto: CreateListOfValuesDto[]) {
598
+ const listOfValuesDto = structuredClone(_listOfValuesDto);
582
599
  if (!listOfValuesDto || listOfValuesDto.length === 0) {
583
600
  this.logger.debug(`No List Of Values found to seed`);
584
601
  return;
585
602
  }
586
603
  for (let j = 0; j < listOfValuesDto.length; j++) {
604
+ const listOfValueDto = listOfValuesDto[j];
605
+ listOfValueDto['module'] = await this.moduleMetadataService.findOneByUserKey(listOfValueDto.moduleUserKey);
587
606
  await this.listOfValuesService.upsert(listOfValuesDto[j]);
588
607
  }
589
608
  }
590
609
 
591
- async seedDashboards(dashboardDtos: CreateDashboardDto[]) {
610
+ async seedDashboards(_dashboardDtos: CreateDashboardDto[]) {
611
+ const dashboardDtos = structuredClone(_dashboardDtos);
592
612
  if (!dashboardDtos || dashboardDtos.length === 0) {
593
613
  this.logger.debug(`No dashboards found to seed`);
594
614
  return;
@@ -598,7 +618,8 @@ export class ModuleMetadataSeederService {
598
618
  }
599
619
  }
600
620
 
601
- async seedScheduledJobs(createScheduledJobDto: CreateScheduledJobDto[]) {
621
+ async seedScheduledJobs(_createScheduledJobDto: CreateScheduledJobDto[]) {
622
+ const createScheduledJobDto = structuredClone(_createScheduledJobDto);
602
623
  if (!createScheduledJobDto || createScheduledJobDto.length === 0) {
603
624
  this.logger.debug(`No scheduled jobs found to seed`);
604
625
  return;
@@ -1697,6 +1697,7 @@
1697
1697
  "dataSourceType": "postgres",
1698
1698
  "userKeyFieldUserKey": "username",
1699
1699
  "isSystem": true,
1700
+ "enableAuditTracking": true,
1700
1701
  "fields": [
1701
1702
  {
1702
1703
  "name": "fullName",
@@ -1709,7 +1710,8 @@
1709
1710
  "index": false,
1710
1711
  "private": false,
1711
1712
  "encrypt": false,
1712
- "isSystem": true
1713
+ "isSystem": true,
1714
+ "enableAuditTracking": true
1713
1715
  },
1714
1716
  {
1715
1717
  "name": "username",
@@ -1722,7 +1724,8 @@
1722
1724
  "index": true,
1723
1725
  "private": false,
1724
1726
  "encrypt": false,
1725
- "isSystem": true
1727
+ "isSystem": true,
1728
+ "enableAuditTracking": true
1726
1729
  },
1727
1730
  {
1728
1731
  "name": "email",
@@ -1735,7 +1738,8 @@
1735
1738
  "index": true,
1736
1739
  "private": false,
1737
1740
  "encrypt": false,
1738
- "isSystem": true
1741
+ "isSystem": true,
1742
+ "enableAuditTracking": true
1739
1743
  },
1740
1744
  {
1741
1745
  "name": "mobile",
@@ -1748,7 +1752,8 @@
1748
1752
  "index": true,
1749
1753
  "private": false,
1750
1754
  "encrypt": false,
1751
- "isSystem": true
1755
+ "isSystem": true,
1756
+ "enableAuditTracking": true
1752
1757
  },
1753
1758
  {
1754
1759
  "name": "password",
@@ -1884,7 +1889,8 @@
1884
1889
  "relationCascade": "cascade",
1885
1890
  "relationModelModuleName": "solid-core",
1886
1891
  "isSystem": true,
1887
- "isRelationManyToManyOwner": true
1892
+ "isRelationManyToManyOwner": true,
1893
+ "enableAuditTracking": true
1888
1894
  },
1889
1895
  {
1890
1896
  "name": "forgotPasswordConfirmedAt",
@@ -12256,5 +12262,33 @@
12256
12262
  ],
12257
12263
  "checksums": [],
12258
12264
  "listOfValues": [],
12259
- "scheduledJobs": []
12265
+ "scheduledJobs": [],
12266
+ "securityRules": [
12267
+ {
12268
+ "name": "model:User-role:Internal User",
12269
+ "description": "Show User record for the current user only",
12270
+ "roleUserKey": "Internal User",
12271
+ "modelMetadataUserKey": "user",
12272
+ "securityRuleConfig": {
12273
+ "filters": {
12274
+ "id": {
12275
+ "$eq": "$activeUserId"
12276
+ }
12277
+ }
12278
+ }
12279
+ },
12280
+ {
12281
+ "name": "model:User-role:Admin",
12282
+ "description": "Show All User records",
12283
+ "roleUserKey": "Admin",
12284
+ "modelMetadataUserKey": "user",
12285
+ "securityRuleConfig": {
12286
+ "filters": {
12287
+ "id": {
12288
+ "$ne": "0"
12289
+ }
12290
+ }
12291
+ }
12292
+ }
12293
+ ]
12260
12294
  }
@@ -126,7 +126,7 @@ export class AuthenticationService {
126
126
  const user = await this.resolveUser(signInDto.username, signInDto.email);
127
127
 
128
128
  if (!user) {
129
- throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
129
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
130
130
  }
131
131
  if (!user.active) {
132
132
  throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_ACTIVE);
@@ -136,7 +136,7 @@ export class AuthenticationService {
136
136
  user.password,
137
137
  );
138
138
  if (!isEqual) {
139
- throw new UnauthorizedException(ERROR_MESSAGES.PASSWORD_INCORRECT);
139
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
140
140
  }
141
141
 
142
142
  return user;
@@ -759,25 +759,31 @@ export class AuthenticationService {
759
759
  // });
760
760
  const user = await this.resolveUser(initiateForgotPasswordDto.username, initiateForgotPasswordDto.email);
761
761
 
762
+ let isValidUser = true // Instead of throwing exceptions we will simply return success message, this is to avoid user enumeration attacks.
762
763
  if (!user) {
763
- throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
764
+ isValidUser = false
765
+ // throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
764
766
  }
765
767
  if (!user.active) {
766
- throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
768
+ isValidUser = false
769
+ // throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
767
770
  }
768
771
 
769
772
  // 2. Validate if user has used a provider which is "local", only then it makes sense for us to initiate the forgot password routine.
770
773
  if (user.lastLoginProvider !== 'local') {
771
- throw new BadRequestException(ERROR_MESSAGES.INVALID_CREDENTIALS);
774
+ isValidUser = false
775
+ // throw new BadRequestException(ERROR_MESSAGES.INVALID_CREDENTIALS);
772
776
  }
773
777
 
774
778
  // 3. Generate a 6 digit validation token, we send this token to the user over their email & mobile number (controlled using configuration).
775
779
  // 4. Save this validation token in new fields on the user record.
776
- const { token, expiresAt } = this.generateForgotPasswordToken();
777
- user.verificationTokenOnForgotPassword = token;
778
- user.verificationTokenOnForgotPasswordExpiresAt = expiresAt;
779
- await this.userRepository.save(user);
780
- this.notifyUserOnForgotPassword(user);
780
+ if (isValidUser) {
781
+ const { token, expiresAt } = this.generateForgotPasswordToken();
782
+ user.verificationTokenOnForgotPassword = token;
783
+ user.verificationTokenOnForgotPasswordExpiresAt = expiresAt;
784
+ await this.userRepository.save(user);
785
+ this.notifyUserOnForgotPassword(user);
786
+ }
781
787
 
782
788
  // 5. Return.
783
789
  return {
@@ -788,8 +794,8 @@ export class AuthenticationService {
788
794
  data: {
789
795
  user: {
790
796
  email: user.email,
791
- mobile: user.mobile,
792
- username: user.username,
797
+ // mobile: user.mobile,
798
+ // username: user.username,
793
799
  },
794
800
  }
795
801
  }
@@ -841,8 +847,8 @@ export class AuthenticationService {
841
847
  return this.dataSource.transaction(async (m) => {
842
848
  // Resolve the user id first (by username/email), but DON'T check the token in JS.
843
849
  const user = await this.resolveUserByVerificationToken(confirmForgotPasswordDto.verificationToken);
844
- if (!user) throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
845
- if (user.lastLoginProvider !== 'local') throw new BadRequestException(ERROR_MESSAGES.INVALID_CREDENTIALS);
850
+ if (!user) throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
851
+ if (user.lastLoginProvider !== 'local') throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
846
852
  if (!user.active) throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
847
853
 
848
854
  // 1) Atomically consume the token (only one request can succeed)