gemcap-be-common 1.3.187 → 1.4.2

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 (45) hide show
  1. package/interfaces/auth-user.interface.d.ts +21 -0
  2. package/interfaces/auth-user.interface.ts +22 -0
  3. package/models/AvailabilitySigns.model.d.ts +11 -11
  4. package/models/AvailabilitySigns.model.js +2 -4
  5. package/models/AvailabilitySigns.model.ts +7 -9
  6. package/models/ReceivableAvailability.model.d.ts +2 -2
  7. package/models/ReceivableAvailability.model.ts +2 -2
  8. package/models/User.model.d.ts +3 -3
  9. package/models/User.model.ts +3 -3
  10. package/models/_index.d.ts +3 -3
  11. package/package.json +1 -1
  12. package/services/availability.service.d.ts +5 -5
  13. package/services/availability.service.js +1 -1
  14. package/services/availability.service.ts +6 -7
  15. package/services/borrowers.db.d.ts +1 -1
  16. package/services/borrowers.db.js +1 -1
  17. package/services/borrowers.db.ts +2 -2
  18. package/services/borrowers.service.d.ts +5 -4
  19. package/services/borrowers.service.js +8 -5
  20. package/services/borrowers.service.ts +9 -5
  21. package/services/compliance-borrowers.service.d.ts +1 -1
  22. package/services/compliance-borrowers.service.js +1 -1
  23. package/services/compliance-borrowers.service.ts +2 -3
  24. package/services/loan-payments.service.d.ts +3 -1
  25. package/services/loan-payments.service.js +5 -4
  26. package/services/loan-payments.service.ts +4 -3
  27. package/services/nodemailer.service.d.ts +0 -2
  28. package/services/nodemailer.service.js +0 -28
  29. package/services/nodemailer.service.ts +0 -35
  30. package/services/signs.service.d.ts +3 -4
  31. package/services/signs.service.js +9 -12
  32. package/services/signs.service.ts +13 -18
  33. package/services/uploads.service.d.ts +3 -1
  34. package/services/uploads.service.js +4 -3
  35. package/services/uploads.service.ts +3 -2
  36. package/services/users.service.d.ts +15 -137
  37. package/services/users.service.js +81 -349
  38. package/services/users.service.ts +88 -380
  39. package/tsconfig.tsbuildinfo +1 -1
  40. package/interfaces/keycloak-role.interface.d.ts +0 -14
  41. package/interfaces/keycloak-role.interface.ts +0 -16
  42. package/interfaces/keycloak-user.interface.d.ts +0 -31
  43. package/interfaces/keycloak-user.interface.js +0 -2
  44. package/interfaces/keycloak-user.interface.ts +0 -30
  45. /package/interfaces/{keycloak-role.interface.js → auth-user.interface.js} +0 -0
@@ -1,24 +1,19 @@
1
1
  import { jwtDecode } from 'jwt-decode';
2
- import _ from 'lodash';
3
2
  import express from 'express';
4
3
  import axios from 'axios';
5
- import dayjs from 'dayjs';
6
4
  import mongoose from 'mongoose';
7
- import qs from 'qs';
8
5
 
9
- import { createLog, ICreateLogParams } from '../db/user-logs.db';
10
- import { IKeycloakUser } from '../interfaces/keycloak-user.interface';
11
- import { IUser, IUserDocument, UserModel } from '../models/User.model';
12
6
  import { BorrowerCompliance } from '../models/BorrowerCompliance.model';
13
7
  import { UserMobileAccess } from '../models/UserMobileAccess.model';
14
- import { ELogActionType, ELogType, UserLog } from '../models/UserLog.model';
15
- import { IGroupedKeycloakRoles, IKeycloakRole } from '../interfaces/keycloak-role.interface';
8
+ import { UserLog } from '../models/UserLog.model';
9
+ import { IUser } from '../interfaces/auth-user.interface';
16
10
 
17
11
  interface IKeycloakConfig {
18
12
  keycloakHost: string;
19
13
  realm: string;
20
14
  adminUser: string;
21
15
  adminPass: string;
16
+ baseUrl: string;
22
17
  }
23
18
 
24
19
  export class UsersService {
@@ -28,410 +23,123 @@ export class UsersService {
28
23
  this.config = config;
29
24
  }
30
25
 
31
- async getUserByKeyCloakId(keycloakUserId: string): Promise<IUserDocument> {
32
- return UserModel.findOne({ keycloakUserId }).lean();
33
- }
34
-
35
- async getUserByToken(req: express.Request): Promise<IUserDocument> {
26
+ async getUserAccessByRequest(req: express.Request): Promise<IUser | null> {
36
27
  const authorization = req.get('Authorization');
37
28
  if (!authorization) {
38
29
  return null;
39
30
  }
40
- const { sub: keycloakUserId }: { sub: string } = jwtDecode(authorization);
41
- return this.getUserByKeyCloakId(keycloakUserId);
42
- }
43
-
44
- async getUserIdByToken(req: express.Request): Promise<string> {
45
- const user = await this.getUserByToken(req);
46
- if (user) {
47
- return user._id.toString();
31
+ const { sub }: { sub: string } = jwtDecode(authorization);
32
+ const user = await this.getUserById(sub);
33
+ if (!user) {
34
+ return null;
48
35
  }
49
- return null;
50
- }
51
-
52
- async getUserRepresentationById(authorization: string, userId: string): Promise<IKeycloakUser> {
53
- const options = {
54
- method: 'GET',
55
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}`,
56
- headers: {
57
- 'Content-Type': 'application/json',
58
- Authorization: `Bearer ${authorization}`,
59
- },
60
- };
61
- const result = await axios.request(options);
62
- return result.data;
63
- }
64
-
65
- async getUserRepresentationByUsername(authorization: string, username: string): Promise<IKeycloakUser> {
66
- const options = {
67
- method: 'GET',
68
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users?username=${username}`,
69
- headers: {
70
- 'Content-Type': 'application/json',
71
- Authorization: `Bearer ${authorization}`,
72
- },
73
- };
74
- const result = await axios.request(options);
75
- const users: IKeycloakUser[] = result.data;
76
- return users.find((user) => user.username === username);
36
+ return user;
77
37
  }
78
38
 
79
- async getKeyCloakAdminBearer() {
80
- const url = `${this.config.keycloakHost}/realms/master/protocol/openid-connect/token`;
81
-
82
- const data = qs.stringify({
83
- username: this.config.adminUser,
84
- password: this.config.adminPass,
85
- client_id: 'admin-cli',
86
- grant_type: 'password',
87
- });
88
-
89
- const headers = {
90
- 'Content-Type': 'application/x-www-form-urlencoded',
91
- };
92
-
93
- const response = await axios.post(url, data, { headers });
94
- return response.data;
39
+ async getUserById(userId: string): Promise<IUser | null> {
40
+ const { data } = await axios.get(`${this.config.baseUrl}/users/by-id/${userId}`);
41
+ return data ?? null;
95
42
  }
96
43
 
97
- async getUserList(authorization: string): Promise<IKeycloakUser[]> {
98
- const options = {
99
- method: 'GET',
100
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users`,
101
- headers: {
102
- 'Content-Type': 'application/json',
103
- Authorization: `Bearer ${authorization}`,
104
- },
105
- };
106
- const result = await axios.request(options);
107
- return result.data;
44
+ async getUserByUsername(username: string): Promise<IUser | null> {
45
+ const { data } = await axios.get(`${this.config.baseUrl}/users/by-username/${username}`);
46
+ return data ?? null;
108
47
  }
109
48
 
110
- async getUsersWithRoles(authorization: string) {
111
- const users = await this.getUserList(authorization);
112
- const usersWithNames = users.map((user) => ({ firstName: '', lastName: '', ...user }));
113
- const usersWithRoles = await this
114
- .mapRolesToUsers(
115
- authorization,
116
- usersWithNames.sort((a, b) => a.createdTimestamp - b.createdTimestamp),
117
- );
118
- const usersAndAccess = (await this.addUserAccess(usersWithRoles)).filter((user) => !!user);
119
- const newUser = usersAndAccess.find((user) => user.username === '!new user');
120
- if (newUser) {
121
- return [newUser, ...usersAndAccess.slice(0, usersAndAccess.length - 1)];
49
+ async getUserByToken(req: express.Request): Promise<IUser | null> {
50
+ const authorization = req.get('Authorization');
51
+ if (!authorization) {
52
+ return null;
122
53
  }
123
- return usersAndAccess;
54
+ const { sub: keycloakUserId }: { sub: string } = jwtDecode(authorization);
55
+ return this.getUserById(keycloakUserId);
124
56
  }
125
57
 
126
- async getUserRoles(authorization: string, userId: string): Promise<{ realmMappings: IKeycloakRole[] }> {
127
- const options = {
128
- method: 'GET',
129
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}/role-mappings`,
130
- headers: {
131
- 'Content-Type': 'application/json',
132
- Authorization: `Bearer ${authorization}`,
133
- },
134
- };
135
- const result = await axios.request(options);
136
- return result.data;
58
+ async getUserIdByToken(req: express.Request): Promise<string | null> {
59
+ const user = await this.getUserByToken(req);
60
+ if (user) {
61
+ return user.id;
62
+ }
63
+ return null;
137
64
  }
138
65
 
139
- async createUser(authorization: string, user): Promise<any> {
140
- const options = {
141
- method: 'POST',
142
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users`,
143
- headers: {
144
- 'Content-Type': 'application/json',
145
- Authorization: `Bearer ${authorization}`,
146
- },
147
- data: {
148
- ...user,
149
- },
150
- };
151
- const result = await axios.request(options);
152
- return result.data;
66
+ async getUserList(): Promise<IUser[]> {
67
+ const { data } = await axios.get(`${this.config.baseUrl}/users/users`);
68
+ return data ?? null;
153
69
  }
154
70
 
155
- async updateUser(authorization: string, userId: string, keyValue): Promise<any> {
156
- const options = {
157
- method: 'PUT',
158
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}`,
159
- headers: {
160
- 'Content-Type': 'application/json',
161
- Authorization: `Bearer ${authorization}`,
162
- },
163
- data: keyValue,
164
- };
165
- const result = await axios.request(options);
166
- return result.data;
71
+ async getUserRoles(userId: string) { // TODO add full description
72
+ const user = await this.getUserById(userId);
73
+ return user.roles;
167
74
  }
168
75
 
169
76
  async updateMobileUser(userId: string, keyValue: { [key: string]: string | number | boolean }) {
170
77
  await UserMobileAccess.findOneAndUpdate({ keycloakUserId: userId }, keyValue, { upsert: true });
171
78
  }
172
79
 
173
- async updateUserAccess(keycloakUserId: string, userAccess) {
174
- await UserModel
175
- .findOneAndUpdate({ keycloakUserId }, userAccess);
176
- }
177
-
178
- async removeUserRoles(authorization: string, userId: string, roles: IKeycloakRole[]): Promise<any> {
179
- const options = {
180
- method: 'DELETE',
181
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}/role-mappings/realm`,
182
- headers: {
183
- 'Content-Type': 'application/json',
184
- Authorization: `Bearer ${authorization}`,
185
- },
186
- data: [...roles],
187
- };
188
- const result = await axios.request(options);
189
- return result.data;
190
- }
191
-
192
- async addUserRoles(authorization: string, userId: string, roles: IKeycloakRole[]): Promise<any> {
193
- const options = {
194
- method: 'POST',
195
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}/role-mappings/realm`,
196
- headers: {
197
- 'Content-Type': 'application/json',
198
- Authorization: `Bearer ${authorization}`,
199
- },
200
- data: [...roles],
201
- };
202
- const result = await axios.request(options);
203
- return result.data;
204
- }
205
-
206
- async resetPassword(authorization: string, userId: string, temporaryPassword: string): Promise<any> {
207
- const options = {
208
- method: 'PUT',
209
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}/reset-password`,
210
- headers: {
211
- 'Content-Type': 'application/json',
212
- Authorization: `Bearer ${authorization}`,
213
- },
214
- data: { value: temporaryPassword, temporary: true },
215
- };
216
- const result = await axios.request(options);
217
- return result.data;
218
- }
219
-
220
- async createNewPasswordWithEmail(authorization: string, userId: string, newPassword: string) {
221
- const options = {
222
- method: 'PUT',
223
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}/reset-password`,
224
- headers: {
225
- 'Content-Type': 'application/json',
226
- Authorization: `Bearer ${authorization}`,
227
- },
228
- data: {
229
- type: 'password',
230
- value: newPassword,
231
- temporary: false,
232
- },
233
- };
234
- const response = await axios.request(options);
235
- return response;
236
- }
237
-
238
- async deleteUser(authorization: string, userId: string) {
239
- const deletedUser = await this.getUserRepresentationById(authorization, userId);
240
- const url = `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${userId}`;
241
- const options = {
242
- method: 'DELETE',
243
- url,
244
- headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${authorization}` },
245
- };
246
- try {
247
- await axios.request(options);
248
- const update = {
249
- isDeleted: true,
250
- firstName: deletedUser.firstName ?? deletedUser.username,
251
- lastName: deletedUser.lastName ?? '',
252
- };
253
- await UserModel.findOneAndUpdate({ keycloakUserId: userId }, update);
254
- } catch (error) {
255
- console.log(error);
256
- }
257
- }
258
-
259
- async getRoleList(authorization: string): Promise<IKeycloakRole[]> {
260
- const options = {
261
- method: 'GET',
262
- url: `${this.config.keycloakHost}/admin/realms/${this.config.realm}/roles`,
263
- headers: {
264
- 'Content-Type': 'application/json',
265
- Authorization: `Bearer ${authorization}`,
266
- },
267
- };
268
- const result = await axios.request(options);
269
- return result.data;
270
- }
271
-
272
- groupRoles(roles: IKeycloakRole[]): IGroupedKeycloakRoles {
273
- return roles.reduce((acc, role) => {
274
- const [module, roleName] = role.name.split('/');
275
- if (!roleName) {
276
- return acc;
277
- }
278
- const addedRoles = acc[module] ?? [];
279
- return { ...acc, [module]: [...addedRoles, { ...role, representation: roleName }] };
280
- }, {});
281
- }
282
-
283
- mapRolesToUsers(authorization: string, users: IKeycloakUser[]) {
284
- const usersWithRolesPromise = users.map(async (user) => {
285
- const roles = await this.getUserRoles(authorization, user.id);
286
- return { ...user, roles: this.groupRoles(roles.realmMappings) };
287
- });
288
- return Promise.all(usersWithRolesPromise);
289
- }
290
-
291
- addUserAccess(users: IKeycloakUser[]) {
292
- const usersWithRolesPromise = users.map(async (user) => {
293
- const foundUser = await UserModel.findOne({ keycloakUserId: user.id }).lean();
294
- const foundMobileUser = await UserMobileAccess.findOne({ keycloakUserId: user.id }).lean();
295
- if (!foundUser) {
296
- return null;
297
- }
298
- return {
299
- ...(_.omit(user, ['id'])),
300
- keycloakUserId: user.id,
301
- _id: foundUser._id,
302
- allBorrowers: foundUser.allBorrowers,
303
- borrowersAccess: foundUser.borrowersAccess,
304
- lastLogin: foundUser.lastLogin,
305
- mobileAccess: {
306
- hasAccess: foundMobileUser?.hasAccess ?? false,
307
- canSignDocument: foundMobileUser?.canSignDocument ?? false,
308
- },
309
- };
310
- });
311
- return Promise.all(usersWithRolesPromise);
312
- }
313
-
314
- async getUserAccess(keycloakUserId: string) {
315
- const foundUser = await UserModel.findOne({ keycloakUserId }).lean();
316
- const borrowersAccess = foundUser.borrowersAccess.map((b) => ({ borrower: b.borrower }));
80
+ async getUserAccess(userId: string) {
81
+ const foundUser = await this.getUserById(userId);
82
+ const borrowersAccess = foundUser.borrowersAccess;
317
83
  const complianceBorrowersAccess =
318
- (await BorrowerCompliance.find({ 'borrower': { $in: borrowersAccess.map((b) => b.borrower) } }))
84
+ (await BorrowerCompliance.find({ 'borrower': { $in: borrowersAccess } }))
319
85
  .map((b) => ({ borrower: b._id.toString() }));
320
- return { allBorrowers: foundUser.allBorrowers, borrowersAccess, complianceBorrowersAccess } as IUser;
321
- }
322
-
323
- async getUserAccessByRequest(req): Promise<IUser> {
324
- const authorization = req.get('Authorization');
325
- if (!authorization) {
326
- return null;
327
- }
328
- const { sub: keycloakUserId }: { sub: string } = jwtDecode(authorization);
329
- return await this.getUserAccess(keycloakUserId);
330
- }
331
-
332
- async updateUserLastLogin(authorization: string) {
333
- const allUsers = await UserModel.find({}).lean();
334
-
335
- await Promise.all(allUsers.map(async (user) => {
336
- const reqUrl = `${this.config.keycloakHost}/admin/realms/${this.config.realm}/events?type=LOGIN&user=${user.keycloakUserId}&max=1`;
337
- const options = {
338
- method: 'GET',
339
- url: reqUrl,
340
- headers: {
341
- 'Content-Type': 'application/json',
342
- Authorization: `Bearer ${authorization}`,
343
- },
344
- };
345
- const result = await axios.request(options);
346
- if (result.data.length > 0) {
347
- await UserModel.findByIdAndUpdate(user._id, { lastLogin: new Date(result.data[0].time) });
348
- }
349
- }));
86
+ return { allBorrowers: foundUser.allBorrowers, borrowersAccess, complianceBorrowersAccess };
350
87
  }
351
88
 
352
89
  async createUserLoginLog() {
353
- const { access_token } = await this.getKeyCloakAdminBearer();
354
- const dateFrom = dayjs().subtract(1, 'day').format('YYYY-MM-DD');
355
- const reqUrl = `${this.config.keycloakHost}/admin/realms/${this.config.realm}/events?type=LOGIN&dateFrom=${dateFrom}&max=10000`;
356
- const options = {
357
- method: 'GET',
358
- url: reqUrl,
359
- headers: {
360
- 'Content-Type': 'application/json',
361
- Authorization: `Bearer ${access_token}`,
362
- },
363
- };
364
- try {
365
- const result = await axios.request(options);
366
- const userDates: { [userId: string]: Set<string> } = {};
367
- result.data.forEach((log: { userId: string, time: number }) => {
368
- const timestamp = new Date(log.time);
369
- const formattedDate = timestamp.getFullYear() +
370
- '-' + ('0' + (timestamp.getMonth() + 1)).slice(-2) +
371
- '-' + ('0' + timestamp.getDate()).slice(-2) +
372
- 'T' + ('0' + timestamp.getHours()).slice(-2) +
373
- ':' + ('0' + timestamp.getMinutes()).slice(-2);
374
-
375
- const userId = log.userId;
376
- if (!userDates[userId]) {
377
- userDates[userId] = new Set<string>();
378
- }
379
- userDates[userId].add(formattedDate);
380
- });
381
- await Promise.all(Object.entries(userDates).map(async ([userId, dateSet]) => {
382
- const user = await UserModel.findOne({ keycloakUserId: userId });
383
- if (!user) {
384
- return;
385
- }
386
- await Promise.all(Array.from(dateSet).map(async (date) => {
387
- const existingLog = await this.getUserLogByDate(String(user._id), new Date(date));
388
- if (!existingLog) {
389
- const newLog: ICreateLogParams = {
390
- action: ELogActionType.CREATE,
391
- timestamp: new Date(date),
392
- logType: ELogType.LOGIN,
393
- userId: String(user._id),
394
- details: {},
395
- };
396
- await createLog(newLog);
397
- }
398
- }));
399
- }));
400
- } catch (e) {
401
- console.error(e);
402
- }
90
+ // const { access_token } = await this.getKeyCloakAdminBearer();
91
+ // const dateFrom = dayjs().subtract(1, 'day').format('YYYY-MM-DD');
92
+ // const reqUrl = `${this.config.keycloakHost}/admin/realms/${this.config.realm}/events?type=LOGIN&dateFrom=${dateFrom}&max=10000`;
93
+ // const options = {
94
+ // method: 'GET',
95
+ // url: reqUrl,
96
+ // headers: {
97
+ // 'Content-Type': 'application/json',
98
+ // Authorization: `Bearer ${access_token}`,
99
+ // },
100
+ // };
101
+ // try {
102
+ // const result = await axios.request(options);
103
+ // const userDates: { [userId: string]: Set<string> } = {};
104
+ // result.data.forEach((log: { userId: string, time: number }) => {
105
+ // const timestamp = new Date(log.time);
106
+ // const formattedDate = timestamp.getFullYear() +
107
+ // '-' + ('0' + (timestamp.getMonth() + 1)).slice(-2) +
108
+ // '-' + ('0' + timestamp.getDate()).slice(-2) +
109
+ // 'T' + ('0' + timestamp.getHours()).slice(-2) +
110
+ // ':' + ('0' + timestamp.getMinutes()).slice(-2);
111
+ //
112
+ // const userId = log.userId;
113
+ // if (!userDates[userId]) {
114
+ // userDates[userId] = new Set<string>();
115
+ // }
116
+ // userDates[userId].add(formattedDate);
117
+ // });
118
+ // await Promise.all(Object.entries(userDates).map(async ([userId, dateSet]) => {
119
+ // const user = await UserModel.findOne({ keycloakUserId: userId });
120
+ // if (!user) {
121
+ // return;
122
+ // }
123
+ // await Promise.all(Array.from(dateSet).map(async (date) => {
124
+ // const existingLog = await this.getUserLogByDate(String(user._id), new Date(date));
125
+ // if (!existingLog) {
126
+ // const newLog: ICreateLogParams = {
127
+ // action: ELogActionType.CREATE,
128
+ // timestamp: new Date(date),
129
+ // logType: ELogType.LOGIN,
130
+ // userId: String(user._id),
131
+ // details: {},
132
+ // };
133
+ // await createLog(newLog);
134
+ // }
135
+ // }));
136
+ // }));
137
+ // } catch (e) {
138
+ // console.error(e);
139
+ // }
403
140
  }
404
141
 
405
142
  async getUserLogByDate(userId: string, date: Date) {
406
143
  return UserLog.findOne({ userId: new mongoose.Types.ObjectId(userId), timestamp: date }).lean();
407
144
  }
408
-
409
- async getUserSecrets(keycloakUserId: string, adminAccessToken: string) {
410
- const reqUrl = `${this.config.keycloakHost}/admin/realms/${this.config.realm}/users/${keycloakUserId}/credentials`;
411
- const options = {
412
- method: 'GET',
413
- url: reqUrl,
414
- headers: {
415
- 'Content-Type': 'application/json',
416
- Authorization: `Bearer ${adminAccessToken}`,
417
- },
418
- };
419
- const result = await axios.request(options);
420
- console.log(result.data);
421
- }
422
-
423
- async updateUserNames() {
424
- const { access_token } = await this.getKeyCloakAdminBearer();
425
- const keycloakUsers = await this.getUserList(access_token);
426
- const users = await UserModel.find({}).lean();
427
- await Promise.all(users.map(async (user) => {
428
- const keycloakUser = keycloakUsers.find((u) => u.id === user.keycloakUserId);
429
- if (keycloakUser) {
430
- await UserModel.findByIdAndUpdate(user._id, {
431
- firstName: keycloakUser.firstName,
432
- lastName: keycloakUser.lastName,
433
- });
434
- }
435
- }));
436
- }
437
145
  }