@tomei/sso 0.57.0 → 0.58.1

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomei/sso",
3
- "version": "0.57.0",
3
+ "version": "0.58.1",
4
4
  "description": "Tomei SSO Package",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -242,7 +242,7 @@ export class GroupReportingUser extends ObjectBase {
242
242
  ApplicationConfig.getComponentConfigValue('system-code');
243
243
  const isPrivileged = await loginUser.checkPrivileges(
244
244
  systemCode,
245
- 'GROUP_REPORTING_USER_CREATE',
245
+ 'GROUP_REPORTING_USER_UPDATE',
246
246
  );
247
247
  if (!isPrivileged) {
248
248
  throw new ClassError(
@@ -35,6 +35,7 @@ import { createHash, randomBytes, randomUUID } from 'crypto';
35
35
  import { AuthContext } from 'types';
36
36
  import UserModel from '../../models/user.entity';
37
37
  import { UserReportingHierarchyRepository } from '../user-reporting-hierarchy/user-reporting-hierarchy.repository';
38
+ import { IUserReportingHierarchyAttr } from 'interfaces/user-reporting-hierarchy.interface';
38
39
 
39
40
  export class User extends UserBase {
40
41
  ObjectId: string;
@@ -2876,4 +2877,68 @@ export class User extends UserBase {
2876
2877
  throw error;
2877
2878
  }
2878
2879
  }
2880
+
2881
+ public async getUserReportingHierarchy(
2882
+ loginUser: LoginUser,
2883
+ dbTransaction: any,
2884
+ ): Promise<
2885
+ {
2886
+ UserReportingHierarchyId: number;
2887
+ UserId: number;
2888
+ Email: string;
2889
+ ContactNo: string;
2890
+ Name: string;
2891
+ Rank: number;
2892
+ }[]
2893
+ > {
2894
+ try {
2895
+ // Part 1: Privilege Checking
2896
+ // Call loginUser.checkPrivileges() method by passing:
2897
+ // SystemCode: Retrieve from app config.
2898
+ // PrivilegeCode: "USER_VIEW".
2899
+ const systemCode =
2900
+ ApplicationConfig.getComponentConfigValue('system-code');
2901
+ const isPrivileged = await loginUser.checkPrivileges(
2902
+ systemCode,
2903
+ 'USER_VIEW',
2904
+ );
2905
+ if (!isPrivileged) {
2906
+ throw new ClassError(
2907
+ 'LoginUser',
2908
+ 'LoginUserErrMsg0X',
2909
+ 'You do not have the privilege to view user reporting hierarchy',
2910
+ );
2911
+ }
2912
+
2913
+ const data = await User._UserReportingHierarchyRepo.findAll({
2914
+ where: {
2915
+ ReportingUserId: this.UserId,
2916
+ },
2917
+ include: [
2918
+ {
2919
+ model: UserModel,
2920
+ as: 'User',
2921
+ attributes: ['Email', 'ContactNo', 'FullName'],
2922
+ },
2923
+ ],
2924
+ transaction: dbTransaction,
2925
+ });
2926
+
2927
+ //format the data
2928
+ const result = data.map((item) => {
2929
+ return {
2930
+ UserReportingHierarchyId: item.UserReportingHierarchyId,
2931
+ UserId: item.UserId,
2932
+ Email: item.User.Email,
2933
+ ContactNo: item.User.ContactNo,
2934
+ Name: item.User.FullName,
2935
+ Rank: item.Rank,
2936
+ };
2937
+ });
2938
+
2939
+ return result;
2940
+ } catch (error) {
2941
+ throw error;
2942
+ }
2943
+ }
2879
2944
  }
@@ -1,6 +1,10 @@
1
1
  import { ClassError, ObjectBase } from '@tomei/general';
2
2
  import { IUserReportingHierarchyAttr } from '../../interfaces/user-reporting-hierarchy.interface';
3
3
  import { UserReportingHierarchyRepository } from './user-reporting-hierarchy.repository';
4
+ import { User } from '../login-user/user';
5
+ import { ApplicationConfig } from '@tomei/config';
6
+ import { ActionEnum, Activity } from '@tomei/activity-history';
7
+ import { Op } from 'sequelize';
4
8
 
5
9
  export class UserReportingHierarchy
6
10
  extends ObjectBase
@@ -61,7 +65,7 @@ export class UserReportingHierarchy
61
65
  }
62
66
 
63
67
  public static async init(
64
- userReportingHierarchyId: number,
68
+ userReportingHierarchyId?: number,
65
69
  dbTransaction?: any,
66
70
  ): Promise<UserReportingHierarchy> {
67
71
  try {
@@ -87,4 +91,415 @@ export class UserReportingHierarchy
87
91
  throw error;
88
92
  }
89
93
  }
94
+
95
+ async createUserReportingHierarchy(
96
+ loginUser: User, //The user performing the operation(typically the logged -in user).
97
+ dbTransaction: any, //Database transaction object to ensure the operation is atomic.
98
+ reportingUserId: number, //The ID of the user who will do the reporting.
99
+ userId: number, //The Id of the user who need to be reported to.
100
+ rank: number, //The rank to be assigned to the user.
101
+ status: 'Active' | 'Inactive', //The initial status of relationship.
102
+ ): Promise<UserReportingHierarchy> {
103
+ // Returns a ReportingUserHierarchy instance representing the newly created record.
104
+ try {
105
+ //Creates a new User Reporting Hierarchy entry in the sso_UserReportingHierarchy table.
106
+
107
+ // Privilege Checking
108
+ // Call the loginUser.checkPrivileges() method by passing:
109
+ // SystemCode: Retrieve from app config.
110
+ // PrivilegeCode: "GROUP_REPORTING_USER_CREATE".
111
+ const systemCode =
112
+ ApplicationConfig.getComponentConfigValue('system-code');
113
+ const isPrivileged = await loginUser.checkPrivileges(
114
+ systemCode,
115
+ 'USER_REPORTING_HIERARCHY_CREATE',
116
+ );
117
+ if (!isPrivileged) {
118
+ throw new ClassError(
119
+ 'UserReportingHierarchy',
120
+ 'UserReportingHierarchyErrMsg02',
121
+ 'User does not have the required privileges',
122
+ 'createUserReportingHierarchy',
123
+ 403,
124
+ );
125
+ }
126
+
127
+ // Validate Input Parameters
128
+ // Ensure userId exists in the sso_User table by calling the User.init() method.
129
+ await User.init(dbTransaction, userId);
130
+ await User.init(dbTransaction, reportingUserId);
131
+
132
+ // Query the sso_UserReportingHierarchy table to see if the relationship is already defined for the user.
133
+ let userReportingHierarchy = await UserReportingHierarchy._Repo.findOne({
134
+ where: {
135
+ ReportingUserId: reportingUserId,
136
+ UserId: userId,
137
+ },
138
+ transaction: dbTransaction,
139
+ });
140
+ // If the record already exists, throw an error.
141
+ if (userReportingHierarchy) {
142
+ throw new ClassError(
143
+ 'UserReportingHierarchy',
144
+ 'UserReportingHierarchyErrMsg03',
145
+ 'Relationship already exists',
146
+ 'createUserReportingHierarchy',
147
+ 400,
148
+ );
149
+ }
150
+ //Query the sso_UserReportingHierarchy table to see if the rank already exists for the reporting user.
151
+ //If the rank already exists, throw an error indicating the rank is already exist.
152
+ userReportingHierarchy = await UserReportingHierarchy._Repo.findOne({
153
+ where: {
154
+ ReportingUserId: reportingUserId,
155
+ Rank: rank,
156
+ },
157
+ transaction: dbTransaction,
158
+ });
159
+ if (userReportingHierarchy) {
160
+ throw new ClassError(
161
+ 'UserReportingHierarchy',
162
+ 'UserReportingHierarchyErrMsg04',
163
+ 'Rank already exists',
164
+ 'createUserReportingHierarchy',
165
+ 400,
166
+ );
167
+ }
168
+
169
+ //Check if one rank before the new rank is not already assigned to the user, if not throw an error
170
+ if (rank > 1) {
171
+ const userReportingHierarchyBefore =
172
+ await UserReportingHierarchy._Repo.findOne({
173
+ where: {
174
+ ReportingUserId: reportingUserId,
175
+ Rank: rank - 1,
176
+ },
177
+ transaction: dbTransaction,
178
+ });
179
+
180
+ if (!userReportingHierarchyBefore) {
181
+ throw new ClassError(
182
+ 'UserReportingHierarchy',
183
+ 'UserReportingHierarchyErrMsg05',
184
+ 'Rank before the new rank is not yet assigned to the user',
185
+ 'createUserReportingHierarchy',
186
+ 400,
187
+ );
188
+ }
189
+ }
190
+
191
+ // Create ReportingUserHierarchy Entry
192
+ // If validation and privilege checks pass, insert a new record in the sso_UserReportingHierarchy table
193
+ this.ReportingUserId = reportingUserId;
194
+ this.UserId = userId;
195
+ this.Rank = rank;
196
+ this.Status = status;
197
+ this._CreatedById = loginUser.UserId;
198
+ this._CreatedAt = new Date();
199
+ this._UpdatedAt = new Date();
200
+ this._UpdatedById = loginUser.UserId;
201
+
202
+ const entityValueAfter: any = {
203
+ ReportingUserId: reportingUserId,
204
+ UserId: userId,
205
+ Rank: rank,
206
+ Status: status,
207
+ CreatedById: loginUser.UserId,
208
+ CreatedAt: this._CreatedAt,
209
+ UpdatedById: loginUser.UserId,
210
+ UpdatedAt: this._UpdatedAt,
211
+ };
212
+
213
+ userReportingHierarchy = await UserReportingHierarchy._Repo.create(
214
+ entityValueAfter,
215
+ {
216
+ transaction: dbTransaction,
217
+ },
218
+ );
219
+
220
+ entityValueAfter.UserReportingHierarchyId =
221
+ userReportingHierarchy.UserReportingHierarchyId;
222
+
223
+ // Record Create Activity
224
+ // Instantiate a new activity from the Activity class, and set:\
225
+ // ActivityId: activity.createId()
226
+ // Action: ActionEnum.Create
227
+ // Description: Create User Reporting Hierarchy
228
+ // EntityType: ReportingUserHierarchy
229
+ // EntityId: newReportingUserHierarchy.ReportingUserHierarchyId
230
+ // EntityValueBefore: Stringified empty object({})
231
+ // EntityValueAfter: EntityValueAfter(stringified representation of the newly created entity)
232
+ const activity = new Activity();
233
+ activity.ActivityId = activity.createId();
234
+ activity.Action = ActionEnum.CREATE;
235
+ activity.Description = 'Create User Reporting Hierarchy';
236
+ activity.EntityType = 'UserReportingHierarchy';
237
+ activity.EntityId =
238
+ userReportingHierarchy.UserReportingHierarchyId.toString();
239
+ activity.EntityValueBefore = JSON.stringify({});
240
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
241
+ // Call the activity create() method by passing:
242
+ // dbTransaction
243
+ // userId: loginUser.UserId
244
+ await activity.create(loginUser.ObjectId, dbTransaction);
245
+ // Return the Created ReportingUserHierarchy
246
+ // Return the newly created ReportingUserHierarchy instance
247
+ return this;
248
+ } catch (error) {
249
+ throw error;
250
+ }
251
+ }
252
+
253
+ async updateUserReportingHierarchy(
254
+ loginUser: User, //The user performing the operation(typically the logged -in user).
255
+ dbTransaction: any, //Database transaction object to ensure the operation is atomic.
256
+ reportingUserId: number, //The ID of the user who will do the reporting.
257
+ userId: number, //The ID of the user who need to be reported to.
258
+ rank: number, //The rank to be assigned to the user.
259
+ status: 'Active' | 'Inactive', //The initial status of the user.
260
+ ): Promise<UserReportingHierarchy> {
261
+ // Returns a ReportingUserHierarchy instance representing the updated record.
262
+ try {
263
+ //Update a User Reporting Hierarchy entry in the sso_UserReportingHierarchy table.
264
+
265
+ // Validate Input Parameters
266
+ // Ensure userId exists in the sso_User table by calling the User.init() method.
267
+ await User.init(dbTransaction, userId);
268
+ await User.init(dbTransaction, reportingUserId);
269
+ // Privilege Checking
270
+ // Call the loginUser.checkPrivileges() method by passing:
271
+ // SystemCode: Retrieve from app config.
272
+ // PrivilegeCode: "GROUP_REPORTING_USER_UPDATE".
273
+ const systemCode =
274
+ ApplicationConfig.getComponentConfigValue('system-code');
275
+ const isPrivileged = await loginUser.checkPrivileges(
276
+ systemCode,
277
+ 'USER_REPORTING_HIERARCHY_UPDATE',
278
+ );
279
+ if (!isPrivileged) {
280
+ throw new ClassError(
281
+ 'UserReportingHierarchy',
282
+ 'UserReportingHierarchyErrMsg02',
283
+ 'User does not have the required privileges',
284
+ 'updateUserReportingHierarchy',
285
+ 403,
286
+ );
287
+ }
288
+
289
+ // Query the sso_UserReportingHierarchy table to see if the userId already exists.
290
+ const userReportingHierarchy = await UserReportingHierarchy._Repo.findOne(
291
+ {
292
+ where: {
293
+ ReportingUserId: reportingUserId,
294
+ UserId: userId,
295
+ UserReportingHierarchyId: {
296
+ [Op.ne]: this.UserReportingHierarchyId,
297
+ },
298
+ },
299
+ transaction: dbTransaction,
300
+ },
301
+ );
302
+ // If the user already exists, throw an error indicating the reporting user is already part of reporting hierarchy.
303
+ if (userReportingHierarchy) {
304
+ throw new ClassError(
305
+ 'UserReportingHierarchy',
306
+ 'UserReportingHierarchyErrMsg03',
307
+ 'Relationship already exists',
308
+ 'updateUserReportingHierarchy',
309
+ );
310
+ }
311
+ //Query the sso_UserReportingHierarchy table to see if the rank already exists in the specified groupCode.
312
+ //If the rank already exists, throw an error indicating the rank is already in part of reporting hierarchy.
313
+ const userReportingRank = await UserReportingHierarchy._Repo.findOne({
314
+ where: {
315
+ ReportingUserId: reportingUserId,
316
+ Rank: rank,
317
+ UserReportingHierarchyId: {
318
+ [Op.ne]: this.UserReportingHierarchyId,
319
+ },
320
+ },
321
+ transaction: dbTransaction,
322
+ });
323
+ if (userReportingRank) {
324
+ throw new ClassError(
325
+ 'UserReportingHierarchy',
326
+ 'UserReportingHierarchyErrMsg04',
327
+ 'Rank already exists',
328
+ 'updateUserReportingHierarchy',
329
+ );
330
+ }
331
+
332
+ //Check if rank before the new rank is not already assigned to the user
333
+ if (rank > 1) {
334
+ const userReportingRankBefore =
335
+ await UserReportingHierarchy._Repo.findOne({
336
+ where: {
337
+ ReportingUserId: reportingUserId,
338
+ Rank: rank - 1,
339
+ UserReportingHierarchyId: {
340
+ [Op.ne]: this.UserReportingHierarchyId,
341
+ },
342
+ },
343
+ transaction: dbTransaction,
344
+ });
345
+
346
+ if (!userReportingRankBefore) {
347
+ throw new ClassError(
348
+ 'UserReportingHierarchy',
349
+ 'UserReportingHierarchyErrMsg05',
350
+ 'Rank before the new rank is not yet assigned to the user',
351
+ 'updateUserReportingHierarchy',
352
+ );
353
+ }
354
+ }
355
+
356
+ // UPDATE ReportingUserHierarchy Entry
357
+ // If validation and privilege checks pass, insert a new record in the sso_UserReportingHierarchy table.
358
+ const entityValueBefore: any = {
359
+ UserReportingHierarchyId: this.UserReportingHierarchyId,
360
+ ReportingUserId: this.ReportingUserId,
361
+ UserId: this.UserId,
362
+ Rank: this.Rank,
363
+ Status: this.Status,
364
+ CreatedById: this._CreatedById,
365
+ CreatedAt: this._CreatedAt,
366
+ UpdatedById: this._UpdatedById,
367
+ UpdatedAt: this._UpdatedAt,
368
+ };
369
+
370
+ this.ReportingUserId = reportingUserId;
371
+ this.UserId = userId;
372
+ this.Rank = rank;
373
+ this.Status = status;
374
+ this._CreatedById = this.CreatedById;
375
+ this._CreatedAt = this.CreatedAt;
376
+ this._UpdatedAt = new Date();
377
+ this._UpdatedById = loginUser.UserId;
378
+
379
+ const entityValueAfter: any = {
380
+ ReportingUserId: reportingUserId,
381
+ UserId: userId,
382
+ Rank: rank,
383
+ Status: status,
384
+ CreatedById: this.CreatedById,
385
+ CreatedAt: this._CreatedAt,
386
+ UpdatedById: loginUser.UserId,
387
+ UpdatedAt: this._UpdatedAt,
388
+ };
389
+
390
+ await UserReportingHierarchy._Repo.update(entityValueAfter, {
391
+ where: {
392
+ UserReportingHierarchyId: this.UserReportingHierarchyId,
393
+ },
394
+ transaction: dbTransaction,
395
+ });
396
+
397
+ // Record Update Activity
398
+ // Instantiate a new activity from the Activity class, and set:\
399
+ // ActivityId: activity.createId()
400
+ // Action: ActionEnum.Update
401
+ // Description: Update User Reporting Hierarchy
402
+ // EntityType: ReportingUserHierarchy
403
+ // EntityId: newReportingUserHierarchy.ReportingUserHierarchyId
404
+ // EntityValueBefore: Stringified empty object({})
405
+ // EntityValueAfter: EntityValueAfter(stringified representation of the newly created entity)
406
+ const activity = new Activity();
407
+ activity.ActivityId = activity.createId();
408
+ activity.Action = ActionEnum.UPDATE;
409
+ activity.Description = 'Update User Reporting Hierarchy';
410
+ activity.EntityType = 'UserReportingHierarchy';
411
+ activity.EntityId = this.UserReportingHierarchyId.toString();
412
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
413
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
414
+ // Call the activity create() method by passing:
415
+ // dbTransaction
416
+ // userId: loginUser.UserId
417
+ await activity.create(loginUser.ObjectId, dbTransaction);
418
+ // Return the Updated ReportingUserHierarchy
419
+ // Return the updated ReportingUserHierarchy instance, including all the relevant details like ReportingUserHierarchyId, groupCode, userId, rank, status, and timestamps for CreatedAt.
420
+ return this;
421
+ } catch (error) {
422
+ throw error;
423
+ }
424
+ }
425
+
426
+ public static async removeUserReportingHierarchy(
427
+ loginUser: User, //The user performing the operation, used for privilege checking and logging.
428
+ dbTransaction: any, // The database transaction object to ensure the operation's atomicity.
429
+ userReportingHierarchyId: number, //The ID of the UserReportingHierarchy to be removed.
430
+ ): Promise<void> {
431
+ // This method removes a UserReportingHierarchy record from the database.
432
+ try {
433
+ // Part 1: Privilege Checking
434
+ // Call loginUser.checkPrivileges() method by passing:
435
+ // SystemCode: Retrieve from app config.
436
+ // PrivilegeCode: "USER_REPORTING_HIERARCHY_REMOVE".
437
+ const systemCode =
438
+ ApplicationConfig.getComponentConfigValue('system-code');
439
+ const isPrivileged = await loginUser.checkPrivileges(
440
+ systemCode,
441
+ 'USER_REPORTING_HIERARCHY_REMOVE',
442
+ );
443
+ if (!isPrivileged) {
444
+ throw new ClassError(
445
+ 'UserReportingHierarchy',
446
+ 'UserReportingHierarchyErrMsg06',
447
+ 'Insufficient privileges to remove reporting hierarchy',
448
+ 'removeUserReportingHierarchy',
449
+ 403,
450
+ );
451
+ }
452
+
453
+ // Part 2: Find User
454
+ // Call UserReportingHierarchy.init(dbTransaction, UserReportingHierarchyId) to check if the user exists.
455
+ const userReportingHierarchy = await UserReportingHierarchy.init(
456
+ userReportingHierarchyId,
457
+ dbTransaction,
458
+ );
459
+
460
+ // Part 3: Remove User
461
+ // Call UserReportingHierarchy._Repo.destroy({ where: { UserReportingHierarchyId: UserReportingHierarchyId }, transaction: dbTransaction }) to remove the user from the database.
462
+ await UserReportingHierarchy._Repo.destroy(
463
+ userReportingHierarchyId,
464
+ dbTransaction,
465
+ );
466
+
467
+ // Part 4: Record Create Activity
468
+ // Initialise EntityValueBefore variable and set it to the UserReportingHierarchy instance before destruction.
469
+ const entityValueBefore = {
470
+ UserReportingHierarchyId:
471
+ userReportingHierarchy.UserReportingHierarchyId,
472
+ ReportingUserId: userReportingHierarchy.ReportingUserId,
473
+ UserId: userReportingHierarchy.UserId,
474
+ Rank: userReportingHierarchy.Rank,
475
+ Status: userReportingHierarchy.Status,
476
+ CreatedById: userReportingHierarchy.CreatedById,
477
+ CreatedAt: userReportingHierarchy.CreatedAt,
478
+ UpdatedById: userReportingHierarchy.UpdatedById,
479
+ UpdatedAt: userReportingHierarchy.UpdatedAt,
480
+ };
481
+ // Instantiate a new activity from the Activity class, and set:
482
+ const activity = new Activity();
483
+ // ActivityId: activity.createId()
484
+ // Action: ActionEnum.Delete
485
+ // Description: Remove User Reporting Hierarchy
486
+ // EntityType: UserReportingHierarchy
487
+ // EntityId: userReportingHierarchyId
488
+ // EntityValueBefore: Stringified representation of the UserReportingHierarchy instance before destroy
489
+ // EntityValueAfter: Stringified empty object ({})
490
+ activity.ActivityId = activity.createId();
491
+ activity.Action = ActionEnum.DELETE;
492
+ activity.Description = 'Remove User Reporting Hierarchy';
493
+ activity.EntityType = 'UserReportingHierarchy';
494
+ activity.EntityId = userReportingHierarchy.toString();
495
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
496
+ activity.EntityValueAfter = JSON.stringify({});
497
+ // Call the activity.create() method by passing:
498
+ // dbTransaction
499
+ // userId: loginUser.UserId
500
+ await activity.create(loginUser.ObjectId, dbTransaction);
501
+ } catch (error) {
502
+ throw error;
503
+ }
504
+ }
90
505
  }