@solidstarters/solid-core 1.2.201 → 1.2.203

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 (262) 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/create-role-metadata.dto.d.ts.map +1 -1
  22. package/dist/dtos/create-role-metadata.dto.js +1 -0
  23. package/dist/dtos/create-role-metadata.dto.js.map +1 -1
  24. package/dist/dtos/navigation.dto.d.ts +6 -0
  25. package/dist/dtos/navigation.dto.d.ts.map +1 -0
  26. package/dist/dtos/navigation.dto.js +33 -0
  27. package/dist/dtos/navigation.dto.js.map +1 -0
  28. package/dist/dtos/sign-in.dto.js +3 -3
  29. package/dist/dtos/sign-in.dto.js.map +1 -1
  30. package/dist/entities/common.entity.js +5 -4
  31. package/dist/entities/common.entity.js.map +1 -1
  32. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  33. package/dist/entities/field-metadata.entity.js +2 -1
  34. package/dist/entities/field-metadata.entity.js.map +1 -1
  35. package/dist/entities/legacy-common.entity.d.ts.map +1 -1
  36. package/dist/entities/legacy-common.entity.js +5 -4
  37. package/dist/entities/legacy-common.entity.js.map +1 -1
  38. package/dist/entities/model-metadata.entity.d.ts.map +1 -1
  39. package/dist/entities/model-metadata.entity.js +5 -1
  40. package/dist/entities/model-metadata.entity.js.map +1 -1
  41. package/dist/factories/mail.factory.d.ts.map +1 -1
  42. package/dist/factories/mail.factory.js.map +1 -1
  43. package/dist/factories/sms.factory.d.ts +14 -0
  44. package/dist/factories/sms.factory.d.ts.map +1 -0
  45. package/dist/factories/sms.factory.js +53 -0
  46. package/dist/factories/sms.factory.js.map +1 -0
  47. package/dist/helpers/date.helper.d.ts.map +1 -1
  48. package/dist/helpers/date.helper.js +13 -4
  49. package/dist/helpers/date.helper.js.map +1 -1
  50. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +3 -0
  51. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
  52. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +99 -0
  53. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
  54. package/dist/helpers/image-encoding.helper.d.ts +10 -0
  55. package/dist/helpers/image-encoding.helper.d.ts.map +1 -0
  56. package/dist/helpers/image-encoding.helper.js +44 -0
  57. package/dist/helpers/image-encoding.helper.js.map +1 -0
  58. package/dist/helpers/module.helper.d.ts.map +1 -1
  59. package/dist/helpers/module.helper.js +2 -0
  60. package/dist/helpers/module.helper.js.map +1 -1
  61. package/dist/helpers/solid-microservice-adapter.service.d.ts +31 -0
  62. package/dist/helpers/solid-microservice-adapter.service.d.ts.map +1 -0
  63. package/dist/helpers/solid-microservice-adapter.service.js +53 -0
  64. package/dist/helpers/solid-microservice-adapter.service.js.map +1 -0
  65. package/dist/helpers/solid-registry.d.ts +3 -0
  66. package/dist/helpers/solid-registry.d.ts.map +1 -1
  67. package/dist/helpers/solid-registry.js +7 -0
  68. package/dist/helpers/solid-registry.js.map +1 -1
  69. package/dist/index.d.ts +11 -6
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +11 -6
  72. package/dist/index.js.map +1 -1
  73. package/dist/jobs/database/{sms-publisher-database.service.d.ts → msg91-sms-publisher-database.service.d.ts} +2 -2
  74. package/dist/jobs/database/msg91-sms-publisher-database.service.d.ts.map +1 -0
  75. package/dist/jobs/database/{sms-publisher-database.service.js → msg91-sms-publisher-database.service.js} +8 -8
  76. package/dist/jobs/database/msg91-sms-publisher-database.service.js.map +1 -0
  77. package/dist/jobs/database/{sms-queue-database-options.d.ts → msg91-sms-queue-database-options.d.ts} +1 -1
  78. package/dist/jobs/database/msg91-sms-queue-database-options.d.ts.map +1 -0
  79. package/dist/jobs/database/{sms-queue-database-options.js → msg91-sms-queue-database-options.js} +1 -1
  80. package/dist/jobs/database/msg91-sms-queue-database-options.js.map +1 -0
  81. package/dist/jobs/database/{sms-subscriber-database.service.d.ts → msg91-sms-subscriber-database.service.d.ts} +5 -5
  82. package/dist/jobs/database/msg91-sms-subscriber-database.service.d.ts.map +1 -0
  83. package/dist/jobs/database/{sms-subscriber-database.service.js → msg91-sms-subscriber-database.service.js} +14 -12
  84. package/dist/jobs/database/msg91-sms-subscriber-database.service.js.map +1 -0
  85. package/dist/jobs/database/otp-subscriber-database.service.d.ts +4 -4
  86. package/dist/jobs/database/otp-subscriber-database.service.d.ts.map +1 -1
  87. package/dist/jobs/database/otp-subscriber-database.service.js +6 -4
  88. package/dist/jobs/database/otp-subscriber-database.service.js.map +1 -1
  89. package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts +3 -3
  90. package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts.map +1 -1
  91. package/dist/jobs/database/twilio-sms-subscriber-database.service.js +6 -4
  92. package/dist/jobs/database/twilio-sms-subscriber-database.service.js.map +1 -1
  93. package/dist/jobs/{sms-publisher.service.d.ts → msg91-otp-publisher.service.d.ts} +2 -2
  94. package/dist/jobs/msg91-otp-publisher.service.d.ts.map +1 -0
  95. package/dist/jobs/{sms-publisher.service.js → msg91-otp-publisher.service.js} +8 -8
  96. package/dist/jobs/msg91-otp-publisher.service.js.map +1 -0
  97. package/dist/jobs/{sms-queue-options.d.ts → msg91-otp-queue-options.d.ts} +1 -1
  98. package/dist/jobs/msg91-otp-queue-options.d.ts.map +1 -0
  99. package/dist/jobs/{otp-queue-options.js → msg91-otp-queue-options.js} +1 -1
  100. package/dist/jobs/msg91-otp-queue-options.js.map +1 -0
  101. package/dist/jobs/{sms-subscriber.service.d.ts → msg91-otp-subscriber.service.d.ts} +6 -6
  102. package/dist/jobs/msg91-otp-subscriber.service.d.ts.map +1 -0
  103. package/dist/jobs/{otp-subscriber.service.js → msg91-otp-subscriber.service.js} +14 -12
  104. package/dist/jobs/msg91-otp-subscriber.service.js.map +1 -0
  105. package/dist/jobs/{otp-publisher.service.d.ts → msg91-sms-publisher.service.d.ts} +2 -2
  106. package/dist/jobs/msg91-sms-publisher.service.d.ts.map +1 -0
  107. package/dist/jobs/{otp-publisher.service.js → msg91-sms-publisher.service.js} +8 -8
  108. package/dist/jobs/msg91-sms-publisher.service.js.map +1 -0
  109. package/dist/jobs/{otp-queue-options.d.ts → msg91-sms-queue-options.d.ts} +1 -1
  110. package/dist/jobs/msg91-sms-queue-options.d.ts.map +1 -0
  111. package/dist/jobs/{sms-queue-options.js → msg91-sms-queue-options.js} +1 -1
  112. package/dist/jobs/msg91-sms-queue-options.js.map +1 -0
  113. package/dist/jobs/{otp-subscriber.service.d.ts → msg91-sms-subscriber.service.d.ts} +7 -7
  114. package/dist/jobs/msg91-sms-subscriber.service.d.ts.map +1 -0
  115. package/dist/jobs/{sms-subscriber.service.js → msg91-sms-subscriber.service.js} +14 -12
  116. package/dist/jobs/msg91-sms-subscriber.service.js.map +1 -0
  117. package/dist/jobs/twilio-sms-subscriber.service.d.ts +3 -3
  118. package/dist/jobs/twilio-sms-subscriber.service.d.ts.map +1 -1
  119. package/dist/jobs/twilio-sms-subscriber.service.js +6 -4
  120. package/dist/jobs/twilio-sms-subscriber.service.js.map +1 -1
  121. package/dist/mappers/list-of-values-mapper.d.ts.map +1 -1
  122. package/dist/mappers/list-of-values-mapper.js +1 -1
  123. package/dist/mappers/list-of-values-mapper.js.map +1 -1
  124. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  125. package/dist/repository/security-rule.repository.js +7 -2
  126. package/dist/repository/security-rule.repository.js.map +1 -1
  127. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  128. package/dist/seeders/module-metadata-seeder.service.js +24 -2
  129. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  130. package/dist/seeders/seed-data/solid-core-metadata.json +71 -25
  131. package/dist/seeders/user-seeder.service.d.ts.map +1 -1
  132. package/dist/seeders/user-seeder.service.js +5 -4
  133. package/dist/seeders/user-seeder.service.js.map +1 -1
  134. package/dist/services/authentication.service.d.ts +6 -3
  135. package/dist/services/authentication.service.d.ts.map +1 -1
  136. package/dist/services/authentication.service.js +53 -18
  137. package/dist/services/authentication.service.js.map +1 -1
  138. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  139. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  140. package/dist/services/crud.service.d.ts +1 -2
  141. package/dist/services/crud.service.d.ts.map +1 -1
  142. package/dist/services/crud.service.js +6 -1
  143. package/dist/services/crud.service.js.map +1 -1
  144. package/dist/services/excel.service.d.ts +1 -0
  145. package/dist/services/excel.service.d.ts.map +1 -1
  146. package/dist/services/excel.service.js +4 -0
  147. package/dist/services/excel.service.js.map +1 -1
  148. package/dist/services/model-metadata.service.d.ts +28 -1
  149. package/dist/services/model-metadata.service.d.ts.map +1 -1
  150. package/dist/services/model-metadata.service.js +109 -2
  151. package/dist/services/model-metadata.service.js.map +1 -1
  152. package/dist/services/setting.service.d.ts.map +1 -1
  153. package/dist/services/setting.service.js +3 -45
  154. package/dist/services/setting.service.js.map +1 -1
  155. package/dist/services/sms/Msg91BaseSMSService.js +6 -6
  156. package/dist/services/sms/Msg91BaseSMSService.js.map +1 -1
  157. package/dist/services/sms/Msg91OTPService.d.ts.map +1 -1
  158. package/dist/services/sms/Msg91OTPService.js +3 -1
  159. package/dist/services/sms/Msg91OTPService.js.map +1 -1
  160. package/dist/services/sms/Msg91SMSService.d.ts.map +1 -1
  161. package/dist/services/sms/Msg91SMSService.js +3 -1
  162. package/dist/services/sms/Msg91SMSService.js.map +1 -1
  163. package/dist/services/sms/TwilioSMSService.d.ts.map +1 -1
  164. package/dist/services/sms/TwilioSMSService.js +2 -0
  165. package/dist/services/sms/TwilioSMSService.js.map +1 -1
  166. package/dist/services/solid-introspect.service.d.ts +1 -0
  167. package/dist/services/solid-introspect.service.d.ts.map +1 -1
  168. package/dist/services/solid-introspect.service.js +14 -0
  169. package/dist/services/solid-introspect.service.js.map +1 -1
  170. package/dist/services/user.service.d.ts +8 -1
  171. package/dist/services/user.service.d.ts.map +1 -1
  172. package/dist/services/user.service.js +15 -4
  173. package/dist/services/user.service.js.map +1 -1
  174. package/dist/solid-core-cli.module.js +1 -1
  175. package/dist/solid-core-cli.module.js.map +1 -1
  176. package/dist/solid-core.module.d.ts.map +1 -1
  177. package/dist/solid-core.module.js +29 -13
  178. package/dist/solid-core.module.js.map +1 -1
  179. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
  180. package/dist/subscribers/scheduled-job.subscriber.js +1 -1
  181. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  182. package/dist/transformers/typeorm/local-date-time-transformer.d.ts +2 -2
  183. package/dist/transformers/typeorm/local-date-time-transformer.d.ts.map +1 -1
  184. package/dist/transformers/typeorm/local-date-time-transformer.js +28 -6
  185. package/dist/transformers/typeorm/local-date-time-transformer.js.map +1 -1
  186. package/dist/tsconfig.tsbuildinfo +1 -1
  187. package/package.json +1 -1
  188. package/src/config/cache.options.ts +6 -3
  189. package/src/config/iam.config.ts +2 -1
  190. package/src/controllers/model-metadata.controller.ts +21 -1
  191. package/src/controllers/setting.controller.ts +32 -36
  192. package/src/decorators/sms-provider.decorator.ts +7 -0
  193. package/src/dtos/create-role-metadata.dto.ts +3 -0
  194. package/src/dtos/navigation.dto.ts +14 -0
  195. package/src/dtos/sign-in.dto.ts +3 -3
  196. package/src/entities/common.entity.ts +7 -7
  197. package/src/entities/field-metadata.entity.ts +1 -1
  198. package/src/entities/legacy-common.entity.ts +6 -5
  199. package/src/entities/model-metadata.entity.ts +1 -1
  200. package/src/factories/mail.factory.ts +0 -1
  201. package/src/factories/sms.factory.ts +43 -0
  202. package/src/helpers/date.helper.ts +38 -9
  203. package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +138 -4
  204. package/src/helpers/image-encoding.helper.ts +71 -0
  205. package/src/helpers/module.helper.ts +3 -0
  206. package/src/helpers/solid-microservice-adapter.service.ts +68 -0
  207. package/src/helpers/solid-registry.ts +9 -0
  208. package/src/index.ts +11 -6
  209. package/src/jobs/database/{sms-publisher-database.service.ts → msg91-sms-publisher-database.service.ts} +2 -2
  210. package/src/jobs/database/{sms-subscriber-database.service.ts → msg91-sms-subscriber-database.service.ts} +9 -4
  211. package/src/jobs/database/otp-subscriber-database.service.ts +8 -2
  212. package/src/jobs/database/twilio-sms-subscriber-database.service.ts +5 -2
  213. package/src/jobs/{otp-publisher.service.ts → msg91-otp-publisher.service.ts} +2 -2
  214. package/src/jobs/{otp-subscriber.service.ts → msg91-otp-subscriber.service.ts} +10 -4
  215. package/src/jobs/{sms-publisher.service.ts → msg91-sms-publisher.service.ts} +2 -2
  216. package/src/jobs/{sms-subscriber.service.ts → msg91-sms-subscriber.service.ts} +9 -4
  217. package/src/jobs/twilio-sms-subscriber.service.ts +6 -2
  218. package/src/mappers/list-of-values-mapper.ts +2 -1
  219. package/src/repository/security-rule.repository.ts +7 -2
  220. package/src/seeders/module-metadata-seeder.service.ts +33 -6
  221. package/src/seeders/seed-data/email-templates/email-on-signup.handlebars.html +155 -0
  222. package/src/seeders/seed-data/sms-templates/text-on-signup.handlebars.txt +10 -0
  223. package/src/seeders/seed-data/solid-core-metadata.json +72 -26
  224. package/src/seeders/user-seeder.service.ts +5 -4
  225. package/src/services/1.js +6 -0
  226. package/src/services/authentication.service.ts +80 -15
  227. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +1 -2
  228. package/src/services/crud.service.ts +23 -19
  229. package/src/services/excel.service.ts +6 -0
  230. package/src/services/model-metadata.service.ts +151 -0
  231. package/src/services/setting.service.ts +12 -52
  232. package/src/services/sms/Msg91BaseSMSService.ts +6 -6
  233. package/src/services/sms/Msg91OTPService.ts +3 -2
  234. package/src/services/sms/Msg91SMSService.ts +3 -1
  235. package/src/services/sms/TwilioSMSService.ts +3 -3
  236. package/src/services/solid-introspect.service.ts +22 -0
  237. package/src/services/user.service.ts +19 -0
  238. package/src/solid-core-cli.module.ts +2 -2
  239. package/src/solid-core.module.ts +33 -13
  240. package/src/subscribers/scheduled-job.subscriber.ts +9 -2
  241. package/src/transformers/typeorm/local-date-time-transformer.ts +38 -13
  242. package/dist/jobs/database/sms-publisher-database.service.d.ts.map +0 -1
  243. package/dist/jobs/database/sms-publisher-database.service.js.map +0 -1
  244. package/dist/jobs/database/sms-queue-database-options.d.ts.map +0 -1
  245. package/dist/jobs/database/sms-queue-database-options.js.map +0 -1
  246. package/dist/jobs/database/sms-subscriber-database.service.d.ts.map +0 -1
  247. package/dist/jobs/database/sms-subscriber-database.service.js.map +0 -1
  248. package/dist/jobs/otp-publisher.service.d.ts.map +0 -1
  249. package/dist/jobs/otp-publisher.service.js.map +0 -1
  250. package/dist/jobs/otp-queue-options.d.ts.map +0 -1
  251. package/dist/jobs/otp-queue-options.js.map +0 -1
  252. package/dist/jobs/otp-subscriber.service.d.ts.map +0 -1
  253. package/dist/jobs/otp-subscriber.service.js.map +0 -1
  254. package/dist/jobs/sms-publisher.service.d.ts.map +0 -1
  255. package/dist/jobs/sms-publisher.service.js.map +0 -1
  256. package/dist/jobs/sms-queue-options.d.ts.map +0 -1
  257. package/dist/jobs/sms-queue-options.js.map +0 -1
  258. package/dist/jobs/sms-subscriber.service.d.ts.map +0 -1
  259. package/dist/jobs/sms-subscriber.service.js.map +0 -1
  260. /package/src/jobs/database/{sms-queue-database-options.ts → msg91-sms-queue-database-options.ts} +0 -0
  261. /package/src/jobs/{otp-queue-options.ts → msg91-otp-queue-options.ts} +0 -0
  262. /package/src/jobs/{sms-queue-options.ts → msg91-sms-queue-options.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.201",
3
+ "version": "1.2.203",
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",
@@ -3,15 +3,19 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
3
3
  import { redisStore } from 'cache-manager-redis-store';
4
4
  import { isRedisConfigured } from 'src/helpers/environment.helper';
5
5
 
6
- export const RedisOptions: CacheModuleAsyncOptions = {
6
+ export const CacheManagerOptions: CacheModuleAsyncOptions = {
7
7
  isGlobal: true,
8
8
  imports: [ConfigModule],
9
9
  useFactory: async (configService: ConfigService) => {
10
+
11
+ // This defaults to in-memory cache
10
12
  if (!isRedisConfigured(configService)) {
11
13
  return {
12
14
  ttl: 0
13
- } // This defaults to in-memory cache
15
+ }
14
16
  }
17
+
18
+ // If redis is configured we use that...
15
19
  const store = await createRedisStore(configService);
16
20
  return {
17
21
  store: () => store,
@@ -28,4 +32,3 @@ async function createRedisStore(configService: ConfigService<Record<string, unkn
28
32
  },
29
33
  });
30
34
  }
31
-
@@ -26,6 +26,7 @@ export const iamConfig = registerAs('iam', () => {
26
26
  iamAutoGeneratedPassword:process.env.IAM_AUTOGENERATED_PASSWORD || true,
27
27
  passwordPepper: process.env.IAM_PASSWORD_PEPPER || '', // Adding a pepper to the password hashing process for extra security,
28
28
  showNameFieldsForRegistration:process.env.IAM_SHOW_NAME_FIELDS_FOR_REGISTRATION === 'true' ? true : false,
29
+ sendWelcomeEmailOnSignup: (process.env.IAM_SEND_WELCOME_EMAIL_ON_SIGNUP ?? 'false').toLowerCase() === 'true',
30
+ sendWelcomeSmsOnSignup: (process.env.IAM_SEND_WELCOME_SMS_ON_SIGNUP ?? 'false').toLowerCase() === 'true',
29
31
  };
30
32
  })
31
-
@@ -5,6 +5,7 @@ import { BasicFilterDto } from '../dtos/basic-filters.dto';
5
5
  import { CreateModelMetadataDto } from '../dtos/create-model-metadata.dto';
6
6
  import { UpdateModelMetaDataDto } from '../dtos/update-model-metadata.dto';
7
7
  import { ModelMetadataService } from '../services/model-metadata.service';
8
+ import { NavigationDto } from 'src/dtos/navigation.dto';
8
9
 
9
10
  @Controller('model-metadata')
10
11
  @ApiTags("Solid Core")
@@ -43,13 +44,31 @@ export class ModelMetadataController {
43
44
  offset: 0,
44
45
  filters: [],
45
46
  groupBy: [],
46
- populate: [],
47
+ populate: [],
47
48
  populateMedia: [],
48
49
  sort: []
49
50
  }
50
51
  return this.modelMetadataService.findMany(basicFilterDto);
51
52
  }
52
53
 
54
+ @ApiBearerAuth("jwt")
55
+ @ApiQuery({ name: 'modelName', required: true, type: String })
56
+ @ApiQuery({ name: 'recordId', required: true, type: Number })
57
+ @ApiQuery({ name: 'limit', required: false, type: Number })
58
+ @ApiQuery({ name: 'offset', required: false, type: Number })
59
+ @ApiQuery({ name: 'fields', required: false, type: Array })
60
+ @ApiQuery({ name: 'sort', required: false, type: Array })
61
+ @ApiQuery({ name: 'groupBy', required: false, type: Array })
62
+ @ApiQuery({ name: 'populate', required: false, type: Array })
63
+ @ApiQuery({ name: 'populateMedia', required: false, type: Array })
64
+ @ApiQuery({ name: 'filters', required: false, type: Array })
65
+ @Get("/navigation")
66
+ async navigation(
67
+ @Query() navigationDto: NavigationDto
68
+ ) {
69
+ return this.modelMetadataService.navigation(navigationDto);
70
+ }
71
+
53
72
  @ApiBearerAuth("jwt")
54
73
  @Get(':id')
55
74
  findOne(@Param('id', ParseIntPipe) id: number, @Query() query: any) {
@@ -94,4 +113,5 @@ export class ModelMetadataController {
94
113
  return this.modelMetadataService.remove(id);
95
114
  }
96
115
 
116
+
97
117
  }
@@ -27,6 +27,26 @@ export class SettingController {
27
27
  return this.service.insertMany(createDtos, filesArray, solidRequestContext);
28
28
  }
29
29
 
30
+ /**
31
+ * Important to keep this method just above the @Put(':id') definition that follows as otherwise it will conflict.
32
+ *
33
+ * @param body
34
+ * @param files
35
+ * @returns
36
+ */
37
+ @ApiBearerAuth("jwt")
38
+ @Put('/bulk')
39
+ @UseInterceptors(AnyFilesInterceptor())
40
+ async updateSettings(@Body() body: any, @UploadedFiles() files: Array<Express.Multer.File>) {
41
+ let settings: CreateSettingDto[] = [];
42
+
43
+ try {
44
+ settings = typeof body.settings === 'string' ? JSON.parse(body.settings) : body.settings;
45
+ } catch (e) {
46
+ throw new BadRequestException('Invalid settings payload');
47
+ }
48
+ return this.service.updateSettings(settings, files);
49
+ }
30
50
 
31
51
  @ApiBearerAuth("jwt")
32
52
  @Put(':id')
@@ -54,7 +74,6 @@ export class SettingController {
54
74
  return this.service.getAllSettings();
55
75
  }
56
76
 
57
-
58
77
  @ApiBearerAuth("jwt")
59
78
  @ApiQuery({ name: 'showHeader', required: false, type: String })
60
79
  @ApiQuery({ name: 'inListView', required: false, type: String })
@@ -97,40 +116,17 @@ export class SettingController {
97
116
  return this.service.delete(id, solidRequestContext);
98
117
  }
99
118
 
100
- @ApiBearerAuth("jwt")
101
- @Post('/bulk-update')
102
- @UseInterceptors(AnyFilesInterceptor())
103
- async updateSettings(
104
- @Body() body: any,
105
- @UploadedFiles() files: Array<Express.Multer.File>
106
- ) {
107
- let settings: CreateSettingDto[] = [];
108
-
109
- try {
110
- settings = typeof body.settings === 'string' ? JSON.parse(body.settings) : body.settings;
111
- } catch (e) {
112
- throw new BadRequestException('Invalid settings payload');
113
- }
114
- return this.service.updateSettings(settings, files);
115
- }
116
-
117
-
118
- @ApiBearerAuth("jwt")
119
- @Post('/bulk/user')
120
- @UseInterceptors(AnyFilesInterceptor())
121
- async updateUserSettings(
122
- @Body() body: any,
123
- @UploadedFiles() files: Array<Express.Multer.File>
124
- ) {
125
- let settings: CreateSettingDto[] = [];
126
-
127
- try {
128
- settings = typeof body.settings === 'string' ? JSON.parse(body.settings) : body.settings;
129
- } catch (e) {
130
- throw new BadRequestException('Invalid settings payload');
131
- }
132
- return this.service.updateSettings(settings, files);
133
- }
134
-
119
+ // @ApiBearerAuth("jwt")
120
+ // @Post('/bulk/user')
121
+ // @UseInterceptors(AnyFilesInterceptor())
122
+ // async updateUserSettings(@Body() body: any, @UploadedFiles() files: Array<Express.Multer.File>) {
123
+ // let settings: CreateSettingDto[] = [];
124
+ // try {
125
+ // settings = typeof body.settings === 'string' ? JSON.parse(body.settings) : body.settings;
126
+ // } catch (e) {
127
+ // throw new BadRequestException('Invalid settings payload');
128
+ // }
129
+ // return this.service.updateSettings(settings, files);
130
+ // }
135
131
 
136
132
  }
@@ -0,0 +1,7 @@
1
+ export const IS_SMS_PROVIDER = 'IS_SMS_PROVIDER';
2
+
3
+ export const SmsProvider = () => {
4
+ return (target: Function) => {
5
+ Reflect.defineMetadata(IS_SMS_PROVIDER, true, target);
6
+ };
7
+ };
@@ -91,6 +91,9 @@ export const INTERNAL_ROLE_PERMISSIONS = [
91
91
  'AuthenticationController.logout',
92
92
  'AuthenticationController.me',
93
93
 
94
+ // Field Metadata permissions
95
+ 'ModelMetadataController.navigation',
96
+
94
97
  // Field Metadata permissions
95
98
  'FieldMetadataController.getSelectionDynamicValues',
96
99
  'FieldMetadataController.getSelectionDynamicValue',
@@ -0,0 +1,14 @@
1
+ import { Type } from "class-transformer";
2
+ import { IsNumber, IsOptional, IsString } from "class-validator";
3
+ import { BasicFilterDto } from "./basic-filters.dto";
4
+
5
+ export class NavigationDto extends BasicFilterDto {
6
+
7
+ @IsString()
8
+ modelName: string;
9
+
10
+ @Type(() => Number)
11
+ @IsNumber()
12
+ @IsOptional()
13
+ recordId: number;
14
+ }
@@ -3,19 +3,19 @@ import { IsEmail, IsNotEmpty, IsOptional, IsString, MinLength } from 'class-vali
3
3
 
4
4
  export class SignInDto {
5
5
 
6
- @ApiProperty({ default: 'admin@example.service.com' })
6
+ @ApiProperty({ default: 'sa@solidxai.com' })
7
7
  @IsEmail()
8
8
  // @IsNotEmpty()
9
9
  @IsOptional()
10
10
  email: string;
11
11
 
12
- @ApiProperty({ default: 'admin@example.service.com' })
12
+ @ApiProperty({ default: 'sa' })
13
13
  @IsString()
14
14
  // @IsNotEmpty()
15
15
  @IsOptional()
16
16
  username: string;
17
17
 
18
- @ApiProperty({ default: 'Admin@3214$' })
18
+ @ApiProperty({ default: '' })
19
19
  @IsOptional()
20
20
  password: string;
21
21
  }
@@ -1,6 +1,6 @@
1
- import { Column, CreateDateColumn, DeleteDateColumn, Index, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
2
- import type { User } from "./user.entity";
3
- import { Exclude, Expose, Type } from "class-transformer";
1
+ import { Column, CreateDateColumn, DeleteDateColumn, Index, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
2
+ import { Exclude, Expose } from "class-transformer";
3
+ import { LocalDateTimeTransformer } from "src/transformers/typeorm/local-date-time-transformer";
4
4
 
5
5
  @Exclude()
6
6
  export abstract class CommonEntity {
@@ -8,13 +8,13 @@ export abstract class CommonEntity {
8
8
  @PrimaryGeneratedColumn({ type: 'integer' })
9
9
  id: number
10
10
 
11
- @CreateDateColumn({ name: "created_at" })
11
+ @CreateDateColumn({ name: "created_at", transformer: LocalDateTimeTransformer })
12
12
  createdAt: Date;
13
13
 
14
- @UpdateDateColumn({ name: "updated_at" })
14
+ @UpdateDateColumn({ name: "updated_at", transformer: LocalDateTimeTransformer })
15
15
  updatedAt: Date;
16
16
 
17
- @DeleteDateColumn({ name: "deleted_at" })
17
+ @DeleteDateColumn({ name: "deleted_at", transformer: LocalDateTimeTransformer })
18
18
  @Index()
19
19
  deletedAt: Date;
20
20
 
@@ -22,7 +22,7 @@ export abstract class CommonEntity {
22
22
  deletedTracker: string;
23
23
 
24
24
  @Expose()
25
- @Column({ name: 'published_at', default: null, nullable: true })
25
+ @Column({ name: 'published_at', default: null, nullable: true, transformer: LocalDateTimeTransformer })
26
26
  publishedAt: Date;
27
27
 
28
28
  @Expose()
@@ -159,7 +159,7 @@ export class FieldMetadata extends CommonEntity {
159
159
  relationJoinTableName: string;
160
160
 
161
161
  @Column({ name: 'enable_audit_tracking', default: false })
162
- enableAuditTracking: boolean;
162
+ enableAuditTracking: boolean = false;
163
163
 
164
164
  @Column({ name: "is_multiSelect", default: false })
165
165
  isMultiSelect: boolean;
@@ -1,6 +1,7 @@
1
1
  import { Exclude, Expose, Type } from "class-transformer";
2
2
  import { Column, CreateDateColumn, DeleteDateColumn, Index, JoinColumn, ManyToOne, UpdateDateColumn } from "typeorm";
3
3
  import type { User } from "./user.entity";
4
+ import { LocalDateTimeTransformer } from "src/transformers/typeorm/local-date-time-transformer";
4
5
 
5
6
  export const LEGACY_TABLE_FIELDS_PREFIX = 'ss';
6
7
 
@@ -11,13 +12,13 @@ export abstract class LegacyCommonEntity {
11
12
  // @Generated("increment")
12
13
  // id: number
13
14
 
14
- @CreateDateColumn({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_created_at` })
15
+ @CreateDateColumn({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_created_at`, transformer: LocalDateTimeTransformer })
15
16
  createdAt: Date;
16
17
 
17
- @UpdateDateColumn({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_updated_at` })
18
+ @UpdateDateColumn({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_updated_at`, transformer: LocalDateTimeTransformer })
18
19
  updatedAt: Date;
19
20
 
20
- @DeleteDateColumn({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_deleted_at` })
21
+ @DeleteDateColumn({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_deleted_at`, transformer: LocalDateTimeTransformer })
21
22
  @Index()
22
23
  deletedAt: Date;
23
24
 
@@ -25,7 +26,7 @@ export abstract class LegacyCommonEntity {
25
26
  deletedTracker: string;
26
27
 
27
28
  @Expose()
28
- @Column({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_published_at`, default: null ,nullable: true})
29
+ @Column({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_published_at`, default: null, nullable: true, transformer: LocalDateTimeTransformer })
29
30
  publishedAt: Date;
30
31
 
31
32
  @Expose()
@@ -51,7 +52,7 @@ export abstract class LegacyCommonEntity {
51
52
  @Expose()
52
53
  @Column({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_created_by_id`, nullable: true })
53
54
  createdBy: number;
54
-
55
+
55
56
  @Expose()
56
57
  @Column({ name: `${LEGACY_TABLE_FIELDS_PREFIX}_updated_by_id`, nullable: true })
57
58
  updatedBy: number;
@@ -34,7 +34,7 @@ export class ModelMetadata extends CommonEntity {
34
34
  enableSoftDelete: boolean;
35
35
 
36
36
  @Column({ name: "enable_audit_tracking", default: false })
37
- enableAuditTracking: boolean;
37
+ enableAuditTracking: boolean = false;
38
38
 
39
39
  @Column({ name: "internationalisation", default: false })
40
40
  internationalisation: boolean;
@@ -20,7 +20,6 @@ export class MailFactory {
20
20
  private readonly commonConfiguration: ConfigType<typeof commonConfig>,
21
21
  ) { }
22
22
 
23
-
24
23
  getMailService(): IMail {
25
24
  const mailServiceName = this.commonConfiguration.emailProvider;
26
25
  const mailProviders = this.solidRegistry.getMailProviders();
@@ -0,0 +1,43 @@
1
+ import { Inject, Injectable, Logger } from "@nestjs/common";
2
+ import { ConfigType } from "@nestjs/config";
3
+ import { ModuleRef } from "@nestjs/core";
4
+ import commonConfig from "src/config/common.config";
5
+ import { SolidRegistry } from "src/helpers/solid-registry";
6
+ import { ISMS } from "src/interfaces";
7
+
8
+ function norm(s?: string) {
9
+ return s?.trim().toLowerCase();
10
+ }
11
+
12
+ // This factory will be use to return a mail service instance, using the configured environment variables
13
+ @Injectable()
14
+ export class SmsFactory {
15
+ private readonly logger = new Logger(this.constructor.name);
16
+
17
+ constructor(
18
+ private readonly moduleRef: ModuleRef,
19
+ private readonly solidRegistry: SolidRegistry,
20
+ @Inject(commonConfig.KEY)
21
+ private readonly commonConfiguration: ConfigType<typeof commonConfig>,
22
+ ) { }
23
+
24
+ getSmsService(name: string = null): ISMS {
25
+ // This is the default provider
26
+ const smsServiceName = name || this.commonConfiguration.smsProvider;
27
+ if (!smsServiceName) {
28
+ throw new Error("Unable to resolve sms provider")
29
+ }
30
+ const smsProviders = this.solidRegistry.getSmsProviders();
31
+
32
+ // Return the instance which matches the smsServicename
33
+ if (!smsProviders.length) {
34
+ // throw new Error("No mail providers are registered.");
35
+ this.logger.error("No sms providers are registered.");
36
+ }
37
+
38
+ const smsServiceProvider = smsProviders.find(provider => provider.name === smsServiceName);
39
+
40
+ return smsServiceProvider.instance as ISMS;
41
+ }
42
+
43
+ }
@@ -1,34 +1,63 @@
1
1
  import dayjs from 'dayjs';
2
2
  import customParseFormat from 'dayjs/plugin/customParseFormat';
3
+
3
4
  dayjs.extend(customParseFormat);
4
5
 
5
6
  export function parseFlexibleDate(value: any): Date | null {
6
7
  if (!value) return null;
8
+
9
+ // Already a valid Date (ExcelJS often gives this)
7
10
  if (value instanceof Date && !isNaN(value.getTime())) {
8
11
  return value;
9
12
  }
13
+
14
+ // Excel serial number
10
15
  if (typeof value === 'number') {
11
16
  const excelEpoch = new Date(Date.UTC(1899, 11, 30));
12
17
  const d = new Date(excelEpoch.getTime() + value * 86400000);
13
18
  return isNaN(d.getTime()) ? null : d;
14
19
  }
15
- const str = value.toString().trim();
20
+
21
+ let str = value.toString().trim();
22
+
23
+ // STRIP "(British Summer Time)" or any "(...)" suffix
24
+ str = str.replace(/\s*\(.*\)$/, '');
25
+
16
26
  const formats = [
27
+ // strict business formats
17
28
  'DD-MM-YYYY',
29
+
30
+ // common alternates
18
31
  'YYYY-MM-DD',
19
32
  'DD/MM/YYYY',
20
33
  'MM/DD/YYYY',
21
34
  'D-M-YYYY',
22
35
  'YYYY/MM/DD',
36
+
37
+ // JS Date.toString() (without timezone name)
38
+ // (handle single-digit day + different offset shapes)
39
+ 'ddd MMM D YYYY HH:mm:ss [GMT]ZZ', // GMT+0100
40
+ 'ddd MMM DD YYYY HH:mm:ss [GMT]ZZ',
41
+ 'ddd MMM D YYYY HH:mm:ss [GMT]Z', // GMT+01:00
42
+ 'ddd MMM DD YYYY HH:mm:ss [GMT]Z',
43
+
44
+ // ISO variants
23
45
  'YYYY-MM-DD HH:mm:ss',
24
- 'YYYY-MM-DDTHH:mm:ss', // ISO without Z
25
- 'YYYY-MM-DDTHH:mm:ss.SSS', // ISO with millis
26
- 'YYYY-MM-DDTHH:mm:ssZ', // ISO with timezone
46
+ 'YYYY-MM-DDTHH:mm:ss',
47
+ 'YYYY-MM-DDTHH:mm:ss.SSS',
48
+ 'YYYY-MM-DDTHH:mm:ssZ',
27
49
  ];
28
- const parsed = dayjs(str, formats, true); // true = strict parsing
29
- if (!parsed.isValid()) {
30
- return null;
50
+
51
+ const parsed = dayjs(str, formats, true); // strict
52
+ if (parsed.isValid()) {
53
+ return parsed.toDate();
54
+ }
55
+
56
+ // Fallback: native Date can parse this JS format very reliably
57
+ const native = new Date(str);
58
+ if (!isNaN(native.getTime())) {
59
+ return native;
31
60
  }
32
- return parsed.toDate();
33
- }
34
61
 
62
+ return null;
63
+ }
@@ -9,20 +9,122 @@ export interface MediaFieldOptions {
9
9
  type: SolidMediaType;
10
10
  required: boolean | undefined | null;
11
11
  fieldName: string | undefined | null;
12
+ mediaMaxSizeKb: number | undefined | null;
13
+ mediaTypes: string[];
12
14
  }
13
15
 
16
+ type MediaType = 'image' | 'audio' | 'video' | 'file';
17
+
18
+ const MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {
19
+ // Images
20
+ 'image/png': 'image',
21
+ 'image/jpeg': 'image',
22
+ 'image/jpg': 'image',
23
+ 'image/webp': 'image',
24
+ 'image/gif': 'image',
25
+ 'image/bmp': 'image',
26
+ 'image/tiff': 'image',
27
+ 'image/svg+xml': 'image',
28
+ 'image/heic': 'image',
29
+ 'image/heif': 'image',
30
+
31
+ // Audio
32
+ 'audio/mpeg': 'audio', // mp3
33
+ 'audio/mp3': 'audio',
34
+ 'audio/wav': 'audio',
35
+ 'audio/x-wav': 'audio',
36
+ 'audio/webm': 'audio',
37
+ 'audio/ogg': 'audio',
38
+ 'audio/aac': 'audio',
39
+ 'audio/mp4': 'audio', // m4a often shows as audio/mp4
40
+ 'audio/x-m4a': 'audio',
41
+ 'audio/flac': 'audio',
42
+
43
+ // Video
44
+ 'video/mp4': 'video',
45
+ 'video/mpeg': 'video',
46
+ 'video/webm': 'video',
47
+ 'video/ogg': 'video',
48
+ 'video/quicktime': 'video', // mov
49
+ 'video/x-msvideo': 'video', // avi
50
+ 'video/x-matroska': 'video',// mkv
51
+ 'video/3gpp': 'video',
52
+ 'video/3gpp2': 'video',
53
+
54
+ // Documents / files (treat as "file")
55
+ 'application/pdf': 'file',
56
+ 'text/plain': 'file',
57
+ 'text/markdown': 'file',
58
+ 'application/json': 'file',
59
+ 'text/csv': 'file',
60
+
61
+ // Office
62
+ 'application/msword': 'file', // doc
63
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx
64
+ 'application/vnd.ms-excel': 'file', // xls
65
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx
66
+ 'application/vnd.ms-powerpoint': 'file', // ppt
67
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,
68
+
69
+ // Archives (optional)
70
+ 'application/zip': 'file',
71
+ 'application/x-zip-compressed': 'file',
72
+ 'application/x-rar-compressed': 'file',
73
+ 'application/x-7z-compressed': 'file',
74
+
75
+ // Common binary fallback category
76
+ 'application/octet-stream': 'file',
77
+ };
78
+
79
+ const EXT_TO_MEDIA_TYPE: Record<string, MediaType> = {
80
+ // Images
81
+ png: 'image', jpg: 'image', jpeg: 'image', webp: 'image', gif: 'image', bmp: 'image', tiff: 'image', svg: 'image', heic: 'image', heif: 'image',
82
+
83
+ // Audio
84
+ mp3: 'audio', wav: 'audio', ogg: 'audio', aac: 'audio', m4a: 'audio', flac: 'audio',
85
+
86
+ // Video
87
+ mp4: 'video', mov: 'video', avi: 'video', mkv: 'video', mpeg: 'video', mpg: 'video', '3gp': 'video', '3g2': 'video',
88
+
89
+ // Files
90
+ pdf: 'file', txt: 'file', md: 'file', csv: 'file', json: 'file',
91
+ doc: 'file', docx: 'file', xls: 'file', xlsx: 'file', ppt: 'file', pptx: 'file',
92
+ zip: 'file', rar: 'file', '7z': 'file',
93
+ };
94
+
95
+
14
96
  export class MediaFieldCrudManager implements FieldCrudManager {
15
97
 
16
98
  constructor(private readonly options: MediaFieldOptions) {
17
99
  }
18
100
 
19
- validate(dto: any, files:Array<Express.Multer.File>): ValidationError[] {
101
+ private resolveMediaType(mimetype?: string, filename?: string): MediaType | null {
102
+ const mt = (mimetype || '').toLowerCase().trim();
103
+ if (mt && MIME_TO_MEDIA_TYPE[mt]) {
104
+ return MIME_TO_MEDIA_TYPE[mt];
105
+ }
106
+
107
+ // Some libs may send "image/*" etc. Treat broad families safely.
108
+ if (mt.startsWith('image/')) return 'image';
109
+ if (mt.startsWith('audio/')) return 'audio';
110
+ if (mt.startsWith('video/')) return 'video';
111
+
112
+ // Fallback to extension if provided
113
+ const ext = (filename || '').split('.').pop()?.toLowerCase();
114
+ if (ext && EXT_TO_MEDIA_TYPE[ext]) {
115
+ return EXT_TO_MEDIA_TYPE[ext];
116
+ }
117
+
118
+ return null;
119
+ }
120
+
121
+ validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {
20
122
  const isValidateForUpdate = dto.id !== undefined; //FIXME: This is a hack, since we are using PUT for update. Once we support PATCH, this will be removed
21
123
  const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);
22
124
  return this.applyValidations(fieldFiles, isValidateForUpdate);
23
125
  }
24
126
 
25
- private applyValidations(fieldFiles:Array<Express.Multer.File>, isValidateForUpdate: boolean): ValidationError[] {
127
+ private applyValidations(fieldFiles: Array<Express.Multer.File>, isValidateForUpdate: boolean): ValidationError[] {
26
128
  switch (this.options.type) {
27
129
  case SolidMediaType.mediaSingle:
28
130
  return this.validateMediaSingle(fieldFiles, isValidateForUpdate);
@@ -33,7 +135,7 @@ export class MediaFieldCrudManager implements FieldCrudManager {
33
135
  }
34
136
  }
35
137
 
36
- private validateMediaSingle(fieldFiles:Array<Express.Multer.File>, isValidateForUpdate: boolean): ValidationError[] {
138
+ private validateMediaSingle(fieldFiles: Array<Express.Multer.File>, isValidateForUpdate: boolean): ValidationError[] {
37
139
  const errors: ValidationError[] = [];
38
140
  if (!isValidateForUpdate && this.options.required && fieldFiles.length === 0) {
39
141
  errors.push({
@@ -47,10 +149,42 @@ export class MediaFieldCrudManager implements FieldCrudManager {
47
149
  error: `${this.options.fieldName} must be a single file`
48
150
  });
49
151
  }
152
+ // validate size
153
+ if (this.options.mediaMaxSizeKb) {
154
+ for (let i = 0; i < fieldFiles.length; i++) {
155
+ const fieldFile = fieldFiles[i];
156
+ const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);
157
+ if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {
158
+ errors.push({
159
+ field: this.options.fieldName,
160
+ error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`
161
+ });
162
+ }
163
+ }
164
+ }
165
+ // validate type
166
+ if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {
167
+ const allowedFileTypes = this.options.mediaTypes as MediaType[];
168
+
169
+ for (let i = 0; i < fieldFiles.length; i++) {
170
+ const fieldFile = fieldFiles[i];
171
+
172
+ const resolvedType = this.resolveMediaType(fieldFile.mimetype, fieldFile.originalname ?? fieldFile.filename ?? '');
173
+ if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {
174
+ errors.push({
175
+ field: this.options.fieldName,
176
+ error: `${this.options.fieldName} file type not allowed. ` +
177
+ `Allowed: ${allowedFileTypes.join(', ')}. ` +
178
+ `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`
179
+ });
180
+ }
181
+ }
182
+ }
183
+
50
184
  return errors;
51
185
  }
52
186
 
53
- private validateMediaMultiple(fieldFiles:Array<Express.Multer.File>, isValidateForUpdate: boolean): ValidationError[] {
187
+ private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>, isValidateForUpdate: boolean): ValidationError[] {
54
188
  const errors: ValidationError[] = [];
55
189
  if (!isValidateForUpdate && this.options.required && fieldFiles.length === 0) {
56
190
  errors.push({