@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.
- package/dist/config/cache.options.d.ts +1 -1
- package/dist/config/cache.options.d.ts.map +1 -1
- package/dist/config/cache.options.js +2 -2
- package/dist/config/cache.options.js.map +1 -1
- package/dist/config/iam.config.d.ts +4 -0
- package/dist/config/iam.config.d.ts.map +1 -1
- package/dist/config/iam.config.js +2 -0
- package/dist/config/iam.config.js.map +1 -1
- package/dist/controllers/model-metadata.controller.d.ts +25 -0
- package/dist/controllers/model-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/model-metadata.controller.js +23 -0
- package/dist/controllers/model-metadata.controller.js.map +1 -1
- package/dist/controllers/setting.controller.d.ts +1 -2
- package/dist/controllers/setting.controller.d.ts.map +1 -1
- package/dist/controllers/setting.controller.js +21 -42
- package/dist/controllers/setting.controller.js.map +1 -1
- package/dist/decorators/sms-provider.decorator.d.ts +3 -0
- package/dist/decorators/sms-provider.decorator.d.ts.map +1 -0
- package/dist/decorators/sms-provider.decorator.js +11 -0
- package/dist/decorators/sms-provider.decorator.js.map +1 -0
- package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-role-metadata.dto.js +1 -0
- package/dist/dtos/create-role-metadata.dto.js.map +1 -1
- package/dist/dtos/navigation.dto.d.ts +6 -0
- package/dist/dtos/navigation.dto.d.ts.map +1 -0
- package/dist/dtos/navigation.dto.js +33 -0
- package/dist/dtos/navigation.dto.js.map +1 -0
- package/dist/dtos/sign-in.dto.js +3 -3
- package/dist/dtos/sign-in.dto.js.map +1 -1
- package/dist/entities/common.entity.js +5 -4
- package/dist/entities/common.entity.js.map +1 -1
- package/dist/entities/field-metadata.entity.d.ts.map +1 -1
- package/dist/entities/field-metadata.entity.js +2 -1
- package/dist/entities/field-metadata.entity.js.map +1 -1
- package/dist/entities/legacy-common.entity.d.ts.map +1 -1
- package/dist/entities/legacy-common.entity.js +5 -4
- package/dist/entities/legacy-common.entity.js.map +1 -1
- package/dist/entities/model-metadata.entity.d.ts.map +1 -1
- package/dist/entities/model-metadata.entity.js +5 -1
- package/dist/entities/model-metadata.entity.js.map +1 -1
- package/dist/factories/mail.factory.d.ts.map +1 -1
- package/dist/factories/mail.factory.js.map +1 -1
- package/dist/factories/sms.factory.d.ts +14 -0
- package/dist/factories/sms.factory.d.ts.map +1 -0
- package/dist/factories/sms.factory.js +53 -0
- package/dist/factories/sms.factory.js.map +1 -0
- package/dist/helpers/date.helper.d.ts.map +1 -1
- package/dist/helpers/date.helper.js +13 -4
- package/dist/helpers/date.helper.js.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +3 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +99 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/helpers/image-encoding.helper.d.ts +10 -0
- package/dist/helpers/image-encoding.helper.d.ts.map +1 -0
- package/dist/helpers/image-encoding.helper.js +44 -0
- package/dist/helpers/image-encoding.helper.js.map +1 -0
- package/dist/helpers/module.helper.d.ts.map +1 -1
- package/dist/helpers/module.helper.js +2 -0
- package/dist/helpers/module.helper.js.map +1 -1
- package/dist/helpers/solid-microservice-adapter.service.d.ts +31 -0
- package/dist/helpers/solid-microservice-adapter.service.d.ts.map +1 -0
- package/dist/helpers/solid-microservice-adapter.service.js +53 -0
- package/dist/helpers/solid-microservice-adapter.service.js.map +1 -0
- package/dist/helpers/solid-registry.d.ts +3 -0
- package/dist/helpers/solid-registry.d.ts.map +1 -1
- package/dist/helpers/solid-registry.js +7 -0
- package/dist/helpers/solid-registry.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/jobs/database/{sms-publisher-database.service.d.ts → msg91-sms-publisher-database.service.d.ts} +2 -2
- package/dist/jobs/database/msg91-sms-publisher-database.service.d.ts.map +1 -0
- package/dist/jobs/database/{sms-publisher-database.service.js → msg91-sms-publisher-database.service.js} +8 -8
- package/dist/jobs/database/msg91-sms-publisher-database.service.js.map +1 -0
- package/dist/jobs/database/{sms-queue-database-options.d.ts → msg91-sms-queue-database-options.d.ts} +1 -1
- package/dist/jobs/database/msg91-sms-queue-database-options.d.ts.map +1 -0
- package/dist/jobs/database/{sms-queue-database-options.js → msg91-sms-queue-database-options.js} +1 -1
- package/dist/jobs/database/msg91-sms-queue-database-options.js.map +1 -0
- package/dist/jobs/database/{sms-subscriber-database.service.d.ts → msg91-sms-subscriber-database.service.d.ts} +5 -5
- package/dist/jobs/database/msg91-sms-subscriber-database.service.d.ts.map +1 -0
- package/dist/jobs/database/{sms-subscriber-database.service.js → msg91-sms-subscriber-database.service.js} +14 -12
- package/dist/jobs/database/msg91-sms-subscriber-database.service.js.map +1 -0
- package/dist/jobs/database/otp-subscriber-database.service.d.ts +4 -4
- package/dist/jobs/database/otp-subscriber-database.service.d.ts.map +1 -1
- package/dist/jobs/database/otp-subscriber-database.service.js +6 -4
- package/dist/jobs/database/otp-subscriber-database.service.js.map +1 -1
- package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts +3 -3
- package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts.map +1 -1
- package/dist/jobs/database/twilio-sms-subscriber-database.service.js +6 -4
- package/dist/jobs/database/twilio-sms-subscriber-database.service.js.map +1 -1
- package/dist/jobs/{sms-publisher.service.d.ts → msg91-otp-publisher.service.d.ts} +2 -2
- package/dist/jobs/msg91-otp-publisher.service.d.ts.map +1 -0
- package/dist/jobs/{sms-publisher.service.js → msg91-otp-publisher.service.js} +8 -8
- package/dist/jobs/msg91-otp-publisher.service.js.map +1 -0
- package/dist/jobs/{sms-queue-options.d.ts → msg91-otp-queue-options.d.ts} +1 -1
- package/dist/jobs/msg91-otp-queue-options.d.ts.map +1 -0
- package/dist/jobs/{otp-queue-options.js → msg91-otp-queue-options.js} +1 -1
- package/dist/jobs/msg91-otp-queue-options.js.map +1 -0
- package/dist/jobs/{sms-subscriber.service.d.ts → msg91-otp-subscriber.service.d.ts} +6 -6
- package/dist/jobs/msg91-otp-subscriber.service.d.ts.map +1 -0
- package/dist/jobs/{otp-subscriber.service.js → msg91-otp-subscriber.service.js} +14 -12
- package/dist/jobs/msg91-otp-subscriber.service.js.map +1 -0
- package/dist/jobs/{otp-publisher.service.d.ts → msg91-sms-publisher.service.d.ts} +2 -2
- package/dist/jobs/msg91-sms-publisher.service.d.ts.map +1 -0
- package/dist/jobs/{otp-publisher.service.js → msg91-sms-publisher.service.js} +8 -8
- package/dist/jobs/msg91-sms-publisher.service.js.map +1 -0
- package/dist/jobs/{otp-queue-options.d.ts → msg91-sms-queue-options.d.ts} +1 -1
- package/dist/jobs/msg91-sms-queue-options.d.ts.map +1 -0
- package/dist/jobs/{sms-queue-options.js → msg91-sms-queue-options.js} +1 -1
- package/dist/jobs/msg91-sms-queue-options.js.map +1 -0
- package/dist/jobs/{otp-subscriber.service.d.ts → msg91-sms-subscriber.service.d.ts} +7 -7
- package/dist/jobs/msg91-sms-subscriber.service.d.ts.map +1 -0
- package/dist/jobs/{sms-subscriber.service.js → msg91-sms-subscriber.service.js} +14 -12
- package/dist/jobs/msg91-sms-subscriber.service.js.map +1 -0
- package/dist/jobs/twilio-sms-subscriber.service.d.ts +3 -3
- package/dist/jobs/twilio-sms-subscriber.service.d.ts.map +1 -1
- package/dist/jobs/twilio-sms-subscriber.service.js +6 -4
- package/dist/jobs/twilio-sms-subscriber.service.js.map +1 -1
- package/dist/mappers/list-of-values-mapper.d.ts.map +1 -1
- package/dist/mappers/list-of-values-mapper.js +1 -1
- package/dist/mappers/list-of-values-mapper.js.map +1 -1
- package/dist/repository/security-rule.repository.d.ts.map +1 -1
- package/dist/repository/security-rule.repository.js +7 -2
- package/dist/repository/security-rule.repository.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +24 -2
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +71 -25
- package/dist/seeders/user-seeder.service.d.ts.map +1 -1
- package/dist/seeders/user-seeder.service.js +5 -4
- package/dist/seeders/user-seeder.service.js.map +1 -1
- package/dist/services/authentication.service.d.ts +6 -3
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +53 -18
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
- package/dist/services/crud.service.d.ts +1 -2
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +6 -1
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/excel.service.d.ts +1 -0
- package/dist/services/excel.service.d.ts.map +1 -1
- package/dist/services/excel.service.js +4 -0
- package/dist/services/excel.service.js.map +1 -1
- package/dist/services/model-metadata.service.d.ts +28 -1
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +109 -2
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +3 -45
- package/dist/services/setting.service.js.map +1 -1
- package/dist/services/sms/Msg91BaseSMSService.js +6 -6
- package/dist/services/sms/Msg91BaseSMSService.js.map +1 -1
- package/dist/services/sms/Msg91OTPService.d.ts.map +1 -1
- package/dist/services/sms/Msg91OTPService.js +3 -1
- package/dist/services/sms/Msg91OTPService.js.map +1 -1
- package/dist/services/sms/Msg91SMSService.d.ts.map +1 -1
- package/dist/services/sms/Msg91SMSService.js +3 -1
- package/dist/services/sms/Msg91SMSService.js.map +1 -1
- package/dist/services/sms/TwilioSMSService.d.ts.map +1 -1
- package/dist/services/sms/TwilioSMSService.js +2 -0
- package/dist/services/sms/TwilioSMSService.js.map +1 -1
- package/dist/services/solid-introspect.service.d.ts +1 -0
- package/dist/services/solid-introspect.service.d.ts.map +1 -1
- package/dist/services/solid-introspect.service.js +14 -0
- package/dist/services/solid-introspect.service.js.map +1 -1
- package/dist/services/user.service.d.ts +8 -1
- package/dist/services/user.service.d.ts.map +1 -1
- package/dist/services/user.service.js +15 -4
- package/dist/services/user.service.js.map +1 -1
- package/dist/solid-core-cli.module.js +1 -1
- package/dist/solid-core-cli.module.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +29 -13
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
- package/dist/subscribers/scheduled-job.subscriber.js +1 -1
- package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
- package/dist/transformers/typeorm/local-date-time-transformer.d.ts +2 -2
- package/dist/transformers/typeorm/local-date-time-transformer.d.ts.map +1 -1
- package/dist/transformers/typeorm/local-date-time-transformer.js +28 -6
- package/dist/transformers/typeorm/local-date-time-transformer.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config/cache.options.ts +6 -3
- package/src/config/iam.config.ts +2 -1
- package/src/controllers/model-metadata.controller.ts +21 -1
- package/src/controllers/setting.controller.ts +32 -36
- package/src/decorators/sms-provider.decorator.ts +7 -0
- package/src/dtos/create-role-metadata.dto.ts +3 -0
- package/src/dtos/navigation.dto.ts +14 -0
- package/src/dtos/sign-in.dto.ts +3 -3
- package/src/entities/common.entity.ts +7 -7
- package/src/entities/field-metadata.entity.ts +1 -1
- package/src/entities/legacy-common.entity.ts +6 -5
- package/src/entities/model-metadata.entity.ts +1 -1
- package/src/factories/mail.factory.ts +0 -1
- package/src/factories/sms.factory.ts +43 -0
- package/src/helpers/date.helper.ts +38 -9
- package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +138 -4
- package/src/helpers/image-encoding.helper.ts +71 -0
- package/src/helpers/module.helper.ts +3 -0
- package/src/helpers/solid-microservice-adapter.service.ts +68 -0
- package/src/helpers/solid-registry.ts +9 -0
- package/src/index.ts +11 -6
- package/src/jobs/database/{sms-publisher-database.service.ts → msg91-sms-publisher-database.service.ts} +2 -2
- package/src/jobs/database/{sms-subscriber-database.service.ts → msg91-sms-subscriber-database.service.ts} +9 -4
- package/src/jobs/database/otp-subscriber-database.service.ts +8 -2
- package/src/jobs/database/twilio-sms-subscriber-database.service.ts +5 -2
- package/src/jobs/{otp-publisher.service.ts → msg91-otp-publisher.service.ts} +2 -2
- package/src/jobs/{otp-subscriber.service.ts → msg91-otp-subscriber.service.ts} +10 -4
- package/src/jobs/{sms-publisher.service.ts → msg91-sms-publisher.service.ts} +2 -2
- package/src/jobs/{sms-subscriber.service.ts → msg91-sms-subscriber.service.ts} +9 -4
- package/src/jobs/twilio-sms-subscriber.service.ts +6 -2
- package/src/mappers/list-of-values-mapper.ts +2 -1
- package/src/repository/security-rule.repository.ts +7 -2
- package/src/seeders/module-metadata-seeder.service.ts +33 -6
- package/src/seeders/seed-data/email-templates/email-on-signup.handlebars.html +155 -0
- package/src/seeders/seed-data/sms-templates/text-on-signup.handlebars.txt +10 -0
- package/src/seeders/seed-data/solid-core-metadata.json +72 -26
- package/src/seeders/user-seeder.service.ts +5 -4
- package/src/services/1.js +6 -0
- package/src/services/authentication.service.ts +80 -15
- package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +1 -2
- package/src/services/crud.service.ts +23 -19
- package/src/services/excel.service.ts +6 -0
- package/src/services/model-metadata.service.ts +151 -0
- package/src/services/setting.service.ts +12 -52
- package/src/services/sms/Msg91BaseSMSService.ts +6 -6
- package/src/services/sms/Msg91OTPService.ts +3 -2
- package/src/services/sms/Msg91SMSService.ts +3 -1
- package/src/services/sms/TwilioSMSService.ts +3 -3
- package/src/services/solid-introspect.service.ts +22 -0
- package/src/services/user.service.ts +19 -0
- package/src/solid-core-cli.module.ts +2 -2
- package/src/solid-core.module.ts +33 -13
- package/src/subscribers/scheduled-job.subscriber.ts +9 -2
- package/src/transformers/typeorm/local-date-time-transformer.ts +38 -13
- package/dist/jobs/database/sms-publisher-database.service.d.ts.map +0 -1
- package/dist/jobs/database/sms-publisher-database.service.js.map +0 -1
- package/dist/jobs/database/sms-queue-database-options.d.ts.map +0 -1
- package/dist/jobs/database/sms-queue-database-options.js.map +0 -1
- package/dist/jobs/database/sms-subscriber-database.service.d.ts.map +0 -1
- package/dist/jobs/database/sms-subscriber-database.service.js.map +0 -1
- package/dist/jobs/otp-publisher.service.d.ts.map +0 -1
- package/dist/jobs/otp-publisher.service.js.map +0 -1
- package/dist/jobs/otp-queue-options.d.ts.map +0 -1
- package/dist/jobs/otp-queue-options.js.map +0 -1
- package/dist/jobs/otp-subscriber.service.d.ts.map +0 -1
- package/dist/jobs/otp-subscriber.service.js.map +0 -1
- package/dist/jobs/sms-publisher.service.d.ts.map +0 -1
- package/dist/jobs/sms-publisher.service.js.map +0 -1
- package/dist/jobs/sms-queue-options.d.ts.map +0 -1
- package/dist/jobs/sms-queue-options.js.map +0 -1
- package/dist/jobs/sms-subscriber.service.d.ts.map +0 -1
- package/dist/jobs/sms-subscriber.service.js.map +0 -1
- /package/src/jobs/database/{sms-queue-database-options.ts → msg91-sms-queue-database-options.ts} +0 -0
- /package/src/jobs/{otp-queue-options.ts → msg91-otp-queue-options.ts} +0 -0
- /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.
|
|
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
|
|
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
|
-
}
|
|
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
|
-
|
package/src/config/iam.config.ts
CHANGED
|
@@ -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
|
|
102
|
-
@UseInterceptors(AnyFilesInterceptor())
|
|
103
|
-
async
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
}
|
|
@@ -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
|
+
}
|
package/src/dtos/sign-in.dto.ts
CHANGED
|
@@ -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: '
|
|
6
|
+
@ApiProperty({ default: 'sa@solidxai.com' })
|
|
7
7
|
@IsEmail()
|
|
8
8
|
// @IsNotEmpty()
|
|
9
9
|
@IsOptional()
|
|
10
10
|
email: string;
|
|
11
11
|
|
|
12
|
-
@ApiProperty({ default: '
|
|
12
|
+
@ApiProperty({ default: 'sa' })
|
|
13
13
|
@IsString()
|
|
14
14
|
// @IsNotEmpty()
|
|
15
15
|
@IsOptional()
|
|
16
16
|
username: string;
|
|
17
17
|
|
|
18
|
-
@ApiProperty({ default: '
|
|
18
|
+
@ApiProperty({ default: '' })
|
|
19
19
|
@IsOptional()
|
|
20
20
|
password: string;
|
|
21
21
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Column, CreateDateColumn, DeleteDateColumn, Index,
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
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
|
|
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
|
-
|
|
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',
|
|
25
|
-
'YYYY-MM-DDTHH:mm:ss.SSS',
|
|
26
|
-
'YYYY-MM-DDTHH:mm:ssZ',
|
|
46
|
+
'YYYY-MM-DDTHH:mm:ss',
|
|
47
|
+
'YYYY-MM-DDTHH:mm:ss.SSS',
|
|
48
|
+
'YYYY-MM-DDTHH:mm:ssZ',
|
|
27
49
|
];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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({
|