@tomei/sso 0.66.0 → 0.66.1-test.1

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 (84) hide show
  1. package/.commitlintrc.json +22 -22
  2. package/.gitlab-ci.yml +237 -16
  3. package/.husky/commit-msg +15 -15
  4. package/.husky/pre-commit +7 -7
  5. package/.prettierrc +4 -4
  6. package/Jenkinsfile +57 -57
  7. package/README.md +23 -23
  8. package/__tests__/unit/components/api-key/api-key.spec.ts +201 -0
  9. package/__tests__/unit/components/group/group.spec.ts +85 -79
  10. package/__tests__/unit/components/group-object-privilege/group-object-privilege.spec.ts +88 -88
  11. package/__tests__/unit/components/group-privilege/group-privilege.spec.ts +68 -68
  12. package/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.ts +79 -67
  13. package/__tests__/unit/components/group-system-access/group-system-access.spec.ts +83 -83
  14. package/__tests__/unit/components/login-user/l.spec.ts +746 -746
  15. package/__tests__/unit/components/login-user/login.spec.ts +2327 -1164
  16. package/__tests__/unit/components/password-hash/password-hash.service.spec.ts +31 -31
  17. package/__tests__/unit/components/system/system.spec.ts +255 -254
  18. package/__tests__/unit/components/system-privilege/system-privilege.spec.ts +83 -83
  19. package/__tests__/unit/components/user-group/user-group.spec.ts +86 -86
  20. package/__tests__/unit/components/user-object-privilege/user-object-privilege.spec.ts +78 -78
  21. package/__tests__/unit/components/user-password-history/user-password-history.spec.ts +165 -0
  22. package/__tests__/unit/components/user-privilege/user-privilege.spec.ts +72 -72
  23. package/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.ts +233 -0
  24. package/__tests__/unit/components/user-system-access/user-system-access.spec.ts +89 -89
  25. package/__tests__/unit/redis-client/redis.service.spec.ts +23 -23
  26. package/__tests__/unit/session/session.service.spec.ts +47 -47
  27. package/__tests__/unit/system-privilege/system-privilage.spec.ts +91 -91
  28. package/coverage/cobertura-coverage.xml +237 -0
  29. package/coverage/test-report.xml +33 -0
  30. package/create-sso-user.sql +39 -39
  31. package/dist/__tests__/unit/components/{group-privilege/group-privilege.test.d.ts → api-key/api-key.spec.d.ts} +1 -1
  32. package/dist/__tests__/unit/components/api-key/api-key.spec.js +158 -0
  33. package/dist/__tests__/unit/components/api-key/api-key.spec.js.map +1 -0
  34. package/dist/__tests__/unit/components/group/group.spec.js +4 -0
  35. package/dist/__tests__/unit/components/group/group.spec.js.map +1 -1
  36. package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js +15 -3
  37. package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js.map +1 -1
  38. package/dist/__tests__/unit/components/login-user/login.spec.js +664 -0
  39. package/dist/__tests__/unit/components/login-user/login.spec.js.map +1 -1
  40. package/dist/__tests__/unit/components/system/system.spec.js +1 -0
  41. package/dist/__tests__/unit/components/system/system.spec.js.map +1 -1
  42. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.d.ts +1 -0
  43. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.js +138 -0
  44. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.js.map +1 -0
  45. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.d.ts +1 -0
  46. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.js +182 -0
  47. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.js.map +1 -0
  48. package/dist/src/components/login-user/login-user.js +2 -2
  49. package/dist/src/components/login-user/login-user.js.map +1 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/eslint.config.mjs +58 -58
  52. package/jest.config.js +16 -14
  53. package/migrations/20240314080602-create-user-table.js +124 -124
  54. package/migrations/20240314080603-create-user-group-table.js +85 -85
  55. package/migrations/20240314080604-create-user-user-group-table.js +55 -55
  56. package/migrations/20240314080605-create-login-history-table.js +53 -53
  57. package/migrations/20240527064925-create-system-table.js +78 -78
  58. package/migrations/20240527064926-create-system-privilege-table.js +71 -71
  59. package/migrations/20240527065342-create-group-table.js +93 -93
  60. package/migrations/20240527065633-create-group-reporting-user-table.js +76 -76
  61. package/migrations/20240528011551-create-group-system-access-table.js +72 -72
  62. package/migrations/20240528023018-user-system-access-table.js +75 -75
  63. package/migrations/20240528032229-user-privilege-table.js +76 -76
  64. package/migrations/20240528063003-create-group-privilege-table.js +76 -76
  65. package/migrations/20240528063051-create-group-object-privilege-table.js +84 -84
  66. package/migrations/20240528063107-create-user-object-privilege-table.js +84 -84
  67. package/migrations/20240528063108-create-api-key-table.js +85 -85
  68. package/migrations/20241104104802-create-building-table.js +95 -95
  69. package/migrations/20250108091132-add-area-manager-user-id-to-building-table.js +14 -14
  70. package/migrations/20250108091133-add-passcode-to-user-table.js +36 -36
  71. package/migrations/20250210115636-create-user-reporting-hierarchy.js +76 -76
  72. package/migrations/20250326043818-crate-user-password-history.js +42 -42
  73. package/migrations/20250610070720-added-MFBypassYN-to-sso-user.js +30 -30
  74. package/migrations/20250805085707-add-bulk-approval-code-to-sso-user.js +29 -0
  75. package/package.json +88 -90
  76. package/sampledotenv +7 -7
  77. package/src/components/login-user/login-user.ts +2 -2
  78. package/tsconfig.build.json +5 -5
  79. package/tsconfig.json +23 -23
  80. package/dist/__tests__/unit/components/group-privilege/group-privilege.test.js +0 -71
  81. package/dist/__tests__/unit/components/group-privilege/group-privilege.test.js.map +0 -1
  82. package/dist/__tests__/unit/components/login-user/login-user.spec.d.ts +0 -0
  83. package/dist/__tests__/unit/components/login-user/login-user.spec.js +0 -6
  84. package/dist/__tests__/unit/components/login-user/login-user.spec.js.map +0 -1
@@ -1,1164 +1,2327 @@
1
- import { SessionService } from '../../../../src/session/session.service';
2
- import { LoginUser } from '../../../../src/components/login-user/login-user';
3
- import { ApplicationConfig, ComponentConfig } from '@tomei/config';
4
- import { UserRepository } from '../../../../src/components/login-user/user.repository';
5
- import { ClassError } from '@tomei/general';
6
- import { Activity } from '@tomei/activity-history';
7
- import { UserStatus } from '../../../../src/enum/user-status.enum';
8
- import { YN } from '../../../../src/enum/yn.enum';
9
- import SystemPrivilegeModel from '../../../../src/models/system-privilege.entity';
10
- import { GroupSystemAccessRepository } from '../../../../src/components/group-system-access/group-system-access.repository';
11
- import { GroupRepository } from '../../../../src/components/group/group.repository';
12
-
13
- // describe('LoginUser', () => {
14
- // afterAll(() => {
15
- // jest.restoreAllMocks();
16
- // });
17
-
18
- // describe('init', () => {
19
- // let sessionService: any;
20
- // let userId: number;
21
- // let dbTransaction: any;
22
-
23
- // beforeEach(() => {
24
- // sessionService = {};
25
- // userId = 1;
26
- // dbTransaction = null;
27
- // });
28
-
29
- // it('should initialize LoginUser with valid userId', async () => {
30
- // const user = {
31
- // UserId: 1,
32
- // FullName: 'John Doe',
33
- // Email: 'john.doe@example.com',
34
- // Password: 'password',
35
- // Status: 'active',
36
- // DefaultPasswordChangedYN: 'yes',
37
- // FirstLoginAt: new Date(),
38
- // LastLoginAt: new Date(),
39
- // MFAEnabled: 1,
40
- // MFAConfig: 'config',
41
- // RecoveryEmail: 'john.doe@example.com',
42
- // FailedLoginAttemptCount: 0,
43
- // LastFailedLoginAt: null,
44
- // LastPasswordChangedAt: new Date(),
45
- // NeedToChangePasswordYN: 'no',
46
- // CreatedById: 1,
47
- // CreatedAt: new Date(),
48
- // UpdatedById: 1,
49
- // UpdatedAt: new Date(),
50
- // Staff: {
51
- // FullName: 'John Doe',
52
- // IdNo: '1234567890',
53
- // Mobile: '1234567890',
54
- // },
55
- // };
56
-
57
- // const findOneMock = jest
58
- // .spyOn(UserRepository.prototype, 'findOne')
59
- // .mockResolvedValueOnce(user as any);
60
-
61
- // const result = await LoginUser.init(
62
- // sessionService,
63
- // userId,
64
- // dbTransaction,
65
- // );
66
-
67
- // expect(findOneMock).toHaveBeenCalledTimes(1);
68
- // expect(findOneMock).toHaveBeenCalledWith({
69
- // where: {
70
- // UserId: userId,
71
- // },
72
- // include: [
73
- // {
74
- // model: expect.anything(),
75
- // },
76
- // ],
77
- // });
78
- // expect(result).toBeInstanceOf(LoginUser);
79
- // expect(result.UserId).toBe(user.UserId);
80
- // expect(result.FullName).toBe(user.FullName);
81
- // expect(result.Email).toBe(user.Email);
82
- // expect(result.Password).toBe(user.Password);
83
- // expect(result.Status).toBe(user.Status);
84
- // expect(result.DefaultPasswordChangedYN).toBe(
85
- // user.DefaultPasswordChangedYN,
86
- // );
87
- // expect(result.FirstLoginAt).toBe(user.FirstLoginAt);
88
- // expect(result.LastLoginAt).toBe(user.LastLoginAt);
89
- // expect(result.MFAEnabled).toBe(user.MFAEnabled);
90
- // expect(result.MFAConfig).toBe(user.MFAConfig);
91
- // expect(result.RecoveryEmail).toBe(user.RecoveryEmail);
92
- // expect(result.FailedLoginAttemptCount).toBe(user.FailedLoginAttemptCount);
93
- // expect(result.LastFailedLoginAt).toBe(user.LastFailedLoginAt);
94
- // expect(result.LastPasswordChangedAt).toBe(user.LastPasswordChangedAt);
95
- // expect(result.NeedToChangePasswordYN).toBe(user.NeedToChangePasswordYN);
96
- // expect(result.CreatedById).toBe(user.CreatedById);
97
- // expect(result.CreatedAt).toBe(user.CreatedAt);
98
- // expect(result.UpdatedById).toBe(user.UpdatedById);
99
- // expect(result.UpdatedAt).toBe(user.UpdatedAt);
100
- // });
101
-
102
- // it('should throw an error when user is not found', async () => {
103
- // const findOneMock = jest
104
- // .spyOn(UserRepository.prototype, 'findOne')
105
- // .mockResolvedValueOnce(null);
106
-
107
- // await expect(
108
- // LoginUser.init(sessionService, userId, dbTransaction),
109
- // ).rejects.toThrow(Error);
110
-
111
- // expect(findOneMock).toHaveBeenCalledTimes(1);
112
- // expect(findOneMock).toHaveBeenCalledWith({
113
- // where: {
114
- // UserId: userId,
115
- // },
116
- // include: [
117
- // {
118
- // model: expect.anything(),
119
- // },
120
- // ],
121
- // });
122
- // });
123
- // });
124
-
125
- // // describe('checkSession', () => {
126
- // // it('should throw an error if session expired', async () => {
127
- // // // Arrange
128
- // // const systemCode = 'EZC';
129
- // // const sessionId = 'ckymxuh8t000137t011w89zgk';
130
- // // const userId = '755';
131
- // // const sessionService = await SessionService.init();
132
- // // const loginUser = await LoginUser.init(sessionService);
133
-
134
- // // // Act
135
- // // const checkSessionPromise = loginUser.checkSession(
136
- // // systemCode,
137
- // // sessionId,
138
- // // userId,
139
- // // );
140
-
141
- // // // Assert
142
- // // await expect(checkSessionPromise).rejects.toThrow('Session expired.');
143
- // // });
144
-
145
- // // it('should refresh the session duration if session is valid', async () => {
146
- // // // Arrange
147
- // // const systemCode = 'EZC';
148
- // // const sessionId = 'ckymxuh8t000137t011w89zgk';
149
- // // const userId = '755';
150
- // // const sessionService = await SessionService.init();
151
- // // const loginUser = await LoginUser.init(sessionService);
152
-
153
- // // // Mock the _SessionService.retrieveUserSession method
154
- // // loginUser['_SessionService'].retrieveUserSession = jest
155
- // // .fn()
156
- // // .mockResolvedValue({
157
- // // systemLogins: [
158
- // // {
159
- // // code: systemCode,
160
- // // sessionId: sessionId,
161
- // // privileges: [],
162
- // // },
163
- // // ],
164
- // // });
165
-
166
- // // // Mock the _SessionService.refreshDuration method
167
- // // loginUser['_SessionService'].refreshDuration = jest.fn();
168
-
169
- // // // Act
170
- // // const systemLogin = await loginUser.checkSession(
171
- // // systemCode,
172
- // // sessionId,
173
- // // userId,
174
- // // );
175
-
176
- // // // Assert
177
- // // expect(
178
- // // loginUser['_SessionService'].retrieveUserSession,
179
- // // ).toHaveBeenCalledWith(userId);
180
- // // expect(loginUser['_SessionService'].refreshDuration).toHaveBeenCalledWith(
181
- // // userId,
182
- // // );
183
- // // expect(systemLogin).toEqual({
184
- // // code: systemCode,
185
- // // sessionId: sessionId,
186
- // // privileges: [],
187
- // // });
188
- // // });
189
- // // });
190
-
191
- // describe('shouldReleaseLock', () => {
192
- // const minuteToAutoRelease = 5;
193
- // const autoReleaseYN = 'Y';
194
-
195
- // beforeEach(() => {
196
- // jest
197
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
198
- // .mockImplementation((componentName: string, configKey: string) => {
199
- // if (configKey === 'minuteToAutoRelease') {
200
- // return minuteToAutoRelease as any;
201
- // }
202
- // if (configKey === 'autoReleaseYN') {
203
- // return autoReleaseYN as any;
204
- // }
205
- // });
206
- // });
207
-
208
- // it('should return true if autoReleaseYN is "Y" and time difference is greater than minuteToAutoRelease', async () => {
209
- // // Arrange
210
- // const lastFailedLoginAt = new Date();
211
- // lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 10); // Set last failed login time to 10 minutes ago
212
- // // Act
213
- // const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
214
-
215
- // // Assert
216
- // expect(result).toBe(true);
217
- // });
218
-
219
- // it('should return false if autoReleaseYN is "Y" and time difference is less than or equal to minuteToAutoRelease', async () => {
220
- // // Arrange
221
- // const lastFailedLoginAt = new Date();
222
- // lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 3); // Set last failed login time to 3 minutes ago
223
-
224
- // // Act
225
- // const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
226
-
227
- // // Assert
228
- // expect(result).toBe(false);
229
- // });
230
-
231
- // it('should return false if autoReleaseYN is "N"', async () => {
232
- // // Arrange
233
- // const lastFailedLoginAt = new Date();
234
-
235
- // // Act
236
- // const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
237
-
238
- // // Assert
239
- // expect(result).toBe(false);
240
- // });
241
- // });
242
-
243
- // describe('releaseLock', () => {
244
- // it('should release the lock for a user', async () => {
245
- // // Mock the necessary dependencies and setup the test data
246
- // const UserId = 1;
247
- // const dbTransaction = null;
248
-
249
- // const updateMock = jest
250
- // .spyOn(LoginUser['_Repository'], 'update')
251
- // .mockImplementationOnce(() => Promise.resolve({}) as any);
252
-
253
- // // Call the method under test
254
- // LoginUser['releaseLock'](UserId, dbTransaction);
255
-
256
- // // Verify the expected behavior
257
- // expect(updateMock).toHaveBeenCalledTimes(1);
258
- // expect(updateMock).toHaveBeenCalledWith(
259
- // {
260
- // FailedLoginAttemptCount: 0,
261
- // Status: 'Active',
262
- // },
263
- // {
264
- // where: {
265
- // UserId,
266
- // },
267
- // transaction: dbTransaction,
268
- // },
269
- // );
270
- // });
271
- // });
272
-
273
- // describe('checkUserInfoDuplicated', () => {
274
- // it('should throw an error if duplicate user info is found', async () => {
275
- // // Mock the dependencies and setup the test data
276
- // const dbTransaction = null;
277
- // const query = {
278
- // Email: 'test@example.com',
279
- // IdType: 'passport',
280
- // IdNo: '123456789',
281
- // ContactNo: '1234567890',
282
- // };
283
-
284
- // // Mock the LoginUser['_Repository'].findAll method to return a user
285
- // jest
286
- // .spyOn(LoginUser['_Repository'], 'findAll')
287
- // .mockResolvedValueOnce([{ id: 1 }] as any);
288
-
289
- // // Assert that the method throws an error
290
- // await expect(
291
- // LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
292
- // ).rejects.toThrowError();
293
- // });
294
-
295
- // it('should not throw an error if duplicate user info is not found', async () => {
296
- // // Mock the dependencies and setup the test data
297
- // const dbTransaction = null;
298
- // const query = {
299
- // Email: 'test@example.com',
300
- // IdType: 'passport',
301
- // IdNo: '123456789',
302
- // ContactNo: '1234567890',
303
- // };
304
-
305
- // // Mock the LoginUser['_Repository'].findAll method to return an empty array
306
- // jest.spyOn(LoginUser['_Repository'], 'findAll').mockResolvedValueOnce([]);
307
-
308
- // // Assert that the method does not throw an error
309
- // await expect(
310
- // LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
311
- // ).resolves.not.toThrowError();
312
- // });
313
- // });
314
-
315
- // describe('generateDefaultPassword', () => {
316
- // const passwordPolicy = {
317
- // minLen: 6,
318
- // maxLen: 10,
319
- // nonAcceptableChar: 'i,l,o',
320
- // numOfCapitalLetters: 1,
321
- // numOfNumbers: 1,
322
- // numOfSpecialChars: 1,
323
- // };
324
- // beforeEach(() => {
325
- // jest
326
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
327
- // .mockImplementation((componentName: string, configKey: string) => {
328
- // if (configKey === 'passwordPolicy') {
329
- // return passwordPolicy as any;
330
- // }
331
- // });
332
- // });
333
-
334
- // it('should generate a default password with the specified length', () => {
335
- // const password = LoginUser['generateDefaultPassword']();
336
- // expect(password.length).toBeGreaterThanOrEqual(6);
337
- // expect(password.length).toBeLessThanOrEqual(10);
338
- // });
339
-
340
- // it('should generate a default password with at least one capital letter', () => {
341
- // const password = LoginUser['generateDefaultPassword']();
342
- // expect(/[A-Z]/.test(password)).toBe(true);
343
- // });
344
-
345
- // it('should generate a default password with at least one number', () => {
346
- // const password = LoginUser['generateDefaultPassword']();
347
- // expect(/[0-9]/.test(password)).toBe(true);
348
- // });
349
-
350
- // it('should generate a default password with at least one special character', () => {
351
- // const password = LoginUser['generateDefaultPassword']();
352
- // expect(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~`]/.test(password)).toBe(true);
353
- // });
354
-
355
- // it('should generate a default password without any non-acceptable characters', () => {
356
- // const password = LoginUser['generateDefaultPassword']();
357
- // const nonAcceptableChars = ['i', 'l', 'o'];
358
- // expect(nonAcceptableChars.some((char) => password.includes(char))).toBe(
359
- // false,
360
- // );
361
- // });
362
- // });
363
-
364
- // describe('setPassword', () => {
365
- // const passwordPolicy = {
366
- // minLen: 6,
367
- // maxLen: 10,
368
- // nonAcceptableChar: 'i,l,o',
369
- // numOfCapitalLetters: 1,
370
- // numOfNumbers: 1,
371
- // numOfSpecialChars: 1,
372
- // };
373
- // beforeEach(() => {
374
- // jest
375
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
376
- // .mockImplementation((componentName: string, configKey: string) => {
377
- // if (configKey === 'passwordPolicy') {
378
- // return passwordPolicy as any;
379
- // }
380
- // });
381
- // });
382
-
383
- // it('should set the password for the user', async () => {
384
- // // Arrange
385
- // const dbTransaction = null;
386
- // const sessionService = await SessionService.init();
387
- // const user = await LoginUser.init(sessionService);
388
- // const password = 'N3wP@ssw0';
389
-
390
- // // Act
391
- // const result = await LoginUser['setPassword'](
392
- // dbTransaction,
393
- // user,
394
- // password,
395
- // );
396
-
397
- // // Assert
398
- // expect(result).toBeInstanceOf(LoginUser);
399
- // await expect(
400
- // LoginUser['setPassword'](dbTransaction, user, password),
401
- // ).resolves.not.toThrowError();
402
- // expect(result.Password).toBeDefined();
403
- // });
404
-
405
- // it('should throw an error if the password does not meet the security requirements', async () => {
406
- // // Arrange
407
- // const dbTransaction = null;
408
- // const sessionService = await SessionService.init();
409
- // const user = await LoginUser.init(sessionService);
410
- // const password = 'weakpassword';
411
-
412
- // // Act & Assert
413
- // await expect(
414
- // LoginUser['setPassword'](dbTransaction, user, password),
415
- // ).rejects.toThrow();
416
- // });
417
- // });
418
-
419
- // // describe('create', () => {
420
- // // let loginUser: LoginUser;
421
- // // let dbTransaction: any;
422
- // // let user: LoginUser;
423
- // // let newUser: any;
424
-
425
- // // beforeEach(async () => {
426
- // // const sessionService = await SessionService.init();
427
- // // loginUser = await LoginUser.init(sessionService);
428
- // // dbTransaction = null;
429
- // // newUser = {
430
- // // UserId: 1,
431
- // // FullName: 'John Doe',
432
- // // Email: 'john.doe@example.com',
433
- // // Password: 'password',
434
- // // Status: 'Active',
435
- // // DefaultPasswordChangedYN: 'N',
436
- // // FirstLoginAt: null,
437
- // // LastLoginAt: null,
438
- // // MFAEnabled: null,
439
- // // MFAConfig: null,
440
- // // RecoveryEmail: null,
441
- // // FailedLoginAttemptCount: 0,
442
- // // LastFailedLoginAt: null,
443
- // // LastPasswordChangedAt: new Date(),
444
- // // NeedToChangePasswordYN: 'N',
445
- // // CreatedById: 1,
446
- // // CreatedAt: new Date(),
447
- // // UpdatedById: 1,
448
- // // UpdatedAt: new Date(),
449
- // // Staff: {
450
- // // FullName: 'John Doe',
451
- // // IdNo: '1234567890',
452
- // // Mobile: '1234567890',
453
- // // },
454
- // // };
455
- // // user = new (LoginUser as any)(sessionService, null, newUser);
456
- // // });
457
-
458
- // // afterEach(() => {
459
- // // jest.clearAllMocks();
460
- // // });
461
-
462
- // // it('should create a new user record', async () => {
463
- // // const checkPrivilegesMock = jest
464
- // // .spyOn(loginUser, 'checkPrivileges')
465
- // // .mockResolvedValueOnce(true);
466
-
467
- // // const checkUserInfoDuplicatedMock = jest
468
- // // .spyOn(LoginUser as any, 'checkUserInfoDuplicated')
469
- // // .mockResolvedValueOnce(undefined);
470
-
471
- // // const generateDefaultPasswordMock = jest
472
- // // .spyOn(LoginUser as any, 'generateDefaultPassword')
473
- // // .mockReturnValueOnce('defaultPassword');
474
-
475
- // // const setPasswordMock = jest
476
- // // .spyOn(LoginUser as any, 'setPassword')
477
- // // .mockResolvedValueOnce(user);
478
-
479
- // // const createMock = jest
480
- // // .spyOn((LoginUser as any)['_Repository'], 'create')
481
- // // .mockResolvedValueOnce({
482
- // // ...newUser,
483
- // // get: () => newUser,
484
- // // });
485
-
486
- // // const activityCreateMock = jest
487
- // // .spyOn((Activity as any).prototype, 'create')
488
- // // .mockResolvedValueOnce(undefined);
489
-
490
- // // jest
491
- // // .spyOn(ApplicationConfig, 'getComponentConfigValue')
492
- // // .mockImplementation((configKey: string) => {
493
- // // if (configKey === 'system-code') {
494
- // // return 'SC';
495
- // // }
496
- // // });
497
-
498
- // // const result = await LoginUser.create(loginUser, dbTransaction, user);
499
-
500
- // // expect(checkPrivilegesMock).toHaveBeenCalledTimes(1);
501
- // // expect(checkPrivilegesMock).toHaveBeenCalledWith(
502
- // // ApplicationConfig.getComponentConfigValue('system-code'),
503
- // // 'User - Create',
504
- // // );
505
-
506
- // // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledTimes(1);
507
- // // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledWith(dbTransaction, {
508
- // // Email: user.Email,
509
- // // IdType: user.IDType,
510
- // // IdNo: user.IDNo,
511
- // // ContactNo: user.ContactNo,
512
- // // });
513
-
514
- // // expect(generateDefaultPasswordMock).toHaveBeenCalledTimes(1);
515
-
516
- // // expect(setPasswordMock).toHaveBeenCalledTimes(1);
517
- // // expect(setPasswordMock).toHaveBeenCalledWith(
518
- // // dbTransaction,
519
- // // user,
520
- // // 'defaultPassword',
521
- // // );
522
-
523
- // // expect(createMock).toHaveBeenCalledTimes(1);
524
-
525
- // // const userInfo = {
526
- // // FullName: user.FullName,
527
- // // IDNo: user.IDNo,
528
- // // Email: user.Email,
529
- // // ContactNo: user.ContactNo,
530
- // // Password: user.Password,
531
- // // Status: UserStatus.ACTIVE,
532
- // // FirstLoginAt: null,
533
- // // LastLoginAt: null,
534
- // // MFAEnabled: null,
535
- // // MFAConfig: null,
536
- // // RecoveryEmail: null,
537
- // // FailedLoginAttemptCount: 0,
538
- // // LastFailedLoginAt: null,
539
- // // LastPasswordChangedAt: null,
540
- // // DefaultPasswordChangedYN: YN.No,
541
- // // NeedToChangePasswordYN: YN.Yes,
542
- // // CreatedById: loginUser.UserId,
543
- // // CreatedAt: new Date(),
544
- // // UpdatedById: loginUser.UserId,
545
- // // UpdatedAt: new Date(),
546
- // // UserId: null,
547
- // // };
548
-
549
- // // expect(createMock).toHaveBeenCalledWith(
550
- // // {
551
- // // Email: userInfo.Email,
552
- // // Password: userInfo.Password,
553
- // // Status: userInfo.Status,
554
- // // DefaultPasswordChangedYN: userInfo.DefaultPasswordChangedYN,
555
- // // FirstLoginAt: userInfo.FirstLoginAt,
556
- // // LastLoginAt: userInfo.LastLoginAt,
557
- // // MFAEnabled: userInfo.MFAEnabled,
558
- // // MFAConfig: userInfo.MFAConfig,
559
- // // RecoveryEmail: userInfo.RecoveryEmail,
560
- // // FailedLoginAttemptCount: userInfo.FailedLoginAttemptCount,
561
- // // LastFailedLoginAt: userInfo.LastFailedLoginAt,
562
- // // LastPasswordChangedAt: userInfo.LastPasswordChangedAt,
563
- // // NeedToChangePasswordYN: userInfo.NeedToChangePasswordYN,
564
- // // CreatedById: userInfo.CreatedById,
565
- // // CreatedAt: expect.any(Date),
566
- // // UpdatedById: userInfo.UpdatedById,
567
- // // UpdatedAt: expect.any(Date),
568
- // // },
569
- // // {
570
- // // transaction: dbTransaction,
571
- // // },
572
- // // );
573
-
574
- // // expect(activityCreateMock).toHaveBeenCalledTimes(1);
575
-
576
- // // expect(result).toBeInstanceOf(LoginUser);
577
- // // expect(result.Email).toBe(userInfo.Email);
578
- // // expect(result.Password).toBe(userInfo.Password);
579
- // // expect(result.Status).toBe(userInfo.Status);
580
- // // expect(result.DefaultPasswordChangedYN).toBe(
581
- // // userInfo.DefaultPasswordChangedYN,
582
- // // );
583
- // // expect(result.FirstLoginAt).toBe(null);
584
- // // expect(result.LastLoginAt).toBe(null);
585
- // // expect(result.MFAEnabled).toBe(userInfo.MFAEnabled);
586
- // // expect(result.MFAConfig).toBe(userInfo.MFAConfig);
587
- // // expect(result.RecoveryEmail).toBe(userInfo.RecoveryEmail);
588
- // // expect(result.FailedLoginAttemptCount).toBe(
589
- // // userInfo.FailedLoginAttemptCount,
590
- // // );
591
- // // expect(result.LastFailedLoginAt).toBe(userInfo.LastFailedLoginAt);
592
- // // expect(result.LastPasswordChangedAt).toBe(userInfo.LastPasswordChangedAt);
593
- // // expect(result.NeedToChangePasswordYN).toBe(
594
- // // userInfo.NeedToChangePasswordYN,
595
- // // );
596
- // // expect(result.CreatedById).toBe(userInfo.CreatedById);
597
- // // expect(result.UpdatedById).toBe(userInfo.UpdatedById);
598
- // // });
599
-
600
- // // it('should throw an error if user dont have the privilege to create new user', async () => {
601
- // // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(false);
602
-
603
- // // await expect(
604
- // // LoginUser.create(loginUser, dbTransaction, user),
605
- // // ).rejects.toThrow(ClassError);
606
- // // });
607
-
608
- // // it('should throw an error if user email is missing', async () => {
609
- // // user.Email = undefined;
610
-
611
- // // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(true);
612
-
613
- // // await expect(
614
- // // LoginUser.create(loginUser, dbTransaction, user),
615
- // // ).rejects.toThrow(ClassError);
616
- // // });
617
- // // });
618
-
619
- // describe('incrementFailedLoginAttemptCount', () => {
620
- // afterAll(() => {
621
- // jest.restoreAllMocks();
622
- // });
623
-
624
- // it('should increment FailedLoginAttemptCount and update user status', async () => {
625
- // // Arrange
626
- // const sessionService = await SessionService.init();
627
- // const loginUser = await LoginUser.init(sessionService);
628
- // loginUser['FailedLoginAttemptCount'] = 2;
629
- // loginUser['LastFailedLoginAt'] = new Date();
630
- // loginUser['Status'] = UserStatus.ACTIVE;
631
-
632
- // const dbTransaction = null;
633
-
634
- // // Mock the static methods and properties
635
- // jest
636
- // .spyOn((LoginUser as any)['_Repository'], 'update')
637
- // .mockReturnValueOnce(null);
638
-
639
- // jest
640
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
641
- // .mockImplementation((componentName: string, configKey: string) => {
642
- // if (configKey === 'maxFailedLoginAttempts') {
643
- // return 3;
644
- // }
645
- // if (configKey === 'autoReleaseYN') {
646
- // return 'Y';
647
- // }
648
- // });
649
-
650
- // // Act
651
- // await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
652
-
653
- // // Assert
654
- // expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
655
- // {
656
- // FailedLoginAttemptCount: 3,
657
- // LastFailedLoginAt: expect.any(Date),
658
- // Status: UserStatus.ACTIVE,
659
- // },
660
- // {
661
- // where: {
662
- // UserId: loginUser.UserId,
663
- // },
664
- // transaction: dbTransaction,
665
- // },
666
- // );
667
- // });
668
-
669
- // it('should throw an error if maxFailedLoginAttempts or autoReleaseYN is missing', async () => {
670
- // // Arrange
671
- // const sessionService = await SessionService.init();
672
- // const loginUser = await LoginUser.init(sessionService);
673
- // loginUser['FailedLoginAttemptCount'] = 2;
674
- // loginUser['LastFailedLoginAt'] = new Date();
675
- // loginUser['Status'] = UserStatus.ACTIVE;
676
-
677
- // const dbTransaction = null;
678
-
679
- // // Mock the static methods and properties
680
- // jest
681
- // .spyOn((LoginUser as any)['_Repository'], 'update')
682
- // .mockReturnValueOnce(null);
683
-
684
- // jest
685
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
686
- // .mockImplementationOnce((componentName: string, configKey: string) => {
687
- // if (configKey === 'maxFailedLoginAttempts') {
688
- // return undefined;
689
- // }
690
- // if (configKey === 'autoReleaseYN') {
691
- // return undefined;
692
- // }
693
- // });
694
-
695
- // // Act and Assert
696
- // await expect(
697
- // loginUser['incrementFailedLoginAttemptCount'](dbTransaction),
698
- // ).rejects.toThrow(
699
- // new ClassError(
700
- // 'LoginUser',
701
- // 'LoginUserErrMsg0X',
702
- // 'Missing maxFailedLoginAttempts and or autoReleaseYN. Please set in config file.',
703
- // ),
704
- // );
705
- // });
706
-
707
- // it('should lock the user account if the failed login attempts exceed the maximum allowed', async () => {
708
- // // Arrange
709
- // const sessionService = await SessionService.init();
710
- // const loginUser = await LoginUser.init(sessionService);
711
- // loginUser['FailedLoginAttemptCount'] = 3;
712
- // loginUser['LastFailedLoginAt'] = new Date();
713
- // loginUser['Status'] = UserStatus.ACTIVE;
714
-
715
- // const dbTransaction = null;
716
-
717
- // // Mock the static methods and properties
718
- // jest
719
- // .spyOn((LoginUser as any)['_Repository'], 'update')
720
- // .mockReturnValueOnce(null);
721
-
722
- // jest
723
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
724
- // .mockImplementation((componentName: string, configKey: string) => {
725
- // if (configKey === 'maxFailedLoginAttempts') {
726
- // return 3;
727
- // }
728
- // if (configKey === 'autoReleaseYN') {
729
- // return 'Y';
730
- // }
731
- // });
732
-
733
- // // Act
734
- // try {
735
- // await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
736
- // expect(false).toBe(true);
737
- // } catch (error) {
738
- // // Assert
739
- // expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
740
- // {
741
- // FailedLoginAttemptCount: 4,
742
- // LastFailedLoginAt: expect.any(Date),
743
- // Status: UserStatus.LOCKED,
744
- // },
745
- // {
746
- // where: {
747
- // UserId: loginUser.UserId,
748
- // },
749
- // transaction: dbTransaction,
750
- // },
751
- // );
752
- // expect(error).toBeInstanceOf(ClassError);
753
- // expect(error.message).toBe(
754
- // 'Your account has been temporarily locked due to too many failed login attempts, please try again later.',
755
- // );
756
- // }
757
- // });
758
-
759
- // it('should permanently lock the user account if the failed login attempts exceed the maximum allowed and autoReleaseYN is N', async () => {
760
- // // Arrange
761
- // const sessionService = await SessionService.init();
762
- // const loginUser = await LoginUser.init(sessionService);
763
- // loginUser['FailedLoginAttemptCount'] = 3;
764
- // loginUser['LastFailedLoginAt'] = new Date();
765
- // loginUser['Status'] = UserStatus.ACTIVE;
766
-
767
- // const dbTransaction = null;
768
-
769
- // // Mock the static methods and properties
770
- // jest
771
- // .spyOn((LoginUser as any)['_Repository'], 'update')
772
- // .mockReturnValueOnce(null);
773
-
774
- // jest
775
- // .spyOn(ComponentConfig, 'getComponentConfigValue')
776
- // .mockImplementation((componentName: string, configKey: string) => {
777
- // if (configKey === 'maxFailedLoginAttempts') {
778
- // return 3;
779
- // }
780
- // if (configKey === 'autoReleaseYN') {
781
- // return 'N';
782
- // }
783
- // });
784
-
785
- // // Act
786
- // try {
787
- // await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
788
- // expect(false).toBe(true);
789
- // } catch (error) {
790
- // // Assert
791
- // expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
792
- // {
793
- // FailedLoginAttemptCount: 4,
794
- // LastFailedLoginAt: expect.any(Date),
795
- // Status: UserStatus.LOCKED,
796
- // },
797
- // {
798
- // where: {
799
- // UserId: loginUser.UserId,
800
- // },
801
- // transaction: dbTransaction,
802
- // },
803
- // );
804
- // expect(error).toBeInstanceOf(ClassError);
805
- // expect(error.message).toBe(
806
- // 'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account',
807
- // );
808
- // }
809
- // });
810
- // });
811
-
812
- // describe('combineSystemAccess', () => {
813
- // it('should combine user and group system access and remove duplicates', async () => {
814
- // // Mock the necessary dependencies
815
- // const sessionService = await SessionService.init();
816
- // const loginUser = await LoginUser.init(sessionService);
817
- // const dbTransaction = null;
818
- // const groups = [
819
- // { InheritParentSystemAccessYN: true },
820
- // { InheritParentSystemAccessYN: false },
821
- // ];
822
-
823
- // // Mock the necessary repository methods
824
- // jest
825
- // .spyOn(LoginUser as any, 'getInheritedSystemAccess')
826
- // .mockResolvedValueOnce([
827
- // { SystemCode: 'system1' },
828
- // { SystemCode: 'system2' },
829
- // ]);
830
- // jest
831
- // .spyOn((LoginUser as any)['_UserSystemAccessRepo'], 'findAll')
832
- // .mockResolvedValueOnce([{ SystemCode: 'system3' }]);
833
-
834
- // // Call the method
835
- // const result = await LoginUser['combineSystemAccess'](
836
- // loginUser,
837
- // dbTransaction,
838
- // groups,
839
- // );
840
-
841
- // // Assert the result
842
- // expect(result).toEqual([
843
- // { SystemCode: 'system3' },
844
- // { SystemCode: 'system1' },
845
- // { SystemCode: 'system2' },
846
- // ]);
847
- // });
848
- // });
849
-
850
- // describe('checkPrivileges', () => {
851
- // it('should return true if user has the specified privilege', async () => {
852
- // // Arrange
853
- // const systemCode = 'SS';
854
- // const privilegeName = 'Privilege 1';
855
- // const sessionService = await SessionService.init();
856
- // const loginUser = await LoginUser.init(sessionService);
857
- // loginUser.ObjectId = '1';
858
-
859
- // // Mock the necessary methods
860
- // const rus = jest
861
- // .spyOn(SessionService.prototype, 'retrieveUserSession')
862
- // .mockResolvedValueOnce({
863
- // systemLogins: [
864
- // {
865
- // id: '1',
866
- // sessionId: 'sessionId',
867
- // code: systemCode,
868
- // privileges: [privilegeName],
869
- // },
870
- // ],
871
- // });
872
- // // Act
873
- // const hasPrivilege = await loginUser.checkPrivileges(
874
- // systemCode,
875
- // privilegeName,
876
- // );
877
-
878
- // // Assert
879
- // expect(hasPrivilege).toBe(true);
880
- // expect(rus).toHaveBeenCalledWith(loginUser.ObjectId);
881
- // });
882
-
883
- // it('should return false if user does not have the specified privilege', async () => {
884
- // // Arrange
885
- // const systemCode = 'SS';
886
- // const privilegeName = 'Privilege 1';
887
- // const sessionService = await SessionService.init();
888
- // const loginUser = await LoginUser.init(sessionService);
889
- // loginUser.ObjectId = '1';
890
-
891
- // // Mock the necessary methods
892
- // const rus = jest
893
- // .spyOn(SessionService.prototype, 'retrieveUserSession')
894
- // .mockResolvedValueOnce({
895
- // systemLogins: [
896
- // {
897
- // id: '1',
898
- // sessionId: 'sessionId',
899
- // code: systemCode,
900
- // privileges: [],
901
- // },
902
- // ],
903
- // });
904
- // // Act
905
- // const hasPrivilege = await loginUser.checkPrivileges(
906
- // systemCode,
907
- // privilegeName,
908
- // );
909
-
910
- // // Assert
911
- // expect(hasPrivilege).toBe(false);
912
- // expect(rus).toHaveBeenCalledWith(loginUser.ObjectId);
913
- // });
914
-
915
- // it('should throw an error if ObjectId is not set', async () => {
916
- // // Arrange
917
- // const systemCode = 'SS';
918
- // const privilegeName = 'Privilege 1';
919
- // const sessionService = await SessionService.init();
920
- // const loginUser = await LoginUser.init(sessionService);
921
- // loginUser.ObjectId = null;
922
-
923
- // // Act & Assert
924
- // await expect(
925
- // loginUser.checkPrivileges(systemCode, privilegeName),
926
- // ).rejects.toThrowError();
927
- // });
928
- // });
929
-
930
- // describe('getObjectPrivileges', () => {
931
- // it('should return an array of privileges', async () => {
932
- // // Mock the dependencies and setup the test data
933
- // const systemCode = 'system1';
934
- // const dbTransaction = null;
935
- // const sessionService = await SessionService.init();
936
- // const loginUser = await LoginUser.init(sessionService);
937
-
938
- // // Mock the UserObjectPrivilegeRepo findAll method
939
- // const findAllMock = jest
940
- // .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
941
- // .mockResolvedValue([
942
- // {
943
- // PrivilegeCode: 'privilege1',
944
- // Privilege: {
945
- // PrivilegeCode: 'privilege1',
946
- // SystemCode: systemCode,
947
- // Name: 'privilege1',
948
- // },
949
- // },
950
- // {
951
- // PrivilegeCode: 'privilege2',
952
- // Privilege: {
953
- // PrivilegeCode: 'privilege2',
954
- // Name: 'privilege2',
955
- // },
956
- // },
957
- // ] as any);
958
-
959
- // // Call the getObjectPrivileges method
960
- // const result = await loginUser['getObjectPrivileges'](
961
- // systemCode,
962
- // dbTransaction,
963
- // );
964
-
965
- // // Assertions
966
- // expect(findAllMock).toHaveBeenCalledTimes(1);
967
- // expect(findAllMock).toHaveBeenCalledWith({
968
- // where: {
969
- // UserId: loginUser.UserId,
970
- // },
971
- // include: {
972
- // model: SystemPrivilegeModel,
973
- // where: {
974
- // SystemCode: systemCode,
975
- // Status: 'Active',
976
- // },
977
- // },
978
- // transaction: dbTransaction,
979
- // });
980
- // expect(result).toEqual(['privilege1', 'privilege2']);
981
- // });
982
-
983
- // it('should throw an error if an exception occurs', async () => {
984
- // // Mock the dependencies and setup the test data
985
- // const systemCode = 'system1';
986
- // const dbTransaction = null;
987
- // const sessionService = await SessionService.init();
988
- // const loginUser = await LoginUser.init(sessionService);
989
-
990
- // // Mock the UserObjectPrivilegeRepo findAll method to throw an error
991
- // jest
992
- // .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
993
- // .mockRejectedValue(new Error('Database error'));
994
-
995
- // // Call the getObjectPrivileges method and expect it to throw an error
996
- // await expect(
997
- // loginUser['getObjectPrivileges'](systemCode, dbTransaction),
998
- // ).rejects.toThrow(Error);
999
- // });
1000
- // });
1001
-
1002
- // describe('getUserPersonalPrivileges', () => {
1003
- // it('should return an array of privileges', async () => {
1004
- // // Arrange
1005
- // const sessionService = await SessionService.init();
1006
- // const loginUser = await LoginUser.init(sessionService);
1007
- // const systemCode = 'system1';
1008
- // const dbTransaction = null;
1009
-
1010
- // // Mock the findAll method of UserPrivilegeRepo
1011
- // const findAllMock = jest.spyOn(
1012
- // LoginUser['_UserPrivilegeRepo'],
1013
- // 'findAll',
1014
- // );
1015
- // findAllMock.mockResolvedValue([
1016
- // { Privilege: { Name: 'privilege1' } },
1017
- // { Privilege: { Name: 'privilege2' } },
1018
- // ] as any);
1019
-
1020
- // // Act
1021
- // const privileges = await loginUser['getUserPersonalPrivileges'](
1022
- // systemCode,
1023
- // dbTransaction,
1024
- // );
1025
-
1026
- // // Assert
1027
- // expect(privileges).toEqual(['privilege1', 'privilege2']);
1028
- // expect(findAllMock).toHaveBeenCalledTimes(1);
1029
- // expect(findAllMock).toHaveBeenCalledWith({
1030
- // where: {
1031
- // UserId: loginUser.UserId,
1032
- // Status: 'Active',
1033
- // },
1034
- // include: {
1035
- // model: SystemPrivilegeModel,
1036
- // where: {
1037
- // SystemCode: systemCode,
1038
- // Status: 'Active',
1039
- // },
1040
- // },
1041
- // transaction: dbTransaction,
1042
- // });
1043
- // });
1044
-
1045
- // it('should throw an error if an error occurs', async () => {
1046
- // // Arrange
1047
- // const sessionService = await SessionService.init();
1048
- // const loginUser = await LoginUser.init(sessionService);
1049
- // const systemCode = 'system1';
1050
- // const dbTransaction = null;
1051
-
1052
- // // Mock the findAll method of UserPrivilegeRepo to throw an error
1053
- // const findAllMock = jest.spyOn(
1054
- // LoginUser['_UserPrivilegeRepo'],
1055
- // 'findAll',
1056
- // );
1057
- // findAllMock.mockRejectedValue(new Error('Database error'));
1058
-
1059
- // // Act and Assert
1060
- // await expect(
1061
- // loginUser['getUserPersonalPrivileges'](systemCode, dbTransaction),
1062
- // ).rejects.toThrow(Error);
1063
-
1064
- // expect(findAllMock).toHaveBeenCalledTimes(1);
1065
- // expect(findAllMock).toHaveBeenCalledWith({
1066
- // where: {
1067
- // UserId: loginUser.UserId,
1068
- // Status: 'Active',
1069
- // },
1070
- // include: {
1071
- // model: SystemPrivilegeModel,
1072
- // where: {
1073
- // SystemCode: systemCode,
1074
- // Status: 'Active',
1075
- // },
1076
- // },
1077
- // transaction: dbTransaction,
1078
- // });
1079
- // });
1080
- // });
1081
-
1082
- // describe('getInheritedSystemAccess', () => {
1083
- // it('should return group system access with its parent group system access if applicable', async () => {
1084
- // // Mock the necessary dependencies
1085
- // const dbTransaction = null;
1086
- // const group = {
1087
- // GroupCode: 'group1',
1088
- // InheritParentPrivilegeYN: 'Y',
1089
- // ParentGroupCode: 'parentGroup',
1090
- // } as any;
1091
- // const parentGroup = {
1092
- // GroupCode: 'parentGroup',
1093
- // InheritParentPrivilegeYN: 'N',
1094
- // ParentGroupCode: null,
1095
- // } as any;
1096
-
1097
- // const systemAccess = [
1098
- // {
1099
- // SystemCode: 'system1',
1100
- // GroupCode: 'group1',
1101
- // System: { SystemCode: 'system1' },
1102
- // },
1103
- // {
1104
- // SystemCode: 'system2',
1105
- // GroupCode: 'group1',
1106
- // System: { SystemCode: 'system1' },
1107
- // },
1108
- // ] as any;
1109
-
1110
- // const parentSystemAccess = [
1111
- // {
1112
- // SystemCode: 'system3',
1113
- // GroupCode: 'parentGroup',
1114
- // System: { SystemCode: 'system3' },
1115
- // },
1116
- // ] as any;
1117
-
1118
- // // Mock the necessary repository methods
1119
- // const groupFindByPkMock = jest
1120
- // .spyOn(GroupRepository.prototype, 'findByPk')
1121
- // .mockResolvedValueOnce(parentGroup as any);
1122
- // const systemAccessFindAllMock = jest
1123
- // .spyOn(GroupSystemAccessRepository.prototype, 'findAll')
1124
- // .mockImplementation((options: any) => {
1125
- // if (options.where.GroupCode === group.GroupCode) {
1126
- // return Promise.resolve(systemAccess);
1127
- // } else if (options.where.GroupCode === parentGroup.GroupCode) {
1128
- // return Promise.resolve(parentSystemAccess);
1129
- // }
1130
- // });
1131
-
1132
- // // Call the method
1133
- // const result = await LoginUser['getInheritedSystemAccess'](
1134
- // dbTransaction,
1135
- // group,
1136
- // );
1137
-
1138
- // console.log(result);
1139
- // // Assert the result
1140
- // expect(result).toEqual([
1141
- // {
1142
- // SystemCode: 'system1',
1143
- // GroupCode: 'group1',
1144
- // System: { SystemCode: 'system1' },
1145
- // },
1146
- // {
1147
- // SystemCode: 'system2',
1148
- // GroupCode: 'group1',
1149
- // System: { SystemCode: 'system1' },
1150
- // },
1151
- // {
1152
- // SystemCode: 'system3',
1153
- // GroupCode: 'parentGroup',
1154
- // System: { SystemCode: 'system3' },
1155
- // },
1156
- // ]);
1157
- // expect(groupFindByPkMock).toHaveBeenCalledWith(
1158
- // group.ParentGroupCode,
1159
- // dbTransaction,
1160
- // );
1161
- // expect(systemAccessFindAllMock).toHaveBeenCalledTimes(2);
1162
- // });
1163
- // });
1164
- // });
1
+ import { SessionService } from '../../../../src/session/session.service';
2
+ import { LoginUser } from '../../../../src/components/login-user/login-user';
3
+ import { ApplicationConfig, ComponentConfig } from '@tomei/config';
4
+ import { UserRepository } from '../../../../src/components/login-user/user.repository';
5
+ import { ClassError } from '@tomei/general';
6
+ import { Activity } from '@tomei/activity-history';
7
+ import { UserStatus } from '../../../../src/enum/user-status.enum';
8
+ import { YN } from '../../../../src/enum/yn.enum';
9
+ import SystemPrivilegeModel from '../../../../src/models/system-privilege.entity';
10
+ import { GroupSystemAccessRepository } from '../../../../src/components/group-system-access/group-system-access.repository';
11
+ import { GroupRepository } from '../../../../src/components/group/group.repository';
12
+ import axios from 'axios';
13
+
14
+ const mockUserData = {
15
+ UserId: 1,
16
+ FullName: 'John Doe',
17
+ Email: 'john.doe@example.com',
18
+ Password: 'password',
19
+ Status: 'Active',
20
+ DefaultPasswordChangedYN: 'N',
21
+ FirstLoginAt: new Date(),
22
+ LastLoginAt: new Date(),
23
+ MFAEnabled: 1,
24
+ MFAConfig: 'config',
25
+ RecoveryEmail: 'john.doe@example.com',
26
+ FailedLoginAttemptCount: 0,
27
+ LastFailedLoginAt: null,
28
+ LastPasswordChangedAt: new Date(),
29
+ NeedToChangePasswordYN: 'N',
30
+ CreatedById: 1,
31
+ CreatedAt: new Date(),
32
+ UpdatedById: 1,
33
+ UpdatedAt: new Date(),
34
+ Staff: {
35
+ FullName: 'John Doe',
36
+ IdNo: '1234567890',
37
+ Mobile: '1234567890',
38
+ },
39
+ };
40
+
41
+ const mockSessionService = {
42
+ setUserSession: jest.fn(),
43
+ retrieveUserSession: jest.fn(),
44
+ refreshDuration: jest.fn(),
45
+ };
46
+
47
+ describe('LoginUser', () => {
48
+ beforeAll(() => {
49
+ // Redis env vars needed for RedisService.init() — actual connection is mocked via jest-initial-setup.ts
50
+ process.env.REDIS_HOST = 'localhost';
51
+ process.env.REDIS_PORT = '6379';
52
+ });
53
+
54
+ afterAll(() => {
55
+ jest.restoreAllMocks();
56
+ });
57
+
58
+ describe('init', () => {
59
+ let sessionService: any;
60
+ let userId: number;
61
+ let dbTransaction: any;
62
+ const mockLoginApiEndpoint = {
63
+ baseUrl: 'http://sso-api',
64
+ getProfile: '/get-profile',
65
+ apiKey: 'test-api-key',
66
+ };
67
+
68
+ beforeEach(() => {
69
+ sessionService = {};
70
+ userId = 1;
71
+ dbTransaction = null;
72
+ jest
73
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
74
+ .mockReturnValue(mockLoginApiEndpoint as any);
75
+ });
76
+
77
+ it('should initialize LoginUser with valid userId', async () => {
78
+ const user = {
79
+ UserId: 1,
80
+ FullName: 'John Doe',
81
+ Email: 'john.doe@example.com',
82
+ Password: 'password',
83
+ Status: 'active',
84
+ DefaultPasswordChangedYN: 'yes',
85
+ FirstLoginAt: new Date(),
86
+ LastLoginAt: new Date(),
87
+ MFAEnabled: 1,
88
+ MFAConfig: 'config',
89
+ RecoveryEmail: 'john.doe@example.com',
90
+ FailedLoginAttemptCount: 0,
91
+ LastFailedLoginAt: null,
92
+ LastPasswordChangedAt: new Date(),
93
+ NeedToChangePasswordYN: 'no',
94
+ CreatedById: 1,
95
+ CreatedAt: new Date(),
96
+ UpdatedById: 1,
97
+ UpdatedAt: new Date(),
98
+ Staff: {
99
+ FullName: 'John Doe',
100
+ IdNo: '1234567890',
101
+ Mobile: '1234567890',
102
+ },
103
+ };
104
+
105
+ const axiosPostMock = jest
106
+ .spyOn(axios, 'post')
107
+ .mockResolvedValueOnce({ data: { loginUser: user } } as any);
108
+
109
+ const result = await LoginUser.init(
110
+ sessionService,
111
+ userId,
112
+ dbTransaction,
113
+ );
114
+
115
+ expect(axiosPostMock).toHaveBeenCalledTimes(1);
116
+ expect(axiosPostMock).toHaveBeenCalledWith(
117
+ `${mockLoginApiEndpoint.baseUrl}${mockLoginApiEndpoint.getProfile}`,
118
+ { UserId: userId },
119
+ { headers: { 'Content-Type': 'application/json', 'x-api-key': mockLoginApiEndpoint.apiKey } },
120
+ );
121
+ expect(result).toBeInstanceOf(LoginUser);
122
+ expect(result.UserId).toBe(user.UserId);
123
+ expect(result.FullName).toBe(user.FullName);
124
+ expect(result.Email).toBe(user.Email);
125
+ expect(result.Status).toBe(user.Status);
126
+ });
127
+
128
+ it('should throw an error when user is not found', async () => {
129
+ const axiosPostMock = jest
130
+ .spyOn(axios, 'post')
131
+ .mockResolvedValueOnce({ data: { loginUser: null } } as any);
132
+
133
+ await expect(
134
+ LoginUser.init(sessionService, userId, dbTransaction),
135
+ ).rejects.toThrow(Error);
136
+
137
+ expect(axiosPostMock).toHaveBeenCalledTimes(1);
138
+ });
139
+ });
140
+
141
+ // describe('checkSession', () => {
142
+ // it('should throw an error if session expired', async () => {
143
+ // // Arrange
144
+ // const systemCode = 'EZC';
145
+ // const sessionId = 'ckymxuh8t000137t011w89zgk';
146
+ // const userId = '755';
147
+ // const sessionService = await SessionService.init();
148
+ // const loginUser = await LoginUser.init(sessionService);
149
+
150
+ // // Act
151
+ // const checkSessionPromise = loginUser.checkSession(
152
+ // systemCode,
153
+ // sessionId,
154
+ // userId,
155
+ // );
156
+
157
+ // // Assert
158
+ // await expect(checkSessionPromise).rejects.toThrow('Session expired.');
159
+ // });
160
+
161
+ // it('should refresh the session duration if session is valid', async () => {
162
+ // // Arrange
163
+ // const systemCode = 'EZC';
164
+ // const sessionId = 'ckymxuh8t000137t011w89zgk';
165
+ // const userId = '755';
166
+ // const sessionService = await SessionService.init();
167
+ // const loginUser = await LoginUser.init(sessionService);
168
+
169
+ // // Mock the _SessionService.retrieveUserSession method
170
+ // loginUser['_SessionService'].retrieveUserSession = jest
171
+ // .fn()
172
+ // .mockResolvedValue({
173
+ // systemLogins: [
174
+ // {
175
+ // code: systemCode,
176
+ // sessionId: sessionId,
177
+ // privileges: [],
178
+ // },
179
+ // ],
180
+ // });
181
+
182
+ // // Mock the _SessionService.refreshDuration method
183
+ // loginUser['_SessionService'].refreshDuration = jest.fn();
184
+
185
+ // // Act
186
+ // const systemLogin = await loginUser.checkSession(
187
+ // systemCode,
188
+ // sessionId,
189
+ // userId,
190
+ // );
191
+
192
+ // // Assert
193
+ // expect(
194
+ // loginUser['_SessionService'].retrieveUserSession,
195
+ // ).toHaveBeenCalledWith(userId);
196
+ // expect(loginUser['_SessionService'].refreshDuration).toHaveBeenCalledWith(
197
+ // userId,
198
+ // );
199
+ // expect(systemLogin).toEqual({
200
+ // code: systemCode,
201
+ // sessionId: sessionId,
202
+ // privileges: [],
203
+ // });
204
+ // });
205
+ // });
206
+
207
+ describe('shouldReleaseLock', () => {
208
+ const minuteToAutoRelease = 5;
209
+ const autoReleaseYN = 'Y';
210
+
211
+ beforeEach(() => {
212
+ jest
213
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
214
+ .mockImplementation((componentName: string, configKey: string) => {
215
+ if (configKey === 'minuteToAutoRelease') {
216
+ return minuteToAutoRelease as any;
217
+ }
218
+ if (configKey === 'autoReleaseYN') {
219
+ return autoReleaseYN as any;
220
+ }
221
+ });
222
+ });
223
+
224
+ it('should return true if autoReleaseYN is "Y" and time difference is greater than minuteToAutoRelease', async () => {
225
+ // Arrange
226
+ const lastFailedLoginAt = new Date();
227
+ lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 10); // Set last failed login time to 10 minutes ago
228
+ // Act
229
+ const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
230
+
231
+ // Assert
232
+ expect(result).toBe(true);
233
+ });
234
+
235
+ it('should return false if autoReleaseYN is "Y" and time difference is less than or equal to minuteToAutoRelease', async () => {
236
+ // Arrange
237
+ const lastFailedLoginAt = new Date();
238
+ lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 3); // Set last failed login time to 3 minutes ago
239
+
240
+ // Act
241
+ const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
242
+
243
+ // Assert
244
+ expect(result).toBe(false);
245
+ });
246
+
247
+ it('should return false if autoReleaseYN is "N"', async () => {
248
+ // Arrange
249
+ const lastFailedLoginAt = new Date();
250
+
251
+ // Act
252
+ const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
253
+
254
+ // Assert
255
+ expect(result).toBe(false);
256
+ });
257
+ });
258
+
259
+ describe('releaseLock', () => {
260
+ it('should release the lock for a user', async () => {
261
+ // Mock the necessary dependencies and setup the test data
262
+ const UserId = 1;
263
+ const dbTransaction = null;
264
+
265
+ const updateMock = jest
266
+ .spyOn(LoginUser['_Repository'], 'update')
267
+ .mockImplementationOnce(() => Promise.resolve({}) as any);
268
+
269
+ // Call the method under test
270
+ LoginUser['releaseLock'](UserId, dbTransaction);
271
+
272
+ // Verify the expected behavior
273
+ expect(updateMock).toHaveBeenCalledTimes(1);
274
+ expect(updateMock).toHaveBeenCalledWith(
275
+ {
276
+ FailedLoginAttemptCount: 0,
277
+ Status: 'Active',
278
+ },
279
+ {
280
+ where: {
281
+ UserId,
282
+ },
283
+ transaction: dbTransaction,
284
+ },
285
+ );
286
+ });
287
+ });
288
+
289
+ describe('checkUserInfoDuplicated', () => {
290
+ it('should throw an error if duplicate user info is found', async () => {
291
+ // Mock the dependencies and setup the test data
292
+ const dbTransaction = null;
293
+ const query = {
294
+ Email: 'test@example.com',
295
+ IdType: 'passport',
296
+ IdNo: '123456789',
297
+ ContactNo: '1234567890',
298
+ };
299
+
300
+ // Mock the LoginUser['_Repository'].findAll method to return a user
301
+ jest
302
+ .spyOn(LoginUser['_Repository'], 'findAll')
303
+ .mockResolvedValueOnce([{ id: 1 }] as any);
304
+
305
+ // Assert that the method throws an error
306
+ await expect(
307
+ LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
308
+ ).rejects.toThrow();
309
+ });
310
+
311
+ it('should not throw an error if duplicate user info is not found', async () => {
312
+ // Mock the dependencies and setup the test data
313
+ const dbTransaction = null;
314
+ const query = {
315
+ Email: 'test@example.com',
316
+ IdType: 'passport',
317
+ IdNo: '123456789',
318
+ ContactNo: '1234567890',
319
+ };
320
+
321
+ // Mock the LoginUser['_Repository'].findAll method to return an empty array
322
+ jest.spyOn(LoginUser['_Repository'], 'findAll').mockResolvedValueOnce([]);
323
+
324
+ // Assert that the method does not throw an error
325
+ await expect(
326
+ LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
327
+ ).resolves.not.toThrow();
328
+ });
329
+ });
330
+
331
+ describe('generateDefaultPassword', () => {
332
+ const passwordPolicy = {
333
+ minLen: 6,
334
+ maxLen: 10,
335
+ nonAcceptableChar: 'i,l,o',
336
+ numOfCapitalLetters: 1,
337
+ numOfNumbers: 1,
338
+ numOfSpecialChars: 1,
339
+ };
340
+ beforeEach(() => {
341
+ jest
342
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
343
+ .mockImplementation((componentName: string, configKey: string) => {
344
+ if (configKey === 'passwordPolicy') {
345
+ return passwordPolicy as any;
346
+ }
347
+ });
348
+ });
349
+
350
+ it('should generate a default password with the specified length', () => {
351
+ const password = LoginUser['generateDefaultPassword']();
352
+ expect(password.length).toBeGreaterThanOrEqual(6);
353
+ expect(password.length).toBeLessThanOrEqual(10);
354
+ });
355
+
356
+ it('should generate a default password with at least one capital letter', () => {
357
+ const password = LoginUser['generateDefaultPassword']();
358
+ expect(/[A-Z]/.test(password)).toBe(true);
359
+ });
360
+
361
+ it('should generate a default password with at least one number', () => {
362
+ const password = LoginUser['generateDefaultPassword']();
363
+ expect(/[0-9]/.test(password)).toBe(true);
364
+ });
365
+
366
+ it('should generate a default password with at least one special character', () => {
367
+ const password = LoginUser['generateDefaultPassword']();
368
+ expect(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~`]/.test(password)).toBe(true);
369
+ });
370
+
371
+ it('should generate a default password without any non-acceptable characters', () => {
372
+ const password = LoginUser['generateDefaultPassword']();
373
+ const nonAcceptableChars = ['i', 'l', 'o'];
374
+ expect(nonAcceptableChars.some((char) => password.includes(char))).toBe(
375
+ false,
376
+ );
377
+ });
378
+ });
379
+
380
+ describe('setPassword', () => {
381
+ const passwordPolicy = {
382
+ minLen: 6,
383
+ maxLen: 10,
384
+ nonAcceptableChar: 'i,l,o',
385
+ numOfCapitalLetters: 1,
386
+ numOfNumbers: 1,
387
+ numOfSpecialChars: 1,
388
+ };
389
+ beforeEach(() => {
390
+ jest
391
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
392
+ .mockImplementation((componentName: string, configKey: string) => {
393
+ if (configKey === 'passwordPolicy') {
394
+ return passwordPolicy as any;
395
+ }
396
+ });
397
+ });
398
+
399
+ it('should set the password for the user', async () => {
400
+ // Arrange
401
+ const dbTransaction = null;
402
+ const sessionService = await SessionService.init();
403
+ const user = await LoginUser.init(sessionService);
404
+ const password = 'N3wP@ssw0';
405
+
406
+ // Act
407
+ const result = await LoginUser['setPassword'](
408
+ dbTransaction,
409
+ user,
410
+ password,
411
+ );
412
+
413
+ // Assert
414
+ expect(result).toBeInstanceOf(LoginUser);
415
+ await expect(
416
+ LoginUser['setPassword'](dbTransaction, user, password),
417
+ ).resolves.not.toThrow();
418
+ expect(result.Password).toBeDefined();
419
+ });
420
+
421
+ it('should throw an error if the password does not meet the security requirements', async () => {
422
+ // Arrange
423
+ const dbTransaction = null;
424
+ const sessionService = await SessionService.init();
425
+ const user = await LoginUser.init(sessionService);
426
+ const password = 'weakpassword';
427
+
428
+ // Act & Assert
429
+ await expect(
430
+ LoginUser['setPassword'](dbTransaction, user, password),
431
+ ).rejects.toThrow();
432
+ });
433
+ });
434
+
435
+ // describe('create', () => {
436
+ // let loginUser: LoginUser;
437
+ // let dbTransaction: any;
438
+ // let user: LoginUser;
439
+ // let newUser: any;
440
+
441
+ // beforeEach(async () => {
442
+ // const sessionService = await SessionService.init();
443
+ // loginUser = await LoginUser.init(sessionService);
444
+ // dbTransaction = null;
445
+ // newUser = {
446
+ // UserId: 1,
447
+ // FullName: 'John Doe',
448
+ // Email: 'john.doe@example.com',
449
+ // Password: 'password',
450
+ // Status: 'Active',
451
+ // DefaultPasswordChangedYN: 'N',
452
+ // FirstLoginAt: null,
453
+ // LastLoginAt: null,
454
+ // MFAEnabled: null,
455
+ // MFAConfig: null,
456
+ // RecoveryEmail: null,
457
+ // FailedLoginAttemptCount: 0,
458
+ // LastFailedLoginAt: null,
459
+ // LastPasswordChangedAt: new Date(),
460
+ // NeedToChangePasswordYN: 'N',
461
+ // CreatedById: 1,
462
+ // CreatedAt: new Date(),
463
+ // UpdatedById: 1,
464
+ // UpdatedAt: new Date(),
465
+ // Staff: {
466
+ // FullName: 'John Doe',
467
+ // IdNo: '1234567890',
468
+ // Mobile: '1234567890',
469
+ // },
470
+ // };
471
+ // user = new (LoginUser as any)(sessionService, null, newUser);
472
+ // });
473
+
474
+ // afterEach(() => {
475
+ // jest.clearAllMocks();
476
+ // });
477
+
478
+ // it('should create a new user record', async () => {
479
+ // const checkPrivilegesMock = jest
480
+ // .spyOn(loginUser, 'checkPrivileges')
481
+ // .mockResolvedValueOnce(true);
482
+
483
+ // const checkUserInfoDuplicatedMock = jest
484
+ // .spyOn(LoginUser as any, 'checkUserInfoDuplicated')
485
+ // .mockResolvedValueOnce(undefined);
486
+
487
+ // const generateDefaultPasswordMock = jest
488
+ // .spyOn(LoginUser as any, 'generateDefaultPassword')
489
+ // .mockReturnValueOnce('defaultPassword');
490
+
491
+ // const setPasswordMock = jest
492
+ // .spyOn(LoginUser as any, 'setPassword')
493
+ // .mockResolvedValueOnce(user);
494
+
495
+ // const createMock = jest
496
+ // .spyOn((LoginUser as any)['_Repository'], 'create')
497
+ // .mockResolvedValueOnce({
498
+ // ...newUser,
499
+ // get: () => newUser,
500
+ // });
501
+
502
+ // const activityCreateMock = jest
503
+ // .spyOn((Activity as any).prototype, 'create')
504
+ // .mockResolvedValueOnce(undefined);
505
+
506
+ // jest
507
+ // .spyOn(ApplicationConfig, 'getComponentConfigValue')
508
+ // .mockImplementation((configKey: string) => {
509
+ // if (configKey === 'system-code') {
510
+ // return 'SC';
511
+ // }
512
+ // });
513
+
514
+ // const result = await LoginUser.create(loginUser, dbTransaction, user);
515
+
516
+ // expect(checkPrivilegesMock).toHaveBeenCalledTimes(1);
517
+ // expect(checkPrivilegesMock).toHaveBeenCalledWith(
518
+ // ApplicationConfig.getComponentConfigValue('system-code'),
519
+ // 'User - Create',
520
+ // );
521
+
522
+ // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledTimes(1);
523
+ // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledWith(dbTransaction, {
524
+ // Email: user.Email,
525
+ // IdType: user.IDType,
526
+ // IdNo: user.IDNo,
527
+ // ContactNo: user.ContactNo,
528
+ // });
529
+
530
+ // expect(generateDefaultPasswordMock).toHaveBeenCalledTimes(1);
531
+
532
+ // expect(setPasswordMock).toHaveBeenCalledTimes(1);
533
+ // expect(setPasswordMock).toHaveBeenCalledWith(
534
+ // dbTransaction,
535
+ // user,
536
+ // 'defaultPassword',
537
+ // );
538
+
539
+ // expect(createMock).toHaveBeenCalledTimes(1);
540
+
541
+ // const userInfo = {
542
+ // FullName: user.FullName,
543
+ // IDNo: user.IDNo,
544
+ // Email: user.Email,
545
+ // ContactNo: user.ContactNo,
546
+ // Password: user.Password,
547
+ // Status: UserStatus.ACTIVE,
548
+ // FirstLoginAt: null,
549
+ // LastLoginAt: null,
550
+ // MFAEnabled: null,
551
+ // MFAConfig: null,
552
+ // RecoveryEmail: null,
553
+ // FailedLoginAttemptCount: 0,
554
+ // LastFailedLoginAt: null,
555
+ // LastPasswordChangedAt: null,
556
+ // DefaultPasswordChangedYN: YN.No,
557
+ // NeedToChangePasswordYN: YN.Yes,
558
+ // CreatedById: loginUser.UserId,
559
+ // CreatedAt: new Date(),
560
+ // UpdatedById: loginUser.UserId,
561
+ // UpdatedAt: new Date(),
562
+ // UserId: null,
563
+ // };
564
+
565
+ // expect(createMock).toHaveBeenCalledWith(
566
+ // {
567
+ // Email: userInfo.Email,
568
+ // Password: userInfo.Password,
569
+ // Status: userInfo.Status,
570
+ // DefaultPasswordChangedYN: userInfo.DefaultPasswordChangedYN,
571
+ // FirstLoginAt: userInfo.FirstLoginAt,
572
+ // LastLoginAt: userInfo.LastLoginAt,
573
+ // MFAEnabled: userInfo.MFAEnabled,
574
+ // MFAConfig: userInfo.MFAConfig,
575
+ // RecoveryEmail: userInfo.RecoveryEmail,
576
+ // FailedLoginAttemptCount: userInfo.FailedLoginAttemptCount,
577
+ // LastFailedLoginAt: userInfo.LastFailedLoginAt,
578
+ // LastPasswordChangedAt: userInfo.LastPasswordChangedAt,
579
+ // NeedToChangePasswordYN: userInfo.NeedToChangePasswordYN,
580
+ // CreatedById: userInfo.CreatedById,
581
+ // CreatedAt: expect.any(Date),
582
+ // UpdatedById: userInfo.UpdatedById,
583
+ // UpdatedAt: expect.any(Date),
584
+ // },
585
+ // {
586
+ // transaction: dbTransaction,
587
+ // },
588
+ // );
589
+
590
+ // expect(activityCreateMock).toHaveBeenCalledTimes(1);
591
+
592
+ // expect(result).toBeInstanceOf(LoginUser);
593
+ // expect(result.Email).toBe(userInfo.Email);
594
+ // expect(result.Password).toBe(userInfo.Password);
595
+ // expect(result.Status).toBe(userInfo.Status);
596
+ // expect(result.DefaultPasswordChangedYN).toBe(
597
+ // userInfo.DefaultPasswordChangedYN,
598
+ // );
599
+ // expect(result.FirstLoginAt).toBe(null);
600
+ // expect(result.LastLoginAt).toBe(null);
601
+ // expect(result.MFAEnabled).toBe(userInfo.MFAEnabled);
602
+ // expect(result.MFAConfig).toBe(userInfo.MFAConfig);
603
+ // expect(result.RecoveryEmail).toBe(userInfo.RecoveryEmail);
604
+ // expect(result.FailedLoginAttemptCount).toBe(
605
+ // userInfo.FailedLoginAttemptCount,
606
+ // );
607
+ // expect(result.LastFailedLoginAt).toBe(userInfo.LastFailedLoginAt);
608
+ // expect(result.LastPasswordChangedAt).toBe(userInfo.LastPasswordChangedAt);
609
+ // expect(result.NeedToChangePasswordYN).toBe(
610
+ // userInfo.NeedToChangePasswordYN,
611
+ // );
612
+ // expect(result.CreatedById).toBe(userInfo.CreatedById);
613
+ // expect(result.UpdatedById).toBe(userInfo.UpdatedById);
614
+ // });
615
+
616
+ // it('should throw an error if user dont have the privilege to create new user', async () => {
617
+ // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(false);
618
+
619
+ // await expect(
620
+ // LoginUser.create(loginUser, dbTransaction, user),
621
+ // ).rejects.toThrow(ClassError);
622
+ // });
623
+
624
+ // it('should throw an error if user email is missing', async () => {
625
+ // user.Email = undefined;
626
+
627
+ // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(true);
628
+
629
+ // await expect(
630
+ // LoginUser.create(loginUser, dbTransaction, user),
631
+ // ).rejects.toThrow(ClassError);
632
+ // });
633
+ // });
634
+
635
+ describe('incrementFailedLoginAttemptCount', () => {
636
+ afterAll(() => {
637
+ jest.restoreAllMocks();
638
+ });
639
+
640
+ it('should increment FailedLoginAttemptCount and update user status', async () => {
641
+ // Arrange
642
+ const sessionService = await SessionService.init();
643
+ const loginUser = await LoginUser.init(sessionService);
644
+ loginUser['FailedLoginAttemptCount'] = 2;
645
+ loginUser['LastFailedLoginAt'] = new Date();
646
+ loginUser['Status'] = UserStatus.ACTIVE;
647
+
648
+ const dbTransaction = null;
649
+
650
+ // Mock the static methods and properties
651
+ jest
652
+ .spyOn((LoginUser as any)['_Repository'], 'update')
653
+ .mockReturnValueOnce(null);
654
+
655
+ jest
656
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
657
+ .mockImplementation((componentName: string, configKey: string) => {
658
+ if (configKey === 'maxFailedLoginAttempts') {
659
+ return 3;
660
+ }
661
+ if (configKey === 'autoReleaseYN') {
662
+ return 'Y';
663
+ }
664
+ });
665
+
666
+ // Act
667
+ await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
668
+
669
+ // Assert
670
+ expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
671
+ {
672
+ FailedLoginAttemptCount: 3,
673
+ LastFailedLoginAt: expect.any(Date),
674
+ Status: UserStatus.ACTIVE,
675
+ },
676
+ {
677
+ where: {
678
+ UserId: loginUser.UserId,
679
+ },
680
+ transaction: dbTransaction,
681
+ },
682
+ );
683
+ });
684
+
685
+ it('should throw an error if maxFailedLoginAttempts or autoReleaseYN is missing', async () => {
686
+ // Arrange
687
+ const sessionService = await SessionService.init();
688
+ const loginUser = await LoginUser.init(sessionService);
689
+ loginUser['FailedLoginAttemptCount'] = 2;
690
+ loginUser['LastFailedLoginAt'] = new Date();
691
+ loginUser['Status'] = UserStatus.ACTIVE;
692
+
693
+ const dbTransaction = null;
694
+
695
+ // Mock the static methods and properties
696
+ jest
697
+ .spyOn((LoginUser as any)['_Repository'], 'update')
698
+ .mockReturnValueOnce(null);
699
+
700
+ jest
701
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
702
+ .mockImplementationOnce((componentName: string, configKey: string) => {
703
+ if (configKey === 'maxFailedLoginAttempts') {
704
+ return undefined;
705
+ }
706
+ if (configKey === 'autoReleaseYN') {
707
+ return undefined;
708
+ }
709
+ });
710
+
711
+ // Act and Assert
712
+ await expect(
713
+ loginUser['incrementFailedLoginAttemptCount'](dbTransaction),
714
+ ).rejects.toThrow(
715
+ new ClassError(
716
+ 'LoginUser',
717
+ 'LoginUserErrMsg0X',
718
+ 'Missing maxFailedLoginAttempts and or autoReleaseYN. Please set in config file.',
719
+ ),
720
+ );
721
+ });
722
+
723
+ it('should lock the user account if the failed login attempts exceed the maximum allowed', async () => {
724
+ // Arrange
725
+ const sessionService = await SessionService.init();
726
+ const loginUser = await LoginUser.init(sessionService);
727
+ loginUser['FailedLoginAttemptCount'] = 3;
728
+ loginUser['LastFailedLoginAt'] = new Date();
729
+ loginUser['Status'] = UserStatus.ACTIVE;
730
+
731
+ const dbTransaction = null;
732
+
733
+ // Mock the static methods and properties
734
+ jest
735
+ .spyOn((LoginUser as any)['_Repository'], 'update')
736
+ .mockReturnValueOnce(null);
737
+
738
+ jest
739
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
740
+ .mockImplementation((componentName: string, configKey: string) => {
741
+ if (configKey === 'maxFailedLoginAttempts') {
742
+ return 3;
743
+ }
744
+ if (configKey === 'autoReleaseYN') {
745
+ return 'Y';
746
+ }
747
+ });
748
+
749
+ // Act
750
+ try {
751
+ await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
752
+ expect(false).toBe(true);
753
+ } catch (error) {
754
+ // Assert
755
+ expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
756
+ {
757
+ FailedLoginAttemptCount: 4,
758
+ LastFailedLoginAt: expect.any(Date),
759
+ Status: UserStatus.LOCKED,
760
+ },
761
+ {
762
+ where: {
763
+ UserId: loginUser.UserId,
764
+ },
765
+ transaction: dbTransaction,
766
+ },
767
+ );
768
+ expect(error).toBeInstanceOf(ClassError);
769
+ expect(error.message).toBe(
770
+ 'Your account has been temporarily locked due to too many failed login attempts, please try again later.',
771
+ );
772
+ }
773
+ });
774
+
775
+ it('should permanently lock the user account if the failed login attempts exceed the maximum allowed and autoReleaseYN is N', async () => {
776
+ // Arrange
777
+ const sessionService = await SessionService.init();
778
+ const loginUser = await LoginUser.init(sessionService);
779
+ loginUser['FailedLoginAttemptCount'] = 3;
780
+ loginUser['LastFailedLoginAt'] = new Date();
781
+ loginUser['Status'] = UserStatus.ACTIVE;
782
+
783
+ const dbTransaction = null;
784
+
785
+ // Mock the static methods and properties
786
+ jest
787
+ .spyOn((LoginUser as any)['_Repository'], 'update')
788
+ .mockReturnValueOnce(null);
789
+
790
+ jest
791
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
792
+ .mockImplementation((componentName: string, configKey: string) => {
793
+ if (configKey === 'maxFailedLoginAttempts') {
794
+ return 3;
795
+ }
796
+ if (configKey === 'autoReleaseYN') {
797
+ return 'N';
798
+ }
799
+ });
800
+
801
+ // Act
802
+ try {
803
+ await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
804
+ expect(false).toBe(true);
805
+ } catch (error) {
806
+ // Assert
807
+ expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
808
+ {
809
+ FailedLoginAttemptCount: 4,
810
+ LastFailedLoginAt: expect.any(Date),
811
+ Status: UserStatus.LOCKED,
812
+ },
813
+ {
814
+ where: {
815
+ UserId: loginUser.UserId,
816
+ },
817
+ transaction: dbTransaction,
818
+ },
819
+ );
820
+ expect(error).toBeInstanceOf(ClassError);
821
+ expect(error.message).toBe(
822
+ 'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account',
823
+ );
824
+ }
825
+ });
826
+ });
827
+
828
+ describe('combineSystemAccess', () => {
829
+ it('should combine user and group system access and remove duplicates', async () => {
830
+ // Mock the necessary dependencies
831
+ const sessionService = await SessionService.init();
832
+ const loginUser = await LoginUser.init(sessionService);
833
+ const dbTransaction = null;
834
+ const groups = [
835
+ { InheritParentSystemAccessYN: true },
836
+ { InheritParentSystemAccessYN: false },
837
+ ];
838
+
839
+ // Mock the necessary repository methods
840
+ jest
841
+ .spyOn(LoginUser as any, 'getInheritedSystemAccess')
842
+ .mockResolvedValueOnce([
843
+ { SystemCode: 'system1' },
844
+ { SystemCode: 'system2' },
845
+ ]);
846
+ jest
847
+ .spyOn((LoginUser as any)['_UserSystemAccessRepo'], 'findAll')
848
+ .mockResolvedValueOnce([{ SystemCode: 'system3' }]);
849
+
850
+ // Call the method
851
+ const result = await LoginUser['combineSystemAccess'](
852
+ loginUser,
853
+ dbTransaction,
854
+ groups,
855
+ );
856
+
857
+ // Assert the result
858
+ expect(result).toEqual([
859
+ { SystemCode: 'system3' },
860
+ { SystemCode: 'system1' },
861
+ { SystemCode: 'system2' },
862
+ ]);
863
+ });
864
+ });
865
+
866
+ describe('checkPrivileges', () => {
867
+ const mockLoginApiEndpoint = {
868
+ baseUrl: 'http://sso-api',
869
+ checkPrivileges: '/check-privileges',
870
+ apiKey: 'test-api-key',
871
+ };
872
+
873
+ beforeEach(() => {
874
+ jest
875
+ .spyOn(ApplicationConfig, 'getComponentConfigValue')
876
+ .mockReturnValue('test-session' as any);
877
+ jest
878
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
879
+ .mockReturnValue(mockLoginApiEndpoint as any);
880
+ });
881
+
882
+ it('should return true if user has the specified privilege', async () => {
883
+ // Arrange
884
+ const systemCode = 'SS';
885
+ const privilegeName = 'Privilege 1';
886
+ const sessionService = await SessionService.init();
887
+ const loginUser = await LoginUser.init(sessionService);
888
+ loginUser.ObjectId = '1';
889
+
890
+ const axiosPostMock = jest
891
+ .spyOn(axios, 'post')
892
+ .mockResolvedValueOnce({ data: { hasPrivilege: true } } as any);
893
+
894
+ // Act
895
+ const hasPrivilege = await loginUser.checkPrivileges(
896
+ systemCode,
897
+ privilegeName,
898
+ );
899
+
900
+ // Assert
901
+ expect(hasPrivilege).toBe(true);
902
+ expect(axiosPostMock).toHaveBeenCalledWith(
903
+ `${mockLoginApiEndpoint.baseUrl}${mockLoginApiEndpoint.checkPrivileges}`,
904
+ { SystemCode: systemCode, SessionName: 'test-session', PrivilegeName: privilegeName, UserId: '1' },
905
+ { headers: { 'Content-Type': 'application/json', 'x-api-key': mockLoginApiEndpoint.apiKey } },
906
+ );
907
+ });
908
+
909
+ it('should return false if user does not have the specified privilege', async () => {
910
+ // Arrange
911
+ const systemCode = 'SS';
912
+ const privilegeName = 'Privilege 1';
913
+ const sessionService = await SessionService.init();
914
+ const loginUser = await LoginUser.init(sessionService);
915
+ loginUser.ObjectId = '1';
916
+
917
+ const axiosPostMock = jest
918
+ .spyOn(axios, 'post')
919
+ .mockResolvedValueOnce({ data: { hasPrivilege: false } } as any);
920
+
921
+ // Act
922
+ const hasPrivilege = await loginUser.checkPrivileges(
923
+ systemCode,
924
+ privilegeName,
925
+ );
926
+
927
+ // Assert
928
+ expect(hasPrivilege).toBe(false);
929
+ });
930
+
931
+ it('should throw an error if ObjectId is not set', async () => {
932
+ // Arrange
933
+ const systemCode = 'SS';
934
+ const privilegeName = 'Privilege 1';
935
+ const sessionService = await SessionService.init();
936
+ const loginUser = await LoginUser.init(sessionService);
937
+ loginUser.ObjectId = null;
938
+
939
+ // Act & Assert
940
+ await expect(
941
+ loginUser.checkPrivileges(systemCode, privilegeName),
942
+ ).rejects.toThrow();
943
+ });
944
+ });
945
+
946
+ describe('getObjectPrivileges', () => {
947
+ it('should return an array of privileges', async () => {
948
+ // Mock the dependencies and setup the test data
949
+ const systemCode = 'system1';
950
+ const dbTransaction = null;
951
+ const sessionService = await SessionService.init();
952
+ const loginUser = await LoginUser.init(sessionService);
953
+
954
+ // Mock the UserObjectPrivilegeRepo findAll method
955
+ const findAllMock = jest
956
+ .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
957
+ .mockResolvedValue([
958
+ {
959
+ PrivilegeCode: 'privilege1',
960
+ Privilege: {
961
+ PrivilegeCode: 'privilege1',
962
+ SystemCode: systemCode,
963
+ Name: 'privilege1',
964
+ },
965
+ },
966
+ {
967
+ PrivilegeCode: 'privilege2',
968
+ Privilege: {
969
+ PrivilegeCode: 'privilege2',
970
+ Name: 'privilege2',
971
+ },
972
+ },
973
+ ] as any);
974
+
975
+ // Call the getObjectPrivileges method
976
+ const result = await loginUser['getObjectPrivileges'](
977
+ systemCode,
978
+ dbTransaction,
979
+ );
980
+
981
+ // Assertions
982
+ expect(findAllMock).toHaveBeenCalledTimes(1);
983
+ expect(findAllMock).toHaveBeenCalledWith({
984
+ where: {
985
+ UserId: loginUser.UserId,
986
+ },
987
+ include: {
988
+ model: SystemPrivilegeModel,
989
+ where: {
990
+ SystemCode: systemCode,
991
+ Status: 'Active',
992
+ },
993
+ },
994
+ transaction: dbTransaction,
995
+ });
996
+ expect(result).toEqual(['privilege1', 'privilege2']);
997
+ });
998
+
999
+ it('should throw an error if an exception occurs', async () => {
1000
+ // Mock the dependencies and setup the test data
1001
+ const systemCode = 'system1';
1002
+ const dbTransaction = null;
1003
+ const sessionService = await SessionService.init();
1004
+ const loginUser = await LoginUser.init(sessionService);
1005
+
1006
+ // Mock the UserObjectPrivilegeRepo findAll method to throw an error
1007
+ jest
1008
+ .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
1009
+ .mockRejectedValue(new Error('Database error'));
1010
+
1011
+ // Call the getObjectPrivileges method and expect it to throw an error
1012
+ await expect(
1013
+ loginUser['getObjectPrivileges'](systemCode, dbTransaction),
1014
+ ).rejects.toThrow(Error);
1015
+ });
1016
+ });
1017
+
1018
+ describe('getUserPersonalPrivileges', () => {
1019
+ it('should return an array of privileges', async () => {
1020
+ // Arrange
1021
+ const sessionService = await SessionService.init();
1022
+ const loginUser = await LoginUser.init(sessionService);
1023
+ const systemCode = 'system1';
1024
+ const dbTransaction = null;
1025
+
1026
+ // Mock the findAll method of UserPrivilegeRepo
1027
+ const findAllMock = jest.spyOn(
1028
+ LoginUser['_UserPrivilegeRepo'],
1029
+ 'findAll',
1030
+ );
1031
+ findAllMock.mockResolvedValue([
1032
+ { Privilege: { PrivilegeCode: 'privilege1' } },
1033
+ { Privilege: { PrivilegeCode: 'privilege2' } },
1034
+ ] as any);
1035
+
1036
+ // Act
1037
+ const privileges = await loginUser['getUserPersonalPrivileges'](
1038
+ systemCode,
1039
+ dbTransaction,
1040
+ );
1041
+
1042
+ // Assert
1043
+ expect(privileges).toEqual(['privilege1', 'privilege2']);
1044
+ expect(findAllMock).toHaveBeenCalledTimes(1);
1045
+ expect(findAllMock).toHaveBeenCalledWith({
1046
+ where: {
1047
+ UserId: loginUser.UserId,
1048
+ Status: 'Active',
1049
+ },
1050
+ include: {
1051
+ model: SystemPrivilegeModel,
1052
+ where: {
1053
+ SystemCode: systemCode,
1054
+ Status: 'Active',
1055
+ },
1056
+ },
1057
+ transaction: dbTransaction,
1058
+ });
1059
+ });
1060
+
1061
+ it('should throw an error if an error occurs', async () => {
1062
+ // Arrange
1063
+ const sessionService = await SessionService.init();
1064
+ const loginUser = await LoginUser.init(sessionService);
1065
+ const systemCode = 'system1';
1066
+ const dbTransaction = null;
1067
+
1068
+ // Mock the findAll method of UserPrivilegeRepo to throw an error
1069
+ const findAllMock = jest.spyOn(
1070
+ LoginUser['_UserPrivilegeRepo'],
1071
+ 'findAll',
1072
+ );
1073
+ findAllMock.mockRejectedValue(new Error('Database error'));
1074
+
1075
+ // Act and Assert
1076
+ await expect(
1077
+ loginUser['getUserPersonalPrivileges'](systemCode, dbTransaction),
1078
+ ).rejects.toThrow(Error);
1079
+
1080
+ expect(findAllMock).toHaveBeenCalledTimes(1);
1081
+ expect(findAllMock).toHaveBeenCalledWith({
1082
+ where: {
1083
+ UserId: loginUser.UserId,
1084
+ Status: 'Active',
1085
+ },
1086
+ include: {
1087
+ model: SystemPrivilegeModel,
1088
+ where: {
1089
+ SystemCode: systemCode,
1090
+ Status: 'Active',
1091
+ },
1092
+ },
1093
+ transaction: dbTransaction,
1094
+ });
1095
+ });
1096
+ });
1097
+
1098
+ describe('getInheritedSystemAccess', () => {
1099
+ it('should return group system access with its parent group system access if applicable', async () => {
1100
+ // Mock the necessary dependencies
1101
+ const dbTransaction = null;
1102
+ const group = {
1103
+ GroupCode: 'group1',
1104
+ InheritParentSystemAccessYN: 'Y',
1105
+ ParentGroupCode: 'parentGroup',
1106
+ } as any;
1107
+ const parentGroup = {
1108
+ GroupCode: 'parentGroup',
1109
+ InheritParentSystemAccessYN: 'N',
1110
+ ParentGroupCode: null,
1111
+ } as any;
1112
+
1113
+ const systemAccess = [
1114
+ {
1115
+ SystemCode: 'system1',
1116
+ GroupCode: 'group1',
1117
+ System: { SystemCode: 'system1' },
1118
+ },
1119
+ {
1120
+ SystemCode: 'system2',
1121
+ GroupCode: 'group1',
1122
+ System: { SystemCode: 'system1' },
1123
+ },
1124
+ ] as any;
1125
+
1126
+ const parentSystemAccess = [
1127
+ {
1128
+ SystemCode: 'system3',
1129
+ GroupCode: 'parentGroup',
1130
+ System: { SystemCode: 'system3' },
1131
+ },
1132
+ ] as any;
1133
+
1134
+ // Mock the necessary repository methods
1135
+ const groupFindByPkMock = jest
1136
+ .spyOn(GroupRepository.prototype, 'findByPk')
1137
+ .mockResolvedValueOnce(parentGroup as any);
1138
+ const systemAccessFindAllMock = jest
1139
+ .spyOn(GroupSystemAccessRepository.prototype, 'findAll')
1140
+ .mockImplementation((options: any) => {
1141
+ if (options.where.GroupCode === group.GroupCode) {
1142
+ return Promise.resolve(systemAccess);
1143
+ } else if (options.where.GroupCode === parentGroup.GroupCode) {
1144
+ return Promise.resolve(parentSystemAccess);
1145
+ }
1146
+ });
1147
+
1148
+ // Call the method
1149
+ const result = await LoginUser['getInheritedSystemAccess'](
1150
+ dbTransaction,
1151
+ group,
1152
+ );
1153
+
1154
+ console.log(result);
1155
+ // Assert the result
1156
+ expect(result).toEqual([
1157
+ {
1158
+ SystemCode: 'system1',
1159
+ GroupCode: 'group1',
1160
+ System: { SystemCode: 'system1' },
1161
+ },
1162
+ {
1163
+ SystemCode: 'system2',
1164
+ GroupCode: 'group1',
1165
+ System: { SystemCode: 'system1' },
1166
+ },
1167
+ {
1168
+ SystemCode: 'system3',
1169
+ GroupCode: 'parentGroup',
1170
+ System: { SystemCode: 'system3' },
1171
+ },
1172
+ ]);
1173
+ expect(groupFindByPkMock).toHaveBeenCalledWith(
1174
+ group.ParentGroupCode,
1175
+ dbTransaction,
1176
+ );
1177
+ expect(systemAccessFindAllMock).toHaveBeenCalledTimes(2);
1178
+ });
1179
+ });
1180
+ });
1181
+
1182
+ // let sessionService: any;
1183
+ // let userId: number;
1184
+ // let dbTransaction: any;
1185
+
1186
+ // beforeEach(() => {
1187
+ // sessionService = {};
1188
+ // userId = 1;
1189
+ // dbTransaction = null;
1190
+ // });
1191
+
1192
+ // it('should initialize LoginUser with valid userId', async () => {
1193
+ // const user = {
1194
+ // UserId: 1,
1195
+ // FullName: 'John Doe',
1196
+ // Email: 'john.doe@example.com',
1197
+ // Password: 'password',
1198
+ // Status: 'active',
1199
+ // DefaultPasswordChangedYN: 'yes',
1200
+ // FirstLoginAt: new Date(),
1201
+ // LastLoginAt: new Date(),
1202
+ // MFAEnabled: 1,
1203
+ // MFAConfig: 'config',
1204
+ // RecoveryEmail: 'john.doe@example.com',
1205
+ // FailedLoginAttemptCount: 0,
1206
+ // LastFailedLoginAt: null,
1207
+ // LastPasswordChangedAt: new Date(),
1208
+ // NeedToChangePasswordYN: 'no',
1209
+ // CreatedById: 1,
1210
+ // CreatedAt: new Date(),
1211
+ // UpdatedById: 1,
1212
+ // UpdatedAt: new Date(),
1213
+ // Staff: {
1214
+ // FullName: 'John Doe',
1215
+ // IdNo: '1234567890',
1216
+ // Mobile: '1234567890',
1217
+ // },
1218
+ // };
1219
+
1220
+ // const findOneMock = jest
1221
+ // .spyOn(UserRepository.prototype, 'findOne')
1222
+ // .mockResolvedValueOnce(user as any);
1223
+
1224
+ // const result = await LoginUser.init(
1225
+ // sessionService,
1226
+ // userId,
1227
+ // dbTransaction,
1228
+ // );
1229
+
1230
+ // expect(findOneMock).toHaveBeenCalledTimes(1);
1231
+ // expect(findOneMock).toHaveBeenCalledWith({
1232
+ // where: {
1233
+ // UserId: userId,
1234
+ // },
1235
+ // include: [
1236
+ // {
1237
+ // model: expect.anything(),
1238
+ // },
1239
+ // ],
1240
+ // });
1241
+ // expect(result).toBeInstanceOf(LoginUser);
1242
+ // expect(result.UserId).toBe(user.UserId);
1243
+ // expect(result.FullName).toBe(user.FullName);
1244
+ // expect(result.Email).toBe(user.Email);
1245
+ // expect(result.Password).toBe(user.Password);
1246
+ // expect(result.Status).toBe(user.Status);
1247
+ // expect(result.DefaultPasswordChangedYN).toBe(
1248
+ // user.DefaultPasswordChangedYN,
1249
+ // );
1250
+ // expect(result.FirstLoginAt).toBe(user.FirstLoginAt);
1251
+ // expect(result.LastLoginAt).toBe(user.LastLoginAt);
1252
+ // expect(result.MFAEnabled).toBe(user.MFAEnabled);
1253
+ // expect(result.MFAConfig).toBe(user.MFAConfig);
1254
+ // expect(result.RecoveryEmail).toBe(user.RecoveryEmail);
1255
+ // expect(result.FailedLoginAttemptCount).toBe(user.FailedLoginAttemptCount);
1256
+ // expect(result.LastFailedLoginAt).toBe(user.LastFailedLoginAt);
1257
+ // expect(result.LastPasswordChangedAt).toBe(user.LastPasswordChangedAt);
1258
+ // expect(result.NeedToChangePasswordYN).toBe(user.NeedToChangePasswordYN);
1259
+ // expect(result.CreatedById).toBe(user.CreatedById);
1260
+ // expect(result.CreatedAt).toBe(user.CreatedAt);
1261
+ // expect(result.UpdatedById).toBe(user.UpdatedById);
1262
+ // expect(result.UpdatedAt).toBe(user.UpdatedAt);
1263
+ // });
1264
+
1265
+ // it('should throw an error when user is not found', async () => {
1266
+ // const findOneMock = jest
1267
+ // .spyOn(UserRepository.prototype, 'findOne')
1268
+ // .mockResolvedValueOnce(null);
1269
+
1270
+ // await expect(
1271
+ // LoginUser.init(sessionService, userId, dbTransaction),
1272
+ // ).rejects.toThrow(Error);
1273
+
1274
+ // expect(findOneMock).toHaveBeenCalledTimes(1);
1275
+ // expect(findOneMock).toHaveBeenCalledWith({
1276
+ // where: {
1277
+ // UserId: userId,
1278
+ // },
1279
+ // include: [
1280
+ // {
1281
+ // model: expect.anything(),
1282
+ // },
1283
+ // ],
1284
+ // });
1285
+ // });
1286
+ // });
1287
+
1288
+ // // describe('checkSession', () => {
1289
+ // // it('should throw an error if session expired', async () => {
1290
+ // // // Arrange
1291
+ // // const systemCode = 'EZC';
1292
+ // // const sessionId = 'ckymxuh8t000137t011w89zgk';
1293
+ // // const userId = '755';
1294
+ // // const sessionService = await SessionService.init();
1295
+ // // const loginUser = await LoginUser.init(sessionService);
1296
+
1297
+ // // // Act
1298
+ // // const checkSessionPromise = loginUser.checkSession(
1299
+ // // systemCode,
1300
+ // // sessionId,
1301
+ // // userId,
1302
+ // // );
1303
+
1304
+ // // // Assert
1305
+ // // await expect(checkSessionPromise).rejects.toThrow('Session expired.');
1306
+ // // });
1307
+
1308
+ // // it('should refresh the session duration if session is valid', async () => {
1309
+ // // // Arrange
1310
+ // // const systemCode = 'EZC';
1311
+ // // const sessionId = 'ckymxuh8t000137t011w89zgk';
1312
+ // // const userId = '755';
1313
+ // // const sessionService = await SessionService.init();
1314
+ // // const loginUser = await LoginUser.init(sessionService);
1315
+
1316
+ // // // Mock the _SessionService.retrieveUserSession method
1317
+ // // loginUser['_SessionService'].retrieveUserSession = jest
1318
+ // // .fn()
1319
+ // // .mockResolvedValue({
1320
+ // // systemLogins: [
1321
+ // // {
1322
+ // // code: systemCode,
1323
+ // // sessionId: sessionId,
1324
+ // // privileges: [],
1325
+ // // },
1326
+ // // ],
1327
+ // // });
1328
+
1329
+ // // // Mock the _SessionService.refreshDuration method
1330
+ // // loginUser['_SessionService'].refreshDuration = jest.fn();
1331
+
1332
+ // // // Act
1333
+ // // const systemLogin = await loginUser.checkSession(
1334
+ // // systemCode,
1335
+ // // sessionId,
1336
+ // // userId,
1337
+ // // );
1338
+
1339
+ // // // Assert
1340
+ // // expect(
1341
+ // // loginUser['_SessionService'].retrieveUserSession,
1342
+ // // ).toHaveBeenCalledWith(userId);
1343
+ // // expect(loginUser['_SessionService'].refreshDuration).toHaveBeenCalledWith(
1344
+ // // userId,
1345
+ // // );
1346
+ // // expect(systemLogin).toEqual({
1347
+ // // code: systemCode,
1348
+ // // sessionId: sessionId,
1349
+ // // privileges: [],
1350
+ // // });
1351
+ // // });
1352
+ // // });
1353
+
1354
+ // describe('shouldReleaseLock', () => {
1355
+ // const minuteToAutoRelease = 5;
1356
+ // const autoReleaseYN = 'Y';
1357
+
1358
+ // beforeEach(() => {
1359
+ // jest
1360
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1361
+ // .mockImplementation((componentName: string, configKey: string) => {
1362
+ // if (configKey === 'minuteToAutoRelease') {
1363
+ // return minuteToAutoRelease as any;
1364
+ // }
1365
+ // if (configKey === 'autoReleaseYN') {
1366
+ // return autoReleaseYN as any;
1367
+ // }
1368
+ // });
1369
+ // });
1370
+
1371
+ // it('should return true if autoReleaseYN is "Y" and time difference is greater than minuteToAutoRelease', async () => {
1372
+ // // Arrange
1373
+ // const lastFailedLoginAt = new Date();
1374
+ // lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 10); // Set last failed login time to 10 minutes ago
1375
+ // // Act
1376
+ // const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
1377
+
1378
+ // // Assert
1379
+ // expect(result).toBe(true);
1380
+ // });
1381
+
1382
+ // it('should return false if autoReleaseYN is "Y" and time difference is less than or equal to minuteToAutoRelease', async () => {
1383
+ // // Arrange
1384
+ // const lastFailedLoginAt = new Date();
1385
+ // lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 3); // Set last failed login time to 3 minutes ago
1386
+
1387
+ // // Act
1388
+ // const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
1389
+
1390
+ // // Assert
1391
+ // expect(result).toBe(false);
1392
+ // });
1393
+
1394
+ // it('should return false if autoReleaseYN is "N"', async () => {
1395
+ // // Arrange
1396
+ // const lastFailedLoginAt = new Date();
1397
+
1398
+ // // Act
1399
+ // const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
1400
+
1401
+ // // Assert
1402
+ // expect(result).toBe(false);
1403
+ // });
1404
+ // });
1405
+
1406
+ // describe('releaseLock', () => {
1407
+ // it('should release the lock for a user', async () => {
1408
+ // // Mock the necessary dependencies and setup the test data
1409
+ // const UserId = 1;
1410
+ // const dbTransaction = null;
1411
+
1412
+ // const updateMock = jest
1413
+ // .spyOn(LoginUser['_Repository'], 'update')
1414
+ // .mockImplementationOnce(() => Promise.resolve({}) as any);
1415
+
1416
+ // // Call the method under test
1417
+ // LoginUser['releaseLock'](UserId, dbTransaction);
1418
+
1419
+ // // Verify the expected behavior
1420
+ // expect(updateMock).toHaveBeenCalledTimes(1);
1421
+ // expect(updateMock).toHaveBeenCalledWith(
1422
+ // {
1423
+ // FailedLoginAttemptCount: 0,
1424
+ // Status: 'Active',
1425
+ // },
1426
+ // {
1427
+ // where: {
1428
+ // UserId,
1429
+ // },
1430
+ // transaction: dbTransaction,
1431
+ // },
1432
+ // );
1433
+ // });
1434
+ // });
1435
+
1436
+ // describe('checkUserInfoDuplicated', () => {
1437
+ // it('should throw an error if duplicate user info is found', async () => {
1438
+ // // Mock the dependencies and setup the test data
1439
+ // const dbTransaction = null;
1440
+ // const query = {
1441
+ // Email: 'test@example.com',
1442
+ // IdType: 'passport',
1443
+ // IdNo: '123456789',
1444
+ // ContactNo: '1234567890',
1445
+ // };
1446
+
1447
+ // // Mock the LoginUser['_Repository'].findAll method to return a user
1448
+ // jest
1449
+ // .spyOn(LoginUser['_Repository'], 'findAll')
1450
+ // .mockResolvedValueOnce([{ id: 1 }] as any);
1451
+
1452
+ // // Assert that the method throws an error
1453
+ // await expect(
1454
+ // LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
1455
+ // ).rejects.toThrowError();
1456
+ // });
1457
+
1458
+ // it('should not throw an error if duplicate user info is not found', async () => {
1459
+ // // Mock the dependencies and setup the test data
1460
+ // const dbTransaction = null;
1461
+ // const query = {
1462
+ // Email: 'test@example.com',
1463
+ // IdType: 'passport',
1464
+ // IdNo: '123456789',
1465
+ // ContactNo: '1234567890',
1466
+ // };
1467
+
1468
+ // // Mock the LoginUser['_Repository'].findAll method to return an empty array
1469
+ // jest.spyOn(LoginUser['_Repository'], 'findAll').mockResolvedValueOnce([]);
1470
+
1471
+ // // Assert that the method does not throw an error
1472
+ // await expect(
1473
+ // LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
1474
+ // ).resolves.not.toThrowError();
1475
+ // });
1476
+ // });
1477
+
1478
+ // describe('generateDefaultPassword', () => {
1479
+ // const passwordPolicy = {
1480
+ // minLen: 6,
1481
+ // maxLen: 10,
1482
+ // nonAcceptableChar: 'i,l,o',
1483
+ // numOfCapitalLetters: 1,
1484
+ // numOfNumbers: 1,
1485
+ // numOfSpecialChars: 1,
1486
+ // };
1487
+ // beforeEach(() => {
1488
+ // jest
1489
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1490
+ // .mockImplementation((componentName: string, configKey: string) => {
1491
+ // if (configKey === 'passwordPolicy') {
1492
+ // return passwordPolicy as any;
1493
+ // }
1494
+ // });
1495
+ // });
1496
+
1497
+ // it('should generate a default password with the specified length', () => {
1498
+ // const password = LoginUser['generateDefaultPassword']();
1499
+ // expect(password.length).toBeGreaterThanOrEqual(6);
1500
+ // expect(password.length).toBeLessThanOrEqual(10);
1501
+ // });
1502
+
1503
+ // it('should generate a default password with at least one capital letter', () => {
1504
+ // const password = LoginUser['generateDefaultPassword']();
1505
+ // expect(/[A-Z]/.test(password)).toBe(true);
1506
+ // });
1507
+
1508
+ // it('should generate a default password with at least one number', () => {
1509
+ // const password = LoginUser['generateDefaultPassword']();
1510
+ // expect(/[0-9]/.test(password)).toBe(true);
1511
+ // });
1512
+
1513
+ // it('should generate a default password with at least one special character', () => {
1514
+ // const password = LoginUser['generateDefaultPassword']();
1515
+ // expect(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~`]/.test(password)).toBe(true);
1516
+ // });
1517
+
1518
+ // it('should generate a default password without any non-acceptable characters', () => {
1519
+ // const password = LoginUser['generateDefaultPassword']();
1520
+ // const nonAcceptableChars = ['i', 'l', 'o'];
1521
+ // expect(nonAcceptableChars.some((char) => password.includes(char))).toBe(
1522
+ // false,
1523
+ // );
1524
+ // });
1525
+ // });
1526
+
1527
+ // describe('setPassword', () => {
1528
+ // const passwordPolicy = {
1529
+ // minLen: 6,
1530
+ // maxLen: 10,
1531
+ // nonAcceptableChar: 'i,l,o',
1532
+ // numOfCapitalLetters: 1,
1533
+ // numOfNumbers: 1,
1534
+ // numOfSpecialChars: 1,
1535
+ // };
1536
+ // beforeEach(() => {
1537
+ // jest
1538
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1539
+ // .mockImplementation((componentName: string, configKey: string) => {
1540
+ // if (configKey === 'passwordPolicy') {
1541
+ // return passwordPolicy as any;
1542
+ // }
1543
+ // });
1544
+ // });
1545
+
1546
+ // it('should set the password for the user', async () => {
1547
+ // // Arrange
1548
+ // const dbTransaction = null;
1549
+ // const sessionService = await SessionService.init();
1550
+ // const user = await LoginUser.init(sessionService);
1551
+ // const password = 'N3wP@ssw0';
1552
+
1553
+ // // Act
1554
+ // const result = await LoginUser['setPassword'](
1555
+ // dbTransaction,
1556
+ // user,
1557
+ // password,
1558
+ // );
1559
+
1560
+ // // Assert
1561
+ // expect(result).toBeInstanceOf(LoginUser);
1562
+ // await expect(
1563
+ // LoginUser['setPassword'](dbTransaction, user, password),
1564
+ // ).resolves.not.toThrowError();
1565
+ // expect(result.Password).toBeDefined();
1566
+ // });
1567
+
1568
+ // it('should throw an error if the password does not meet the security requirements', async () => {
1569
+ // // Arrange
1570
+ // const dbTransaction = null;
1571
+ // const sessionService = await SessionService.init();
1572
+ // const user = await LoginUser.init(sessionService);
1573
+ // const password = 'weakpassword';
1574
+
1575
+ // // Act & Assert
1576
+ // await expect(
1577
+ // LoginUser['setPassword'](dbTransaction, user, password),
1578
+ // ).rejects.toThrow();
1579
+ // });
1580
+ // });
1581
+
1582
+ // // describe('create', () => {
1583
+ // // let loginUser: LoginUser;
1584
+ // // let dbTransaction: any;
1585
+ // // let user: LoginUser;
1586
+ // // let newUser: any;
1587
+
1588
+ // // beforeEach(async () => {
1589
+ // // const sessionService = await SessionService.init();
1590
+ // // loginUser = await LoginUser.init(sessionService);
1591
+ // // dbTransaction = null;
1592
+ // // newUser = {
1593
+ // // UserId: 1,
1594
+ // // FullName: 'John Doe',
1595
+ // // Email: 'john.doe@example.com',
1596
+ // // Password: 'password',
1597
+ // // Status: 'Active',
1598
+ // // DefaultPasswordChangedYN: 'N',
1599
+ // // FirstLoginAt: null,
1600
+ // // LastLoginAt: null,
1601
+ // // MFAEnabled: null,
1602
+ // // MFAConfig: null,
1603
+ // // RecoveryEmail: null,
1604
+ // // FailedLoginAttemptCount: 0,
1605
+ // // LastFailedLoginAt: null,
1606
+ // // LastPasswordChangedAt: new Date(),
1607
+ // // NeedToChangePasswordYN: 'N',
1608
+ // // CreatedById: 1,
1609
+ // // CreatedAt: new Date(),
1610
+ // // UpdatedById: 1,
1611
+ // // UpdatedAt: new Date(),
1612
+ // // Staff: {
1613
+ // // FullName: 'John Doe',
1614
+ // // IdNo: '1234567890',
1615
+ // // Mobile: '1234567890',
1616
+ // // },
1617
+ // // };
1618
+ // // user = new (LoginUser as any)(sessionService, null, newUser);
1619
+ // // });
1620
+
1621
+ // // afterEach(() => {
1622
+ // // jest.clearAllMocks();
1623
+ // // });
1624
+
1625
+ // // it('should create a new user record', async () => {
1626
+ // // const checkPrivilegesMock = jest
1627
+ // // .spyOn(loginUser, 'checkPrivileges')
1628
+ // // .mockResolvedValueOnce(true);
1629
+
1630
+ // // const checkUserInfoDuplicatedMock = jest
1631
+ // // .spyOn(LoginUser as any, 'checkUserInfoDuplicated')
1632
+ // // .mockResolvedValueOnce(undefined);
1633
+
1634
+ // // const generateDefaultPasswordMock = jest
1635
+ // // .spyOn(LoginUser as any, 'generateDefaultPassword')
1636
+ // // .mockReturnValueOnce('defaultPassword');
1637
+
1638
+ // // const setPasswordMock = jest
1639
+ // // .spyOn(LoginUser as any, 'setPassword')
1640
+ // // .mockResolvedValueOnce(user);
1641
+
1642
+ // // const createMock = jest
1643
+ // // .spyOn((LoginUser as any)['_Repository'], 'create')
1644
+ // // .mockResolvedValueOnce({
1645
+ // // ...newUser,
1646
+ // // get: () => newUser,
1647
+ // // });
1648
+
1649
+ // // const activityCreateMock = jest
1650
+ // // .spyOn((Activity as any).prototype, 'create')
1651
+ // // .mockResolvedValueOnce(undefined);
1652
+
1653
+ // // jest
1654
+ // // .spyOn(ApplicationConfig, 'getComponentConfigValue')
1655
+ // // .mockImplementation((configKey: string) => {
1656
+ // // if (configKey === 'system-code') {
1657
+ // // return 'SC';
1658
+ // // }
1659
+ // // });
1660
+
1661
+ // // const result = await LoginUser.create(loginUser, dbTransaction, user);
1662
+
1663
+ // // expect(checkPrivilegesMock).toHaveBeenCalledTimes(1);
1664
+ // // expect(checkPrivilegesMock).toHaveBeenCalledWith(
1665
+ // // ApplicationConfig.getComponentConfigValue('system-code'),
1666
+ // // 'User - Create',
1667
+ // // );
1668
+
1669
+ // // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledTimes(1);
1670
+ // // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledWith(dbTransaction, {
1671
+ // // Email: user.Email,
1672
+ // // IdType: user.IDType,
1673
+ // // IdNo: user.IDNo,
1674
+ // // ContactNo: user.ContactNo,
1675
+ // // });
1676
+
1677
+ // // expect(generateDefaultPasswordMock).toHaveBeenCalledTimes(1);
1678
+
1679
+ // // expect(setPasswordMock).toHaveBeenCalledTimes(1);
1680
+ // // expect(setPasswordMock).toHaveBeenCalledWith(
1681
+ // // dbTransaction,
1682
+ // // user,
1683
+ // // 'defaultPassword',
1684
+ // // );
1685
+
1686
+ // // expect(createMock).toHaveBeenCalledTimes(1);
1687
+
1688
+ // // const userInfo = {
1689
+ // // FullName: user.FullName,
1690
+ // // IDNo: user.IDNo,
1691
+ // // Email: user.Email,
1692
+ // // ContactNo: user.ContactNo,
1693
+ // // Password: user.Password,
1694
+ // // Status: UserStatus.ACTIVE,
1695
+ // // FirstLoginAt: null,
1696
+ // // LastLoginAt: null,
1697
+ // // MFAEnabled: null,
1698
+ // // MFAConfig: null,
1699
+ // // RecoveryEmail: null,
1700
+ // // FailedLoginAttemptCount: 0,
1701
+ // // LastFailedLoginAt: null,
1702
+ // // LastPasswordChangedAt: null,
1703
+ // // DefaultPasswordChangedYN: YN.No,
1704
+ // // NeedToChangePasswordYN: YN.Yes,
1705
+ // // CreatedById: loginUser.UserId,
1706
+ // // CreatedAt: new Date(),
1707
+ // // UpdatedById: loginUser.UserId,
1708
+ // // UpdatedAt: new Date(),
1709
+ // // UserId: null,
1710
+ // // };
1711
+
1712
+ // // expect(createMock).toHaveBeenCalledWith(
1713
+ // // {
1714
+ // // Email: userInfo.Email,
1715
+ // // Password: userInfo.Password,
1716
+ // // Status: userInfo.Status,
1717
+ // // DefaultPasswordChangedYN: userInfo.DefaultPasswordChangedYN,
1718
+ // // FirstLoginAt: userInfo.FirstLoginAt,
1719
+ // // LastLoginAt: userInfo.LastLoginAt,
1720
+ // // MFAEnabled: userInfo.MFAEnabled,
1721
+ // // MFAConfig: userInfo.MFAConfig,
1722
+ // // RecoveryEmail: userInfo.RecoveryEmail,
1723
+ // // FailedLoginAttemptCount: userInfo.FailedLoginAttemptCount,
1724
+ // // LastFailedLoginAt: userInfo.LastFailedLoginAt,
1725
+ // // LastPasswordChangedAt: userInfo.LastPasswordChangedAt,
1726
+ // // NeedToChangePasswordYN: userInfo.NeedToChangePasswordYN,
1727
+ // // CreatedById: userInfo.CreatedById,
1728
+ // // CreatedAt: expect.any(Date),
1729
+ // // UpdatedById: userInfo.UpdatedById,
1730
+ // // UpdatedAt: expect.any(Date),
1731
+ // // },
1732
+ // // {
1733
+ // // transaction: dbTransaction,
1734
+ // // },
1735
+ // // );
1736
+
1737
+ // // expect(activityCreateMock).toHaveBeenCalledTimes(1);
1738
+
1739
+ // // expect(result).toBeInstanceOf(LoginUser);
1740
+ // // expect(result.Email).toBe(userInfo.Email);
1741
+ // // expect(result.Password).toBe(userInfo.Password);
1742
+ // // expect(result.Status).toBe(userInfo.Status);
1743
+ // // expect(result.DefaultPasswordChangedYN).toBe(
1744
+ // // userInfo.DefaultPasswordChangedYN,
1745
+ // // );
1746
+ // // expect(result.FirstLoginAt).toBe(null);
1747
+ // // expect(result.LastLoginAt).toBe(null);
1748
+ // // expect(result.MFAEnabled).toBe(userInfo.MFAEnabled);
1749
+ // // expect(result.MFAConfig).toBe(userInfo.MFAConfig);
1750
+ // // expect(result.RecoveryEmail).toBe(userInfo.RecoveryEmail);
1751
+ // // expect(result.FailedLoginAttemptCount).toBe(
1752
+ // // userInfo.FailedLoginAttemptCount,
1753
+ // // );
1754
+ // // expect(result.LastFailedLoginAt).toBe(userInfo.LastFailedLoginAt);
1755
+ // // expect(result.LastPasswordChangedAt).toBe(userInfo.LastPasswordChangedAt);
1756
+ // // expect(result.NeedToChangePasswordYN).toBe(
1757
+ // // userInfo.NeedToChangePasswordYN,
1758
+ // // );
1759
+ // // expect(result.CreatedById).toBe(userInfo.CreatedById);
1760
+ // // expect(result.UpdatedById).toBe(userInfo.UpdatedById);
1761
+ // // });
1762
+
1763
+ // // it('should throw an error if user dont have the privilege to create new user', async () => {
1764
+ // // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(false);
1765
+
1766
+ // // await expect(
1767
+ // // LoginUser.create(loginUser, dbTransaction, user),
1768
+ // // ).rejects.toThrow(ClassError);
1769
+ // // });
1770
+
1771
+ // // it('should throw an error if user email is missing', async () => {
1772
+ // // user.Email = undefined;
1773
+
1774
+ // // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(true);
1775
+
1776
+ // // await expect(
1777
+ // // LoginUser.create(loginUser, dbTransaction, user),
1778
+ // // ).rejects.toThrow(ClassError);
1779
+ // // });
1780
+ // // });
1781
+
1782
+ // describe('incrementFailedLoginAttemptCount', () => {
1783
+ // afterAll(() => {
1784
+ // jest.restoreAllMocks();
1785
+ // });
1786
+
1787
+ // it('should increment FailedLoginAttemptCount and update user status', async () => {
1788
+ // // Arrange
1789
+ // const sessionService = await SessionService.init();
1790
+ // const loginUser = await LoginUser.init(sessionService);
1791
+ // loginUser['FailedLoginAttemptCount'] = 2;
1792
+ // loginUser['LastFailedLoginAt'] = new Date();
1793
+ // loginUser['Status'] = UserStatus.ACTIVE;
1794
+
1795
+ // const dbTransaction = null;
1796
+
1797
+ // // Mock the static methods and properties
1798
+ // jest
1799
+ // .spyOn((LoginUser as any)['_Repository'], 'update')
1800
+ // .mockReturnValueOnce(null);
1801
+
1802
+ // jest
1803
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1804
+ // .mockImplementation((componentName: string, configKey: string) => {
1805
+ // if (configKey === 'maxFailedLoginAttempts') {
1806
+ // return 3;
1807
+ // }
1808
+ // if (configKey === 'autoReleaseYN') {
1809
+ // return 'Y';
1810
+ // }
1811
+ // });
1812
+
1813
+ // // Act
1814
+ // await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
1815
+
1816
+ // // Assert
1817
+ // expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
1818
+ // {
1819
+ // FailedLoginAttemptCount: 3,
1820
+ // LastFailedLoginAt: expect.any(Date),
1821
+ // Status: UserStatus.ACTIVE,
1822
+ // },
1823
+ // {
1824
+ // where: {
1825
+ // UserId: loginUser.UserId,
1826
+ // },
1827
+ // transaction: dbTransaction,
1828
+ // },
1829
+ // );
1830
+ // });
1831
+
1832
+ // it('should throw an error if maxFailedLoginAttempts or autoReleaseYN is missing', async () => {
1833
+ // // Arrange
1834
+ // const sessionService = await SessionService.init();
1835
+ // const loginUser = await LoginUser.init(sessionService);
1836
+ // loginUser['FailedLoginAttemptCount'] = 2;
1837
+ // loginUser['LastFailedLoginAt'] = new Date();
1838
+ // loginUser['Status'] = UserStatus.ACTIVE;
1839
+
1840
+ // const dbTransaction = null;
1841
+
1842
+ // // Mock the static methods and properties
1843
+ // jest
1844
+ // .spyOn((LoginUser as any)['_Repository'], 'update')
1845
+ // .mockReturnValueOnce(null);
1846
+
1847
+ // jest
1848
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1849
+ // .mockImplementationOnce((componentName: string, configKey: string) => {
1850
+ // if (configKey === 'maxFailedLoginAttempts') {
1851
+ // return undefined;
1852
+ // }
1853
+ // if (configKey === 'autoReleaseYN') {
1854
+ // return undefined;
1855
+ // }
1856
+ // });
1857
+
1858
+ // // Act and Assert
1859
+ // await expect(
1860
+ // loginUser['incrementFailedLoginAttemptCount'](dbTransaction),
1861
+ // ).rejects.toThrow(
1862
+ // new ClassError(
1863
+ // 'LoginUser',
1864
+ // 'LoginUserErrMsg0X',
1865
+ // 'Missing maxFailedLoginAttempts and or autoReleaseYN. Please set in config file.',
1866
+ // ),
1867
+ // );
1868
+ // });
1869
+
1870
+ // it('should lock the user account if the failed login attempts exceed the maximum allowed', async () => {
1871
+ // // Arrange
1872
+ // const sessionService = await SessionService.init();
1873
+ // const loginUser = await LoginUser.init(sessionService);
1874
+ // loginUser['FailedLoginAttemptCount'] = 3;
1875
+ // loginUser['LastFailedLoginAt'] = new Date();
1876
+ // loginUser['Status'] = UserStatus.ACTIVE;
1877
+
1878
+ // const dbTransaction = null;
1879
+
1880
+ // // Mock the static methods and properties
1881
+ // jest
1882
+ // .spyOn((LoginUser as any)['_Repository'], 'update')
1883
+ // .mockReturnValueOnce(null);
1884
+
1885
+ // jest
1886
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1887
+ // .mockImplementation((componentName: string, configKey: string) => {
1888
+ // if (configKey === 'maxFailedLoginAttempts') {
1889
+ // return 3;
1890
+ // }
1891
+ // if (configKey === 'autoReleaseYN') {
1892
+ // return 'Y';
1893
+ // }
1894
+ // });
1895
+
1896
+ // // Act
1897
+ // try {
1898
+ // await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
1899
+ // expect(false).toBe(true);
1900
+ // } catch (error) {
1901
+ // // Assert
1902
+ // expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
1903
+ // {
1904
+ // FailedLoginAttemptCount: 4,
1905
+ // LastFailedLoginAt: expect.any(Date),
1906
+ // Status: UserStatus.LOCKED,
1907
+ // },
1908
+ // {
1909
+ // where: {
1910
+ // UserId: loginUser.UserId,
1911
+ // },
1912
+ // transaction: dbTransaction,
1913
+ // },
1914
+ // );
1915
+ // expect(error).toBeInstanceOf(ClassError);
1916
+ // expect(error.message).toBe(
1917
+ // 'Your account has been temporarily locked due to too many failed login attempts, please try again later.',
1918
+ // );
1919
+ // }
1920
+ // });
1921
+
1922
+ // it('should permanently lock the user account if the failed login attempts exceed the maximum allowed and autoReleaseYN is N', async () => {
1923
+ // // Arrange
1924
+ // const sessionService = await SessionService.init();
1925
+ // const loginUser = await LoginUser.init(sessionService);
1926
+ // loginUser['FailedLoginAttemptCount'] = 3;
1927
+ // loginUser['LastFailedLoginAt'] = new Date();
1928
+ // loginUser['Status'] = UserStatus.ACTIVE;
1929
+
1930
+ // const dbTransaction = null;
1931
+
1932
+ // // Mock the static methods and properties
1933
+ // jest
1934
+ // .spyOn((LoginUser as any)['_Repository'], 'update')
1935
+ // .mockReturnValueOnce(null);
1936
+
1937
+ // jest
1938
+ // .spyOn(ComponentConfig, 'getComponentConfigValue')
1939
+ // .mockImplementation((componentName: string, configKey: string) => {
1940
+ // if (configKey === 'maxFailedLoginAttempts') {
1941
+ // return 3;
1942
+ // }
1943
+ // if (configKey === 'autoReleaseYN') {
1944
+ // return 'N';
1945
+ // }
1946
+ // });
1947
+
1948
+ // // Act
1949
+ // try {
1950
+ // await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
1951
+ // expect(false).toBe(true);
1952
+ // } catch (error) {
1953
+ // // Assert
1954
+ // expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
1955
+ // {
1956
+ // FailedLoginAttemptCount: 4,
1957
+ // LastFailedLoginAt: expect.any(Date),
1958
+ // Status: UserStatus.LOCKED,
1959
+ // },
1960
+ // {
1961
+ // where: {
1962
+ // UserId: loginUser.UserId,
1963
+ // },
1964
+ // transaction: dbTransaction,
1965
+ // },
1966
+ // );
1967
+ // expect(error).toBeInstanceOf(ClassError);
1968
+ // expect(error.message).toBe(
1969
+ // 'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account',
1970
+ // );
1971
+ // }
1972
+ // });
1973
+ // });
1974
+
1975
+ // describe('combineSystemAccess', () => {
1976
+ // it('should combine user and group system access and remove duplicates', async () => {
1977
+ // // Mock the necessary dependencies
1978
+ // const sessionService = await SessionService.init();
1979
+ // const loginUser = await LoginUser.init(sessionService);
1980
+ // const dbTransaction = null;
1981
+ // const groups = [
1982
+ // { InheritParentSystemAccessYN: true },
1983
+ // { InheritParentSystemAccessYN: false },
1984
+ // ];
1985
+
1986
+ // // Mock the necessary repository methods
1987
+ // jest
1988
+ // .spyOn(LoginUser as any, 'getInheritedSystemAccess')
1989
+ // .mockResolvedValueOnce([
1990
+ // { SystemCode: 'system1' },
1991
+ // { SystemCode: 'system2' },
1992
+ // ]);
1993
+ // jest
1994
+ // .spyOn((LoginUser as any)['_UserSystemAccessRepo'], 'findAll')
1995
+ // .mockResolvedValueOnce([{ SystemCode: 'system3' }]);
1996
+
1997
+ // // Call the method
1998
+ // const result = await LoginUser['combineSystemAccess'](
1999
+ // loginUser,
2000
+ // dbTransaction,
2001
+ // groups,
2002
+ // );
2003
+
2004
+ // // Assert the result
2005
+ // expect(result).toEqual([
2006
+ // { SystemCode: 'system3' },
2007
+ // { SystemCode: 'system1' },
2008
+ // { SystemCode: 'system2' },
2009
+ // ]);
2010
+ // });
2011
+ // });
2012
+
2013
+ // describe('checkPrivileges', () => {
2014
+ // it('should return true if user has the specified privilege', async () => {
2015
+ // // Arrange
2016
+ // const systemCode = 'SS';
2017
+ // const privilegeName = 'Privilege 1';
2018
+ // const sessionService = await SessionService.init();
2019
+ // const loginUser = await LoginUser.init(sessionService);
2020
+ // loginUser.ObjectId = '1';
2021
+
2022
+ // // Mock the necessary methods
2023
+ // const rus = jest
2024
+ // .spyOn(SessionService.prototype, 'retrieveUserSession')
2025
+ // .mockResolvedValueOnce({
2026
+ // systemLogins: [
2027
+ // {
2028
+ // id: '1',
2029
+ // sessionId: 'sessionId',
2030
+ // code: systemCode,
2031
+ // privileges: [privilegeName],
2032
+ // },
2033
+ // ],
2034
+ // });
2035
+ // // Act
2036
+ // const hasPrivilege = await loginUser.checkPrivileges(
2037
+ // systemCode,
2038
+ // privilegeName,
2039
+ // );
2040
+
2041
+ // // Assert
2042
+ // expect(hasPrivilege).toBe(true);
2043
+ // expect(rus).toHaveBeenCalledWith(loginUser.ObjectId);
2044
+ // });
2045
+
2046
+ // it('should return false if user does not have the specified privilege', async () => {
2047
+ // // Arrange
2048
+ // const systemCode = 'SS';
2049
+ // const privilegeName = 'Privilege 1';
2050
+ // const sessionService = await SessionService.init();
2051
+ // const loginUser = await LoginUser.init(sessionService);
2052
+ // loginUser.ObjectId = '1';
2053
+
2054
+ // // Mock the necessary methods
2055
+ // const rus = jest
2056
+ // .spyOn(SessionService.prototype, 'retrieveUserSession')
2057
+ // .mockResolvedValueOnce({
2058
+ // systemLogins: [
2059
+ // {
2060
+ // id: '1',
2061
+ // sessionId: 'sessionId',
2062
+ // code: systemCode,
2063
+ // privileges: [],
2064
+ // },
2065
+ // ],
2066
+ // });
2067
+ // // Act
2068
+ // const hasPrivilege = await loginUser.checkPrivileges(
2069
+ // systemCode,
2070
+ // privilegeName,
2071
+ // );
2072
+
2073
+ // // Assert
2074
+ // expect(hasPrivilege).toBe(false);
2075
+ // expect(rus).toHaveBeenCalledWith(loginUser.ObjectId);
2076
+ // });
2077
+
2078
+ // it('should throw an error if ObjectId is not set', async () => {
2079
+ // // Arrange
2080
+ // const systemCode = 'SS';
2081
+ // const privilegeName = 'Privilege 1';
2082
+ // const sessionService = await SessionService.init();
2083
+ // const loginUser = await LoginUser.init(sessionService);
2084
+ // loginUser.ObjectId = null;
2085
+
2086
+ // // Act & Assert
2087
+ // await expect(
2088
+ // loginUser.checkPrivileges(systemCode, privilegeName),
2089
+ // ).rejects.toThrowError();
2090
+ // });
2091
+ // });
2092
+
2093
+ // describe('getObjectPrivileges', () => {
2094
+ // it('should return an array of privileges', async () => {
2095
+ // // Mock the dependencies and setup the test data
2096
+ // const systemCode = 'system1';
2097
+ // const dbTransaction = null;
2098
+ // const sessionService = await SessionService.init();
2099
+ // const loginUser = await LoginUser.init(sessionService);
2100
+
2101
+ // // Mock the UserObjectPrivilegeRepo findAll method
2102
+ // const findAllMock = jest
2103
+ // .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
2104
+ // .mockResolvedValue([
2105
+ // {
2106
+ // PrivilegeCode: 'privilege1',
2107
+ // Privilege: {
2108
+ // PrivilegeCode: 'privilege1',
2109
+ // SystemCode: systemCode,
2110
+ // Name: 'privilege1',
2111
+ // },
2112
+ // },
2113
+ // {
2114
+ // PrivilegeCode: 'privilege2',
2115
+ // Privilege: {
2116
+ // PrivilegeCode: 'privilege2',
2117
+ // Name: 'privilege2',
2118
+ // },
2119
+ // },
2120
+ // ] as any);
2121
+
2122
+ // // Call the getObjectPrivileges method
2123
+ // const result = await loginUser['getObjectPrivileges'](
2124
+ // systemCode,
2125
+ // dbTransaction,
2126
+ // );
2127
+
2128
+ // // Assertions
2129
+ // expect(findAllMock).toHaveBeenCalledTimes(1);
2130
+ // expect(findAllMock).toHaveBeenCalledWith({
2131
+ // where: {
2132
+ // UserId: loginUser.UserId,
2133
+ // },
2134
+ // include: {
2135
+ // model: SystemPrivilegeModel,
2136
+ // where: {
2137
+ // SystemCode: systemCode,
2138
+ // Status: 'Active',
2139
+ // },
2140
+ // },
2141
+ // transaction: dbTransaction,
2142
+ // });
2143
+ // expect(result).toEqual(['privilege1', 'privilege2']);
2144
+ // });
2145
+
2146
+ // it('should throw an error if an exception occurs', async () => {
2147
+ // // Mock the dependencies and setup the test data
2148
+ // const systemCode = 'system1';
2149
+ // const dbTransaction = null;
2150
+ // const sessionService = await SessionService.init();
2151
+ // const loginUser = await LoginUser.init(sessionService);
2152
+
2153
+ // // Mock the UserObjectPrivilegeRepo findAll method to throw an error
2154
+ // jest
2155
+ // .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
2156
+ // .mockRejectedValue(new Error('Database error'));
2157
+
2158
+ // // Call the getObjectPrivileges method and expect it to throw an error
2159
+ // await expect(
2160
+ // loginUser['getObjectPrivileges'](systemCode, dbTransaction),
2161
+ // ).rejects.toThrow(Error);
2162
+ // });
2163
+ // });
2164
+
2165
+ // describe('getUserPersonalPrivileges', () => {
2166
+ // it('should return an array of privileges', async () => {
2167
+ // // Arrange
2168
+ // const sessionService = await SessionService.init();
2169
+ // const loginUser = await LoginUser.init(sessionService);
2170
+ // const systemCode = 'system1';
2171
+ // const dbTransaction = null;
2172
+
2173
+ // // Mock the findAll method of UserPrivilegeRepo
2174
+ // const findAllMock = jest.spyOn(
2175
+ // LoginUser['_UserPrivilegeRepo'],
2176
+ // 'findAll',
2177
+ // );
2178
+ // findAllMock.mockResolvedValue([
2179
+ // { Privilege: { Name: 'privilege1' } },
2180
+ // { Privilege: { Name: 'privilege2' } },
2181
+ // ] as any);
2182
+
2183
+ // // Act
2184
+ // const privileges = await loginUser['getUserPersonalPrivileges'](
2185
+ // systemCode,
2186
+ // dbTransaction,
2187
+ // );
2188
+
2189
+ // // Assert
2190
+ // expect(privileges).toEqual(['privilege1', 'privilege2']);
2191
+ // expect(findAllMock).toHaveBeenCalledTimes(1);
2192
+ // expect(findAllMock).toHaveBeenCalledWith({
2193
+ // where: {
2194
+ // UserId: loginUser.UserId,
2195
+ // Status: 'Active',
2196
+ // },
2197
+ // include: {
2198
+ // model: SystemPrivilegeModel,
2199
+ // where: {
2200
+ // SystemCode: systemCode,
2201
+ // Status: 'Active',
2202
+ // },
2203
+ // },
2204
+ // transaction: dbTransaction,
2205
+ // });
2206
+ // });
2207
+
2208
+ // it('should throw an error if an error occurs', async () => {
2209
+ // // Arrange
2210
+ // const sessionService = await SessionService.init();
2211
+ // const loginUser = await LoginUser.init(sessionService);
2212
+ // const systemCode = 'system1';
2213
+ // const dbTransaction = null;
2214
+
2215
+ // // Mock the findAll method of UserPrivilegeRepo to throw an error
2216
+ // const findAllMock = jest.spyOn(
2217
+ // LoginUser['_UserPrivilegeRepo'],
2218
+ // 'findAll',
2219
+ // );
2220
+ // findAllMock.mockRejectedValue(new Error('Database error'));
2221
+
2222
+ // // Act and Assert
2223
+ // await expect(
2224
+ // loginUser['getUserPersonalPrivileges'](systemCode, dbTransaction),
2225
+ // ).rejects.toThrow(Error);
2226
+
2227
+ // expect(findAllMock).toHaveBeenCalledTimes(1);
2228
+ // expect(findAllMock).toHaveBeenCalledWith({
2229
+ // where: {
2230
+ // UserId: loginUser.UserId,
2231
+ // Status: 'Active',
2232
+ // },
2233
+ // include: {
2234
+ // model: SystemPrivilegeModel,
2235
+ // where: {
2236
+ // SystemCode: systemCode,
2237
+ // Status: 'Active',
2238
+ // },
2239
+ // },
2240
+ // transaction: dbTransaction,
2241
+ // });
2242
+ // });
2243
+ // });
2244
+
2245
+ // describe('getInheritedSystemAccess', () => {
2246
+ // it('should return group system access with its parent group system access if applicable', async () => {
2247
+ // // Mock the necessary dependencies
2248
+ // const dbTransaction = null;
2249
+ // const group = {
2250
+ // GroupCode: 'group1',
2251
+ // InheritParentPrivilegeYN: 'Y',
2252
+ // ParentGroupCode: 'parentGroup',
2253
+ // } as any;
2254
+ // const parentGroup = {
2255
+ // GroupCode: 'parentGroup',
2256
+ // InheritParentPrivilegeYN: 'N',
2257
+ // ParentGroupCode: null,
2258
+ // } as any;
2259
+
2260
+ // const systemAccess = [
2261
+ // {
2262
+ // SystemCode: 'system1',
2263
+ // GroupCode: 'group1',
2264
+ // System: { SystemCode: 'system1' },
2265
+ // },
2266
+ // {
2267
+ // SystemCode: 'system2',
2268
+ // GroupCode: 'group1',
2269
+ // System: { SystemCode: 'system1' },
2270
+ // },
2271
+ // ] as any;
2272
+
2273
+ // const parentSystemAccess = [
2274
+ // {
2275
+ // SystemCode: 'system3',
2276
+ // GroupCode: 'parentGroup',
2277
+ // System: { SystemCode: 'system3' },
2278
+ // },
2279
+ // ] as any;
2280
+
2281
+ // // Mock the necessary repository methods
2282
+ // const groupFindByPkMock = jest
2283
+ // .spyOn(GroupRepository.prototype, 'findByPk')
2284
+ // .mockResolvedValueOnce(parentGroup as any);
2285
+ // const systemAccessFindAllMock = jest
2286
+ // .spyOn(GroupSystemAccessRepository.prototype, 'findAll')
2287
+ // .mockImplementation((options: any) => {
2288
+ // if (options.where.GroupCode === group.GroupCode) {
2289
+ // return Promise.resolve(systemAccess);
2290
+ // } else if (options.where.GroupCode === parentGroup.GroupCode) {
2291
+ // return Promise.resolve(parentSystemAccess);
2292
+ // }
2293
+ // });
2294
+
2295
+ // // Call the method
2296
+ // const result = await LoginUser['getInheritedSystemAccess'](
2297
+ // dbTransaction,
2298
+ // group,
2299
+ // );
2300
+
2301
+ // console.log(result);
2302
+ // // Assert the result
2303
+ // expect(result).toEqual([
2304
+ // {
2305
+ // SystemCode: 'system1',
2306
+ // GroupCode: 'group1',
2307
+ // System: { SystemCode: 'system1' },
2308
+ // },
2309
+ // {
2310
+ // SystemCode: 'system2',
2311
+ // GroupCode: 'group1',
2312
+ // System: { SystemCode: 'system1' },
2313
+ // },
2314
+ // {
2315
+ // SystemCode: 'system3',
2316
+ // GroupCode: 'parentGroup',
2317
+ // System: { SystemCode: 'system3' },
2318
+ // },
2319
+ // ]);
2320
+ // expect(groupFindByPkMock).toHaveBeenCalledWith(
2321
+ // group.ParentGroupCode,
2322
+ // dbTransaction,
2323
+ // );
2324
+ // expect(systemAccessFindAllMock).toHaveBeenCalledTimes(2);
2325
+ // });
2326
+ // });
2327
+ // });