refs #6085 aclMail back #1869

Merged
carlossa merged 16 commits from 6085-ACLsMail into dev 2024-01-03 07:56:11 +00:00
15 changed files with 151 additions and 174 deletions
Showing only changes of commit 6d486fbec9 - Show all commits

View File

@ -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();
});
});

View File

@ -1,5 +1,6 @@
-- Definición de la tabla mailAliasACL -- Definición de la tabla mailAliasACL
carlossa marked this conversation as resolved Outdated
Outdated
Review

Cambiar a nueva versión

Cambiar a nueva versión
CREATE TABLE `account`.`mailAliasACL` (
carlossa marked this conversation as resolved Outdated
Outdated
Review

CREATE OR REPLACE

CREATE OR REPLACE
CREATE OR REPLACE TABLE `account`.`mailAliasAcl` (
`mailAliasFk` int(10) unsigned NOT NULL, `mailAliasFk` int(10) unsigned NOT NULL,
`roleFk` int(10) unsigned NOT NULL, `roleFk` int(10) unsigned NOT NULL,
FOREIGN KEY (`mailAliasFk`) REFERENCES `account`.`mailAlias` (`id`), FOREIGN KEY (`mailAliasFk`) REFERENCES `account`.`mailAlias` (`id`),

View File

@ -3002,3 +3002,10 @@ INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`)
(1, 'Error in VAT calculation'), (1, 'Error in VAT calculation'),
(2, 'Error in sales details'), (2, 'Error in sales details'),
(3, 'Error in customer data'); (3, 'Error in customer data');
INSERT INTO `account`.`mailAliasAcl` (`mailAliasFk`, `roleFk`)
VALUES
(1, 1),
(2, 9),
(3, 15);

View File

@ -68,3 +68,4 @@ Load more results: Cargar más resultados
Send cau: Enviar cau 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 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 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
Outdated
Review

este alias de correo

este alias de correo

View File

@ -329,5 +329,7 @@
"The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mínima", "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", "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", "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
Outdated
Review

Habria que traducirlo aqui

Habria que traducirlo aqui
"The alias cant be modified": "The alias cant be modified"
} }

View File

@ -14,6 +14,9 @@
"MailAliasAccount": { "MailAliasAccount": {
"dataSource": "vn" "dataSource": "vn"
}, },
"MailAliasAcl": {
"dataSource": "vn"
},
"MailConfig": { "MailConfig": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -2,54 +2,54 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { 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 => { Self.observe('before save', async ctx => {
const changes = ctx.currentInstance || ctx.instance; const changes = ctx.currentInstance || ctx.instance;
await Self.hasGrant(ctx, changes.mailAlias); await checkModifyPermission(ctx, changes.mailAlias);
}); });
Self.observe('before delete', async ctx => { Self.observe('before delete', async ctx => {
const mailAliasAccount = await Self.findById(ctx.where.id); const mailAliasAccount = await Self.findById(ctx.where.id);
await Self.hasGrant(ctx, mailAliasAccount.mailAlias); await checkModifyPermission(ctx, mailAliasAccount.mailAlias);
}); });
/** async function checkModifyPermission(ctx, mailAliasFk) {
* Checks if current user has const userId = ctx.options.accessToken.userId;
* grant to add/remove alias const available = await Self.getAvailable(userId);
* if (!available.has(mailAliasFk))
* @param {Object} ctx - Request context throw new UserError('The alias cant be modified');
carlossa marked this conversation as resolved
Review

myOptions no tiene utilidad

myOptions no tiene utilidad
* @param {Interger} mailAlias - mailAlias id }
* @return {Boolean} True for user with grant
carlossa marked this conversation as resolved Outdated
Outdated
Review

options no esta definida en ningún sitio

options no esta definida en ningún sitio
*/ Self.getAvailable = async function(userId, options) {
Self.hasGrant = async function(ctx, mailAlias) {
const models = Self.app.models; 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
Outdated
Review

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

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'); const myOptions = {};
if (canEditAlias) return true;
const user = await models.VnUser.findById(userId, {fields: ['hasGrant']}); if (typeof options == 'object')
if (!user.hasGrant) Object.assign(myOptions, options);
throw new UserError(`You don't have grant privilege`);
const account = await models.Account.findById(userId, { const roles = await models.RoleMapping.find({
fields: ['id'], fields: ['roleId'],
include: { where: {principalId: userId}
relation: 'aliases', }, myOptions);
scope: {
fields: ['mailAlias'] 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
Outdated
Review

Se ha quedado un console log

Se ha quedado un console log
},
} }
carlossa marked this conversation as resolved Outdated
Outdated
Review

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

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
} }, myOptions);
}); const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk);
return new Set(mailAliasArray);
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;
}; };
}; };

View File

@ -1,43 +1,33 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
carlossa marked this conversation as resolved Outdated
Outdated
Review

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 => { module.exports = Self => {
carlossa marked this conversation as resolved Outdated
Outdated
Review

mmmm

mmmm
require('../methods/notification/getList')(Self); Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')
Self.observe('before save', async function(ctx) { return new UserError(`You already have the mailAlias`);
await checkModifyPermission(ctx); return err;
}); });
Self.observe('before delete', async function(ctx) { Self.observe('before save', async ctx => {
await checkModifyPermission(ctx); const changes = ctx.currentInstance || ctx.instance;
await checkModifyPermission(ctx, changes.mailAlias);
carlossa marked this conversation as resolved Outdated
Outdated
Review

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;

No se usa ese fichero, se usa account, solucionado

No se usa ese fichero, se usa account, solucionado
}); });
async function checkModifyPermission(ctx) { Self.observe('before delete', async ctx => {
const models = Self.app.models; const mailAliasAccount = await Self.findById(ctx.where.id);
const instance = ctx.instance;
await checkModifyPermission(ctx, mailAliasAccount.mailAlias);
});
async function checkModifyPermission(ctx, mailAliasFk) {
const userId = ctx.options.accessToken.userId; const userId = ctx.options.accessToken.userId;
const available = await Self.getAvailable(userId);
let mailAliasFk; if (!available.has(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))
throw new UserError('The alias cant be modified'); throw new UserError('The alias cant be modified');
} }
Self.getAvailable = async function(userId, options) { Self.getAvailable = async function(userId, options) {
const availableMailAliasMap = new Map();
const models = Self.app.models; const models = Self.app.models;
const myOptions = {}; const myOptions = {};
@ -51,20 +41,15 @@ module.exports = Self => {
}, myOptions); }, myOptions);
const availableMailAlias = await models.MailAliasAcl.find({ const availableMailAlias = await models.MailAliasAcl.find({
fields: ['mailAliasFk', 'roleFk'], fields: ['mailAliasFk'],
include: {relation: 'roleFk'}, include: {relation: 'mailAlias'},
where: { where: {
roleFk: { roleFk: {
inq: roles.map(role => role.roleId), inq: roles.map(role => role.roleId),
}, },
} }
}, myOptions); }, myOptions);
const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk);
for (available of availableMailAlias) { return new Set(mailAliasArray);
availableMailAliasMap.set(available.mailAliasFk, {
mailAliasFk: available.mailAliasFk,
});
}
return availableMailAliasMap;
}; };
}; };

View File

@ -1,28 +1,30 @@
{ {
"name": "mailAliasACL", "name": "MailAliasAcl",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "account.mailAliasACL" "table": "account.mailAliasAcl"
} }
}, },
"properties": { "properties": {
"mailAliasFk": { "mailAliasFk": {
"id": true,
"type": "number" "type": "number"
}, },
"roleFk": { "roleFk": {
"id": true,
"type": "number" "type": "number"
} }
}, },
"relations": { "relations": {
"mailAlias": { "mailAlias": {
"type": "belongsTo", "type": "belongsTo",
"model": "VnUser", "model": "MailAlias",
"foreignKey": "mailAliasFk" "foreignKey": "mailAliasFk"
}, },
"role": { "role": {
"type": "belongsTo", "type": "belongsTo",
"model": "VnUser", "model": "Role",
"foreignKey": "roleFk" "foreignKey": "roleFk"
} }
} }

View File

@ -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
});

View File

@ -1,4 +0,0 @@
import './main';
import './index/';
import './create';
import './search-panel';

View File

@ -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
});

View File

@ -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')
});

View File

@ -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
});

View File

@ -7,4 +7,3 @@ import './descriptor';
import './create'; import './create';
import './basic-data'; import './basic-data';
import './users'; import './users';
import './acl';