@solidxai/core 0.1.9-beta.7 → 0.1.9

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 (165) hide show
  1. package/LICENSE +89 -0
  2. package/README.md +3 -1
  3. package/dist/constants/chatter-message.constants.d.ts +6 -0
  4. package/dist/constants/chatter-message.constants.d.ts.map +1 -1
  5. package/dist/constants/chatter-message.constants.js +7 -1
  6. package/dist/constants/chatter-message.constants.js.map +1 -1
  7. package/dist/controllers/authentication.controller.d.ts +12 -0
  8. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  9. package/dist/controllers/authentication.controller.js +13 -0
  10. package/dist/controllers/authentication.controller.js.map +1 -1
  11. package/dist/controllers/chatter-message.controller.d.ts +1 -0
  12. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  13. package/dist/controllers/chatter-message.controller.js +12 -0
  14. package/dist/controllers/chatter-message.controller.js.map +1 -1
  15. package/dist/controllers/facebook-authentication.controller.d.ts +27 -0
  16. package/dist/controllers/facebook-authentication.controller.d.ts.map +1 -0
  17. package/dist/controllers/facebook-authentication.controller.js +117 -0
  18. package/dist/controllers/facebook-authentication.controller.js.map +1 -0
  19. package/dist/controllers/menu-item-metadata.controller.d.ts +1 -0
  20. package/dist/controllers/menu-item-metadata.controller.d.ts.map +1 -1
  21. package/dist/controllers/menu-item-metadata.controller.js +15 -0
  22. package/dist/controllers/menu-item-metadata.controller.js.map +1 -1
  23. package/dist/controllers/microsoft-authentication.controller.d.ts +27 -0
  24. package/dist/controllers/microsoft-authentication.controller.d.ts.map +1 -0
  25. package/dist/controllers/microsoft-authentication.controller.js +118 -0
  26. package/dist/controllers/microsoft-authentication.controller.js.map +1 -0
  27. package/dist/controllers/setting.controller.d.ts +2 -2
  28. package/dist/controllers/setting.controller.js +2 -2
  29. package/dist/decorators/auth.decorator.d.ts.map +1 -1
  30. package/dist/decorators/computed-field-provider.decorator.d.ts.map +1 -1
  31. package/dist/decorators/dashboard-question-data-provider.decorator.d.ts.map +1 -1
  32. package/dist/decorators/dashboard-selection-provider.decorator.d.ts.map +1 -1
  33. package/dist/decorators/disallow-in-production.decorator.d.ts.map +1 -1
  34. package/dist/decorators/error-codes-provider.decorator.d.ts.map +1 -1
  35. package/dist/decorators/extension-user-creation-provider.decorator.d.ts.map +1 -1
  36. package/dist/decorators/is-not-in-enum.decorator.d.ts.map +1 -1
  37. package/dist/decorators/mail-provider.decorator.d.ts.map +1 -1
  38. package/dist/decorators/roles.decorator.d.ts.map +1 -1
  39. package/dist/decorators/scheduled-job-provider.decorator.d.ts.map +1 -1
  40. package/dist/decorators/security-rule-config-provider.decorator.d.ts.map +1 -1
  41. package/dist/decorators/selection-provider.decorator.d.ts.map +1 -1
  42. package/dist/decorators/sms-provider.decorator.d.ts.map +1 -1
  43. package/dist/decorators/solid-database-module.decorator.d.ts.map +1 -1
  44. package/dist/decorators/whatsapp-provider.decorator.d.ts.map +1 -1
  45. package/dist/dtos/create-chatter-message.dto.d.ts +1 -0
  46. package/dist/dtos/create-chatter-message.dto.d.ts.map +1 -1
  47. package/dist/dtos/create-chatter-message.dto.js +7 -1
  48. package/dist/dtos/create-chatter-message.dto.js.map +1 -1
  49. package/dist/dtos/post-chatter-message.dto.d.ts +1 -0
  50. package/dist/dtos/post-chatter-message.dto.d.ts.map +1 -1
  51. package/dist/dtos/post-chatter-message.dto.js +6 -1
  52. package/dist/dtos/post-chatter-message.dto.js.map +1 -1
  53. package/dist/dtos/update-chatter-message.dto.d.ts +1 -0
  54. package/dist/dtos/update-chatter-message.dto.d.ts.map +1 -1
  55. package/dist/dtos/update-chatter-message.dto.js +7 -1
  56. package/dist/dtos/update-chatter-message.dto.js.map +1 -1
  57. package/dist/entities/chatter-message.entity.d.ts +1 -0
  58. package/dist/entities/chatter-message.entity.d.ts.map +1 -1
  59. package/dist/entities/chatter-message.entity.js +5 -1
  60. package/dist/entities/chatter-message.entity.js.map +1 -1
  61. package/dist/entities/user.entity.d.ts +8 -0
  62. package/dist/entities/user.entity.d.ts.map +1 -1
  63. package/dist/entities/user.entity.js +33 -1
  64. package/dist/entities/user.entity.js.map +1 -1
  65. package/dist/helpers/cors.helper.js +1 -1
  66. package/dist/helpers/cors.helper.js.map +1 -1
  67. package/dist/helpers/facebook-oauth.helper.d.ts +8 -0
  68. package/dist/helpers/facebook-oauth.helper.d.ts.map +1 -0
  69. package/dist/helpers/facebook-oauth.helper.js +11 -0
  70. package/dist/helpers/facebook-oauth.helper.js.map +1 -0
  71. package/dist/helpers/microsoft-oauth.helper.d.ts +9 -0
  72. package/dist/helpers/microsoft-oauth.helper.d.ts.map +1 -0
  73. package/dist/helpers/microsoft-oauth.helper.js +12 -0
  74. package/dist/helpers/microsoft-oauth.helper.js.map +1 -0
  75. package/dist/helpers/security.helper.d.ts.map +1 -1
  76. package/dist/helpers/string.helper.d.ts.map +1 -1
  77. package/dist/helpers/user-helper.d.ts.map +1 -1
  78. package/dist/helpers/user-helper.js +4 -0
  79. package/dist/helpers/user-helper.js.map +1 -1
  80. package/dist/index.d.ts +2 -0
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +2 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/interfaces.d.ts +19 -0
  85. package/dist/interfaces.d.ts.map +1 -1
  86. package/dist/interfaces.js.map +1 -1
  87. package/dist/passport-strategies/facebook-oauth.strategy.d.ts +16 -0
  88. package/dist/passport-strategies/facebook-oauth.strategy.d.ts.map +1 -0
  89. package/dist/passport-strategies/facebook-oauth.strategy.js +96 -0
  90. package/dist/passport-strategies/facebook-oauth.strategy.js.map +1 -0
  91. package/dist/passport-strategies/microsoft-oauth.strategy.d.ts +14 -0
  92. package/dist/passport-strategies/microsoft-oauth.strategy.d.ts.map +1 -0
  93. package/dist/passport-strategies/microsoft-oauth.strategy.js +77 -0
  94. package/dist/passport-strategies/microsoft-oauth.strategy.js.map +1 -0
  95. package/dist/seeders/seed-data/solid-core-metadata.json +27 -58
  96. package/dist/services/api-key.service.d.ts +17 -1
  97. package/dist/services/api-key.service.d.ts.map +1 -1
  98. package/dist/services/api-key.service.js +38 -2
  99. package/dist/services/api-key.service.js.map +1 -1
  100. package/dist/services/authentication.service.d.ts +61 -27
  101. package/dist/services/authentication.service.d.ts.map +1 -1
  102. package/dist/services/authentication.service.js +356 -164
  103. package/dist/services/authentication.service.js.map +1 -1
  104. package/dist/services/chatter-message.service.d.ts +1 -0
  105. package/dist/services/chatter-message.service.d.ts.map +1 -1
  106. package/dist/services/chatter-message.service.js +24 -7
  107. package/dist/services/chatter-message.service.js.map +1 -1
  108. package/dist/services/crud-helper.service.d.ts.map +1 -1
  109. package/dist/services/model-metadata.service.js +1 -1
  110. package/dist/services/model-metadata.service.js.map +1 -1
  111. package/dist/services/setting.service.d.ts +5 -2
  112. package/dist/services/setting.service.d.ts.map +1 -1
  113. package/dist/services/setting.service.js +51 -6
  114. package/dist/services/setting.service.js.map +1 -1
  115. package/dist/services/settings/default-settings-provider.service.d.ts +846 -0
  116. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  117. package/dist/services/settings/default-settings-provider.service.js +1096 -117
  118. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  119. package/dist/services/user.service.d.ts +12 -8
  120. package/dist/services/user.service.d.ts.map +1 -1
  121. package/dist/services/user.service.js +143 -32
  122. package/dist/services/user.service.js.map +1 -1
  123. package/dist/solid-core.module.d.ts.map +1 -1
  124. package/dist/solid-core.module.js +11 -3
  125. package/dist/solid-core.module.js.map +1 -1
  126. package/dist/transformers/array-transformer.d.ts.map +1 -1
  127. package/dist/transformers/boolean-transformer.d.ts.map +1 -1
  128. package/dist/transformers/datetime-transformer.d.ts.map +1 -1
  129. package/dist/transformers/integer-transformer.d.ts.map +1 -1
  130. package/dist/validators/is-parsable-int.d.ts.map +1 -1
  131. package/nest +0 -0
  132. package/package.json +8 -2
  133. package/src/constants/chatter-message.constants.ts +7 -0
  134. package/src/controllers/authentication.controller.ts +8 -1
  135. package/src/controllers/chatter-message.controller.ts +6 -0
  136. package/src/controllers/facebook-authentication.controller.ts +113 -0
  137. package/src/controllers/menu-item-metadata.controller.ts +21 -15
  138. package/src/controllers/microsoft-authentication.controller.ts +116 -0
  139. package/src/dtos/create-chatter-message.dto.ts +11 -0
  140. package/src/dtos/post-chatter-message.dto.ts +4 -0
  141. package/src/dtos/update-chatter-message.dto.ts +13 -1
  142. package/src/entities/chatter-message.entity.ts +4 -1
  143. package/src/entities/user.entity.ts +32 -0
  144. package/src/helpers/cors.helper.ts +1 -1
  145. package/src/helpers/facebook-oauth.helper.ts +17 -0
  146. package/src/helpers/microsoft-oauth.helper.ts +19 -0
  147. package/src/helpers/user-helper.ts +4 -0
  148. package/src/index.ts +2 -0
  149. package/src/interfaces.ts +32 -1
  150. package/src/passport-strategies/facebook-oauth.strategy.ts +115 -0
  151. package/src/passport-strategies/microsoft-oauth.strategy.ts +70 -0
  152. package/src/seeders/seed-data/solid-core-metadata.json +27 -58
  153. package/src/services/api-key.service.ts +77 -35
  154. package/src/services/authentication.service.ts +1947 -1432
  155. package/src/services/chatter-message.service.ts +23 -3
  156. package/src/services/model-metadata.service.ts +1 -1
  157. package/src/services/setting.service.ts +64 -8
  158. package/src/services/settings/default-settings-provider.service.ts +1168 -156
  159. package/src/services/user.service.ts +220 -61
  160. package/src/solid-core.module.ts +25 -8
  161. package/dev-grooming-docs/ozzy-prompts.txt +0 -70
  162. package/docs/grouping-enhancements.md +0 -89
  163. package/docs/seed-changes.md +0 -65
  164. package/docs/test-data-workflow.md +0 -200
  165. package/docs/type-declaration-import-issue.md +0 -24
@@ -1,37 +1,68 @@
1
- import { BadRequestException, forwardRef, Inject, Injectable } from '@nestjs/common';
1
+ import {
2
+ BadRequestException,
3
+ forwardRef,
4
+ Inject,
5
+ Injectable,
6
+ } from "@nestjs/common";
2
7
  import { ModuleRef } from "@nestjs/core";
3
- import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
4
- import { CRUDService } from 'src/services/crud.service';
5
- import { EntityManager, Repository } from 'typeorm';
8
+ import { InjectEntityManager, InjectRepository } from "@nestjs/typeorm";
9
+ import { CRUDService } from "src/services/crud.service";
10
+ import { EntityManager, Repository } from "typeorm";
6
11
  import type { SolidCoreSetting } from "src/services/settings/default-settings-provider.service";
7
12
 
8
-
9
- import { OauthUserDto } from '../dtos/oauth-user-dto';
10
- import { RoleMetadata } from '../entities/role-metadata.entity';
11
- import { User } from '../entities/user.entity';
12
- import { ActiveUserData } from '../interfaces/active-user-data.interface';
13
- import { ERROR_MESSAGES } from 'src/constants/error-messages';
14
- import { UserRepository } from 'src/repository/user.repository';
15
- import { RoleMetadataRepository } from 'src/repository/role-metadata.repository';
16
- import { HashingService } from './hashing.service';
13
+ import { OauthUserDto } from "../dtos/oauth-user-dto";
14
+ import { RoleMetadata } from "../entities/role-metadata.entity";
15
+ import { User } from "../entities/user.entity";
16
+ import { ActiveUserData } from "../interfaces/active-user-data.interface";
17
+ import { ERROR_MESSAGES } from "src/constants/error-messages";
18
+ import { UserRepository } from "src/repository/user.repository";
19
+ import { RoleMetadataRepository } from "src/repository/role-metadata.repository";
20
+ import { HashingService } from "./hashing.service";
17
21
 
18
22
  @Injectable()
19
23
  export class UserService extends CRUDService<User> {
24
+ private buildFacebookUsernameBase(name?: string): string {
25
+ const normalized = (name || "")
26
+ .trim()
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9]+/g, "_")
29
+ .replace(/^_+|_+$/g, "");
30
+ return normalized || "facebook_user";
31
+ }
32
+
33
+ private async resolveUniqueUsername(
34
+ preferredUsername: string,
35
+ // fallbackUsername: string,
36
+ ): Promise<string> {
37
+ let candidate = preferredUsername;
38
+ let suffix = 0;
39
+
40
+ while (await this.repo.findOne({ where: { username: candidate } })) {
41
+ suffix += 1;
42
+ candidate = `${preferredUsername}_${suffix}`;
43
+ }
44
+
45
+ if (candidate) {
46
+ return candidate;
47
+ }
48
+
49
+ // return fallbackUsername;
50
+ }
51
+
20
52
  constructor(
21
53
  readonly hashingService: HashingService,
22
54
  @InjectEntityManager()
23
55
  readonly entityManager: EntityManager,
24
56
  // @InjectRepository(User, 'default')
25
57
  readonly repo: UserRepository,
26
- @InjectRepository(User, 'default')
58
+ @InjectRepository(User, "default")
27
59
  readonly nonSecurityRuleAwareRepo: Repository<User>,
28
60
  // @InjectRepository(RoleMetadata)
29
61
  // private readonly roleRepository: Repository<RoleMetadata>,
30
62
  private readonly roleRepository: RoleMetadataRepository,
31
63
  readonly moduleRef: ModuleRef,
32
-
33
64
  ) {
34
- super(entityManager, repo, 'user', 'solid-core', moduleRef);
65
+ super(entityManager, repo, "user", "solid-core", moduleRef);
35
66
  }
36
67
 
37
68
  override async delete(id: number, solidRequestContext: any = {}) {
@@ -44,13 +75,19 @@ export class UserService extends CRUDService<User> {
44
75
  return super.delete(id, solidRequestContext);
45
76
  }
46
77
 
47
- override async deleteMany(ids: number[], solidRequestContext: any = {}): Promise<any> {
78
+ override async deleteMany(
79
+ ids: number[],
80
+ solidRequestContext: any = {},
81
+ ): Promise<any> {
48
82
  if (!ids || ids.length === 0) {
49
83
  throw new Error(ERROR_MESSAGES.DELETE_IDS_REQUIRED);
50
84
  }
51
85
 
52
86
  // ❌ If the active user is trying to delete themselves
53
- if (solidRequestContext?.activeUser?.sub && ids.includes(solidRequestContext.activeUser.id)) {
87
+ if (
88
+ solidRequestContext?.activeUser?.sub &&
89
+ ids.includes(solidRequestContext.activeUser.id)
90
+ ) {
54
91
  throw new BadRequestException(ERROR_MESSAGES.DELETE_SELF_NOT_ALLOWED);
55
92
  }
56
93
 
@@ -60,9 +97,9 @@ export class UserService extends CRUDService<User> {
60
97
  async findOneByEmail(email: string): Promise<User> {
61
98
  return await this.repo.findOne({
62
99
  where: {
63
- email: email
100
+ email: email,
64
101
  },
65
- relations: {}
102
+ relations: {},
66
103
  });
67
104
  // if (!entity) {
68
105
  // throw new NotFoundException(`user with email #${email} not found`);
@@ -73,18 +110,18 @@ export class UserService extends CRUDService<User> {
73
110
  async findOneByAccessCode(accessCode: string): Promise<User> {
74
111
  return await this.repo.findOne({
75
112
  where: {
76
- accessCode: accessCode
113
+ accessCode: accessCode,
77
114
  },
78
- relations: {}
115
+ relations: {},
79
116
  });
80
117
  }
81
118
 
82
119
  async findOneByUsername(username: string): Promise<User> {
83
120
  return await this.repo.findOne({
84
121
  where: {
85
- username: username
122
+ username: username,
86
123
  },
87
- relations: {}
124
+ relations: {},
88
125
  });
89
126
  // if (!entity) {
90
127
  // throw new NotFoundException(`user with username ${username} not found`);
@@ -96,8 +133,8 @@ export class UserService extends CRUDService<User> {
96
133
  const user = await this.repo.findOne({
97
134
  where: { id: id },
98
135
  relations: {
99
- roles: true
100
- }
136
+ roles: true,
137
+ },
101
138
  });
102
139
  if (!user) {
103
140
  throw new Error(ERROR_MESSAGES.USER_NOT_FOUND);
@@ -113,21 +150,22 @@ export class UserService extends CRUDService<User> {
113
150
  const user = await this.repo.findOne({
114
151
  where: { username: username },
115
152
  relations: {
116
- roles: true
117
- }
153
+ roles: true,
154
+ },
118
155
  });
119
156
  if (!user) {
120
157
  throw new Error(ERROR_MESSAGES.USER_NOT_FOUND_BY_USERNAME(username));
121
158
  }
122
- const role = await this.roleRepository.findOne({ where: { name: roleName } });
159
+ const role = await this.roleRepository.findOne({
160
+ where: { name: roleName },
161
+ });
123
162
  if (!role) {
124
163
  throw new Error(ERROR_MESSAGES.ROLE_NOT_FOUND(roleName));
125
164
  }
126
165
 
127
166
  if (user.roles && user.roles.length > 0) {
128
167
  user.roles.push(role);
129
- }
130
- else {
168
+ } else {
131
169
  user.roles = [role];
132
170
  }
133
171
 
@@ -137,7 +175,7 @@ export class UserService extends CRUDService<User> {
137
175
  async addRolesToUser(username: string, roleNames: string[]): Promise<User> {
138
176
  const user = await this.nonSecurityRuleAwareRepo.findOne({
139
177
  where: { username: username },
140
- relations: { roles: true }
178
+ relations: { roles: true },
141
179
  });
142
180
 
143
181
  if (!user) {
@@ -145,43 +183,47 @@ export class UserService extends CRUDService<User> {
145
183
  }
146
184
 
147
185
  const roles = await this.roleRepository.find({
148
- where: roleNames.map(roleName => ({ name: roleName }))
186
+ where: roleNames.map((roleName) => ({ name: roleName })),
149
187
  });
150
188
 
151
189
  if (roles.length !== roleNames.length) {
152
- const foundRoleNames = roles.map(role => role.name);
153
- const missingRoles = roleNames.filter(roleName => !foundRoleNames.includes(roleName));
190
+ const foundRoleNames = roles.map((role) => role.name);
191
+ const missingRoles = roleNames.filter(
192
+ (roleName) => !foundRoleNames.includes(roleName),
193
+ );
154
194
  throw new Error(ERROR_MESSAGES.ROLES_NOT_FOUND(missingRoles));
155
195
  }
156
196
 
157
- const currentRoles = user.roles.map(role => role.name);
197
+ const currentRoles = user.roles.map((role) => role.name);
158
198
 
159
- const rolesToAdd = roles.filter(role => !currentRoles.includes(role.name));
199
+ const rolesToAdd = roles.filter(
200
+ (role) => !currentRoles.includes(role.name),
201
+ );
160
202
 
161
- const rolesToRemove = user.roles.filter(role => !roleNames.includes(role.name));
203
+ const rolesToRemove = user.roles.filter(
204
+ (role) => !roleNames.includes(role.name),
205
+ );
162
206
 
163
207
  if (rolesToAdd.length > 0) {
164
208
  user.roles.push(...rolesToAdd);
165
209
  }
166
210
 
167
211
  if (rolesToRemove.length > 0) {
168
- user.roles = user.roles.filter(role => !rolesToRemove.includes(role));
212
+ user.roles = user.roles.filter((role) => !rolesToRemove.includes(role));
169
213
  }
170
214
 
171
215
  return await this.nonSecurityRuleAwareRepo.save(user);
172
216
  }
173
217
 
174
-
175
218
  async removeRoleFromUser(username: string, roleName: string): Promise<User> {
176
-
177
219
  // load the role with the respective permissions.
178
220
  const user = await this.repo.findOne({
179
221
  where: {
180
- username: username
222
+ username: username,
181
223
  },
182
224
  relations: {
183
- roles: true
184
- }
225
+ roles: true,
226
+ },
185
227
  });
186
228
 
187
229
  if (!user) {
@@ -189,7 +231,7 @@ export class UserService extends CRUDService<User> {
189
231
  }
190
232
 
191
233
  // modify the permissions array.
192
- user.roles = user.roles.filter(role => role.name !== roleName);
234
+ user.roles = user.roles.filter((role) => role.name !== roleName);
193
235
 
194
236
  return await this.repo.save(user);
195
237
  }
@@ -201,11 +243,11 @@ export class UserService extends CRUDService<User> {
201
243
  email: oauthUserDto.email,
202
244
  },
203
245
  relations: {
204
- roles: true
205
- }
246
+ roles: true,
247
+ },
206
248
  });
207
249
 
208
- // if we are unable to find a user then we need to create one.
250
+ // if we are unable to find a user then we need to create one.
209
251
  if (!user) {
210
252
  const user = new User();
211
253
  user.username = oauthUserDto.email;
@@ -220,9 +262,12 @@ export class UserService extends CRUDService<User> {
220
262
  const savedUser = await this.repo.save(user);
221
263
 
222
264
  // Initialize the user roles
223
- await this.initializeRolesForNewUser([this.settingService.getConfigValue<SolidCoreSetting>('defaultRole')], savedUser);
265
+ await this.initializeRolesForNewUser(
266
+ [this.settingService.getConfigValue<SolidCoreSetting>("defaultRole")],
267
+ savedUser,
268
+ );
224
269
  }
225
- // else we update the user and store the generated code & access token.
270
+ // else we update the user and store the generated code & access token.
226
271
  else {
227
272
  const entity = await this.repo.preload({
228
273
  id: user.id,
@@ -239,21 +284,138 @@ export class UserService extends CRUDService<User> {
239
284
  return user;
240
285
  }
241
286
 
242
- async findUsersByRole(roleName: string, relations: any = {}): Promise<User[]> {
287
+ async resolveUserOnOauthFacebook(oauthUserDto: OauthUserDto): Promise<User> {
288
+ const normalizedEmail = oauthUserDto.email?.trim().toLowerCase() || null;
289
+ let user: User | null = null;
290
+
291
+ if (oauthUserDto.providerId) {
292
+ user = await this.repo.findOne({
293
+ where: {
294
+ facebookId: oauthUserDto.providerId,
295
+ },
296
+ relations: {
297
+ roles: true,
298
+ },
299
+ });
300
+ }
301
+
302
+ if (!user) {
303
+ const facebookProviderFallback = `facebook_${oauthUserDto.providerId}`;
304
+ const facebookNameUsername = this.buildFacebookUsernameBase(
305
+ oauthUserDto.name,
306
+ );
307
+ // let username = normalizedEmail || facebookNameUsername;
308
+ let username = facebookNameUsername;
309
+
310
+ let email = normalizedEmail;
311
+
312
+ // Avoid clashing with local users that already own the same email/username.
313
+ if (normalizedEmail) {
314
+ const existingByEmail = await this.repo.findOne({
315
+ where: { email: normalizedEmail },
316
+ });
317
+ if (existingByEmail) {
318
+ username = facebookNameUsername;
319
+ email = null;
320
+ }
321
+ }
322
+ username = await this.resolveUniqueUsername(
323
+ username,
324
+ // facebookProviderFallback,
325
+ );
326
+
327
+ const newUser = new User();
328
+ newUser.username = username;
329
+ newUser.email = email;
330
+ newUser.fullName = oauthUserDto.name;
331
+ newUser.lastLoginProvider = oauthUserDto.provider;
332
+ newUser.accessCode = oauthUserDto.accessCode;
333
+ newUser.facebookAccessToken = oauthUserDto.accessToken;
334
+ newUser.facebookId = oauthUserDto.providerId;
335
+ newUser.facebookProfilePicture = oauthUserDto.picture;
336
+
337
+ const savedUser = await this.repo.save(newUser);
338
+
339
+ await this.initializeRolesForNewUser(
340
+ [this.settingService.getConfigValue<SolidCoreSetting>("defaultRole")],
341
+ savedUser,
342
+ );
343
+ return savedUser;
344
+ } else {
345
+ const entity = await this.repo.preload({
346
+ id: user.id,
347
+ lastLoginProvider: oauthUserDto.provider,
348
+ accessCode: oauthUserDto.accessCode,
349
+ facebookAccessToken: oauthUserDto.accessToken,
350
+ facebookId: oauthUserDto.providerId,
351
+ facebookProfilePicture: oauthUserDto.picture,
352
+ });
353
+ await this.repo.save(entity);
354
+ return entity;
355
+ }
356
+ }
357
+
358
+ async resolveUserOnOauthMicrosoft(oauthUserDto: OauthUserDto): Promise<User> {
359
+ const user = await this.repo.findOne({
360
+ where: {
361
+ email: oauthUserDto.email,
362
+ },
363
+ relations: {
364
+ roles: true,
365
+ },
366
+ });
367
+
368
+ if (!user) {
369
+ const newUser = new User();
370
+ newUser.username = oauthUserDto.email;
371
+ newUser.email = oauthUserDto.email;
372
+ newUser.fullName = oauthUserDto.name;
373
+ newUser.lastLoginProvider = oauthUserDto.provider;
374
+ newUser.accessCode = oauthUserDto.accessCode;
375
+ newUser.microsoftAccessToken = oauthUserDto.accessToken;
376
+ newUser.microsoftId = oauthUserDto.providerId;
377
+ newUser.microsoftProfilePicture = oauthUserDto.picture;
378
+
379
+ const savedUser = await this.repo.save(newUser);
380
+
381
+ await this.initializeRolesForNewUser(
382
+ [this.settingService.getConfigValue<SolidCoreSetting>("defaultRole")],
383
+ savedUser,
384
+ );
385
+ } else {
386
+ const entity = await this.repo.preload({
387
+ id: user.id,
388
+ lastLoginProvider: oauthUserDto.provider,
389
+ accessCode: oauthUserDto.accessCode,
390
+ microsoftAccessToken: oauthUserDto.accessToken,
391
+ microsoftId: oauthUserDto.providerId,
392
+ microsoftProfilePicture: oauthUserDto.picture,
393
+ });
394
+
395
+ await this.repo.save(entity);
396
+ }
397
+ return user;
398
+ }
399
+
400
+ async findUsersByRole(
401
+ roleName: string,
402
+ relations: any = {},
403
+ ): Promise<User[]> {
243
404
  return await this.repo.find({
244
405
  where: {
245
406
  roles: {
246
- name: roleName
247
- }
407
+ name: roleName,
408
+ },
248
409
  },
249
- relations: relations
410
+ relations: relations,
250
411
  });
251
412
  }
252
413
 
253
414
  async checkIfPermissionExists(query: any, activeUser: ActiveUserData) {
254
-
255
- const matchingPermssions = activeUser.permissions.filter((p) => query.permissionNames.includes(p));
256
- return matchingPermssions
415
+ const matchingPermssions = activeUser.permissions.filter((p) =>
416
+ query.permissionNames.includes(p),
417
+ );
418
+ return matchingPermssions;
257
419
  }
258
420
 
259
421
  async initializeRolesForNewUser(roles: string[], user: User) {
@@ -261,7 +423,7 @@ export class UserService extends CRUDService<User> {
261
423
  throw new BadRequestException(ERROR_MESSAGES.USER_MISSING_ID);
262
424
  }
263
425
  let userRoles = [];
264
- // Default Internal user role assigned
426
+ // Default Internal user role assigned
265
427
  userRoles.push("Internal User");
266
428
  if (roles) {
267
429
  userRoles = [...userRoles, ...roles];
@@ -285,7 +447,4 @@ export class UserService extends CRUDService<User> {
285
447
  passwordSchemeVersion: this.hashingService.currentVersion(),
286
448
  };
287
449
  }
288
-
289
-
290
450
  }
291
-
@@ -26,7 +26,7 @@ import { ModuleMetadata } from './entities/module-metadata.entity';
26
26
  import { CommandService } from './helpers/command.service';
27
27
  import { SchematicService } from './helpers/schematic.service';
28
28
  import { ListOfValuesSelectionProvider } from './services/selection-providers/list-of-values-selection-providers.service';
29
- import { PseudoForeignKeySelectionProvider } from './services/selection-providers/pseudo-foreign-key-selection-provider.service'
29
+ import { PseudoForeignKeySelectionProvider } from './services/selection-providers/pseudo-foreign-key-selection-provider.service';
30
30
  import { ModuleMetadataSeederService } from './seeders/module-metadata-seeder.service';
31
31
  import { ModuleTestDataService } from './seeders/module-test-data.service';
32
32
  import { CrudHelperService } from './services/crud-helper.service';
@@ -55,6 +55,11 @@ import { ActionMetadataController } from './controllers/action-metadata.controll
55
55
  import { ActionMetadata } from './entities/action-metadata.entity';
56
56
  import { ActionMetadataService } from './services/action-metadata.service';
57
57
 
58
+ import { FacebookAuthenticationController } from './controllers/facebook-authentication.controller';
59
+ import { MicrosoftAuthenticationController } from './controllers/microsoft-authentication.controller';
60
+ import { FacebookOAuthStrategy } from './passport-strategies/facebook-oauth.strategy';
61
+ import { MicrosoftOAuthStrategy } from './passport-strategies/microsoft-oauth.strategy';
62
+
58
63
  import { HttpModule } from '@nestjs/axios';
59
64
  import { JwtModule } from '@nestjs/jwt';
60
65
  import { SeedCommand } from './commands/seed.command';
@@ -133,7 +138,14 @@ import { BcryptService } from './services/bcrypt.service';
133
138
  import { UuidExternalIdEntityComputedFieldProvider } from './services/computed-fields/entity/uuid-externalid-entity-computed-field-provider.service';
134
139
  import { UuidExternalIdComputedFieldProvider } from './services/computed-fields/uuid-external-id-computed-field-provider.service';
135
140
  import { EmailTemplateService } from './services/email-template.service';
136
- import { DiskFileService, S3FileService, FileServiceFactory, DiskStoragePathBuilder, S3StoragePathBuilder, StoragePathBuilderFactory } from './services/file';
141
+ import {
142
+ DiskFileService,
143
+ S3FileService,
144
+ FileServiceFactory,
145
+ DiskStoragePathBuilder,
146
+ S3StoragePathBuilder,
147
+ StoragePathBuilderFactory,
148
+ } from './services/file';
137
149
  import { HashingService } from './services/hashing.service';
138
150
  import { ElasticEmailService } from './services/mail/elastic-email.service';
139
151
  import { SMTPEMailService } from './services/mail/smtp-email.service';
@@ -229,7 +241,6 @@ import { SmtpEmailQueueSubscriberDatabase } from './jobs/database/smtp-email-sub
229
241
  import { TwilioSmsQueuePublisherDatabase } from './jobs/database/twilio-sms-publisher-database.service';
230
242
  import { TwilioSmsQueueSubscriberDatabase } from './jobs/database/twilio-sms-subscriber-database.service';
231
243
 
232
-
233
244
  // import { ThrottlerModule } from '@nestjs/throttler';
234
245
  import { IngestCommand } from './commands/ingest.command';
235
246
  import { MailFactory } from './factories/mail.factory';
@@ -380,7 +391,6 @@ import { InfoCommand } from './commands/info.command';
380
391
  import { ListOfRolesSelectionProvider } from './services/selection-providers/list-of-roles-selectionproviders.service';
381
392
  import { Entity } from 'typeorm';
382
393
 
383
-
384
394
  @Global()
385
395
  @Module({
386
396
  imports: [
@@ -442,12 +452,12 @@ import { Entity } from 'typeorm';
442
452
  // you can also expose CORS here (not needed for simple <img>):
443
453
  // res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
444
454
  },
445
- }
455
+ },
446
456
  }),
447
457
  MulterModule.registerAsync({
448
458
  imports: [ConfigModule],
449
459
  useFactory: async (configService: ConfigService) => ({
450
- dest: process.env.AB_MEDIA_UPLOAD_DIR ?? "media-uploads",
460
+ dest: process.env.AB_MEDIA_UPLOAD_DIR ?? 'media-uploads',
451
461
  }),
452
462
  inject: [ConfigService],
453
463
  }),
@@ -474,6 +484,8 @@ import { Entity } from 'typeorm';
474
484
  ExportTransactionController,
475
485
  FieldMetadataController,
476
486
  GoogleAuthenticationController,
487
+ FacebookAuthenticationController,
488
+ MicrosoftAuthenticationController,
477
489
  ImportTransactionController,
478
490
  ImportTransactionErrorLogController,
479
491
  ListOfValuesController,
@@ -524,7 +536,7 @@ import { Entity } from 'typeorm';
524
536
  },
525
537
  {
526
538
  provide: APP_FILTER,
527
- useClass: HttpExceptionFilter
539
+ useClass: HttpExceptionFilter,
528
540
  },
529
541
  ModuleMetadataService,
530
542
  ModuleMetadataHelperService,
@@ -640,6 +652,8 @@ import { Entity } from 'typeorm';
640
652
  RefreshTokenIdsStorageService,
641
653
  SsoCodeStorageService,
642
654
  GoogleOauthStrategy,
655
+ FacebookOAuthStrategy,
656
+ MicrosoftOAuthStrategy,
643
657
  UserRegistrationListener,
644
658
  TestQueuePublisher,
645
659
  TestQueueSubscriber,
@@ -873,7 +887,10 @@ import { Entity } from 'typeorm';
873
887
  export class SolidCoreModule implements NestModule {
874
888
  configure(consumer: MiddlewareConsumer) {
875
889
  consumer
876
- .apply(express.json({ limit: '10mb' }), express.urlencoded({ limit: '10mb', extended: true }))
890
+ .apply(
891
+ express.json({ limit: '10mb' }),
892
+ express.urlencoded({ limit: '10mb', extended: true }),
893
+ )
877
894
  .forRoutes('*');
878
895
  }
879
896
  }
@@ -1,70 +0,0 @@
1
- Hi Ozzy,
2
- Can you give me instructions to create a new model in the fees portal module, you can call it address-master.
3
- This model needs to have the following fields.
4
- 1. address1 - shortText
5
- 2. address2 - shortText
6
- 3. addressType - selectionStatic with values - home, office & other.
7
- 4. city - many2one with the city model
8
- 5. state - many2one with the state model
9
- 6. pincode - many2one with the state model.
10
-
11
- After I add this model I want to start storing student address.
12
-
13
- To do this if you can also give me instructions on how to add a relation field to the student model, you can call this field studentAddress.
14
-
15
-
16
-
17
-
18
-
19
-
20
- Can you now create a new computed field provider.
21
- - You can call this provider: StateTotalCitiesComputedFieldProvider
22
- - This will be a post computation provider and will depend on the city model being inserted, deleted, updated.
23
- - The implementation simply needs to take a count of cities that belong to the same state as the city being mutated and update the state totalCities field.
24
-
25
-
26
- Can you now create a new computed field provider.
27
- - You can call this provider: StateTotalPopulationComputedFieldProvider
28
- - This will be a post computation provider and will depend on the city model being inserted, deleted, updated.
29
- - The implementation simply needs to take a sum of population of each city that belong to the same state as the city being mutated and update the state totalPopulation field.
30
-
31
-
32
- Can you now create a new computed field provider.
33
- - You can call this provider: StateTotalGdpComputedFieldProvider
34
- - This will be a post computation provider and will depend on the city model being inserted, deleted, updated.
35
- - The implementation simply needs to take a sum of gdp of each city that belong to the same state as the city being mutated and update the state totalGdp field.
36
- - I will add the totalGdp field to the state model after I have the computed provider TS code.
37
-
38
-
39
- # Testing prompt sequence
40
-
41
- ## Create Module
42
- Can you create a new module called address-master. This will be used to store address master data.
43
-
44
- ## Add Model - Country
45
- Can you add a new model to the address-master module called country.
46
- This will have name, description (richText), countryCode. You can assume name & countryCode to be unique. But only name will be used as a userkey.
47
- Also enable audit tracking on the model and all its fields.
48
- Make sure the table name is properly prefixed with the module name snake case.
49
-
50
- ## Add Model - Language
51
- Can you add a new model to the address-master module called language.
52
- This will have language, languageIsoCode. You can assume language to be unique.
53
- Also for the languageIsoCode, can you create a field with type staticSelection add a bunch (20 odd, include at-least 7-8 indian languages also) of commonly spoken languages with their respective language codes as values.
54
- Also enable audit tracking on the model and all its fields.
55
- Make sure the table name is properly prefixed with the module name snake case.
56
-
57
- ## Add Model - Country Language
58
-
59
- Can you now add a new model called CountrySpokenLanguages, this model will have 2 many-to-one fields.
60
- 1. country - many-to-one with the country model.
61
- 2. spokenLanguage - many-to-one with the language model.
62
- 3. spokenBy - int field storing data representing how many people speak that language.
63
- Also enable audit tracking on the model and all its fields.
64
- Make sure the table name is properly prefixed with the module name snake case.
65
-
66
- ## Add Model - Country Population Trend
67
- Can you add a model called CountryPopulationTrend, this model has the following fields.
68
- 1. country - many-to-one with the country model.
69
- 2. entryDate - date field.
70
- 3. populationAsOnDate - int field storing the population of that country as on that date.