refs #6085 aclMail back #1869
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
-- Definición de la tabla mailAliasACL
|
||||
carlossa marked this conversation as resolved
Outdated
|
||||
CREATE TABLE `account`.`mailAliasACL` (
|
||||
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
CREATE OR REPLACE CREATE OR REPLACE
|
||||
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`),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
este alias de correo este alias de correo
|
||||
|
|
|
@ -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",
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
Habria que traducirlo aqui Habria que traducirlo aqui
|
||||
"The alias cant be modified": "The alias cant be modified"
|
||||
}
|
|
@ -14,6 +14,9 @@
|
|||
"MailAliasAccount": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"MailAliasAcl": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"MailConfig": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -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');
|
||||
carlossa marked this conversation as resolved
juan
commented
myOptions no tiene utilidad myOptions no tiene utilidad
|
||||
}
|
||||
|
||||
carlossa marked this conversation as resolved
Outdated
juan
commented
options no esta definida en ningún sitio options no esta definida en ningún sitio
|
||||
Self.getAvailable = async function(userId, options) {
|
||||
const models = Self.app.models;
|
||||
const accessToken = {req: {accessToken: ctx.options.accessToken}};
|
||||
const userId = accessToken.req.accessToken.userId;
|
||||
|
||||
carlossa marked this conversation as resolved
Outdated
juan
commented
Un Un `findOne` sería mes adequat. I faría la inversa, primer traure els registres de MailAliasAcl i despres comprobar si el usuari te algún dells en findOne
|
||||
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),
|
||||
carlossa marked this conversation as resolved
Outdated
juan
commented
Se ha quedado un console log Se ha quedado un console log
|
||||
},
|
||||
}
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
Estic dubtant de si igual valdria la pena possar tb mailAliasFk: mailAliasFk Este enfoque se pareix al de notificactions (que es com te vaig dir) pero igual en este cas com no es crida des de altre lloc per a demanar el llistat igual no val la pena fer-ho igual Estic dubtant de si igual valdria la pena possar tb mailAliasFk: mailAliasFk
Aixina despres no cal buscarlo concretament.
Este enfoque se pareix al de notificactions (que es com te vaig dir) pero igual en este cas com no es crida des de altre lloc per a demanar el llistat igual no val la pena fer-ho igual
|
||||
});
|
||||
|
||||
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);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,43 +1,33 @@
|
|||
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
Pq el codi esta duplicat en modules/account/back/models/mail-alias-acl.js i modules/account/back/models/mail-alias-account.js ? Pq el codi esta duplicat en modules/account/back/models/mail-alias-acl.js i modules/account/back/models/mail-alias-account.js ?
|
||||
|
||||
module.exports = Self => {
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
mmmm mmmm
|
||||
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);
|
||||
carlossa marked this conversation as resolved
Outdated
alexm
commented
Esta part mirala be pq soles has de comprovar el userId del que esta fent el canvi const userId = ctx.options.accessToken.userId; Esta part mirala be pq soles has de comprovar el userId del que esta fent el canvi const userId = ctx.options.accessToken.userId;
carlossa
commented
No se usa ese fichero, se usa account, solucionado No se usa ese fichero, se usa account, solucionado
|
||||
});
|
||||
|
||||
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);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
|
@ -1,4 +0,0 @@
|
|||
import './main';
|
||||
import './index/';
|
||||
import './create';
|
||||
import './search-panel';
|
|
@ -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
|
||||
});
|
|
@ -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')
|
||||
});
|
|
@ -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
|
||||
});
|
|
@ -7,4 +7,3 @@ import './descriptor';
|
|||
import './create';
|
||||
import './basic-data';
|
||||
import './users';
|
||||
import './acl';
|
||||
|
|
Cambiar a nueva versión