@solidstarters/solid-core 1.2.58 → 1.2.60

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 (53) hide show
  1. package/dist/config/iam.config.d.ts +2 -0
  2. package/dist/config/iam.config.d.ts.map +1 -1
  3. package/dist/config/iam.config.js +1 -0
  4. package/dist/config/iam.config.js.map +1 -1
  5. package/dist/controllers/setting.controller.d.ts +3 -0
  6. package/dist/controllers/setting.controller.d.ts.map +1 -1
  7. package/dist/controllers/setting.controller.js +23 -0
  8. package/dist/controllers/setting.controller.js.map +1 -1
  9. package/dist/dtos/create-setting.dto.d.ts +2 -15
  10. package/dist/dtos/create-setting.dto.d.ts.map +1 -1
  11. package/dist/dtos/create-setting.dto.js +6 -77
  12. package/dist/dtos/create-setting.dto.js.map +1 -1
  13. package/dist/dtos/update-setting.dto.d.ts +2 -15
  14. package/dist/dtos/update-setting.dto.d.ts.map +1 -1
  15. package/dist/dtos/update-setting.dto.js +6 -77
  16. package/dist/dtos/update-setting.dto.js.map +1 -1
  17. package/dist/dtos/update-settings.dto.d.ts +4 -0
  18. package/dist/dtos/update-settings.dto.d.ts.map +1 -0
  19. package/dist/dtos/update-settings.dto.js +26 -0
  20. package/dist/dtos/update-settings.dto.js.map +1 -0
  21. package/dist/entities/setting.entity.d.ts +2 -15
  22. package/dist/entities/setting.entity.d.ts.map +1 -1
  23. package/dist/entities/setting.entity.js +4 -65
  24. package/dist/entities/setting.entity.js.map +1 -1
  25. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  26. package/dist/seeders/module-metadata-seeder.service.js +1 -18
  27. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  28. package/dist/seeders/seed-data/solid-core-metadata.json +7 -174
  29. package/dist/services/authentication.service.d.ts +3 -1
  30. package/dist/services/authentication.service.d.ts.map +1 -1
  31. package/dist/services/authentication.service.js +12 -17
  32. package/dist/services/authentication.service.js.map +1 -1
  33. package/dist/services/setting.service.d.ts +4 -0
  34. package/dist/services/setting.service.d.ts.map +1 -1
  35. package/dist/services/setting.service.js +139 -7
  36. package/dist/services/setting.service.js.map +1 -1
  37. package/dist/services/user.service.d.ts +5 -2
  38. package/dist/services/user.service.d.ts.map +1 -1
  39. package/dist/services/user.service.js +21 -3
  40. package/dist/services/user.service.js.map +1 -1
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +1 -1
  43. package/src/config/iam.config.ts +1 -0
  44. package/src/controllers/setting.controller.ts +13 -1
  45. package/src/dtos/create-setting.dto.ts +10 -59
  46. package/src/dtos/update-setting.dto.ts +10 -60
  47. package/src/dtos/update-settings.dto.ts +7 -0
  48. package/src/entities/setting.entity.ts +8 -46
  49. package/src/seeders/module-metadata-seeder.service.ts +1 -19
  50. package/src/seeders/seed-data/solid-core-metadata.json +7 -174
  51. package/src/services/authentication.service.ts +10 -16
  52. package/src/services/setting.service.ts +163 -14
  53. package/src/services/user.service.ts +28 -5
@@ -38,31 +38,88 @@ export class SettingService extends CRUDService<Setting> {
38
38
  );
39
39
  }
40
40
 
41
- async wrapSettings(): Promise<Record<string, any>> {
42
- const settingsArray: any[] = await this.repo.find();
41
+ async seedDefaultSettings(): Promise<void> {
42
+ const settingsSeederData = {
43
+ allowPublicRegistration: this.iamConfiguration.allowPublicRegistration,
44
+ iamPasswordRegistrationEnabled: this.iamConfiguration.iamPasswordRegistrationEnabled,
45
+ passwordlessRegistration: this.iamConfiguration.passwordlessRegistration,
46
+ activateUserOnRegistration: this.iamConfiguration.activateUserOnRegistration,
47
+ iamGoogleOAuthEnabled: false,
48
+ authPagesLayout: "center",
49
+ authPagesTheme: "light",
50
+ appTitle: process.env.SOLID_APP_NAME || "Solid App",
51
+ appLogo: "",
52
+ appDescription: "",
53
+ appTnc: "",
54
+ appPrivacyPolicy: "",
55
+ defaultRole: this.iamConfiguration.defaultRole,
56
+ shouldQueueEmails: this.commonConfiguration.shouldQueueEmails,
57
+ shouldQueueSms: this.commonConfiguration.shouldQueueSms
58
+ };
43
59
 
44
- if (!settingsArray || settingsArray.length === 0) {
45
- return this.getDefaultSettings();
60
+ const existingSettings = await this.repo.find();
61
+ const existingKeys = new Set(existingSettings.map(s => s.key));
62
+
63
+ const settingsToInsert: Setting[] = [];
64
+ for (const [key, value] of Object.entries(settingsSeederData)) {
65
+ if (!existingKeys.has(key)) {
66
+ const setting = new Setting();
67
+ setting.key = key;
68
+ setting.value = typeof value === 'boolean' ? value.toString() :
69
+ Array.isArray(value) ? value.join(',') :
70
+ value === null || value === undefined ? '' : String(value);
71
+ settingsToInsert.push(setting);
72
+ }
46
73
  }
47
74
 
48
- const settings = settingsArray[0];
75
+ if (settingsToInsert.length > 0) {
76
+ await this.repo.save(settingsToInsert);
77
+ }
78
+ }
49
79
 
80
+ async wrapSettings(): Promise<Record<string, any>> {
81
+ const settingsArray: Setting[] = await this.repo.find();
82
+
83
+ if (!settingsArray || settingsArray.length === 0) {
84
+ return this.getDefaultSettings();
85
+ }
86
+
87
+ const settingsMap: Record<string, any> = {};
88
+ for (const setting of settingsArray) {
89
+ if (setting.key && setting.value !== undefined && setting.value !== null) {
90
+ let value = setting.value;
91
+
92
+ if (value === 'true' || value === 'false') {
93
+ settingsMap[setting.key] = value === 'true';
94
+ }
95
+ else if (!isNaN(Number(value)) && value.trim() !== '') {
96
+ settingsMap[setting.key] = Number(value);
97
+ }
98
+ else if (value.includes(',')) {
99
+ settingsMap[setting.key] = value.split(',').map(item => item.trim());
100
+ }
101
+ else {
102
+ settingsMap[setting.key] = value;
103
+ }
104
+ }
105
+ }
106
+
50
107
  const defaultSettings = this.getDefaultSettings();
51
-
108
+
52
109
  const mergedSettings = Object.keys(defaultSettings).reduce((acc, key) => {
53
- acc[key] = settings[key] !== null && settings[key] !== undefined ? settings[key] : defaultSettings[key];
110
+ acc[key] = settingsMap[key] !== undefined ? settingsMap[key] : defaultSettings[key];
54
111
  return acc;
55
112
  }, {} as Record<string, any>);
56
-
113
+
57
114
  return mergedSettings;
58
115
  }
59
-
116
+
60
117
  private getDefaultSettings(): Record<string, any> {
61
118
  return {
62
- iamAllowPublicRegistration: this.iamConfiguration.allowPublicRegistration,
63
- iamPasswordRegistrationEnabled: false,
64
- iamPasswordLessRegistrationEnabled: this.iamConfiguration.passwordlessRegistration,
65
- iamActivateUserOnRegistration: this.iamConfiguration.activateUserOnRegistration,
119
+ allowPublicRegistration: this.iamConfiguration.allowPublicRegistration,
120
+ iamPasswordRegistrationEnabled: this.iamConfiguration.iamPasswordRegistrationEnabled,
121
+ passwordlessRegistration: this.iamConfiguration.passwordlessRegistration,
122
+ activateUserOnRegistration: this.iamConfiguration.activateUserOnRegistration,
66
123
  iamGoogleOAuthEnabled: false,
67
124
  authPagesLayout: "center",
68
125
  authPagesTheme: "light",
@@ -71,10 +128,102 @@ export class SettingService extends CRUDService<Setting> {
71
128
  appDescription: "",
72
129
  appTnc: "",
73
130
  appPrivacyPolicy: "",
74
- iamDefaultRole: this.iamConfiguration.defaultRole,
131
+ defaultRole: this.iamConfiguration.defaultRole,
75
132
  shouldQueueEmails: this.commonConfiguration.shouldQueueEmails,
76
133
  shouldQueueSms: this.commonConfiguration.shouldQueueSms
77
134
  };
78
135
  }
79
136
 
137
+ async getConfigValue(settingKey: string) {
138
+ try {
139
+ const settingsArray: Setting[] = await this.repo.find();
140
+ const settingEntry = settingsArray.find(setting => setting.key === settingKey);
141
+
142
+ if (settingEntry && settingEntry.value !== null && settingEntry.value !== undefined) {
143
+ const value = settingEntry.value;
144
+
145
+ if (value === 'true' || value === 'false') {
146
+ return value === 'true';
147
+ }
148
+ else if (!isNaN(Number(value)) && value.trim() !== '') {
149
+ return Number(value);
150
+ }
151
+ else if (value.includes(',')) {
152
+ return value.split(',').map(item => item.trim());
153
+ }
154
+ else {
155
+ return value;
156
+ }
157
+ }
158
+
159
+ const defaultSettings = this.getDefaultSettings();
160
+ return defaultSettings[settingKey];
161
+ } catch (error) {
162
+ const defaultSettings = this.getDefaultSettings();
163
+ return defaultSettings[settingKey];
164
+ }
165
+ }
166
+
167
+ async updateSettings(settings: Record<string, any>): Promise<Setting[]> {
168
+ const existingSettings = await this.repo.find();
169
+ const existingKeys = new Set(existingSettings.map(s => s.key));
170
+
171
+ const settingsToUpdate: Setting[] = [];
172
+ const settingsToCreate: Setting[] = [];
173
+
174
+ for (const [key, value] of Object.entries(settings)) {
175
+ const stringValue = typeof value === 'boolean' ? value.toString() :
176
+ Array.isArray(value) ? value.join(',') :
177
+ value === null || value === undefined ? '' : String(value);
178
+
179
+ if (existingKeys.has(key)) {
180
+ const existingSetting = existingSettings.find(s => s.key === key);
181
+ if (existingSetting) {
182
+ existingSetting.value = stringValue;
183
+ settingsToUpdate.push(existingSetting);
184
+ }
185
+ } else {
186
+ const newSetting = new Setting();
187
+ newSetting.key = key;
188
+ newSetting.value = stringValue;
189
+ settingsToCreate.push(newSetting);
190
+ }
191
+ }
192
+
193
+ if (settingsToUpdate.length > 0) {
194
+ await this.repo.save(settingsToUpdate);
195
+ }
196
+
197
+ if (settingsToCreate.length > 0) {
198
+ await this.repo.save(settingsToCreate);
199
+ }
200
+
201
+ return [...settingsToUpdate, ...settingsToCreate];
202
+ }
203
+
204
+ async getAllSettings(): Promise<Record<string, any>> {
205
+ const settingsArray = await this.repo.find();
206
+ const settingsMap: Record<string, any> = {};
207
+
208
+ for (const setting of settingsArray) {
209
+ if (setting.key && setting.value !== undefined && setting.value !== null) {
210
+ const value = setting.value;
211
+
212
+ if (value === 'true' || value === 'false') {
213
+ settingsMap[setting.key] = value === 'true';
214
+ }
215
+ else if (!isNaN(Number(value)) && value.trim() !== '') {
216
+ settingsMap[setting.key] = Number(value);
217
+ }
218
+ else if (value.includes(',')) {
219
+ settingsMap[setting.key] = value.split(',').map(item => item.trim());
220
+ }
221
+ else {
222
+ settingsMap[setting.key] = value;
223
+ }
224
+ }
225
+ }
226
+
227
+ return settingsMap;
228
+ }
80
229
  }
@@ -1,5 +1,5 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { ConfigService } from '@nestjs/config';
1
+ import { BadRequestException, Inject, Injectable } from '@nestjs/common';
2
+ import { ConfigService, ConfigType } from '@nestjs/config';
3
3
  import { DiscoveryService, ModuleRef } from "@nestjs/core";
4
4
  import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
5
5
  import { CrudHelperService } from "src/services/crud-helper.service";
@@ -14,6 +14,7 @@ import { OauthUserDto } from '../dtos/oauth-user-dto';
14
14
  import { RoleMetadata } from '../entities/role-metadata.entity';
15
15
  import { User } from '../entities/user.entity';
16
16
  import { ActiveUserData } from '../interfaces/active-user-data.interface';
17
+ import { iamConfig } from 'src/config/iam.config';
17
18
 
18
19
  @Injectable()
19
20
  export class UserService extends CRUDService<User> {
@@ -30,8 +31,10 @@ export class UserService extends CRUDService<User> {
30
31
  readonly repo: Repository<User>,
31
32
  @InjectRepository(RoleMetadata)
32
33
  private readonly roleRepository: Repository<RoleMetadata>,
33
- readonly moduleRef: ModuleRef
34
-
34
+ readonly moduleRef: ModuleRef,
35
+ @Inject(iamConfig.KEY)
36
+ private readonly iamConfiguration: ConfigType<typeof iamConfig>,
37
+
35
38
  ) {
36
39
  super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'user', 'solid-core', moduleRef);
37
40
  }
@@ -195,7 +198,10 @@ export class UserService extends CRUDService<User> {
195
198
  user.googleId = oauthUserDto.providerId;
196
199
  user.googleProfilePicture = oauthUserDto.picture;
197
200
 
198
- return await this.repo.save(user);
201
+ const savedUser = await this.repo.save(user);
202
+
203
+ // Initialize the user roles
204
+ this.initializeRolesForNewUser([this.iamConfiguration.defaultRole], savedUser);
199
205
  }
200
206
  // else we update the user and store the generated code & access token.
201
207
  else {
@@ -230,4 +236,21 @@ export class UserService extends CRUDService<User> {
230
236
  const matchingPermssions = activeUser.permissions.filter((p) => query.permissionNames.includes(p));
231
237
  return matchingPermssions
232
238
  }
239
+
240
+ initializeRolesForNewUser(roles: string[], user: User) {
241
+ if (!user.id) {
242
+ throw new BadRequestException('User must exist before initializing roles');
243
+ }
244
+ let userRoles = [];
245
+ // Default Internal user role assigned
246
+ userRoles.push("Internal User");
247
+ if (roles) {
248
+ userRoles = [...userRoles, ...roles];
249
+ }
250
+ userRoles = Array.from(new Set([...userRoles]));
251
+ if (userRoles.length > 0) {
252
+ this.addRolesToUser(user.username, userRoles);
253
+ }
254
+ }
255
+
233
256
  }