diff --git a/back/models/specs/mailAliasAccount.spec.js b/back/models/specs/mailAliasAccount.spec.js new file mode 100644 index 0000000000..46d447f901 --- /dev/null +++ b/back/models/specs/mailAliasAccount.spec.js @@ -0,0 +1,73 @@ +const models = require('vn-loopback/server/server').models; + +fdescribe('loopback model MailAliasAccount', () => { + it('should fail to add a mail Alias if the worker doesnt have ACLs', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 1}}; + await models.MailAliasAccount.create({mailAliasFk: 2, roleFk: 5}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual('The alias cant be modified'); + }); + + it('should add a mail Alias', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 9}}; + await models.MailAliasAccount.create({mailAliasFk: 2, roleFk: 5}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toBeUndefined(); + }); + + it('should add a mail Alias of an inherit role', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 9}}; + await models.MailAliasAccount.create({mailAliasFk: 3, roleFk: 5}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toBeUndefined(); + }); + + it('should delete a mail Alias', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 1}}; + const mailAclId = 2; + await models.MailAliasAccount.destroyAll({id: mailAclId}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toBeUndefined(); + }); +}); + diff --git a/db/changes/235001/00-aclsMails.sql b/db/changes/235001/00-aclsMails.sql index 92603aec48..5cfea40301 100644 --- a/db/changes/235001/00-aclsMails.sql +++ b/db/changes/235001/00-aclsMails.sql @@ -1,5 +1,6 @@ -- Definición de la tabla mailAliasACL -CREATE TABLE `account`.`mailAliasACL` ( + +CREATE OR REPLACE TABLE `account`.`mailAliasAcl` ( `mailAliasFk` int(10) unsigned NOT NULL, `roleFk` int(10) unsigned NOT NULL, FOREIGN KEY (`mailAliasFk`) REFERENCES `account`.`mailAlias` (`id`), diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 93b7b796f1..62f96b459f 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -3002,3 +3002,10 @@ INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`) (1, 'Error in VAT calculation'), (2, 'Error in sales details'), (3, 'Error in customer data'); + +INSERT INTO `account`.`mailAliasAcl` (`mailAliasFk`, `roleFk`) + VALUES + (1, 1), + (2, 9), + (3, 15); + diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml index 96c34d98ca..1b9bbb40b3 100644 --- a/front/core/locale/es.yml +++ b/front/core/locale/es.yml @@ -68,3 +68,4 @@ Load more results: Cargar más resultados Send cau: Enviar cau By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc ExplainReason: Explique el motivo por el que no deberia aparecer este fallo +You already have the mailAlias: Ya tienes este mail diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 01384efb42..2e516bf120 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -329,5 +329,7 @@ "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mínima", "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima", "Cannot past travels with entries": "No se pueden pasar envíos con entradas", - "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}" + "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}", + "You already have the mailAlias": "You already have the mailAlias", + "The alias cant be modified": "The alias cant be modified" } \ No newline at end of file diff --git a/modules/account/back/model-config.json b/modules/account/back/model-config.json index b4bd6dbafd..0cd43d0cec 100644 --- a/modules/account/back/model-config.json +++ b/modules/account/back/model-config.json @@ -14,6 +14,9 @@ "MailAliasAccount": { "dataSource": "vn" }, + "MailAliasAcl": { + "dataSource": "vn" + }, "MailConfig": { "dataSource": "vn" }, diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js index 6f5213f24b..a951896893 100644 --- a/modules/account/back/models/mail-alias-account.js +++ b/modules/account/back/models/mail-alias-account.js @@ -2,54 +2,54 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(`You already have the mailAlias`); + return err; + }); + Self.observe('before save', async ctx => { const changes = ctx.currentInstance || ctx.instance; - await Self.hasGrant(ctx, changes.mailAlias); + await checkModifyPermission(ctx, changes.mailAlias); }); Self.observe('before delete', async ctx => { const mailAliasAccount = await Self.findById(ctx.where.id); - await Self.hasGrant(ctx, mailAliasAccount.mailAlias); + await checkModifyPermission(ctx, mailAliasAccount.mailAlias); }); - /** - * Checks if current user has - * grant to add/remove alias - * - * @param {Object} ctx - Request context - * @param {Interger} mailAlias - mailAlias id - * @return {Boolean} True for user with grant - */ - Self.hasGrant = async function(ctx, mailAlias) { + async function checkModifyPermission(ctx, mailAliasFk) { + const userId = ctx.options.accessToken.userId; + const available = await Self.getAvailable(userId); + if (!available.has(mailAliasFk)) + throw new UserError('The alias cant be modified'); + } + + Self.getAvailable = async function(userId, options) { const models = Self.app.models; - const accessToken = {req: {accessToken: ctx.options.accessToken}}; - const userId = accessToken.req.accessToken.userId; - const canEditAlias = await models.ACL.checkAccessAcl(accessToken, 'MailAliasAccount', 'canEditAlias', 'WRITE'); - if (canEditAlias) return true; + const myOptions = {}; - const user = await models.VnUser.findById(userId, {fields: ['hasGrant']}); - if (!user.hasGrant) - throw new UserError(`You don't have grant privilege`); + if (typeof options == 'object') + Object.assign(myOptions, options); - const account = await models.Account.findById(userId, { - fields: ['id'], - include: { - relation: 'aliases', - scope: { - fields: ['mailAlias'] - } + const roles = await models.RoleMapping.find({ + fields: ['roleId'], + where: {principalId: userId} + }, myOptions); + + const availableMailAlias = await models.MailAliasAcl.find({ + fields: ['mailAliasFk'], + include: {relation: 'mailAlias'}, + where: { + roleFk: { + inq: roles.map(role => role.roleId), + }, } - }); - - const aliases = account.aliases().map(alias => alias.mailAlias); - - const hasAlias = aliases.includes(mailAlias); - if (!hasAlias) - throw new UserError(`You cannot assign/remove an alias that you are not assigned to`); - - return true; + }, myOptions); + const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk); + return new Set(mailAliasArray); }; }; diff --git a/modules/account/back/models/mail-alias-acl.js b/modules/account/back/models/mail-alias-acl.js index 4a74472fed..a951896893 100644 --- a/modules/account/back/models/mail-alias-acl.js +++ b/modules/account/back/models/mail-alias-acl.js @@ -1,43 +1,33 @@ + const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - require('../methods/notification/getList')(Self); - - Self.observe('before save', async function(ctx) { - await checkModifyPermission(ctx); + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(`You already have the mailAlias`); + return err; }); - Self.observe('before delete', async function(ctx) { - await checkModifyPermission(ctx); + Self.observe('before save', async ctx => { + const changes = ctx.currentInstance || ctx.instance; + + await checkModifyPermission(ctx, changes.mailAlias); }); - async function checkModifyPermission(ctx) { - const models = Self.app.models; - const instance = ctx.instance; + Self.observe('before delete', async ctx => { + const mailAliasAccount = await Self.findById(ctx.where.id); + + await checkModifyPermission(ctx, mailAliasAccount.mailAlias); + }); + + async function checkModifyPermission(ctx, mailAliasFk) { const userId = ctx.options.accessToken.userId; - - let mailAliasFk; - let roleFk; - - if (instance) { - mailAliasFk = instance.mailAliasFk; - roleFk = instance.roleFk; - } else { - const mailAliasAcl = await models.MailAlias.findById(ctx.where.id); - mailAliasFk = mailAliasAcl.id; - roleFk = mailAliasAcl.roleFk; - } - - const role = await models.VnUser.findById(roleFk, {fields: ['id', 'role']}); - const available = await Self.getAvailable(roleFk); - const hasAcl = available.has(mailAliasFk); - - if (!hasAcl || (userId.role != role)) + const available = await Self.getAvailable(userId); + if (!available.has(mailAliasFk)) throw new UserError('The alias cant be modified'); } Self.getAvailable = async function(userId, options) { - const availableMailAliasMap = new Map(); const models = Self.app.models; const myOptions = {}; @@ -51,20 +41,15 @@ module.exports = Self => { }, myOptions); const availableMailAlias = await models.MailAliasAcl.find({ - fields: ['mailAliasFk', 'roleFk'], - include: {relation: 'roleFk'}, + fields: ['mailAliasFk'], + include: {relation: 'mailAlias'}, where: { roleFk: { inq: roles.map(role => role.roleId), }, } }, myOptions); - - for (available of availableMailAlias) { - availableMailAliasMap.set(available.mailAliasFk, { - mailAliasFk: available.mailAliasFk, - }); - } - return availableMailAliasMap; + const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk); + return new Set(mailAliasArray); }; }; diff --git a/modules/account/back/models/mail-alias-acl.json b/modules/account/back/models/mail-alias-acl.json index 2e44f38ebb..014b95d144 100644 --- a/modules/account/back/models/mail-alias-acl.json +++ b/modules/account/back/models/mail-alias-acl.json @@ -1,28 +1,30 @@ { - "name": "mailAliasACL", + "name": "MailAliasAcl", "base": "VnModel", "options": { "mysql": { - "table": "account.mailAliasACL" + "table": "account.mailAliasAcl" } }, "properties": { "mailAliasFk": { + "id": true, "type": "number" }, "roleFk": { + "id": true, "type": "number" } }, "relations": { "mailAlias": { "type": "belongsTo", - "model": "VnUser", + "model": "MailAlias", "foreignKey": "mailAliasFk" }, "role": { "type": "belongsTo", - "model": "VnUser", + "model": "Role", "foreignKey": "roleFk" } } diff --git a/modules/account/front/alias/acl/create/index.js b/modules/account/front/alias/acl/create/index.js deleted file mode 100644 index 58e70e4aa7..0000000000 --- a/modules/account/front/alias/acl/create/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import ngModule from '../../../module'; -import Section from 'salix/components/section'; - -export default class Controller extends Section { - constructor(...args) { - super(...args); - this.accessTypes = [ - {name: '*'}, - {name: 'READ'}, - {name: 'WRITE'} - ]; - this.permissions = [ - {name: 'ALLOW'}, - {name: 'DENY'} - ]; - - this.models = []; - for (let model in window.validations) - this.models.push({name: model}); - - this.acl = { - property: '*', - principalType: 'ROLE', - accessType: 'READ', - permission: 'ALLOW' - }; - } -} - -ngModule.component('vnAclMailCreate', { - // template: require('./index.html'), - controller: Controller -}); diff --git a/modules/account/front/alias/acl/index.js b/modules/account/front/alias/acl/index.js deleted file mode 100644 index 8393859a5a..0000000000 --- a/modules/account/front/alias/acl/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import './main'; -import './index/'; -import './create'; -import './search-panel'; diff --git a/modules/account/front/alias/acl/index/index.js b/modules/account/front/alias/acl/index/index.js deleted file mode 100644 index 5d8d495747..0000000000 --- a/modules/account/front/alias/acl/index/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import ngModule from '../../../module'; -import Section from 'salix/components/section'; - -export default class Controller extends Section { - onDelete(row) { - return this.$http.delete(`ACLs/${row.id}`) - .then(() => this.$.model.refresh()) - .then(() => this.vnApp.showSuccess(this.$t('ACL removed'))); - } -} - -ngModule.component('vnAclMailIndex', { - // template: require('./index.html'), - controller: Controller -}); diff --git a/modules/account/front/alias/acl/main/index.js b/modules/account/front/alias/acl/main/index.js deleted file mode 100644 index 97f04ee503..0000000000 --- a/modules/account/front/alias/acl/main/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import ngModule from '../../../module'; -import ModuleMain from 'salix/components/module-main'; - -export default class ACL extends ModuleMain { - exprBuilder(param, value) { - switch (param) { - case 'search': - return {model: {like: `%${value}%`}}; - default: - return {[param]: value}; - } - } -} - -ngModule.vnComponent('vnAclMailComponent', { - controller: ACL - // template: require('./index.html') -}); diff --git a/modules/account/front/alias/acl/search-panel/index.js b/modules/account/front/alias/acl/search-panel/index.js deleted file mode 100644 index 67db333834..0000000000 --- a/modules/account/front/alias/acl/search-panel/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import ngModule from '../../../module'; -import SearchPanel from 'core/components/searchbar/search-panel'; - -export default class Controller extends SearchPanel { - constructor(...args) { - super(...args); - this.accessTypes = [ - {name: '*'}, - {name: 'READ'}, - {name: 'WRITE'} - ]; - this.permissions = [ - {name: 'ALLOW'}, - {name: 'DENY'} - ]; - - this.models = []; - for (let model in window.validations) - this.models.push({name: model}); - } -} - -ngModule.component('vnAclSearchPanel', { - // template: require('./index.html'), - controller: Controller -}); diff --git a/modules/account/front/alias/index.js b/modules/account/front/alias/index.js index 5984217494..8eed3a3d3d 100644 --- a/modules/account/front/alias/index.js +++ b/modules/account/front/alias/index.js @@ -7,4 +7,3 @@ import './descriptor'; import './create'; import './basic-data'; import './users'; -import './acl';