Source: roles-dal.js

const {Role, Permission, Op} = require('../sequelize-model'),
    {rbac} = require('../../common/config/config'),
    tryCatch = require('../../common/util/functions-utils');

const getSpecificById = roleId => tryCatch(() => Role.findByPk(roleId));

/**
 * @module
 */
module.exports = {

    /**
     * Creates a new role with a possible role Hierarchy, if the role already exists returns the existing one.
     * @param {string} role
     * @returns {Promise<void>}
     */
    create: async (role, parent_role) => tryCatch(async () => {
        await rbac.createRole(role, true);
        if (parent_role) {
            await rbac.grantByName((await getSpecificById(parent_role)).role, role);
        }
        return (await Role.findOrCreate({defaults: {parent_role}, where: {role}}))[0];
    }),
    /**
     * Changes the parent role of the Role specified by the id, the parent_role parameter should be an object containing a field label which contains the name of the parent role
     * and field value which contains the id of the parent role. Ex: role.update(3,{label:'admin',value:1});
     * @param {int} id
     * @param {int} parent_role
     * @returns {Promise<{insertedRows: (Object|Error), parent_role: *}>}
     */
    update: async (id, parent_role) => {
        const rbacRole = getSpecificById(id).then(({role})=>rbac.getRole(role));
        rbac.grant(await rbac.getRole(parent_role.label), await rbacRole);
        return Promise.resolve({insertedRows: await tryCatch(() => Role.update({parent_role: parent_role.value}, {where: {id}})), parent_role});
    },


    /**
     * Returns a specific role by its id
     * @param {int} roleId
     * @returns {Promise<*>}
     */
    getSpecificById,

    /**
     * Returns all roles that own a parent_role
     * @returns {Promise<Object|Error>}
     */
    getWithParents: () => tryCatch(() => Role.findAll({where: {parent_role: {[Op.ne]: null}}})),

    /**
     *  Returns a role by its name
     * @param {string} roleName
     * @returns {Promise<Object|Error>}
     */
    getByName: roleName => tryCatch(() => Role.findOne({where: {role: roleName}})),
    /**
     * Delete a specific role by its roleId
     * @param {int} roleId
     * @returns {Promise<void>}
     */
    delete: async roleId =>
        tryCatch(async () => {
            await getSpecificById(roleId).then(({role})=>rbac.removeByName(role));
            return Promise.resolve({deletedRows: await Role.destroy({where: {id: roleId}})});
        }),
    /**
     * Returns all roles
     * @returns {Promise<void>}
     */
    get: () => tryCatch(() => Role.findAll({raw: true})),
    /**
     * Changes the parent role of the given Role, the parentRole parameter should be an object containing a field role which contains the name of the parent role and field id
     * which contains the id of the parent role, the parameter role should be an object containing a field role with the role name and a field id with the role's id.
     * Ex: role.addParentRole({role:'develloper',id:3},{role:'admin',id:1});
     * @param {string} role
     * @param {int} parentRole
     * @returns {Promise<Object|Error>}
     */
    addParentRole: (role, parentRole) => tryCatch(async () => {
        rbac.grant(await rbac.getRole(parentRole.role), await rbac.getRole(role.role));
        return Role.update({parent_role: parentRole.id}, {where: {id: role.id,}});
    }),

};