Source:permissionService.js

/**
 * Angular Perms
 * Copyright 2016 Andreas Stocker
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
 * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
(function () {
    'use strict';
    var
        module = angular.module('ngPerms');
    /**
     * Provider for the PermissionService
     *
     * @name PermissionServiceProvider
     * @ngdoc provider
     */
    module.provider('PermissionService',
        function () {
            'ngInject';
            var
                provider = this,
                /**
                 * List of services to get permission from.
                 * @private
                 * @memberOf PermissionServiceProvider
                 * @type {Array}
                 */
                permissionGetters = [];
            /**
             * Registers a new permission getter function to get permissions from.
             * @memberOf PermissionServiceProvider
             * @param {Function} permissionGetterFn
             */
            provider.registerPermissionGetter = function (permissionGetterFn) {
                if (permissionGetters.indexOf(permissionGetterFn) !== -1) {
                    console.warn("PermissionServiceProvider: Given permission getter is already registered.");
                    return;
                }
                console.log("PermissionServiceProvider: Register new permission getter.");
                permissionGetters.push(permissionGetterFn);
            };
            /**
             * Unregisters a registered permission getter function.
             * @memberOf PermissionServiceProvider
             * @param {Function} permissionGetterFn
             */
            provider.unregisterPermissionGetter = function (permissionGetterFn) {
                var
                    getterIndex = permissionGetters.indexOf(permissionGetterFn),
                    getterFound = getterIndex !== -1;
                if (!getterFound) {
                    console.warn("PermissionServiceProvider: Given permission getter is not registered.");
                    return;
                }
                console.log("PermissionServiceProvider: Unregister given permission getter.");
                permissionGetters.splice(getterIndex, 1);
            };
            /**
             * Gets the actual service object.
             * @name PermissionService
             * @ngdoc factory
             * @returns {Object}
             */
            provider.$get = function ($rootScope) {
                'ngInject';
                var
                    self = {},
                    /**
                     * Prototype of all angular scopes.
                     * @private
                     * @memberOf PermissionService
                     * @type {Object}
                     */
                    scopePrototype = Object.getPrototypeOf($rootScope),
                    /**
                     * Mapping for permission aliases to permission check functions.
                     * @private
                     * @memberOf PermissionService
                     * @type {{}}
                     */
                    permMapping = {};
                /**
                 * Defines a permission alias used in the UI
                 * @memberOf PermissionService
                 * @param name
                 * @param perms
                 * @return {*}
                 */
                self.define = function (name, perms) {
                    console.log("PermissionService: Define permission alias '" + name + "'.");
                    // make sure we are working on an array of permissions
                    perms = angular.isArray(perms) ? perms : [perms];
                    var
                        /**
                         * Checks if all permission conditions validate to true. A permission
                         * condition can either be a function or a string (permission name).
                         * @return {boolean}
                         */
                        checkFn = function (args) {
                            for (var i = 0; i < perms.length; i++) {
                                var
                                    perm = perms[i];
                                // if perm is a function, call it with the PermissionService
                                // as a first argument.
                                if (angular.isFunction(perm)) {
                                    if (!perm.apply(self, args)) {
                                        return false;
                                    }
                                }
                                // if perm is a string, use the has method to check for the
                                // permission. this checks for other permission aliases, or
                                // backend permissions.
                                else if (angular.isString(perm)) {
                                    if (!self.has(perm)) {
                                        return false;
                                    }
                                }
                                // if perm is neither a string nor a function, default
                                // to false.
                                else {
                                    console.error("PermissionService: Given permission condition is neither a function nor a string.");
                                    return false;
                                }
                            }
                            return true;
                        };
                    // publish the permission alias in the mapping
                    permMapping[name] = checkFn;
                    return self;
                };
                /**
                 * Checks if the currently logged in user has permission for the given permission alias.
                 * @memberOf PermissionService
                 * @param name
                 * @return {boolean}
                 */
                self.has = function (name) {
                    console.log("PermissionService: Check permission '" + name + "'.");
                    var
                        args = Array.prototype.slice.call(arguments, 1),
                        i;
                    // check if the asked permission alias exists. if not, check
                    // the registered permission getters. if any of them grands the
                    // permission, the check is passed.
                    if (!permMapping.hasOwnProperty(name)) {
                        for (i = 0; i < permissionGetters.length; i++) {
                            if (permissionGetters[i](name)) {
                                return true;
                            }
                        }
                        return false;
                    }
                    return !!permMapping[name](args);
                };
                /*
                 * Publish the register and unregister methods for permission getters on
                 * the service as well.
                 */
                self.registerPermissionGetter = provider.registerPermissionGetter;
                self.unregisterPermissionGetter = provider.unregisterPermissionGetter;
                /*
                 * Publish permission function on the root scope prototype so they are available in
                 * all templates.
                 */
                scopePrototype.perms = {};
                scopePrototype.perms.has = self.has;
                return self;
            }
        }
    );
})();