@solidstarters/solid-core 1.2.201 → 1.2.202

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 (224) hide show
  1. package/dist/config/cache.options.d.ts +1 -1
  2. package/dist/config/cache.options.d.ts.map +1 -1
  3. package/dist/config/cache.options.js +2 -2
  4. package/dist/config/cache.options.js.map +1 -1
  5. package/dist/config/iam.config.d.ts +4 -0
  6. package/dist/config/iam.config.d.ts.map +1 -1
  7. package/dist/config/iam.config.js +2 -0
  8. package/dist/config/iam.config.js.map +1 -1
  9. package/dist/controllers/model-metadata.controller.d.ts +25 -0
  10. package/dist/controllers/model-metadata.controller.d.ts.map +1 -1
  11. package/dist/controllers/model-metadata.controller.js +23 -0
  12. package/dist/controllers/model-metadata.controller.js.map +1 -1
  13. package/dist/controllers/setting.controller.d.ts +1 -2
  14. package/dist/controllers/setting.controller.d.ts.map +1 -1
  15. package/dist/controllers/setting.controller.js +21 -42
  16. package/dist/controllers/setting.controller.js.map +1 -1
  17. package/dist/decorators/sms-provider.decorator.d.ts +3 -0
  18. package/dist/decorators/sms-provider.decorator.d.ts.map +1 -0
  19. package/dist/decorators/sms-provider.decorator.js +11 -0
  20. package/dist/decorators/sms-provider.decorator.js.map +1 -0
  21. package/dist/dtos/navigation.dto.d.ts +6 -0
  22. package/dist/dtos/navigation.dto.d.ts.map +1 -0
  23. package/dist/dtos/navigation.dto.js +33 -0
  24. package/dist/dtos/navigation.dto.js.map +1 -0
  25. package/dist/dtos/sign-in.dto.js +3 -3
  26. package/dist/dtos/sign-in.dto.js.map +1 -1
  27. package/dist/entities/common.entity.js +5 -4
  28. package/dist/entities/common.entity.js.map +1 -1
  29. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  30. package/dist/entities/field-metadata.entity.js +2 -1
  31. package/dist/entities/field-metadata.entity.js.map +1 -1
  32. package/dist/entities/legacy-common.entity.d.ts.map +1 -1
  33. package/dist/entities/legacy-common.entity.js +5 -4
  34. package/dist/entities/legacy-common.entity.js.map +1 -1
  35. package/dist/entities/model-metadata.entity.d.ts.map +1 -1
  36. package/dist/entities/model-metadata.entity.js +5 -1
  37. package/dist/entities/model-metadata.entity.js.map +1 -1
  38. package/dist/factories/mail.factory.d.ts.map +1 -1
  39. package/dist/factories/mail.factory.js.map +1 -1
  40. package/dist/factories/sms.factory.d.ts +14 -0
  41. package/dist/factories/sms.factory.d.ts.map +1 -0
  42. package/dist/factories/sms.factory.js +53 -0
  43. package/dist/factories/sms.factory.js.map +1 -0
  44. package/dist/helpers/date.helper.d.ts.map +1 -1
  45. package/dist/helpers/date.helper.js +13 -4
  46. package/dist/helpers/date.helper.js.map +1 -1
  47. package/dist/helpers/solid-registry.d.ts +3 -0
  48. package/dist/helpers/solid-registry.d.ts.map +1 -1
  49. package/dist/helpers/solid-registry.js +7 -0
  50. package/dist/helpers/solid-registry.js.map +1 -1
  51. package/dist/index.d.ts +9 -6
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +9 -6
  54. package/dist/index.js.map +1 -1
  55. package/dist/jobs/database/{sms-publisher-database.service.d.ts → msg91-sms-publisher-database.service.d.ts} +2 -2
  56. package/dist/jobs/database/msg91-sms-publisher-database.service.d.ts.map +1 -0
  57. package/dist/jobs/database/{sms-publisher-database.service.js → msg91-sms-publisher-database.service.js} +8 -8
  58. package/dist/jobs/database/msg91-sms-publisher-database.service.js.map +1 -0
  59. package/dist/jobs/database/{sms-queue-database-options.d.ts → msg91-sms-queue-database-options.d.ts} +1 -1
  60. package/dist/jobs/database/msg91-sms-queue-database-options.d.ts.map +1 -0
  61. package/dist/jobs/database/{sms-queue-database-options.js → msg91-sms-queue-database-options.js} +1 -1
  62. package/dist/jobs/database/msg91-sms-queue-database-options.js.map +1 -0
  63. package/dist/jobs/database/{sms-subscriber-database.service.d.ts → msg91-sms-subscriber-database.service.d.ts} +5 -5
  64. package/dist/jobs/database/msg91-sms-subscriber-database.service.d.ts.map +1 -0
  65. package/dist/jobs/database/{sms-subscriber-database.service.js → msg91-sms-subscriber-database.service.js} +14 -12
  66. package/dist/jobs/database/msg91-sms-subscriber-database.service.js.map +1 -0
  67. package/dist/jobs/database/otp-subscriber-database.service.d.ts +4 -4
  68. package/dist/jobs/database/otp-subscriber-database.service.d.ts.map +1 -1
  69. package/dist/jobs/database/otp-subscriber-database.service.js +6 -4
  70. package/dist/jobs/database/otp-subscriber-database.service.js.map +1 -1
  71. package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts +3 -3
  72. package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts.map +1 -1
  73. package/dist/jobs/database/twilio-sms-subscriber-database.service.js +6 -4
  74. package/dist/jobs/database/twilio-sms-subscriber-database.service.js.map +1 -1
  75. package/dist/jobs/{sms-publisher.service.d.ts → msg91-otp-publisher.service.d.ts} +2 -2
  76. package/dist/jobs/msg91-otp-publisher.service.d.ts.map +1 -0
  77. package/dist/jobs/{sms-publisher.service.js → msg91-otp-publisher.service.js} +8 -8
  78. package/dist/jobs/msg91-otp-publisher.service.js.map +1 -0
  79. package/dist/jobs/{sms-queue-options.d.ts → msg91-otp-queue-options.d.ts} +1 -1
  80. package/dist/jobs/msg91-otp-queue-options.d.ts.map +1 -0
  81. package/dist/jobs/{otp-queue-options.js → msg91-otp-queue-options.js} +1 -1
  82. package/dist/jobs/msg91-otp-queue-options.js.map +1 -0
  83. package/dist/jobs/{sms-subscriber.service.d.ts → msg91-otp-subscriber.service.d.ts} +6 -6
  84. package/dist/jobs/msg91-otp-subscriber.service.d.ts.map +1 -0
  85. package/dist/jobs/{otp-subscriber.service.js → msg91-otp-subscriber.service.js} +14 -12
  86. package/dist/jobs/msg91-otp-subscriber.service.js.map +1 -0
  87. package/dist/jobs/{otp-publisher.service.d.ts → msg91-sms-publisher.service.d.ts} +2 -2
  88. package/dist/jobs/msg91-sms-publisher.service.d.ts.map +1 -0
  89. package/dist/jobs/{otp-publisher.service.js → msg91-sms-publisher.service.js} +8 -8
  90. package/dist/jobs/msg91-sms-publisher.service.js.map +1 -0
  91. package/dist/jobs/{otp-queue-options.d.ts → msg91-sms-queue-options.d.ts} +1 -1
  92. package/dist/jobs/msg91-sms-queue-options.d.ts.map +1 -0
  93. package/dist/jobs/{sms-queue-options.js → msg91-sms-queue-options.js} +1 -1
  94. package/dist/jobs/msg91-sms-queue-options.js.map +1 -0
  95. package/dist/jobs/{otp-subscriber.service.d.ts → msg91-sms-subscriber.service.d.ts} +7 -7
  96. package/dist/jobs/msg91-sms-subscriber.service.d.ts.map +1 -0
  97. package/dist/jobs/{sms-subscriber.service.js → msg91-sms-subscriber.service.js} +14 -12
  98. package/dist/jobs/msg91-sms-subscriber.service.js.map +1 -0
  99. package/dist/jobs/twilio-sms-subscriber.service.d.ts +3 -3
  100. package/dist/jobs/twilio-sms-subscriber.service.d.ts.map +1 -1
  101. package/dist/jobs/twilio-sms-subscriber.service.js +6 -4
  102. package/dist/jobs/twilio-sms-subscriber.service.js.map +1 -1
  103. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  104. package/dist/seeders/module-metadata-seeder.service.js +23 -1
  105. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  106. package/dist/seeders/seed-data/solid-core-metadata.json +30 -25
  107. package/dist/seeders/user-seeder.service.d.ts.map +1 -1
  108. package/dist/seeders/user-seeder.service.js +5 -4
  109. package/dist/seeders/user-seeder.service.js.map +1 -1
  110. package/dist/services/authentication.service.d.ts +6 -3
  111. package/dist/services/authentication.service.d.ts.map +1 -1
  112. package/dist/services/authentication.service.js +48 -13
  113. package/dist/services/authentication.service.js.map +1 -1
  114. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  115. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  116. package/dist/services/crud.service.d.ts +1 -2
  117. package/dist/services/crud.service.d.ts.map +1 -1
  118. package/dist/services/crud.service.js.map +1 -1
  119. package/dist/services/excel.service.d.ts +1 -0
  120. package/dist/services/excel.service.d.ts.map +1 -1
  121. package/dist/services/excel.service.js +4 -0
  122. package/dist/services/excel.service.js.map +1 -1
  123. package/dist/services/model-metadata.service.d.ts +28 -1
  124. package/dist/services/model-metadata.service.d.ts.map +1 -1
  125. package/dist/services/model-metadata.service.js +109 -2
  126. package/dist/services/model-metadata.service.js.map +1 -1
  127. package/dist/services/setting.service.d.ts.map +1 -1
  128. package/dist/services/setting.service.js +3 -45
  129. package/dist/services/setting.service.js.map +1 -1
  130. package/dist/services/sms/Msg91BaseSMSService.js +6 -6
  131. package/dist/services/sms/Msg91BaseSMSService.js.map +1 -1
  132. package/dist/services/sms/Msg91OTPService.d.ts.map +1 -1
  133. package/dist/services/sms/Msg91OTPService.js +3 -1
  134. package/dist/services/sms/Msg91OTPService.js.map +1 -1
  135. package/dist/services/sms/Msg91SMSService.d.ts.map +1 -1
  136. package/dist/services/sms/Msg91SMSService.js +3 -1
  137. package/dist/services/sms/Msg91SMSService.js.map +1 -1
  138. package/dist/services/sms/TwilioSMSService.d.ts.map +1 -1
  139. package/dist/services/sms/TwilioSMSService.js +2 -0
  140. package/dist/services/sms/TwilioSMSService.js.map +1 -1
  141. package/dist/services/solid-introspect.service.d.ts +1 -0
  142. package/dist/services/solid-introspect.service.d.ts.map +1 -1
  143. package/dist/services/solid-introspect.service.js +14 -0
  144. package/dist/services/solid-introspect.service.js.map +1 -1
  145. package/dist/solid-core-cli.module.js +1 -1
  146. package/dist/solid-core-cli.module.js.map +1 -1
  147. package/dist/solid-core.module.d.ts.map +1 -1
  148. package/dist/solid-core.module.js +22 -13
  149. package/dist/solid-core.module.js.map +1 -1
  150. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
  151. package/dist/subscribers/scheduled-job.subscriber.js +1 -1
  152. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  153. package/dist/transformers/typeorm/local-date-time-transformer.d.ts +2 -2
  154. package/dist/transformers/typeorm/local-date-time-transformer.d.ts.map +1 -1
  155. package/dist/transformers/typeorm/local-date-time-transformer.js +28 -6
  156. package/dist/transformers/typeorm/local-date-time-transformer.js.map +1 -1
  157. package/dist/tsconfig.tsbuildinfo +1 -1
  158. package/package.json +1 -1
  159. package/src/config/cache.options.ts +6 -3
  160. package/src/config/iam.config.ts +2 -1
  161. package/src/controllers/model-metadata.controller.ts +21 -1
  162. package/src/controllers/setting.controller.ts +32 -36
  163. package/src/decorators/sms-provider.decorator.ts +7 -0
  164. package/src/dtos/navigation.dto.ts +14 -0
  165. package/src/dtos/sign-in.dto.ts +3 -3
  166. package/src/entities/common.entity.ts +7 -7
  167. package/src/entities/field-metadata.entity.ts +1 -1
  168. package/src/entities/legacy-common.entity.ts +6 -5
  169. package/src/entities/model-metadata.entity.ts +1 -1
  170. package/src/factories/mail.factory.ts +0 -1
  171. package/src/factories/sms.factory.ts +43 -0
  172. package/src/helpers/date.helper.ts +38 -9
  173. package/src/helpers/solid-registry.ts +9 -0
  174. package/src/index.ts +9 -6
  175. package/src/jobs/database/{sms-publisher-database.service.ts → msg91-sms-publisher-database.service.ts} +2 -2
  176. package/src/jobs/database/{sms-subscriber-database.service.ts → msg91-sms-subscriber-database.service.ts} +9 -4
  177. package/src/jobs/database/otp-subscriber-database.service.ts +8 -2
  178. package/src/jobs/database/twilio-sms-subscriber-database.service.ts +5 -2
  179. package/src/jobs/{otp-publisher.service.ts → msg91-otp-publisher.service.ts} +2 -2
  180. package/src/jobs/{otp-subscriber.service.ts → msg91-otp-subscriber.service.ts} +10 -4
  181. package/src/jobs/{sms-publisher.service.ts → msg91-sms-publisher.service.ts} +2 -2
  182. package/src/jobs/{sms-subscriber.service.ts → msg91-sms-subscriber.service.ts} +9 -4
  183. package/src/jobs/twilio-sms-subscriber.service.ts +6 -2
  184. package/src/seeders/module-metadata-seeder.service.ts +30 -5
  185. package/src/seeders/seed-data/email-templates/email-on-signup.handlebars.html +155 -0
  186. package/src/seeders/seed-data/sms-templates/text-on-signup.handlebars.txt +10 -0
  187. package/src/seeders/seed-data/solid-core-metadata.json +31 -26
  188. package/src/seeders/user-seeder.service.ts +5 -4
  189. package/src/services/authentication.service.ts +73 -10
  190. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +1 -2
  191. package/src/services/crud.service.ts +17 -18
  192. package/src/services/excel.service.ts +6 -0
  193. package/src/services/model-metadata.service.ts +151 -0
  194. package/src/services/setting.service.ts +12 -52
  195. package/src/services/sms/Msg91BaseSMSService.ts +6 -6
  196. package/src/services/sms/Msg91OTPService.ts +3 -2
  197. package/src/services/sms/Msg91SMSService.ts +3 -1
  198. package/src/services/sms/TwilioSMSService.ts +3 -3
  199. package/src/services/solid-introspect.service.ts +22 -0
  200. package/src/solid-core-cli.module.ts +2 -2
  201. package/src/solid-core.module.ts +24 -13
  202. package/src/subscribers/scheduled-job.subscriber.ts +9 -2
  203. package/src/transformers/typeorm/local-date-time-transformer.ts +38 -13
  204. package/dist/jobs/database/sms-publisher-database.service.d.ts.map +0 -1
  205. package/dist/jobs/database/sms-publisher-database.service.js.map +0 -1
  206. package/dist/jobs/database/sms-queue-database-options.d.ts.map +0 -1
  207. package/dist/jobs/database/sms-queue-database-options.js.map +0 -1
  208. package/dist/jobs/database/sms-subscriber-database.service.d.ts.map +0 -1
  209. package/dist/jobs/database/sms-subscriber-database.service.js.map +0 -1
  210. package/dist/jobs/otp-publisher.service.d.ts.map +0 -1
  211. package/dist/jobs/otp-publisher.service.js.map +0 -1
  212. package/dist/jobs/otp-queue-options.d.ts.map +0 -1
  213. package/dist/jobs/otp-queue-options.js.map +0 -1
  214. package/dist/jobs/otp-subscriber.service.d.ts.map +0 -1
  215. package/dist/jobs/otp-subscriber.service.js.map +0 -1
  216. package/dist/jobs/sms-publisher.service.d.ts.map +0 -1
  217. package/dist/jobs/sms-publisher.service.js.map +0 -1
  218. package/dist/jobs/sms-queue-options.d.ts.map +0 -1
  219. package/dist/jobs/sms-queue-options.js.map +0 -1
  220. package/dist/jobs/sms-subscriber.service.d.ts.map +0 -1
  221. package/dist/jobs/sms-subscriber.service.js.map +0 -1
  222. /package/src/jobs/database/{sms-queue-database-options.ts → msg91-sms-queue-database-options.ts} +0 -0
  223. /package/src/jobs/{otp-queue-options.ts → msg91-otp-queue-options.ts} +0 -0
  224. /package/src/jobs/{sms-queue-options.ts → msg91-sms-queue-options.ts} +0 -0
@@ -49,6 +49,7 @@ import { RoleMetadataService } from './role-metadata.service';
49
49
  import { SettingService } from './setting.service';
50
50
  import { UserActivityHistoryService } from './user-activity-history.service';
51
51
  import { UserService } from './user.service';
52
+ import { SmsFactory } from 'src/factories/sms.factory';
52
53
 
53
54
  enum LoginProvider {
54
55
  LOCAL = 'local',
@@ -79,7 +80,8 @@ export class AuthenticationService {
79
80
  private readonly httpService: HttpService,
80
81
  // private readonly mailService: SMTPEMailService,
81
82
  private readonly mailServiceFactory: MailFactory,
82
- private readonly smsService: Msg91OTPService,
83
+ // private readonly smsService: Msg91OTPService,
84
+ private readonly smsFactory: SmsFactory,
83
85
  private readonly eventEmitter: EventEmitter2,
84
86
  private readonly settingService: SettingService,
85
87
  private readonly roleMetadataService: RoleMetadataService,
@@ -197,7 +199,7 @@ export class AuthenticationService {
197
199
  // Merge the extended signUpDto attributes into the user entity
198
200
  //@ts-ignore
199
201
  const extensionUser = extensionUserRepo.merge(extensionUserRepo.create() as T, extensionUserDto);
200
- var { user, pwd, autoGeneratedPwd } = await this.populateForSignup<T>(extensionUser, signUpDto, true, onForcePasswordChange);
202
+ var { user, pwd, autoGeneratedPwd } = await this.populateForSignup<T>(extensionUser, signUpDto, extensionUserDto.active ?? true, onForcePasswordChange);
201
203
  const savedUser = await extensionUserRepo.save(user);
202
204
 
203
205
  await this.handlePostSignup(savedUser, signUpDto.roles, pwd, autoGeneratedPwd);
@@ -278,6 +280,9 @@ export class AuthenticationService {
278
280
  if (user.forcePasswordChange && autoGeneratedPwd) {
279
281
  this.notifyUserOnForcePasswordChange(user, autoGeneratedPwd);
280
282
  }
283
+
284
+ // Send welcome notifications (email/SMS) if enabled.
285
+ await this.notifyUserOnSignup(user);
281
286
  }
282
287
 
283
288
 
@@ -323,6 +328,56 @@ export class AuthenticationService {
323
328
 
324
329
  }
325
330
 
331
+ private isWelcomeEmailEnabled(): boolean {
332
+ return this.iamConfiguration.sendWelcomeEmailOnSignup;
333
+ }
334
+
335
+ private isWelcomeSmsEnabled(): boolean {
336
+ return this.iamConfiguration.sendWelcomeSmsOnSignup;
337
+ }
338
+
339
+ private async notifyUserOnSignup(user: User) {
340
+ const companyLogo = await this.getCompanyLogo();
341
+ // Email welcome
342
+ if (this.isWelcomeEmailEnabled()) {
343
+ const mailService = this.mailServiceFactory.getMailService();
344
+ mailService.sendEmailUsingTemplate(
345
+ user.email,
346
+ 'email-on-signup',
347
+ {
348
+ solidAppName: process.env.SOLID_APP_NAME,
349
+ solidAppWebsiteUrl: process.env.SOLID_APP_WEBSITE_URL,
350
+ frontendLoginPageUrl: process.env.IAM_FRONTEND_APP_LOGIN_PAGE_URL,
351
+ email: user.email,
352
+ fullName: user.fullName,
353
+ userName: user.username,
354
+ companyLogoUrl: companyLogo
355
+ },
356
+ this.commonConfiguration.shouldQueueEmails,
357
+ null,
358
+ null,
359
+ 'user',
360
+ user.id
361
+ );
362
+ }
363
+
364
+ // SMS welcome
365
+ if (this.isWelcomeSmsEnabled() && user.mobile) {
366
+ const smsService = this.smsFactory.getSmsService();
367
+ smsService.sendSMSUsingTemplate(
368
+ user.mobile,
369
+ 'text-on-signup',
370
+ {
371
+ solidAppName: process.env.SOLID_APP_NAME,
372
+ frontendLoginPageUrl: process.env.IAM_FRONTEND_APP_LOGIN_PAGE_URL,
373
+ firstName: user.username,
374
+ fullName: user.fullName ? user.fullName : user.username
375
+ },
376
+ this.commonConfiguration.shouldQueueSms,
377
+ );
378
+ }
379
+ }
380
+
326
381
  async otpInitiateRegistration(signUpDto: OTPSignUpDto) {
327
382
  try {
328
383
  if (!this.isPasswordlessRegistrationEnabled()) {
@@ -444,7 +499,8 @@ export class AuthenticationService {
444
499
  );
445
500
  }
446
501
  if (registrationValidationSources.includes(RegistrationValidationSource.MOBILE)) {
447
- this.smsService.sendSMSUsingTemplate(
502
+ const smsService = this.smsFactory.getSmsService();
503
+ smsService.sendSMSUsingTemplate(
448
504
  user.mobile,
449
505
  'otp-on-register',
450
506
  {
@@ -454,7 +510,8 @@ export class AuthenticationService {
454
510
  firstName: user.username,
455
511
  fullName: user.fullName ? user.fullName : user.username,
456
512
  companyLogoUrl: companyLogo
457
- }
513
+ },
514
+ this.commonConfiguration.shouldQueueSms,
458
515
  );
459
516
  }
460
517
  }
@@ -649,7 +706,8 @@ export class AuthenticationService {
649
706
  );
650
707
  }
651
708
  if (loginType === RegistrationValidationSource.MOBILE) {
652
- this.smsService.sendSMSUsingTemplate(
709
+ const smsService = this.smsFactory.getSmsService();
710
+ smsService.sendSMSUsingTemplate(
653
711
  user.mobile,
654
712
  'otp-on-login',
655
713
  {
@@ -659,7 +717,8 @@ export class AuthenticationService {
659
717
  firstName: user.username,
660
718
  fullName: user.fullName ? user.fullName : user.username,
661
719
  companyLogoUrl: companyLogo
662
- }
720
+ },
721
+ this.commonConfiguration.shouldQueueSms,
663
722
  );
664
723
  }
665
724
  }
@@ -888,7 +947,8 @@ export class AuthenticationService {
888
947
  }
889
948
  // Assuming all users do not have mobile as mandatory.
890
949
  if (forgotPasswordSendVerificationTokenOn == ForgotPasswordSendVerificationTokenOn.MOBILE && user.mobile) {
891
- this.smsService.sendSMSUsingTemplate(
950
+ const smsService = this.smsFactory.getSmsService();
951
+ smsService.sendSMSUsingTemplate(
892
952
  user.mobile,
893
953
  'forgot-password',
894
954
  {
@@ -897,7 +957,8 @@ export class AuthenticationService {
897
957
  verificationTokenOnForgotPassword: user.verificationTokenOnForgotPassword,
898
958
  firstName: user.username,
899
959
  companyLogoUrl: companyLogo
900
- }
960
+ },
961
+ this.commonConfiguration.shouldQueueSms,
901
962
  );
902
963
  }
903
964
  }
@@ -977,7 +1038,8 @@ export class AuthenticationService {
977
1038
  }
978
1039
  // Assuming all users do not have mobile as mandatory.
979
1040
  if (forgotPasswordSendVerificationTokenOn == ForgotPasswordSendVerificationTokenOn.MOBILE && user.mobile) {
980
- this.smsService.sendSMSUsingTemplate(
1041
+ const smsService = this.smsFactory.getSmsService();
1042
+ smsService.sendSMSUsingTemplate(
981
1043
  user.mobile,
982
1044
  'forgot-password',
983
1045
  {
@@ -986,7 +1048,8 @@ export class AuthenticationService {
986
1048
  verificationTokenOnForgotPassword: user.verificationTokenOnForgotPassword,
987
1049
  firstName: user.username,
988
1050
  companyLogoUrl: companyLogo
989
- }
1051
+ },
1052
+ this.commonConfiguration.shouldQueueSms,
990
1053
  );
991
1054
  }
992
1055
  }
@@ -28,8 +28,7 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
28
28
  return 'Provider used to compute external ID for a CommonEntity with support for static or dynamic prefix.';
29
29
  }
30
30
 
31
- async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>
32
- ) {
31
+ async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>) {
33
32
  const { prefix, length, dynamicFieldPrefix } = computedFieldMetadata.computedFieldValueProviderCtxt;
34
33
  const eventContext = computedFieldMetadata.eventContext;
35
34
  const entityName = eventContext?.metadataName ?? eventContext.databaseEntity?.constructor?.name ?? '';
@@ -1,8 +1,8 @@
1
- import { BadRequestException, Inject, NotFoundException } from "@nestjs/common";
1
+ import { BadRequestException, NotFoundException } from "@nestjs/common";
2
2
  import { ConfigService } from "@nestjs/config";
3
3
  import { DiscoveryService, ModuleRef } from "@nestjs/core";
4
4
  import { isArray } from "class-validator";
5
- import { CommonEntity, SolidBaseRepository, User } from "src";
5
+ import { CommonEntity, FileService, SolidBaseRepository, User } from "src";
6
6
  import { ERROR_MESSAGES } from "src/constants/error-messages";
7
7
  import { SUCCESS_MESSAGES } from "src/constants/success-messages";
8
8
  import { EntityManager, FindOptionsWhere, In, IsNull, Not, QueryFailedError, SelectQueryBuilder } from "typeorm";
@@ -34,7 +34,6 @@ import { ShortTextFieldCrudManager } from "../helpers/field-crud-managers/ShortT
34
34
  import { UUIDFieldCrudManager } from "../helpers/field-crud-managers/UUIDFieldCrudManager";
35
35
  import { FieldCrudManager, MediaWithFullUrl } from "../interfaces";
36
36
  import { CrudHelperService, FilterCombinator, UserIdFields } from "./crud-helper.service";
37
- import { FileService } from "./file.service";
38
37
  import { HashingService } from "./hashing.service";
39
38
  import { getMediaStorageProvider } from "./mediaStorageProviders";
40
39
  import { ModelMetadataService } from "./model-metadata.service";
@@ -45,19 +44,19 @@ import { BasicGroupFilterDto } from "src/dtos/basic-group-filters.dto";
45
44
  export class CRUDService<T extends CommonEntity> { // Add two generic value i.e Person,CreatePersonDto, so we get the proper types in our service
46
45
 
47
46
  constructor(
48
- readonly modelMetadataService: ModelMetadataService,
49
- readonly moduleMetadataService: ModuleMetadataService,
50
- readonly configService: ConfigService,
51
- readonly fileService: FileService,
52
- readonly discoveryService: DiscoveryService,
53
- readonly crudHelperService: CrudHelperService,
47
+ readonly modelMetadataService: ModelMetadataService, // go away
48
+ readonly moduleMetadataService: ModuleMetadataService, // go away
49
+ readonly configService: ConfigService, // we don't use it - go away
50
+ readonly fileService: FileService, // we don't use it - go away
51
+ readonly discoveryService: DiscoveryService, // go away
52
+ readonly crudHelperService: CrudHelperService, // go away
54
53
  readonly entityManager: EntityManager,
55
54
  readonly repo: SolidBaseRepository<T>,
56
55
  readonly modelName: string,
57
56
  readonly moduleName: string,
58
57
  readonly moduleRef: ModuleRef,
59
- readonly defaultEntityManager? : EntityManager
60
-
58
+ readonly defaultEntityManager?: EntityManager
59
+
61
60
  //We can just have the Model Entity here
62
61
  ) { }
63
62
 
@@ -435,11 +434,11 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
435
434
  }
436
435
 
437
436
  private isSkipComputation(isPartialUpdate: boolean, computedFieldMetadata: FieldMetadata) {
438
- if (isPartialUpdate) return true; // If it is a partial update, then skip computation
439
- if (computedFieldMetadata.computedFieldTriggerConfig && computedFieldMetadata.computedFieldTriggerConfig.length > 0) {
440
- return true; // computedFieldTriggerConfig is a new field introduced as part of the IEntityComputedFieldProvider new interface, so this computation will be skiipped in crud service & will be called in the subscriber instead
441
- }
442
- return false; // If it is not a partial update, then do not skip computation
437
+ if (isPartialUpdate) return true; // If it is a partial update, then skip computation
438
+ if (computedFieldMetadata.computedFieldTriggerConfig && computedFieldMetadata.computedFieldTriggerConfig.length > 0) {
439
+ return true; // computedFieldTriggerConfig is a new field introduced as part of the IEntityComputedFieldProvider new interface, so this computation will be skiipped in crud service & will be called in the subscriber instead
440
+ }
441
+ return false; // If it is not a partial update, then do not skip computation
443
442
  }
444
443
 
445
444
  async find(basicFilterDto: BasicFilterDto, solidRequestContext: any = {}) {
@@ -705,7 +704,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
705
704
  return mediaDetails as MediaWithFullUrl[];
706
705
  }
707
706
 
708
- async findOne(id: number, query: any={}, solidRequestContext: any = {}) {
707
+ async findOne(id: number, query: any = {}, solidRequestContext: any = {}) {
709
708
  const { populate = [], fields = [], populateMedia = [] } = query;
710
709
 
711
710
  // const normalizedFields = this.crudHelperService.normalize(fields);
@@ -1065,7 +1064,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
1065
1064
  return updatedEntity
1066
1065
  }
1067
1066
 
1068
- private getDefaultEntityManager(){
1067
+ private getDefaultEntityManager() {
1069
1068
  return this.defaultEntityManager ?? this.entityManager;
1070
1069
  }
1071
1070
  }
@@ -1,6 +1,7 @@
1
1
  import { Injectable, Logger } from '@nestjs/common';
2
2
  import * as ExcelJS from 'exceljs';
3
3
  import { ERROR_MESSAGES } from 'src/constants/error-messages';
4
+ import { parseFlexibleDate } from 'src/helpers/date.helper';
4
5
  import { PassThrough, Readable } from 'stream';
5
6
 
6
7
  export interface ExcelReadOptions {
@@ -302,4 +303,9 @@ export class ExcelService {
302
303
 
303
304
  return { headers, rows };
304
305
  }
306
+
307
+ public parseAndValidateDate(value: string): Date | null {
308
+ return parseFlexibleDate(value);
309
+ }
310
+
305
311
  }
@@ -30,6 +30,9 @@ import { CrudHelperService } from './crud-helper.service';
30
30
  import { FieldMetadataService } from './field-metadata.service';
31
31
  import { MediaStorageProviderMetadataService } from './media-storage-provider-metadata.service';
32
32
  import { RoleMetadataService } from './role-metadata.service';
33
+ import { NavigationDto } from 'src/dtos/navigation.dto';
34
+ import { SolidIntrospectService } from './solid-introspect.service';
35
+ import { CRUDService } from './crud.service';
33
36
 
34
37
  @Injectable()
35
38
  export class ModelMetadataService {
@@ -50,6 +53,8 @@ export class ModelMetadataService {
50
53
  private readonly fieldMetadataService: FieldMetadataService,
51
54
  private readonly roleService: RoleMetadataService,
52
55
  private readonly moduleMetadataHelperService: ModuleMetadataHelperService,
56
+ readonly introspectService: SolidIntrospectService,
57
+
53
58
  // No longer used.
54
59
  // private readonly generateCodePublihser: GenerateCodePublisherDatabase,
55
60
  ) { }
@@ -1291,4 +1296,150 @@ export class ModelMetadataService {
1291
1296
  });
1292
1297
  }
1293
1298
 
1299
+ async navigation(navigationDto: NavigationDto) {
1300
+ const { recordId, modelName, ...basicFilterDto } = navigationDto;
1301
+
1302
+ const modelServiceInstanceWrapper =
1303
+ this.introspectService.getProvider(`${classify(modelName)}Service`);
1304
+
1305
+ if (!modelServiceInstanceWrapper) {
1306
+ throw new BadRequestException(
1307
+ `Invalid model name (${modelName}) specified in Navigation.`,
1308
+ );
1309
+ }
1310
+
1311
+ const modelService: CRUDService<any> = modelServiceInstanceWrapper.instance;
1312
+
1313
+ const recs = await modelService.find(basicFilterDto);
1314
+
1315
+ // navigation only works for paginated results
1316
+ if (!('records' in recs) || !('currentPage' in recs.meta)) {
1317
+ return {
1318
+ prev: null,
1319
+ next: null,
1320
+ meta: null,
1321
+ };
1322
+ }
1323
+
1324
+ const { records, meta } = recs;
1325
+
1326
+ // --------------------
1327
+ // Find record index in page
1328
+ // --------------------
1329
+ const index = records.findIndex(r => String(r.id) === String(recordId));
1330
+
1331
+ if (index === -1) {
1332
+ throw new BadRequestException(`Record not found in current page`);
1333
+ }
1334
+
1335
+ // --------------------
1336
+ // Pagination calculations
1337
+ // --------------------
1338
+ const limit = meta.perPage;
1339
+ const currentOffset = (meta.currentPage - 1) * meta.perPage;
1340
+ const currentIndexGlobal = currentOffset + index + 1;
1341
+
1342
+
1343
+ let prev: { record: any; offset: number; limit: number } | null = null;
1344
+ let next: { record: any; offset: number; limit: number } | null = null;
1345
+
1346
+ // --------------------
1347
+ // PREV
1348
+ // --------------------
1349
+ if (index > 0) {
1350
+ prev = {
1351
+ record: records[index - 1],
1352
+ offset: currentOffset,
1353
+ limit,
1354
+ };
1355
+ } else if (meta.prevPage !== null) {
1356
+ const prevOffset = (meta.prevPage - 1) * meta.perPage;
1357
+
1358
+ const prevPage = await modelService.find({
1359
+ ...basicFilterDto,
1360
+ offset: prevOffset,
1361
+ limit,
1362
+ });
1363
+
1364
+ if ('records' in prevPage) {
1365
+ const record = prevPage.records.at(-1) ?? null;
1366
+ if (record) {
1367
+ prev = {
1368
+ record,
1369
+ offset: prevOffset,
1370
+ limit,
1371
+ };
1372
+ }
1373
+ }
1374
+ }
1375
+
1376
+ // --------------------
1377
+ // NEXT
1378
+ // --------------------
1379
+ if (index < records.length - 1) {
1380
+ next = {
1381
+ record: records[index + 1],
1382
+ offset: currentOffset,
1383
+ limit,
1384
+ };
1385
+ } else if (meta.nextPage !== null) {
1386
+ const nextOffset = (meta.nextPage - 1) * meta.perPage;
1387
+
1388
+ const nextPage = await modelService.find({
1389
+ ...basicFilterDto,
1390
+ offset: nextOffset,
1391
+ limit,
1392
+ });
1393
+
1394
+ if ('records' in nextPage) {
1395
+ const record = nextPage.records[0] ?? null;
1396
+ if (record) {
1397
+ next = {
1398
+ record,
1399
+ offset: nextOffset,
1400
+ limit,
1401
+ };
1402
+ }
1403
+ }
1404
+ }
1405
+
1406
+ // --------------------
1407
+ // RESPONSE
1408
+ // --------------------
1409
+ return {
1410
+ prev: prev
1411
+ ? {
1412
+ recordId: prev.record.id,
1413
+ offset: prev.offset,
1414
+ limit: prev.limit,
1415
+ }
1416
+ : null,
1417
+
1418
+ next: next
1419
+ ? {
1420
+ recordId: next.record.id,
1421
+ offset: next.offset,
1422
+ limit: next.limit,
1423
+ }
1424
+ : null,
1425
+ meta: {
1426
+ totalRecords: meta.totalRecords,
1427
+ perPage: meta.perPage,
1428
+ currentPage: meta.currentPage,
1429
+ totalPages: meta.totalPages,
1430
+
1431
+ currentIndexInPage: index,
1432
+ currentIndexGlobal,
1433
+
1434
+ hasPrev: !!prev,
1435
+ hasNext: !!next,
1436
+
1437
+ prevPage: meta.prevPage,
1438
+ nextPage: meta.nextPage,
1439
+ },
1440
+
1441
+ };
1442
+ }
1443
+
1444
+
1294
1445
  }
@@ -46,49 +46,7 @@ export class SettingService extends CRUDService<Setting> {
46
46
  }
47
47
 
48
48
  async seedDefaultSettings(): Promise<void> {
49
- const settingsSeederData = {
50
- passwordlessRegistrationValidateWhat: this.iamConfiguration.passwordlessRegistrationValidateWhat,
51
- allowPublicRegistration: this.iamConfiguration.allowPublicRegistration,
52
- passwordBasedAuth: this.iamConfiguration.passwordBasedAuth,
53
- passwordLessAuth: this.iamConfiguration.passwordLessAuth,
54
- activateUserOnRegistration: this.iamConfiguration.activateUserOnRegistration,
55
- iamGoogleOAuthEnabled: false,
56
- authPagesLayout: "center",
57
- authPagesTheme: "light",
58
- appLogo: null,
59
- companylogo: null,
60
- favicon: null,
61
- appLogoPosition: "in_form_view",
62
- showAuthContent: false,
63
- appTitle: process.env.SOLID_APP_NAME || "Solid App",
64
- appSubtitle: process.env.SOLID_APP_SUBTITLE || "Lorem Ipsum",
65
- appDescription: process.env.SOLID_APP_DESCRIPTION || "lorem ipsum",
66
- showLegalLinks: false,
67
- appTnc: null,
68
- appPrivacyPolicy: null,
69
- defaultRole: this.iamConfiguration.defaultRole,
70
- shouldQueueEmails: this.commonConfiguration.shouldQueueEmails,
71
- shouldQueueSms: this.commonConfiguration.shouldQueueSms,
72
- enableDarkMode: true,
73
- copyright: null,
74
- enableUsername: true,
75
- enabledNotification: true,
76
- contactSupportEmail: null,
77
- contactSupportDisplayName: null,
78
- contactSupportIcon: null,
79
- authScreenRightBackgroundImage: null,
80
- authScreenLeftBackgroundImage: null,
81
- authScreenCenterBackgroundImage: null,
82
- authenticationPasswordRegex: this.iamConfiguration.PASSWORD_REGEX,
83
- authenticationPasswordRegexErrorMessage: this.iamConfiguration.PASSWORD_REGEX_ERROR_MESSAGE,
84
- authenticationPasswordComplexityDescription: this.iamConfiguration.PASSWORD_COMPLEXITY_DESC,
85
- solidXGenAiCodeBuilderConfig: JSON.stringify({
86
- defaultProvider: "",
87
- availableProviders: []
88
- }),
89
- showNameFieldsForRegistration: this.iamConfiguration.showNameFieldsForRegistration,
90
- forceChangePasswordOnFirstLogin: this.iamConfiguration.forceChangePasswordOnFirstLogin
91
- };
49
+ const settingsSeederData = this.getDefaultSettings();
92
50
 
93
51
  const existingSettings = await this.repo.find();
94
52
  const existingKeys = new Set(existingSettings.map(s => s.key));
@@ -178,11 +136,12 @@ export class SettingService extends CRUDService<Setting> {
178
136
  appLogo: null,
179
137
  companylogo: null,
180
138
  favicon: null,
181
- appLogoPosition: "in_form_view", //in_form_view | in_image_view
139
+ // in_form_view | in_image_view
140
+ appLogoPosition: "in_form_view",
182
141
  showAuthContent: false,
183
142
  appTitle: process.env.SOLID_APP_NAME || "Solid App",
184
- appSubtitle: null,
185
- appDescription: null,
143
+ appSubtitle: process.env.SOLID_APP_SUBTITLE || "",
144
+ appDescription: process.env.SOLID_APP_DESCRIPTION || "",
186
145
  showLegalLinks: false,
187
146
  appTnc: null,
188
147
  appPrivacyPolicy: null,
@@ -212,6 +171,10 @@ export class SettingService extends CRUDService<Setting> {
212
171
  };
213
172
  }
214
173
 
174
+ // private async getSettingsFromRepo(): Promise<Setting[]> {
175
+ // const cachedSettings = await this.cacheManager.get('cached-system-settings');
176
+ // }
177
+
215
178
  async getConfigValue(settingKey: string) {
216
179
  try {
217
180
  const settingsArray: Setting[] = await this.repo.find();
@@ -242,10 +205,7 @@ export class SettingService extends CRUDService<Setting> {
242
205
  }
243
206
  }
244
207
 
245
- async updateSettings(
246
- settings: CreateSettingDto[] = [],
247
- uploadedFiles: Array<Express.Multer.File> = []
248
- ): Promise<Setting[]> {
208
+ async updateSettings(settings: CreateSettingDto[] = [], uploadedFiles: Array<Express.Multer.File> = []): Promise<Setting[]> {
249
209
  const activeUser = this.requestContextService.getActiveUser();
250
210
  const userId = activeUser?.sub;
251
211
 
@@ -381,8 +341,8 @@ export class SettingService extends CRUDService<Setting> {
381
341
 
382
342
  const { showHeader, inListView } = getMcpUrlDto;
383
343
 
384
- if(process.env.MCP_ENABLED === 'false') {
385
- throw new ForbiddenException(ERROR_MESSAGES.FORBIDDEN);
344
+ if (process.env.MCP_ENABLED === 'false') {
345
+ throw new ForbiddenException(ERROR_MESSAGES.FORBIDDEN);
386
346
  }
387
347
 
388
348
  if (solidRequestContext.activeUser) {
@@ -22,8 +22,8 @@ export abstract class Msg91BaseSMSService implements ISMS {
22
22
 
23
23
  async sendSMSUsingTemplate(to: string, templateName: string, templateParams: any, shouldQueueSms = false): Promise<any> {
24
24
  // Load template and evaluate it.
25
- const emailTemplate = await this.smsTemplateService.findOneByName(templateName);
26
- if (!emailTemplate) {
25
+ const smsTemplate = await this.smsTemplateService.findOneByName(templateName);
26
+ if (!smsTemplate) {
27
27
  throw new Error(`Invalid template name ${templateName}`);
28
28
  }
29
29
 
@@ -33,12 +33,12 @@ export abstract class Msg91BaseSMSService implements ISMS {
33
33
 
34
34
  // The below code is only for reference, msh91 maintains the SMS templates in their database, and we need to only specify the templateId.
35
35
  // The below was designed assuming that there are certain sms gateways who do not work this way.
36
- if (emailTemplate.body) {
37
- const bodyTemplate = Handlebars.compile(emailTemplate.body);
36
+ if (smsTemplate.body) {
37
+ const bodyTemplate = Handlebars.compile(smsTemplate.body);
38
38
  body = bodyTemplate(templateParams);
39
39
  }
40
- if (emailTemplate.smsProviderTemplateId) {
41
- templateId = emailTemplate.smsProviderTemplateId;
40
+ if (smsTemplate.smsProviderTemplateId) {
41
+ templateId = smsTemplate.smsProviderTemplateId;
42
42
  }
43
43
  if (!body && !templateId) {
44
44
  throw new Error(`Invalid template, neither body nor templateId specified on template with name ${templateName}`);
@@ -7,6 +7,7 @@ import { SmsTemplateService } from "../sms-template.service";
7
7
  import { Msg91BaseSMSService } from "./Msg91BaseSMSService";
8
8
  import { ISMS } from "../../interfaces";
9
9
  import { PublisherFactory } from "../queues/publisher-factory.service";
10
+ import { SmsProvider } from "src/decorators/sms-provider.decorator";
10
11
 
11
12
  interface OtpParams {
12
13
  otp: string,
@@ -16,16 +17,16 @@ interface OtpParams {
16
17
  }
17
18
 
18
19
  @Injectable()
20
+ @SmsProvider()
19
21
  export class Msg91OTPService extends Msg91BaseSMSService implements ISMS {
20
22
  constructor(
21
23
  @Inject(commonConfig.KEY)
22
24
  commonConfiguration: ConfigType<typeof commonConfig>,
23
- // smsPublisher: OTPQueuePublisher,
24
25
  publisherFactory: PublisherFactory<any>,
25
26
  smsTemplateService: SmsTemplateService,
26
27
  private readonly httpService: HttpService,
27
28
  ) {
28
- super(commonConfiguration, 'OTPQueuePublisher', publisherFactory, smsTemplateService);
29
+ super(commonConfiguration, 'Msg91OTPQueuePublisher', publisherFactory, smsTemplateService);
29
30
  }
30
31
 
31
32
  async sendSMSSynchronously(message: QueueMessage<any>): Promise<any> {
@@ -7,8 +7,10 @@ import { SmsTemplateService } from "../sms-template.service";
7
7
  import { Msg91BaseSMSService } from "./Msg91BaseSMSService";
8
8
  import { ISMS } from "../../interfaces";
9
9
  import { PublisherFactory } from "../queues/publisher-factory.service";
10
+ import { SmsProvider } from "src/decorators/sms-provider.decorator";
10
11
 
11
12
  @Injectable()
13
+ @SmsProvider()
12
14
  export class Msg91SMSService extends Msg91BaseSMSService implements ISMS {
13
15
  constructor(
14
16
  @Inject(commonConfig.KEY)
@@ -18,7 +20,7 @@ export class Msg91SMSService extends Msg91BaseSMSService implements ISMS {
18
20
  smsTemplateService: SmsTemplateService,
19
21
  private readonly httpService: HttpService,
20
22
  ) {
21
- super(commonConfiguration, 'SmsQueuePublisher', publisherFactory, smsTemplateService)
23
+ super(commonConfiguration, 'Msg91SmsQueuePublisher', publisherFactory, smsTemplateService)
22
24
  }
23
25
 
24
26
  async sendSMSSynchronously(message: QueueMessage<any>): Promise<any> {
@@ -7,9 +7,11 @@ import { ISMS } from "../../interfaces";
7
7
  import { PublisherFactory } from "../queues/publisher-factory.service";
8
8
  import twilio from 'twilio';
9
9
  import { QueueMessage } from "src/interfaces/mq";
10
+ import { SmsProvider } from "src/decorators/sms-provider.decorator";
10
11
 
11
12
 
12
13
  @Injectable()
14
+ @SmsProvider()
13
15
  export class TwilioSMSService implements ISMS {
14
16
  private readonly logger = new Logger(TwilioSMSService.name);
15
17
 
@@ -18,9 +20,7 @@ export class TwilioSMSService implements ISMS {
18
20
  private commonConfiguration: ConfigType<typeof commonConfig>,
19
21
  private publisherFactory: PublisherFactory<any>,
20
22
  private smsTemplateService: SmsTemplateService,
21
- ) {
22
- // super(commonConfiguration, 'OTPQueuePublisher', publisherFactory, smsTemplateService);
23
- }
23
+ ) { }
24
24
 
25
25
  async sendSMS(to: string, body: string, shouldQueueSms: boolean): Promise<any> {
26
26
  const accountSid = this.commonConfiguration.twilio.accountSid;