Built motion from commit 9e1399f3.|2.5.37
[motion2.git] / public / tvox / js / auth.service.js
1 (function() {
2   'use strict';
3
4   angular.module('motion.auth', []).factory('Auth', AuthService);
5
6   /** @ngInject */
7   function AuthService($mdDialog, $cookies, $q, $window, $document, api) {
8     var motionCurrentUser;
9
10     var service = {
11       getToken: getToken,
12       getCurrentUser: getCurrentUser,
13       getPermissions: getPermissions,
14       hasChildrenPermissions: hasChildrenPermissions,
15       hasModulePermissions: hasModulePermissions,
16       hasModulesPermissions: hasModulesPermissions,
17       hasRole: hasRole,
18       hasPermission: hasPermission,
19       hasResourcePermission: hasResourcePermission,
20       hasSectionPermissions: hasSectionPermissions,
21       hasSectionsPermissions: hasSectionsPermissions,
22       isAgent: isAgent,
23       isAdmin: isAdmin,
24       isLoggedIn: isLoggedIn,
25       isTelephone: isTelephone,
26       isUser: isUser,
27       login: login,
28       logout: logout,
29       parseCrudPermissions: parseCrudPermissions,
30       queueLogin: queueLogin,
31       reloadPermissions: reloadPermissions,
32       removeCookies: removeCookies,
33       retrieveUser: retrieveUser,
34       setCurrentUser: setCurrentUser,
35       getAuthenticationType: getAuthenticationType,
36       loginSSO: loginSSO
37     };
38
39     return service;
40
41     /**
42      * Gets the authorization token
43      * @return {Object} Authorization token
44      */
45     function getToken() {
46       return $cookies.get('motion.token');
47     }
48
49     /**
50      * Gets the currently logged in user
51      * @return {Object} The currently logged in user
52      */
53     function getCurrentUser() {
54       return motionCurrentUser;
55     }
56
57     /**
58      * Sets the currently logged in user
59      * @param {Object} user - The currently logged in user
60      */
61     function setCurrentUser(user) {
62       motionCurrentUser = _.merge(motionCurrentUser, user);
63     }
64
65     /**
66      * Adds an agent to the queues
67      * @param {Object} intrf - The agent interface
68      * @return {Object} Updated user
69      */
70     function queueLogin(intrf) {
71       return $q(function(resolve, reject) {
72         api.user
73           .login({
74             id: motionCurrentUser.id,
75             device: 'web',
76             intrf: intrf
77           })
78           .$promise.then(function(user) {
79             resolve(user);
80           })
81           .catch(function(err) {
82             reject(err);
83           });
84       });
85     }
86
87     /**
88      * Removes an agent from the queues
89      */
90     function queueLogout() {
91       return $q(function(resolve, reject) {
92         api.user
93           .logout({
94             id: motionCurrentUser.id,
95             device: 'web'
96           })
97           .$promise.then(function() {
98             resolve();
99           })
100           .catch(function(err) {
101             reject(err);
102           });
103       });
104     }
105
106     /**
107      * Sets the user's online status if the role is 'admin' or 'user'
108      * @return {Object} Updated user
109      */
110     function setOnlineStatus(status) {
111       return $q(function(resolve, reject) {
112         var data = {
113           online: status,
114           lastLoginAt: status ? moment().format('YYYY-MM-DD HH:mm:ss') : undefined
115         };
116         api.user
117           .update({
118               id: motionCurrentUser.id
119             },
120             data
121           )
122           .$promise.then(function(user) {
123             resolve(user);
124           })
125           .catch(function(err) {
126             reject(err);
127           });
128       });
129     }
130
131     /**
132      * Authenticate user and save token
133      * @param  {Object} user - The user which requires authentication
134      * @return {Promise}
135      */
136     function login(user) {
137       return $q(function(resolve, reject) {
138         api.auth
139           .local(user)
140           .$promise.then(function(res) {
141             console.log("RES", res.token);
142             $cookies.put('motion.token', res.token, {
143               secure: true,
144               samesite: 'strict'
145             });
146
147             return api.user.get({
148               id: res.id
149             }).$promise;
150           })
151           .then(function(user) {
152             motionCurrentUser = user;
153             motionCurrentUser.lastLoginAt = moment().format('YYYY-MM-DD HH:mm:ss');
154             setAuthenticationType('LOCAL_LOGIN');
155           })
156           .then(function() {
157             if (isAgent() && motionCurrentUser.showWebBar === 1 && motionCurrentUser.hotdesk) {
158               return $mdDialog.show({
159                 controller: 'HotDeskDialogController',
160                 controllerAs: 'vm',
161                 templateUrl: 'app/auth/services/hotdesk/dialog.html',
162                 parent: angular.element($document.body),
163                 clickOutsideToClose: false,
164                 resolve: {
165                   telephones: function(apiResolver) {
166                     return apiResolver.resolve('user@get', {
167                       fields: 'id,fullname,name,internal',
168                       role: 'telephone',
169                       nolimit: true
170                     });
171                   }
172                 }
173               });
174             }
175           })
176           .then(function(intrf) {
177             if (isAgent() && motionCurrentUser.showWebBar !== 0) {
178               return queueLogin(intrf);
179             } else if (isAdmin() || isUser()) {
180               return setOnlineStatus(true);
181             } else {
182               return;
183             }
184           })
185           .then(function(updatedUser) {
186             motionCurrentUser = _.assign(motionCurrentUser, updatedUser);
187             resolve();
188           })
189           .catch(function(err) {
190             reject(err);
191           });
192       });
193     }
194
195     /**
196      * Removes authentication cookies and local storage data
197      */
198     function removeCookies() {
199       $cookies.remove('motion.token');
200       if (motionCurrentUser) {
201         $window.localStorage.removeItem('motion.user:' + motionCurrentUser.id);
202         $window.localStorage.removeItem('motion.authenticationtype');
203
204         motionCurrentUser = null;
205       }
206     }
207
208     /**
209      * Delete access token and user info
210      * @param {Boolean} logoutBySomeoneElse Flag to discriminate who initiated the logout
211      */
212     function logout(logoutBySomeoneElse) {
213       return $q(function(resolve, reject) {
214         if (logoutBySomeoneElse) {
215           removeCookies();
216           resolve();
217         } else {
218           $q.resolve()
219             .then(function() {
220               if (isAgent() && motionCurrentUser.showWebBar !== 0) {
221                 return queueLogout();
222               } else if (isAdmin() || isUser()) {
223                 return setOnlineStatus(false);
224               } else {
225                 return;
226               }
227             })
228             .then(function() {
229               removeCookies();
230               resolve();
231             })
232             .catch(function(err) {
233               reject(err);
234             });
235         }
236       });
237     }
238
239     /**
240      * Checks if a user is logged by retrieving the authentication token
241      * @return {Boolean}
242      */
243     function isLoggedIn() {
244       return getToken() ? true : false;
245     }
246
247     /**
248      * Checks if an user is an 'agent'
249      * @return {Boolean}
250      */
251     function isAgent() {
252       return motionCurrentUser.role === 'agent';
253     }
254
255     /**
256      * Checks if an user is an 'admin'
257      * @return {Boolean}
258      */
259     function isAdmin() {
260       return motionCurrentUser.role === 'admin';
261     }
262
263     /**
264      * Checks if an user is an 'user'
265      * @return {Boolean}
266      */
267     function isUser() {
268       return motionCurrentUser.role === 'user';
269     }
270
271     /**
272      * Checks if an user is a 'telephone'
273      * @return {Boolean}
274      */
275     function isTelephone() {
276       return motionCurrentUser.role === 'telephone';
277     }
278
279     /**
280      * Retrieves the current logged in user
281      * @return {Boolean}
282      */
283     function retrieveUser() {
284       return $q(function(resolve, reject) {
285         api.user
286           .whoami()
287           .$promise.then(function(user) {
288             if (user.role === 'user') {
289               return getPermissions(user.userProfileId).then(function(permissions) {
290                 user.permissions = permissions;
291                 return user;
292               });
293             } else {
294               return user;
295             }
296           })
297           .then(function(user) {
298             motionCurrentUser = user;
299             resolve(motionCurrentUser);
300           })
301           .catch(function(err) {
302             reject(err);
303           });
304       });
305     }
306
307     /**
308      * Checks if a user has a specified role
309      * @param  {String} role - The role to check against
310      * @return {Boolean}
311      */
312     function hasRole(role) {
313       return motionCurrentUser ? motionCurrentUser.role === role : false;
314     }
315
316     /**
317      * Check if a user has a specified permissions
318      * @param  {String} id - The section id to verify
319      * @return {Boolean}
320      */
321     function hasPermission(id) {
322       return motionCurrentUser ? _.includes(motionCurrentUser.permissions, id) : false;
323     }
324
325     /**
326      * Get permissions from User Profile
327      * @param  {Integer} userProfileId - The id of the User Profile to
328      */
329     function getPermissions(userProfileId) {
330       var permissions = [];
331
332       return $q(function(resolve, reject) {
333         if (!userProfileId) {
334           resolve(permissions);
335         }
336
337         return api.userProfile
338           .getSections({
339             id: userProfileId
340           })
341           .$promise.then(function(sections) {
342             for (var i = 0; i < sections.length; i++) {
343               var item = sections[i];
344               permissions.push(item.sectionId);
345               if (item.subsections) {
346                 permissions = _.concat(permissions, item.subsections);
347               }
348             }
349
350             return permissions;
351           })
352           .then(function(permissions) {
353             resolve(permissions);
354           })
355           .catch(function(err) {
356             reject('Error retrieving user profile permissions', err);
357           });
358       });
359     }
360
361     /**
362      * Determine if a section should be visible because of the visibility of one of its subsections
363      * @param {Array} ids The list of subsections ids
364      */
365     function hasChildrenPermissions(ids) {
366       if (!ids) return false;
367
368       return _.some(ids, function(id) {
369         return hasPermission(id);
370       });
371     }
372
373     /**
374      * Reload permissions for the current user on a page reload
375      *
376      */
377     function reloadPermissions() {
378       return $q(function(resolve, reject) {
379         getPermissions(motionCurrentUser.userProfileId)
380           .then(function(permissions) {
381             motionCurrentUser.permissions = permissions;
382             resolve();
383           })
384           .catch(function(err) {
385             reject(err);
386           });
387       });
388     }
389
390     /**
391      * Parse the crud permissions
392      * @param {String} crudPermissions The crud permissions as stored on the database (red : Read | Edit | Delete)
393      */
394     function parseCrudPermissions(crudPermissions) {
395       if (isAdmin()) {
396         return {
397           readOnly: false,
398           canEdit: true,
399           canDelete: true
400         };
401       } else {
402         if (!crudPermissions) {
403           return {
404             readOnly: true,
405             canEdit: false,
406             canDelete: false
407           };
408         } else {
409           return {
410             readOnly: _.includes(crudPermissions, 'r') && crudPermissions.length === 1 ? true : false,
411             canEdit: _.includes(crudPermissions, 'e') ? true : false,
412             canDelete: _.includes(crudPermissions, 'd') ? true : false
413           };
414         }
415       }
416     }
417
418     /**
419      * Check if the user has valid permission on a specific resource
420      * @param {Number} sectionId The id of the parent section
421      * @param {Number} resourceId The id of the resource to check
422      */
423     function hasResourcePermission(sectionId, resourceId) {
424       return $q(function(resolve, reject) {
425         return api.userProfileSection
426           .get({
427             userProfileId: motionCurrentUser.userProfileId,
428             sectionId: sectionId
429           })
430           .$promise.then(function(entities) {
431             var section = entities.rows[0];
432             // If AutoAssociation is enabled it means that all resources are available
433             if (section.autoAssociation) return resolve();
434             // Checking if the current section does not require single resource association
435             var navigationItem = msNavigationService.getActiveItem().node;
436             if (navigationItem.permissions && navigationItem.permissions.association === false) return resolve();
437             // Retrieving sections's associated resources
438             return api.userProfileResource
439               .get({
440                 sectionId: section.id,
441                 nolimit: true
442               })
443               .$promise.then(function(entities) {
444                 var resources = entities.rows;
445                 _.some(resources, ['resourceId', resourceId]) ? resolve() : reject();
446               });
447           })
448           .catch(function(err) {
449             reject('Error retrieving user profile permissions', err);
450           });
451       });
452     }
453
454     /**
455      * Check if the user has valid permission on a section
456      * @param {Integer} id The section id
457      */
458     function hasSectionPermissions(id) {
459       return $q(function(resolve, reject) {
460         var data = {};
461         return reloadPermissions()
462           .then(function() {
463             if (_.includes(motionCurrentUser.permissions, id)) {
464               data[id] = true;
465             }
466             resolve(data);
467           })
468           .catch(function(err) {
469             reject(err);
470           });
471       });
472     }
473
474     /**
475      * Check if the user has valid permission on all the sections specified
476      * @param {Array} sections The ids of the sections
477      * @return {Object} Object with each section as key
478      */
479     function hasSectionsPermissions(sections) {
480       return $q(function(resolve, reject) {
481         var data = {};
482
483         if (isAdmin()) {
484           sections.forEach(function(key) {
485             data[key] = true;
486           });
487           resolve(data);
488         } else {
489           return reloadPermissions()
490             .then(function() {
491               sections.forEach(function(id) {
492                 if (_.includes(motionCurrentUser.permissions, id)) {
493                   data[id] = true;
494                 }
495               });
496               resolve(data);
497             })
498             .catch(function(err) {
499               reject(err);
500             });
501         }
502       });
503     }
504
505     /**
506      * Check if the user has valid permissions on at least one section of a module
507      * @param {String} category The category name
508      */
509     function hasModulePermissions(category) {
510       return $q(function(resolve, reject) {
511         if (isAdmin()) {
512           resolve(true);
513         } else {
514           api.userProfileSection
515             .get({
516               userProfileId: motionCurrentUser.userProfileId
517             })
518             .$promise.then(function(entities) {
519               var sections = entities && entities.rows ? entities.rows : [];
520               if (!_.isEmpty(sections)) {
521                 var enabledSections = _.filter(sections, function(section) {
522                   return section.enabled;
523                 });
524                 resolve(_.some(enabledSections, ['category', category]));
525               } else {
526                 resolve(false);
527               }
528             })
529             .catch(function(err) {
530               reject(err);
531             });
532         }
533       });
534     }
535
536     /**
537      * Check if the user has valid permissions on at least one section for each module
538      * @param {Array} categories The categories' names
539      * @return {Object} Object with each module as key
540      */
541     function hasModulesPermissions(categories) {
542       return $q(function(resolve, reject) {
543         var data = {};
544
545         if (isAdmin()) {
546           categories.forEach(function(key) {
547             data[key] = true;
548           });
549           resolve(data);
550         } else {
551           api.userProfileSection
552             .get({
553               userProfileId: motionCurrentUser.userProfileId
554             })
555             .$promise.then(function(entities) {
556               var sections = entities && entities.rows ? entities.rows : [];
557               if (!_.isEmpty(sections)) {
558                 var enabledCategories = _(sections)
559                   .filter(function(section) {
560                     return section.enabled && _.includes(categories, section.category);
561                   })
562                   .uniqBy(function(section) {
563                     return section.category;
564                   })
565                   .map(function(section) {
566                     return section.category;
567                   })
568                   .value();
569
570                 enabledCategories.forEach(function(key) {
571                   data[key] = true;
572                 });
573                 resolve(data);
574               } else {
575                 resolve({});
576               }
577             })
578             .catch(function(err) {
579               reject(err);
580             });
581         }
582       });
583     }
584
585     /**
586      * Return authentication type choose by user
587      */
588     function getAuthenticationType() {
589       return $window.localStorage['motion.authenticationtype'] || 'NONE';
590     }
591
592     function setAuthenticationType(authenticationType) {
593       $window.localStorage['motion.authenticationtype'] = authenticationType;
594     }
595
596     function loginSSO(provider) {
597       setAuthenticationType('SSO_LOGIN');
598       return '/api/auth/' + provider;
599     }
600   }
601 })();