@solidstarters/solid-core 1.2.66 → 1.2.68

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 (49) hide show
  1. package/dist/dtos/create-field-metadata.dto.d.ts +1 -0
  2. package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
  3. package/dist/dtos/create-field-metadata.dto.js +7 -1
  4. package/dist/dtos/create-field-metadata.dto.js.map +1 -1
  5. package/dist/entities/field-metadata.entity.d.ts +1 -0
  6. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  7. package/dist/entities/field-metadata.entity.js +5 -1
  8. package/dist/entities/field-metadata.entity.js.map +1 -1
  9. package/dist/helpers/field-crud-managers/SelectionDynamicFieldCrudManager.d.ts +1 -0
  10. package/dist/helpers/field-crud-managers/SelectionDynamicFieldCrudManager.d.ts.map +1 -1
  11. package/dist/helpers/field-crud-managers/SelectionDynamicFieldCrudManager.js +15 -1
  12. package/dist/helpers/field-crud-managers/SelectionDynamicFieldCrudManager.js.map +1 -1
  13. package/dist/helpers/field-crud-managers/SelectionStaticFieldCrudManager.d.ts +2 -1
  14. package/dist/helpers/field-crud-managers/SelectionStaticFieldCrudManager.d.ts.map +1 -1
  15. package/dist/helpers/field-crud-managers/SelectionStaticFieldCrudManager.js +16 -2
  16. package/dist/helpers/field-crud-managers/SelectionStaticFieldCrudManager.js.map +1 -1
  17. package/dist/providers/list-of-values-selection-providers.service.d.ts.map +1 -1
  18. package/dist/providers/list-of-values-selection-providers.service.js +15 -5
  19. package/dist/providers/list-of-values-selection-providers.service.js.map +1 -1
  20. package/dist/seeders/seed-data/solid-core-metadata.json +23 -51
  21. package/dist/services/authentication.service.d.ts +3 -1
  22. package/dist/services/authentication.service.d.ts.map +1 -1
  23. package/dist/services/authentication.service.js +12 -3
  24. package/dist/services/authentication.service.js.map +1 -1
  25. package/dist/services/crud.service.js +2 -2
  26. package/dist/services/crud.service.js.map +1 -1
  27. package/dist/services/field-metadata.service.d.ts.map +1 -1
  28. package/dist/services/field-metadata.service.js +4 -2
  29. package/dist/services/field-metadata.service.js.map +1 -1
  30. package/dist/services/model-metadata.service.d.ts.map +1 -1
  31. package/dist/services/model-metadata.service.js +11 -9
  32. package/dist/services/model-metadata.service.js.map +1 -1
  33. package/dist/services/user.service.d.ts +1 -1
  34. package/dist/services/user.service.d.ts.map +1 -1
  35. package/dist/services/user.service.js +2 -2
  36. package/dist/services/user.service.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +1 -1
  39. package/src/dtos/create-field-metadata.dto.ts +5 -0
  40. package/src/entities/field-metadata.entity.ts +3 -0
  41. package/src/helpers/field-crud-managers/SelectionDynamicFieldCrudManager.ts +24 -0
  42. package/src/helpers/field-crud-managers/SelectionStaticFieldCrudManager.ts +25 -3
  43. package/src/providers/list-of-values-selection-providers.service.ts +14 -5
  44. package/src/seeders/seed-data/solid-core-metadata.json +26 -56
  45. package/src/services/authentication.service.ts +16 -4
  46. package/src/services/crud.service.ts +2 -2
  47. package/src/services/field-metadata.service.ts +4 -2
  48. package/src/services/model-metadata.service.ts +15 -12
  49. package/src/services/user.service.ts +6 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.66",
3
+ "version": "1.2.68",
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",
@@ -409,4 +409,9 @@ export class CreateFieldMetadataDto {
409
409
  @IsOptional()
410
410
  @IsBoolean()
411
411
  enableAuditTracking?: boolean;
412
+
413
+ @IsOptional()
414
+ @ApiProperty({ description: 'Is MultiSelect Field', })
415
+ @IsBoolean()
416
+ isMultiSelect: boolean;
412
417
  }
@@ -155,4 +155,7 @@ export class FieldMetadata extends CommonEntity {
155
155
 
156
156
  @Column({ name: 'enable_audit_tracking', default: false })
157
157
  enableAuditTracking: boolean;
158
+
159
+ @Column({ name: "is_multiSelect", default: false })
160
+ isMultiSelect: boolean;
158
161
  }
@@ -10,6 +10,7 @@ export interface SelectionDynamicFieldOptions {
10
10
  selectionDynamicProviderCtxt: any;
11
11
  fieldName: string;
12
12
  discoveryService: DiscoveryService;
13
+ isMultiSelect: boolean | undefined | null;
13
14
  }
14
15
 
15
16
  export class SelectionDynamicFieldCrudManager implements FieldCrudManager {
@@ -19,8 +20,31 @@ export class SelectionDynamicFieldCrudManager implements FieldCrudManager {
19
20
 
20
21
  async validate(dto: any): Promise<ValidationError[]> {
21
22
  const fieldValue: any = dto[this.options.fieldName];
23
+ const isMultiSelect = this.options?.isMultiSelect;
24
+
25
+ // return this.applyValidations(fieldValue);
26
+ // Handle multi-select scenario
27
+ if (isMultiSelect) {
28
+ let values: any[];
29
+
30
+ try {
31
+ // Try to parse the field value, which should be a JSON stringified array
32
+ values = JSON.parse(fieldValue);
33
+ } catch {
34
+ // If parsing fails, fallback to a single value
35
+ values = [fieldValue];
36
+ }
37
+
38
+ // Apply validations to each value asynchronously
39
+ const allErrors = await Promise.all(values.map(value => this.applyValidations(value)));
40
+
41
+ // Flatten the array of errors and return
42
+ return allErrors.flat();
43
+ } else {
44
+ // For non-multi-select, apply validations to the single field value
22
45
  return this.applyValidations(fieldValue);
23
46
  }
47
+ }
24
48
 
25
49
  private async applyValidations(fieldValue: any): Promise<ValidationError[]> {
26
50
  const errors: ValidationError[] = [];
@@ -7,6 +7,7 @@ export interface SelectionStaticFieldOptions {
7
7
  selectionValueType: SelectionValueType;
8
8
  required: boolean | undefined | null;
9
9
  fieldName: string;
10
+ isMultiSelect: boolean | undefined | null;
10
11
  }
11
12
 
12
13
  export class SelectionStaticFieldCrudManager implements FieldCrudManager {
@@ -14,9 +15,30 @@ export class SelectionStaticFieldCrudManager implements FieldCrudManager {
14
15
  constructor(private readonly options: SelectionStaticFieldOptions) {
15
16
  }
16
17
 
17
- validate(dto: any): ValidationError[] {
18
- const fieldValue: any = dto[this.options.fieldName];
19
- return this.applyValidations(fieldValue);
18
+ async validate(dto: any): Promise<ValidationError[]> {
19
+ const fieldValue: any = dto[this.options.fieldName];
20
+ // return this.applyValidations(fieldValue);
21
+ const isMultiSelect = this.options?.isMultiSelect;
22
+ if (isMultiSelect) {
23
+ let values: any[];
24
+
25
+ try {
26
+ // Try to parse the field value, which should be a JSON stringified array
27
+ values = JSON.parse(fieldValue);
28
+ } catch {
29
+ // If parsing fails, fallback to a single value
30
+ values = [fieldValue];
31
+ }
32
+
33
+ // Apply validations to each value asynchronously
34
+ const allErrors = await Promise.all(values.map(value => this.applyValidations(value)));
35
+
36
+ // Flatten the array of errors and return
37
+ return allErrors.flat();
38
+ } else {
39
+ // For non-multi-select, apply validations to the single field value
40
+ return this.applyValidations(fieldValue);
41
+ }
20
42
  }
21
43
 
22
44
  private applyValidations(fieldValue: any): ValidationError[] {
@@ -34,12 +34,21 @@ export class ListOfValuesSelectionProvider implements ISelectionProvider<ListOfV
34
34
 
35
35
  async values(query: string, ctxt: ListOfValuesProviderContext): Promise<readonly ISelectionProviderValues[]> {
36
36
  const basicFilterQuery = new BasicFilterDto(DEFAULT_LIMIT, 0);
37
- basicFilterQuery.filters = {
38
- type: {
39
- $eq: ctxt.type
40
- }
37
+ if (ctxt.type) {
38
+ basicFilterQuery.filters = {
39
+ type: {
40
+ $eq: ctxt.type
41
+ }
42
+ };
43
+ }
44
+ if (query) {
45
+ basicFilterQuery.filters = {
46
+ ...basicFilterQuery.filters,
47
+ display: {
48
+ $containsi: `%${query}%`
49
+ }
50
+ };
41
51
  }
42
-
43
52
  const lovs = await this.listOfValuesService.find(basicFilterQuery);
44
53
  const selectionValues = lovs.records.map(lov => {
45
54
  return {
@@ -910,6 +910,20 @@
910
910
  "encrypt": false,
911
911
  "columnName": "relation_join_table_name",
912
912
  "isSystem": true
913
+ },
914
+ {
915
+ "name": "isMultiSelect",
916
+ "displayName": "Is MultiSelect",
917
+ "type": "boolean",
918
+ "ormType": "boolean",
919
+ "defaultValue": "false",
920
+ "required": false,
921
+ "unique": false,
922
+ "index": false,
923
+ "private": false,
924
+ "encrypt": false,
925
+ "columnName": "is_multiSelect",
926
+ "isSystem": true
913
927
  }
914
928
  ]
915
929
  },
@@ -3807,7 +3821,7 @@
3807
3821
  "name": "media-menu-item",
3808
3822
  "sequenceNumber": 3,
3809
3823
  "actionUserKey": "media-root",
3810
- "moduleUserKey": "solid-core",
3824
+ "moduleUserKey": "solid-core",
3811
3825
  "parentMenuItemUserKey": ""
3812
3826
  },
3813
3827
  {
@@ -3980,32 +3994,11 @@
3980
3994
  {
3981
3995
  "attrs": {
3982
3996
  "className": "pi pi-cog",
3983
- "label": "Generate Code"
3984
- },
3985
- "action": {
3986
- "title": "",
3987
- "body": "",
3988
- "confirmBtnLabel": "Generate Code",
3989
- "cancelBtnLabel": "Cancel",
3990
- "customComponent": "GenerateModuleCodeRowAction",
3991
- "customComponentIsSystem": true,
3992
- "endpoint": ""
3993
- }
3994
- }
3995
- ],
3996
- "headerButtons": [
3997
- {
3998
- "attrs": {
3999
- "className": "pi pi-cog",
4000
- "label": "Generate Code"
4001
- },
4002
- "action": {
4003
- "title": "",
4004
- "body": "",
4005
- "confirmBtnLabel": "Generate Code",
4006
- "cancelBtnLabel": "Cancel",
4007
- "customComponent": "GenerateModuleCode",
4008
- "endpoint": ""
3997
+ "label": "Generate Code",
3998
+ "action": "GenerateModuleCodeRowAction",
3999
+ "openInPopup": true,
4000
+ "actionInContextMenu": true,
4001
+ "customComponentIsSystem": true
4009
4002
  }
4010
4003
  }
4011
4004
  ]
@@ -4172,32 +4165,11 @@
4172
4165
  {
4173
4166
  "attrs": {
4174
4167
  "className": "pi pi-cog",
4175
- "label": "Generate Code"
4176
- },
4177
- "action": {
4178
- "title": "",
4179
- "body": "",
4180
- "confirmBtnLabel": "Generate Code",
4181
- "cancelBtnLabel": "Cancel",
4182
- "customComponent": "GenerateModelCodeRowAction",
4168
+ "label": "Generate Code",
4169
+ "action": "GenerateModelCodeRowAction",
4183
4170
  "customComponentIsSystem": true,
4184
- "endpoint": ""
4185
- }
4186
- }
4187
- ],
4188
- "headerButtons": [
4189
- {
4190
- "attrs": {
4191
- "className": "pi pi-cog",
4192
- "label": "Generate Code"
4193
- },
4194
- "action": {
4195
- "title": "",
4196
- "body": "",
4197
- "confirmBtnLabel": "Generate Code",
4198
- "cancelBtnLabel": "Cancel",
4199
- "customComponent": "GenerateModelCode",
4200
- "endpoint": ""
4171
+ "actionInContextMenu": true,
4172
+ "openInPopup": true
4201
4173
  }
4202
4174
  }
4203
4175
  ]
@@ -6046,7 +6018,7 @@
6046
6018
  "attrs": {
6047
6019
  "name": "name",
6048
6020
  "isSearchable": true
6049
- }
6021
+ }
6050
6022
  },
6051
6023
  {
6052
6024
  "type": "field",
@@ -6210,7 +6182,6 @@
6210
6182
  ]
6211
6183
  }
6212
6184
  },
6213
-
6214
6185
  {
6215
6186
  "name": "media-list-view",
6216
6187
  "displayName": "Solid Media Model",
@@ -8673,6 +8644,5 @@
8673
8644
  }
8674
8645
  ],
8675
8646
  "checksums": [],
8676
- "listOfValues": [
8677
- ]
8647
+ "listOfValues": []
8678
8648
  }
@@ -41,6 +41,7 @@ import {
41
41
  } from "../constants";
42
42
  import { SettingService } from './setting.service';
43
43
  import { CreateUserDto } from 'src/dtos/create-user.dto';
44
+ import { RoleMetadataService } from './role-metadata.service';
44
45
 
45
46
  enum LoginProvider {
46
47
  LOCAL = 'local',
@@ -73,6 +74,8 @@ export class AuthenticationService {
73
74
  private readonly smsService: Msg91OTPService,
74
75
  private readonly eventEmitter: EventEmitter2,
75
76
  private readonly settingService: SettingService,
77
+ private readonly roleMetadataService: RoleMetadataService
78
+
76
79
  ) { }
77
80
 
78
81
  async resolveUser(username: string, email: string) {
@@ -145,7 +148,7 @@ export class AuthenticationService {
145
148
  var { user, pwd, autoGeneratedPwd } = await this.populateForSignup<T>(extensionUser, signUpDto);
146
149
  const savedUser = await extensionUserRepo.save(user);
147
150
 
148
- await this.handlePostSignup(savedUser, signUpDto.roles, pwd, autoGeneratedPwd);
151
+ await this.handlePostSignup(savedUser, signUpDto.roles, pwd, autoGeneratedPwd);
149
152
 
150
153
  return savedUser;
151
154
  }
@@ -158,15 +161,23 @@ export class AuthenticationService {
158
161
  }
159
162
  }
160
163
 
161
-
164
+
162
165
  private async populateForSignup<T extends User>(user: T, signUpDto: SignUpDto, isUserActive: boolean = true) {
163
166
  // const user = new User();
167
+
168
+ if (signUpDto.roles && signUpDto.roles.length > 0) {
169
+ for (let i = 0; i < signUpDto.roles.length; i++) {
170
+ const roleName = signUpDto.roles[i];
171
+ await this.roleMetadataService.findRoleByName(roleName);
172
+ }
173
+ }
164
174
  user.username = signUpDto.username;
165
175
  user.email = signUpDto.email;
166
176
  user.fullName = signUpDto.fullName;
167
177
  if (signUpDto.mobile) {
168
178
  user.mobile = signUpDto.mobile;
169
179
  }
180
+
170
181
  // If password has been specified by the user, then we simply create & activate the user based on the configuration parameter "activateUserOnRegistration".
171
182
  let pwd = '';
172
183
  let autoGeneratedPwd = '';
@@ -186,8 +197,9 @@ export class AuthenticationService {
186
197
  return { user, pwd, autoGeneratedPwd };
187
198
  }
188
199
 
189
- private async handlePostSignup(user: User, roles: string[]=[], pwd: string, autoGeneratedPwd: string) {
190
- this.userService.initializeRolesForNewUser(roles, user);
200
+
201
+ private async handlePostSignup(user: User, roles: string[] = [], pwd: string, autoGeneratedPwd: string) {
202
+ await this.userService.initializeRolesForNewUser(roles, user);
191
203
  // Tanay: Adding user password to history table
192
204
  const userPasswordHistory = new UserPasswordHistory();
193
205
  userPasswordHistory.passwordHash = pwd;
@@ -366,7 +366,7 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
366
366
  // Validation against the selectionStatic values. No transformation is required
367
367
  // If the value is not in the selectionStatic values, then throw
368
368
  // Also validate against the selectionType
369
- const options = { ...commonOptions, selectionStaticValues: fieldMetadata.selectionStaticValues, selectionValueType: fieldMetadata.selectionValueType as SelectionValueType };
369
+ const options = { ...commonOptions, selectionStaticValues: fieldMetadata.selectionStaticValues, selectionValueType: fieldMetadata.selectionValueType as SelectionValueType, isMultiSelect: fieldMetadata.isMultiSelect};
370
370
  return new SelectionStaticFieldCrudManager(options);
371
371
  }
372
372
  case SolidFieldType.selectionDynamic: {// [HOLD]
@@ -375,7 +375,7 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
375
375
  // dataSource: string; // The name of the selection provider
376
376
  // filterSchema : json // This is a custom json object that every data source will handle accordingly. We could validate the query against the selection provider
377
377
  // values : string[]; // The values returned by the selection provider
378
- const options = { ...commonOptions, selectionDynamicProvider: fieldMetadata.selectionDynamicProvider, selectionDynamicProviderCtxt: fieldMetadata.selectionDynamicProviderCtxt, selectionValueType: fieldMetadata.selectionValueType as SelectionValueType, discoveryService: this.discoveryService };
378
+ const options = { ...commonOptions, selectionDynamicProvider: fieldMetadata.selectionDynamicProvider, selectionDynamicProviderCtxt: fieldMetadata.selectionDynamicProviderCtxt, selectionValueType: fieldMetadata.selectionValueType as SelectionValueType, discoveryService: this.discoveryService, isMultiSelect: fieldMetadata.isMultiSelect};
379
379
  return new SelectionDynamicFieldCrudManager(options);
380
380
  }
381
381
  case SolidFieldType.uuid: {
@@ -866,7 +866,8 @@ export class FieldMetadataService {
866
866
  "encryptionType",
867
867
  "decryptWhen",
868
868
  "columnName",
869
- "enableAuditTracking"
869
+ "enableAuditTracking",
870
+ "isMultiSelect"
870
871
  ];
871
872
 
872
873
  case SolidFieldType.selectionDynamic:
@@ -889,7 +890,8 @@ export class FieldMetadataService {
889
890
  "decryptWhen",
890
891
  "columnName",
891
892
  "isUserKey",
892
- "enableAuditTracking"
893
+ "enableAuditTracking",
894
+ "isMultiSelect"
893
895
  ];
894
896
  case SolidFieldType.computed:
895
897
  return [
@@ -184,16 +184,19 @@ export class ModelMetadataService {
184
184
  relations: {},
185
185
  });
186
186
  createDto['module'] = resolvedModule;
187
+
188
+ if (createDto['parentModelId']) {
189
+ const resolvedParentModel = await this.dataSource
190
+ .getRepository(ModelMetadata)
191
+ .findOne({
192
+ where: {
193
+ id: createDto['parentModelId'],
194
+ },
195
+ relations: {},
196
+ });
197
+ createDto['parentModel'] = resolvedParentModel;
198
+ }
187
199
 
188
- const resolvedParentModel = await this.dataSource
189
- .getRepository(ModelMetadata)
190
- .findOne({
191
- where: {
192
- id: createDto['parentModelId'],
193
- },
194
- relations: {},
195
- });
196
- createDto['parentModel'] = resolvedParentModel;
197
200
  const { fields: fieldsMetadata, ...modelMetaDataWithoutFields } = createDto;
198
201
  const modelMetadata = this.modelMetadataRepo.create(modelMetaDataWithoutFields);
199
202
  let model = await manager.save(modelMetadata);
@@ -515,8 +518,8 @@ export class ModelMetadataService {
515
518
 
516
519
  // Generate the code for models which are linked to fields having an inverse relation
517
520
  const coModelSingularNames = model.fields.
518
- filter(field => field.type === SolidFieldType.relation && field.relationCreateInverse === true)
519
- .map(field => field.relationCoModelSingularName);
521
+ filter(field => field.type === SolidFieldType.relation && field.relationCreateInverse === true)
522
+ .map(field => field.relationCoModelSingularName);
520
523
 
521
524
  for (const singularName of coModelSingularNames) {
522
525
  const coModel = await this.findOneBySingularName(singularName);
@@ -525,7 +528,7 @@ export class ModelMetadataService {
525
528
  dryRun: options.dryRun
526
529
  };
527
530
  await this.generateCode(inverseOptions);
528
- }
531
+ }
529
532
 
530
533
  await this.generateVAMConfig(model.id);
531
534
 
@@ -34,7 +34,7 @@ export class UserService extends CRUDService<User> {
34
34
  readonly moduleRef: ModuleRef,
35
35
  @Inject(iamConfig.KEY)
36
36
  private readonly iamConfiguration: ConfigType<typeof iamConfig>,
37
-
37
+
38
38
  ) {
39
39
  super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'user', 'solid-core', moduleRef);
40
40
  }
@@ -237,20 +237,20 @@ export class UserService extends CRUDService<User> {
237
237
  return matchingPermssions
238
238
  }
239
239
 
240
- initializeRolesForNewUser(roles: string[], user: User) {
240
+ async initializeRolesForNewUser(roles: string[], user: User) {
241
241
  if (!user.id) {
242
- throw new BadRequestException('User must exist before initializing roles');
242
+ throw new BadRequestException('User must exist before initializing roles');
243
243
  }
244
244
  let userRoles = [];
245
245
  // Default Internal user role assigned
246
246
  userRoles.push("Internal User");
247
247
  if (roles) {
248
- userRoles = [...userRoles, ...roles];
248
+ userRoles = [...userRoles, ...roles];
249
249
  }
250
250
  userRoles = Array.from(new Set([...userRoles]));
251
251
  if (userRoles.length > 0) {
252
- this.addRolesToUser(user.username, userRoles);
252
+ await this.addRolesToUser(user.username, userRoles);
253
253
  }
254
- }
254
+ }
255
255
 
256
256
  }