@tomei/sso 0.57.0 → 0.58.0

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.0",
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,410 @@ 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
+ userReportingHierarchy = await UserReportingHierarchy._Repo.findOne({
171
+ where: {
172
+ ReportingUserId: reportingUserId,
173
+ Rank: rank - 1,
174
+ },
175
+ transaction: dbTransaction,
176
+ });
177
+
178
+ if (!userReportingHierarchy) {
179
+ throw new ClassError(
180
+ 'UserReportingHierarchy',
181
+ 'UserReportingHierarchyErrMsg05',
182
+ 'Rank before the new rank is not yet assigned to the user',
183
+ 'createUserReportingHierarchy',
184
+ 400,
185
+ );
186
+ }
187
+
188
+ // Create ReportingUserHierarchy Entry
189
+ // If validation and privilege checks pass, insert a new record in the sso_UserReportingHierarchy table
190
+ this.ReportingUserId = reportingUserId;
191
+ this.UserId = userId;
192
+ this.Rank = rank;
193
+ this.Status = status;
194
+ this._CreatedById = loginUser.UserId;
195
+ this._CreatedAt = new Date();
196
+ this._UpdatedAt = new Date();
197
+ this._UpdatedById = loginUser.UserId;
198
+
199
+ const entityValueAfter: any = {
200
+ ReportingUserId: reportingUserId,
201
+ UserId: userId,
202
+ Rank: rank,
203
+ Status: status,
204
+ CreatedById: loginUser.UserId,
205
+ CreatedAt: this._CreatedAt,
206
+ UpdatedById: loginUser.UserId,
207
+ UpdatedAt: this._UpdatedAt,
208
+ };
209
+
210
+ userReportingHierarchy = await UserReportingHierarchy._Repo.create(
211
+ entityValueAfter,
212
+ {
213
+ transaction: dbTransaction,
214
+ },
215
+ );
216
+
217
+ entityValueAfter.UserReportingHierarchyId =
218
+ userReportingHierarchy.UserReportingHierarchyId;
219
+
220
+ // Record Create Activity
221
+ // Instantiate a new activity from the Activity class, and set:\
222
+ // ActivityId: activity.createId()
223
+ // Action: ActionEnum.Create
224
+ // Description: Create User Reporting Hierarchy
225
+ // EntityType: ReportingUserHierarchy
226
+ // EntityId: newReportingUserHierarchy.ReportingUserHierarchyId
227
+ // EntityValueBefore: Stringified empty object({})
228
+ // EntityValueAfter: EntityValueAfter(stringified representation of the newly created entity)
229
+ const activity = new Activity();
230
+ activity.ActivityId = activity.createId();
231
+ activity.Action = ActionEnum.CREATE;
232
+ activity.Description = 'Create User Reporting Hierarchy';
233
+ activity.EntityType = 'UserReportingHierarchy';
234
+ activity.EntityId =
235
+ userReportingHierarchy.UserReportingHierarchyId.toString();
236
+ activity.EntityValueBefore = JSON.stringify({});
237
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
238
+ // Call the activity create() method by passing:
239
+ // dbTransaction
240
+ // userId: loginUser.UserId
241
+ await activity.create(loginUser.ObjectId, dbTransaction);
242
+ // Return the Created ReportingUserHierarchy
243
+ // Return the newly created ReportingUserHierarchy instance
244
+ return this;
245
+ } catch (error) {
246
+ throw error;
247
+ }
248
+ }
249
+
250
+ async updateUserReportingHierarchy(
251
+ loginUser: User, //The user performing the operation(typically the logged -in user).
252
+ dbTransaction: any, //Database transaction object to ensure the operation is atomic.
253
+ reportingUserId: number, //The ID of the user who will do the reporting.
254
+ userId: number, //The ID of the user who need to be reported to.
255
+ rank: number, //The rank to be assigned to the user.
256
+ status: 'Active' | 'Inactive', //The initial status of the user.
257
+ ): Promise<UserReportingHierarchy> {
258
+ // Returns a ReportingUserHierarchy instance representing the updated record.
259
+ try {
260
+ //Update a User Reporting Hierarchy entry in the sso_UserReportingHierarchy table.
261
+
262
+ // Validate Input Parameters
263
+ // Ensure userId exists in the sso_User table by calling the User.init() method.
264
+ await User.init(dbTransaction, userId);
265
+ await User.init(dbTransaction, reportingUserId);
266
+ // Privilege Checking
267
+ // Call the loginUser.checkPrivileges() method by passing:
268
+ // SystemCode: Retrieve from app config.
269
+ // PrivilegeCode: "GROUP_REPORTING_USER_UPDATE".
270
+ const systemCode =
271
+ ApplicationConfig.getComponentConfigValue('system-code');
272
+ const isPrivileged = await loginUser.checkPrivileges(
273
+ systemCode,
274
+ 'USER_REPORTING_HIERARCHY_UPDATE',
275
+ );
276
+ if (!isPrivileged) {
277
+ throw new ClassError(
278
+ 'UserReportingHierarchy',
279
+ 'UserReportingHierarchyErrMsg02',
280
+ 'User does not have the required privileges',
281
+ 'updateUserReportingHierarchy',
282
+ 403,
283
+ );
284
+ }
285
+
286
+ // Query the sso_UserReportingHierarchy table to see if the userId already exists.
287
+ const userReportingHierarchy = await UserReportingHierarchy._Repo.findOne(
288
+ {
289
+ where: {
290
+ ReportingUserId: reportingUserId,
291
+ UserId: userId,
292
+ UserReportingHierarchyId: {
293
+ [Op.ne]: this.UserReportingHierarchyId,
294
+ },
295
+ },
296
+ transaction: dbTransaction,
297
+ },
298
+ );
299
+ // If the user already exists, throw an error indicating the reporting user is already part of reporting hierarchy.
300
+ if (userReportingHierarchy) {
301
+ throw new ClassError(
302
+ 'UserReportingHierarchy',
303
+ 'UserReportingHierarchyErrMsg03',
304
+ 'Relationship already exists',
305
+ 'updateUserReportingHierarchy',
306
+ );
307
+ }
308
+ //Query the sso_UserReportingHierarchy table to see if the rank already exists in the specified groupCode.
309
+ //If the rank already exists, throw an error indicating the rank is already in part of reporting hierarchy.
310
+ const userReportingRank = await UserReportingHierarchy._Repo.findOne({
311
+ where: {
312
+ ReportingUserId: reportingUserId,
313
+ Rank: rank,
314
+ UserReportingHierarchyId: {
315
+ [Op.ne]: this.UserReportingHierarchyId,
316
+ },
317
+ },
318
+ transaction: dbTransaction,
319
+ });
320
+ if (userReportingRank) {
321
+ throw new ClassError(
322
+ 'UserReportingHierarchy',
323
+ 'UserReportingHierarchyErrMsg04',
324
+ 'Rank already exists',
325
+ 'updateUserReportingHierarchy',
326
+ );
327
+ }
328
+
329
+ //Check if rank before the new rank is not already assigned to the user
330
+ const userReportingRankBefore =
331
+ await UserReportingHierarchy._Repo.findOne({
332
+ where: {
333
+ ReportingUserId: reportingUserId,
334
+ Rank: rank - 1,
335
+ UserReportingHierarchyId: {
336
+ [Op.ne]: this.UserReportingHierarchyId,
337
+ },
338
+ },
339
+ transaction: dbTransaction,
340
+ });
341
+
342
+ if (!userReportingRankBefore) {
343
+ throw new ClassError(
344
+ 'UserReportingHierarchy',
345
+ 'UserReportingHierarchyErrMsg05',
346
+ 'Rank before the new rank is not yet assigned to the user',
347
+ 'updateUserReportingHierarchy',
348
+ );
349
+ }
350
+
351
+ // UPDATE ReportingUserHierarchy Entry
352
+ // If validation and privilege checks pass, insert a new record in the sso_UserReportingHierarchy table.
353
+ const entityValueBefore: any = {
354
+ UserReportingHierarchyId: this.UserReportingHierarchyId,
355
+ ReportingUserId: this.ReportingUserId,
356
+ UserId: this.UserId,
357
+ Rank: this.Rank,
358
+ Status: this.Status,
359
+ CreatedById: this._CreatedById,
360
+ CreatedAt: this._CreatedAt,
361
+ UpdatedById: this._UpdatedById,
362
+ UpdatedAt: this._UpdatedAt,
363
+ };
364
+
365
+ this.ReportingUserId = reportingUserId;
366
+ this.UserId = userId;
367
+ this.Rank = rank;
368
+ this.Status = status;
369
+ this._CreatedById = this.CreatedById;
370
+ this._CreatedAt = this.CreatedAt;
371
+ this._UpdatedAt = new Date();
372
+ this._UpdatedById = loginUser.UserId;
373
+
374
+ const entityValueAfter: any = {
375
+ ReportingUserId: reportingUserId,
376
+ UserId: userId,
377
+ Rank: rank,
378
+ Status: status,
379
+ CreatedById: this.CreatedById,
380
+ CreatedAt: this._CreatedAt,
381
+ UpdatedById: loginUser.UserId,
382
+ UpdatedAt: this._UpdatedAt,
383
+ };
384
+
385
+ await UserReportingHierarchy._Repo.update(entityValueAfter, {
386
+ where: {
387
+ UserReportingHierarchyId: this.UserReportingHierarchyId,
388
+ },
389
+ transaction: dbTransaction,
390
+ });
391
+
392
+ // Record Update Activity
393
+ // Instantiate a new activity from the Activity class, and set:\
394
+ // ActivityId: activity.createId()
395
+ // Action: ActionEnum.Update
396
+ // Description: Update User Reporting Hierarchy
397
+ // EntityType: ReportingUserHierarchy
398
+ // EntityId: newReportingUserHierarchy.ReportingUserHierarchyId
399
+ // EntityValueBefore: Stringified empty object({})
400
+ // EntityValueAfter: EntityValueAfter(stringified representation of the newly created entity)
401
+ const activity = new Activity();
402
+ activity.ActivityId = activity.createId();
403
+ activity.Action = ActionEnum.UPDATE;
404
+ activity.Description = 'Update User Reporting Hierarchy';
405
+ activity.EntityType = 'UserReportingHierarchy';
406
+ activity.EntityId = this.UserReportingHierarchyId.toString();
407
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
408
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
409
+ // Call the activity create() method by passing:
410
+ // dbTransaction
411
+ // userId: loginUser.UserId
412
+ await activity.create(loginUser.ObjectId, dbTransaction);
413
+ // Return the Updated ReportingUserHierarchy
414
+ // Return the updated ReportingUserHierarchy instance, including all the relevant details like ReportingUserHierarchyId, groupCode, userId, rank, status, and timestamps for CreatedAt.
415
+ return this;
416
+ } catch (error) {
417
+ throw error;
418
+ }
419
+ }
420
+
421
+ public static async removeUserReportingHierarchy(
422
+ loginUser: User, //The user performing the operation, used for privilege checking and logging.
423
+ dbTransaction: any, // The database transaction object to ensure the operation's atomicity.
424
+ userReportingHierarchyId: number, //The ID of the UserReportingHierarchy to be removed.
425
+ ): Promise<void> {
426
+ // This method removes a UserReportingHierarchy record from the database.
427
+ try {
428
+ // Part 1: Privilege Checking
429
+ // Call loginUser.checkPrivileges() method by passing:
430
+ // SystemCode: Retrieve from app config.
431
+ // PrivilegeCode: "USER_REPORTING_HIERARCHY_REMOVE".
432
+ const systemCode =
433
+ ApplicationConfig.getComponentConfigValue('system-code');
434
+ const isPrivileged = await loginUser.checkPrivileges(
435
+ systemCode,
436
+ 'USER_REPORTING_HIERARCHY_REMOVE',
437
+ );
438
+ if (!isPrivileged) {
439
+ throw new ClassError(
440
+ 'UserReportingHierarchy',
441
+ 'UserReportingHierarchyErrMsg06',
442
+ 'Insufficient privileges to remove reporting hierarchy',
443
+ 'removeUserReportingHierarchy',
444
+ 403,
445
+ );
446
+ }
447
+
448
+ // Part 2: Find User
449
+ // Call UserReportingHierarchy.init(dbTransaction, UserReportingHierarchyId) to check if the user exists.
450
+ const userReportingHierarchy = await UserReportingHierarchy.init(
451
+ userReportingHierarchyId,
452
+ dbTransaction,
453
+ );
454
+
455
+ // Part 3: Remove User
456
+ // Call UserReportingHierarchy._Repo.destroy({ where: { UserReportingHierarchyId: UserReportingHierarchyId }, transaction: dbTransaction }) to remove the user from the database.
457
+ await UserReportingHierarchy._Repo.destroy(
458
+ userReportingHierarchyId,
459
+ dbTransaction,
460
+ );
461
+
462
+ // Part 4: Record Create Activity
463
+ // Initialise EntityValueBefore variable and set it to the UserReportingHierarchy instance before destruction.
464
+ const entityValueBefore = {
465
+ UserReportingHierarchyId:
466
+ userReportingHierarchy.UserReportingHierarchyId,
467
+ ReportingUserId: userReportingHierarchy.ReportingUserId,
468
+ UserId: userReportingHierarchy.UserId,
469
+ Rank: userReportingHierarchy.Rank,
470
+ Status: userReportingHierarchy.Status,
471
+ CreatedById: userReportingHierarchy.CreatedById,
472
+ CreatedAt: userReportingHierarchy.CreatedAt,
473
+ UpdatedById: userReportingHierarchy.UpdatedById,
474
+ UpdatedAt: userReportingHierarchy.UpdatedAt,
475
+ };
476
+ // Instantiate a new activity from the Activity class, and set:
477
+ const activity = new Activity();
478
+ // ActivityId: activity.createId()
479
+ // Action: ActionEnum.Delete
480
+ // Description: Remove User Reporting Hierarchy
481
+ // EntityType: UserReportingHierarchy
482
+ // EntityId: userReportingHierarchyId
483
+ // EntityValueBefore: Stringified representation of the UserReportingHierarchy instance before destroy
484
+ // EntityValueAfter: Stringified empty object ({})
485
+ activity.ActivityId = activity.createId();
486
+ activity.Action = ActionEnum.DELETE;
487
+ activity.Description = 'Remove User Reporting Hierarchy';
488
+ activity.EntityType = 'UserReportingHierarchy';
489
+ activity.EntityId = userReportingHierarchy.toString();
490
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
491
+ activity.EntityValueAfter = JSON.stringify({});
492
+ // Call the activity.create() method by passing:
493
+ // dbTransaction
494
+ // userId: loginUser.UserId
495
+ await activity.create(loginUser.ObjectId, dbTransaction);
496
+ } catch (error) {
497
+ throw error;
498
+ }
499
+ }
90
500
  }