1 var UserManager = library.RestStandardized.build();
  2 var AdminUtils = library.AdminUtils.build();
  3 
  4 /**
  5  * @name UserManager_GET
  6  * @class Collects user info
  7  * @description GET /wf/restapi/v2/admin/userManager: This endpoint can collect all users info or a specific users info given the "userId" or "username"
  8  * @param [userId] search for a specific user by user id
  9  * @param [username] search for a specific user by username
 10  * @param [pretty=false] format the response to be human readable?
 11  *
 12  * @example GET /wf/restapi/v2/admin/userManager
 13  * Response:
 14  *
 15  [
 16   {
 17     "lastName": "",
 18     "substitutionMap": {
 19       "$username": "root",
 20       "$today": "2020-07-31",
 21       "$user:ldap:position": "dbadmin"
 22     },
 23     "country": "",
 24     "city": "",
 25     "company": "",
 26     "state": "",
 27     "email": "root@localhost",
 28     "zip": "",
 29     "ext": "",
 30     "address2": "",
 31     "address1": "",
 32     "dept": "",
 33     "userId": 1,
 34     "firstName": "",
 35     "phone": "",
 36     "middleName": "",
 37     "position": "dbadmin",
 38     "username": "root",
 39     "type": "Global Administrator",
 40     "status": "Active",
 41     "primaryGroup": 6,
 42     "groups": [
 43       6,
 44       8
 45     ]
 46   },
 47  {
 48     "lastName": "tester",
 49     "substitutionMap": {},
 50     "country": "Belgium",
 51     "city": "Gent",
 52     "company": "Esko",
 53     "state": "",
 54     "email": "tester@localhost.com",
 55     "zip": "BE-9051",
 56     "ext": "",
 57     "address2": "",
 58     "address1": "Kortrijksesteenweg 1095",
 59     "dept": "Engineering",
 60     "userId": 7,
 61     "firstName": "test",
 62     "phone": "",
 63     "middleName": "a",
 64     "position": "Engineer",
 65     "username": "testUser",
 66     "type": "Global Administrator",
 67     "status": "Active",
 68     "primaryGroup": 6,
 69     "groups": [
 70       0,
 71       6,
 72       8
 73     ]
 74   }
 75  ]
 76  * @example GET /wf/restapi/v2/admin/userManager?username=testUser
 77  * Response:
 78  *
 79  [
 80   {
 81     "lastName": "tester",
 82     "substitutionMap": {},
 83     "country": "Belgium",
 84     "city": "Gent",
 85     "company": "Esko",
 86     "state": "",
 87     "email": "tester@localhost.com",
 88     "zip": "BE-9051",
 89     "ext": "",
 90     "address2": "",
 91     "address1": "Kortrijksesteenweg 1095",
 92     "dept": "Engineering",
 93     "userId": 7,
 94     "firstName": "test",
 95     "phone": "",
 96     "middleName": "a",
 97     "position": "Engineer",
 98     "username": "testUser",
 99     "type": "Global Administrator",
100     "status": "Active",
101     "primaryGroup": 6,
102     "groups": [
103       0,
104       6,
105       8
106     ]
107   }
108  ]
109  * @example GET /wf/restapi/v2/admin/userManager?userId=7
110  * Response:
111  *
112  [
113   {
114     "lastName": "tester",
115     "substitutionMap": {},
116     "country": "Belgium",
117     "city": "Gent",
118     "company": "Esko",
119     "state": "",
120     "email": "tester@localhost.com",
121     "zip": "BE-9051",
122     "ext": "",
123     "address2": "",
124     "address1": "Kortrijksesteenweg 1095",
125     "dept": "Engineering",
126     "userId": 7,
127     "firstName": "test",
128     "phone": "",
129     "middleName": "a",
130     "position": "Engineer",
131     "username": "testUser",
132     "type": "Global Administrator",
133     "status": "Active",
134     "primaryGroup": 6,
135     "groups": [
136       0,
137       6,
138       8
139     ]
140   }
141  ]
142  */
143 UserManager.doGet = function (theRequestData) {
144   if (!context.getUser().isGlobalAdmin()) {
145     return UserManager.setStatus(
146       UserManager.errors.e403,
147       "Global Admin User Required"
148     );
149   }
150   var aUsers = [];
151   var aUser = findUser(theRequestData);
152   if (aUser !== null) {
153     aUsers.push(aUser);
154   }
155   if (!Boolean(theRequestData.username) && !Boolean(theRequestData.userId)) {
156     aUsers = findAllUsers();
157   }
158   return AdminUtils.jsArray(aUsers, function (theUser) {
159     return AdminUtils.jsUser(theUser);
160   });
161 };
162 
163 /**
164  * @name UserManager_POST
165  * @class Creates new users
166  * @description POST /wf/restapi/v2/admin/userManager: Creates new users or fails if the user already exists by the username.
167  *
168  * @param users An array of user objects to create. These objects should have the same structure as collected from UserManager_GET but without the "userId" attribute.
169  * @param [pretty=false] format the response to be human readable?
170  *
171  * @example POST /wf/restapi/v2/admin/userManager
172  * Body form-data:
173  * users =
174  [
175   {
176     "lastName": "user_last",
177     "substitutionMap": {},
178     "country": "USA",
179     "city": "Minneapolis",
180     "company": "",
181     "state": "",
182     "email": "",
183     "zip": "55401",
184     "ext": "",
185     "address2": "",
186     "address1": "",
187     "dept": "Engineering",
188     "firstName": "user",
189     "phone": "",
190     "middleName": "",
191     "position": "vertical",
192     "username": "user_1",
193     "type": "Global Administrator",
194     "status": "Active",
195     "primaryGroup": 6,
196     "groups": [
197       0,
198       6,
199       8
200     ]
201   },
202   {
203     "username": "user_2"
204   }
205  ]
206  * Response:
207  [
208   {
209     "lastName": "user_last",
210     "substitutionMap": {},
211     "country": "USA",
212     "city": "Minneapolis",
213     "company": "",
214     "state": "",
215     "email": "",
216     "zip": "55401",
217     "ext": "",
218     "address2": "",
219     "address1": "",
220     "dept": "Engineering",
221     "userId": 3,
222     "firstName": "user",
223     "phone": "",
224     "middleName": "",
225     "position": "",
226     "username": "user_1",
227     "type": "Global Administrator",
228     "status": "Active",
229     "groups": [
230       0,
231       6,
232       8
233     ]
234   },
235   {
236     "substitutionMap": {},
237     "userId": 4,
238     "username": "user_2",
239     "type": "General User",
240     "status": "Active",
241     "groups": []
242   }
243  ]
244  */
245 UserManager.doPost = function (theRequestData) {
246   if (!context.getUser().isGlobalAdmin()) {
247     return UserManager.setStatus(
248       UserManager.errors.e403,
249       "Global Admin User Required"
250     );
251   }
252   var aUsers = UserManager.massageToArray(theRequestData.users);
253   return AdminUtils.jsArray(aUsers, function (aUser) {
254     //theres no need to find a user by ID here
255     //we only want to create a user if it doesn't exist already
256     if (aUser.userId != null && aUser.userId != undefined) {
257       delete aUser.userId;
258     }
259     if (!Boolean(aUser.username)) {
260       return UserManager.setStatus(
261         UserManager.errors.e400,
262         "Username not provided"
263       );
264     }
265     var anExistingUser = findUser(aUser);
266     if (anExistingUser != null) {
267       var anError = UserManager.setStatus(
268         UserManager.errors.e400,
269         "User already exists"
270       );
271       anError.user = AdminUtils.jsUser(anExistingUser);
272       return anError;
273     }
274     var anUpdated;
275     try {
276       anUpdated = createOrUpdateUser(aUser, null);
277     } catch (anE) {
278       logger.error(anE + "\n" + anE.stack);
279       userManager.deleteUser(aUser.username);
280       return UserManager.setStatus(
281         UserManager.errors.e500,
282         "Failed to create user: " + anE.message
283       );
284     }
285     return AdminUtils.jsUser(anUpdated);
286   });
287 };
288 
289 /**
290  * @name UserManager_PUT
291  * @class Creates or updates new users
292  * @description PUT /wf/restapi/v2/admin/userManager: Creates new users or overwrites the user with the provided user object
293  *
294  * @param users An array of user objects to create or update. These objects should have the same structure as collected from UserManager_GET.
295  * If you are creating a new user the "userId" attribute is not required, but it is required to update an existing user.
296  * @param [pretty=false] format the response to be human readable?
297  *
298  * @example PUT /wf/restapi/v2/admin/userManager  (Creating new users)
299  * Body form-data:
300  * users =
301  [
302   {
303     "lastName": "user_last",
304     "substitutionMap": {},
305     "country": "USA",
306     "city": "Minneapolis",
307     "company": "",
308     "state": "",
309     "email": "",
310     "zip": "55401",
311     "ext": "",
312     "address2": "",
313     "address1": "",
314     "dept": "Engineering",
315     "firstName": "user",
316     "phone": "",
317     "middleName": "",
318     "position": "vertical",
319     "username": "user_1",
320     "type": "Global Administrator",
321     "status": "Active",
322     "primaryGroup": 6,
323     "groups": [
324       0,
325       6,
326       8
327     ]
328   },
329   {
330     "username": "user_2"
331   }
332  ]
333  * Response:
334  [
335   {
336     "lastName": "user_last",
337     "substitutionMap": {},
338     "country": "USA",
339     "city": "Minneapolis",
340     "company": "",
341     "state": "",
342     "email": "",
343     "zip": "55401",
344     "ext": "",
345     "address2": "",
346     "address1": "",
347     "dept": "Engineering",
348     "userId": 3,
349     "firstName": "user",
350     "phone": "",
351     "middleName": "",
352     "position": "",
353     "username": "user_1",
354     "type": "Global Administrator",
355     "status": "Active",
356     "groups": [
357       0,
358       6,
359       8
360     ]
361   },
362   {
363     "substitutionMap": {},
364     "userId": 4,
365     "username": "user_2",
366     "type": "General User",
367     "status": "Active",
368     "groups": []
369   }
370  ]
371 
372  * @example PUT /wf/restapi/v2/admin/userManager  (Updating a user(user_1 id:3) from the last example. city, username, groups are updated)
373  * Body form-data:
374  * users =
375  [
376   {
377     "lastName": "user_last",
378     "substitutionMap": {},
379     "country": "USA",
380     "city": "Minneapolis",
381     "company": "",
382     "state": "Minnesota",
383     "email": "",
384     "zip": "55401",
385     "ext": "",
386     "address2": "",
387     "address1": "",
388     "dept": "Engineering",
389     "userId": 3,
390     "firstName": "user",
391     "phone": "",
392     "middleName": "",
393     "position": "vertical",
394     "username": "user 1",
395     "type": "Global Administrator",
396     "status": "Active",
397     "primaryGroup": 6,
398     "groups": [
399       0,
400       6
401     ]
402   }
403  ]
404  * Response:
405  [
406   {
407     "lastName": "user_last",
408     "substitutionMap": {},
409     "country": "USA",
410     "city": "Minneapolis",
411     "company": "",
412     "state": "Minnesota",
413     "email": "",
414     "zip": "55401",
415     "ext": "",
416     "address2": "",
417     "address1": "",
418     "dept": "Engineering",
419     "userId": 3,
420     "firstName": "user",
421     "phone": "",
422     "middleName": "",
423     "position": "",
424     "username": "user 1",
425     "type": "Global Administrator",
426     "status": "Active",
427     "groups": [
428       0,
429       6
430     ]
431   }
432  ]
433  */
434 UserManager.doPut = function (theRequestData) {
435   if (!context.getUser().isGlobalAdmin()) {
436     return UserManager.setStatus(
437       UserManager.errors.e403,
438       "Global Admin User Required"
439     );
440   }
441   var aUsers = UserManager.massageToArray(theRequestData.users);
442   return AdminUtils.jsArray(aUsers, function (aUser) {
443     var anUpdated;
444     try {
445       anUpdated = createOrUpdateUser(
446         aUser,
447         aUser
448       );
449     } catch (anE) {
450       logger.error(anE + "\n" + anE.stack);
451       return UserManager.setStatus(UserManager.errors.e500, anE.message);
452     }
453     return AdminUtils.jsUser(anUpdated);
454   });
455 };
456 
457 /**
458  * @name UserManager_DELETE
459  * @class Removes users
460  * @description  DELETE /wf/restapi/v2/admin/userManager: Removes users from MediaBeacon
461  * @param users An array of user objects to remove. These objects can have the same structure as collected from UserManager_GET, but only require "userId" or "username".
462  * @param [pretty=false] format the response to be human readable?
463  *
464  * @example DELETE /wf/restapi/v2/admin/userManager
465  * Body form-data:
466  * users =
467  [
468   {
469     "lastName": "user_last",
470     "substitutionMap": {},
471     "country": "USA",
472     "city": "Minneapolis",
473     "company": "",
474     "state": "Minnesota",
475     "email": "",
476     "zip": "55401",
477     "ext": "",
478     "address2": "",
479     "address1": "",
480     "dept": "Engineering",
481     "userId": 3,
482     "firstName": "user",
483     "phone": "",
484     "middleName": "",
485     "position": "vertical",
486     "username": "user 1",
487     "type": "Global Administrator",
488     "status": "Active",
489     "primaryGroup": 6,
490     "groups": [
491       0,
492       6
493     ]
494   },
495   {
496     "username": "user_2"
497   },
498   {
499     "userId": "5"
500   }
501  ]
502  * Response:
503  [
504   {
505     "lastName": "user_last",
506     "country": "USA",
507     "city": "Minneapolis",
508     "company": "",
509     "state": "Minnesota",
510     "email": "",
511     "zip": "55401",
512     "ext": "",
513     "address2": "",
514     "address1": "",
515     "dept": "Engineering",
516     "userId": 3,
517     "firstName": "user",
518     "phone": "",
519     "middleName": "",
520     "position": "",
521     "username": "user 1",
522     "type": null,
523     "status": "",
524     "groups": []
525   },
526   {
527     "lastName": "",
528     "country": "",
529     "city": "",
530     "company": "",
531     "state": "",
532     "email": "",
533     "zip": "",
534     "ext": "",
535     "address2": "",
536     "address1": "",
537     "dept": "",
538     "userId": 4,
539     "firstName": "",
540     "phone": "",
541     "middleName": "",
542     "position": "",
543     "username": "user_2",
544     "type": null,
545     "status": "",
546     "groups": []
547   },
548   {
549     "userId": 5,
550     "username": "removebyid",
551     "type": null,
552     "status": "",
553     "groups": []
554   }
555  ]
556  */
557 UserManager.doDelete = function (theRequestData) {
558   if (!context.getUser().isGlobalAdmin()) {
559     return UserManager.setStatus(
560       UserManager.errors.e403,
561       "Global Admin User Required"
562     );
563   }
564   var aUsers = UserManager.massageToArray(theRequestData.users);
565   return AdminUtils.jsArray(aUsers, function (aUser) {
566     var anExistingUser = findUser(aUser);
567     if (anExistingUser == null) {
568       //user is already deleted. do nothing
569       return null;
570     }
571     try {
572       userManager.deleteUser(anExistingUser.username);
573     } catch (anE) {
574       logger.error(anE + "\n" + anE.stack);
575       var anError = UserManager.setStatus(UserManager.errors.e500, anE.message);
576       anError.user = AdminUtils.jsUser(anExistingUser, true);
577       return anError;
578     }
579     return AdminUtils.jsUser(anExistingUser);
580   });
581 };
582 
583 UserManager.run();
584 
585 /**
586  * Find a user by its userId or username in the data object
587  * @param theData
588  * @returns {*}
589  */
590 function findUser(theData) {
591   if (theData.userId != undefined && theData.userId != null) {
592     return userManager.findByUserId(theData.userId);
593   } else if (!!theData.username) {
594     return userManager.findUserByUsername(theData.username);
595   }
596   return null;
597 }
598 
599 function findAllUsers() {
600   var aUserIds = [];
601   new SQL().query("SELECT j9c_user_id FROM j9t_user", function (theData) {
602     aUserIds.push(theData["j9c_user_id"]);
603   });
604   for (var i in aUserIds) {
605     aUserIds[i] = userManager.findByUserId(aUserIds[i]);
606   }
607   return aUserIds;
608 }
609 
610 function createOrUpdateUser(theJsUser, theUserInMB) {
611 	var aUserInMB = null;
612   if (theUserInMB != null)
613   {
614 	  aUserInMB = userManager.findByUserId(theUserInMB.userId);
615 	  if (aUserInMB == null)
616 	  {
617 		  aUserInMB = userManager.findUserByUsername(theUserInMB.username);
618 	  }
619   }
620   if (aUserInMB != null && theJsUser.username == null)
621   {
622 	  theJsUser.username = aUserInMB.username;
623   }
624   theUserInMB = aUserInMB == null ? userManager.createUser(theJsUser.username, generateUUID()) : aUserInMB;
625   //Set user data
626   var aSetters = [
627     "firstName",
628     "middleName",
629     "lastName",
630     "address2",
631     "address1",
632     "city",
633     "state",
634     "email",
635     "zip",
636     "ext",
637     "dept",
638     "userId",
639     "phone",
640     "country",
641     "company",
642     "position",
643 	"status",
644   ];
645   var aModified = false;
646   for (var anAttribute in theJsUser) {
647     if (aSetters.indexOf(anAttribute) < 0) {
648       continue;
649     }
650     if (theUserInMB[anAttribute] !== theJsUser[anAttribute]) {
651       theUserInMB[anAttribute] = theJsUser[anAttribute];
652       aModified = true;
653     }
654   }
655   if (aModified) {
656     theUserInMB.updateContactInfo();
657   }
658   if (theJsUser.type != undefined && theJsUser.type !== theUserInMB.getType()) {
659     theUserInMB.setType(theJsUser.type);
660   }
661   if (
662     theJsUser.status != undefined &&
663     theJsUser.status !== theUserInMB.getStatus()
664   ) {
665     theUserInMB.setStatus(theJsUser.status);
666   }
667   if (theJsUser.username !== theUserInMB.username) {
668     userManager.renameUser(theUserInMB, theJsUser.username);
669     theUserInMB = userManager.findByUserId(theUserInMB.userId);
670   }
671   var aPrimaryGroupId =
672     theUserInMB.getPrimaryGroup() != null
673       ? theUserInMB.getPrimaryGroup().id
674       : undefined;
675   if (
676     theJsUser.primaryGroup != undefined &&
677     theJsUser.primaryGroup !== aPrimaryGroupId
678   ) {
679     var aNewPrimary = groupManager.findGroupById(theJsUser.primaryGroup);
680     userManager.setPrimaryGroup(theUserInMB, aNewPrimary.name);
681     theUserInMB = userManager.findByUserId(theUserInMB.userId);
682   }
683   var aModifiedGroups = AdminUtils.resolveArrayDifferences(
684     theJsUser.groups,
685     AdminUtils.jsArray(theUserInMB.getGroups(), function (theGroup) {
686       return theGroup.id;
687     }),
688     function (theGroupToAdd) {
689       userManager.addToGroup(
690         theUserInMB.username,
691         groupManager.findGroupById(theGroupToAdd).name
692       );
693     },
694     function (theGroupToRemove) {
695       userManager.removeFromGroup(
696         theUserInMB.username,
697         groupManager.findGroupById(theGroupToRemove).name
698       );
699     }
700   );
701   if (aModifiedGroups) {
702     //Update the user if we've made changes
703     theUserInMB = userManager.findByUserId(theUserInMB.userId);
704   }
705   return theUserInMB;
706 }
707