Merge pull request 'hotfix_mailAlias' (!1664) from hotfix_mailAlias into master
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #1664
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
Vicent Llopis 2023-07-13 06:43:31 +00:00
commit 988ff96016
11 changed files with 75 additions and 218 deletions

View File

@ -1,68 +0,0 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('addAlias', {
description: 'Add an alias if the user has the grant',
accessType: 'WRITE',
accepts: [
{
arg: 'ctx',
type: 'Object',
http: {source: 'context'}
},
{
arg: 'id',
type: 'number',
required: true,
description: 'The user id',
http: {source: 'path'}
},
{
arg: 'mailAlias',
type: 'number',
description: 'The new alias for user',
required: true
}
],
http: {
path: `/:id/addAlias`,
verb: 'POST'
}
});
Self.addAlias = async function(ctx, id, mailAlias, options) {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
if (!user.hasGrant)
throw new UserError(`You don't have grant privilege`);
const account = await models.Account.findById(userId, {
fields: ['id'],
include: {
relation: 'aliases',
scope: {
fields: ['mailAlias']
}
}
}, myOptions);
const aliases = account.aliases().map(alias => alias.mailAlias);
const hasAlias = aliases.includes(mailAlias);
if (!hasAlias)
throw new UserError(`You cannot assign an alias that you are not assigned to`);
return models.MailAliasAccount.create({
mailAlias: mailAlias,
account: id
}, myOptions);
};
};

View File

@ -1,55 +0,0 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('removeAlias', {
description: 'Remove alias if the user has the grant',
accessType: 'WRITE',
accepts: [
{
arg: 'ctx',
type: 'Object',
http: {source: 'context'}
},
{
arg: 'id',
type: 'number',
required: true,
description: 'The user id',
http: {source: 'path'}
},
{
arg: 'mailAlias',
type: 'number',
description: 'The alias to delete',
required: true
}
],
http: {
path: `/:id/removeAlias`,
verb: 'POST'
}
});
Self.removeAlias = async function(ctx, id, mailAlias, options) {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const canRemoveAlias = await models.ACL.checkAccessAcl(ctx, 'VnUser', 'canRemoveAlias', 'WRITE');
if (userId != id && !canRemoveAlias) throw new UserError(`You don't have grant privilege`);
const mailAliasAccount = await models.MailAliasAccount.findOne({
where: {
mailAlias: mailAlias,
account: id
}
}, myOptions);
await mailAliasAccount.destroy(myOptions);
};
};

View File

@ -1,68 +0,0 @@
const {models} = require('vn-loopback/server/server');
describe('VnUser addAlias()', () => {
const employeeId = 1;
const sysadminId = 66;
const developerId = 9;
const customerId = 2;
const mailAlias = 1;
it('should throw an error when user not has privileges', async() => {
const ctx = {req: {accessToken: {userId: employeeId}}};
const tx = await models.VnUser.beginTransaction({});
let error;
try {
const options = {transaction: tx};
await models.VnUser.addAlias(ctx, employeeId, mailAlias, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
expect(error.message).toContain(`You don't have grant privilege`);
});
it('should throw an error when user has privileges but not has the role from user', async() => {
const ctx = {req: {accessToken: {userId: sysadminId}}};
const tx = await models.VnUser.beginTransaction({});
let error;
try {
const options = {transaction: tx};
await models.VnUser.addAlias(ctx, employeeId, mailAlias, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
expect(error.message).toContain(`You cannot assign an alias that you are not assigned to`);
});
it('should add an alias', async() => {
const ctx = {req: {accessToken: {userId: developerId}}};
const tx = await models.VnUser.beginTransaction({});
let result;
try {
const options = {transaction: tx};
const user = await models.VnUser.findById(developerId, null, options);
await user.updateAttribute('hasGrant', true, options);
result = await models.VnUser.addAlias(ctx, customerId, mailAlias, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
}
expect(result.mailAlias).toBe(mailAlias);
expect(result.account).toBe(customerId);
});
});

View File

@ -11,8 +11,6 @@ module.exports = function(Self) {
require('../methods/vn-user/validate-token')(Self);
require('../methods/vn-user/privileges')(Self);
require('../methods/vn-user/renew-token')(Self);
require('../methods/vn-user/addAlias')(Self);
require('../methods/vn-user/removeAlias')(Self);
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');

View File

@ -1,11 +0,0 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('VnUser', 'addAlias', 'WRITE', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('VnUser', 'removeAlias', 'WRITE', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('VnUser', 'canRemoveAlias', 'WRITE', 'ALLOW', 'ROLE', 'itManagement');

View File

@ -0,0 +1,8 @@
DELETE FROM `salix`.`ACL` WHERE model = 'MailAliasAccount';
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('MailAliasAccount', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('MailAliasAccount', 'create', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('MailAliasAccount', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('MailAliasAccount', 'canEditAlias', 'WRITE', 'ALLOW', 'ROLE', 'itManagement');

View File

@ -299,5 +299,5 @@
"Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado",
"Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}",
"You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado"
"You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado"
}

View File

@ -0,0 +1,55 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.observe('before save', async ctx => {
const changes = ctx.currentInstance || ctx.instance;
await Self.hasGrant(ctx, changes.mailAlias);
});
Self.observe('before delete', async ctx => {
const mailAliasAccount = await Self.findById(ctx.where.id);
await Self.hasGrant(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) {
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 user = await models.VnUser.findById(userId, {fields: ['hasGrant']});
if (!user.hasGrant)
throw new UserError(`You don't have grant privilege`);
const account = await models.Account.findById(userId, {
fields: ['id'],
include: {
relation: 'aliases',
scope: {
fields: ['mailAlias']
}
}
});
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

@ -21,11 +21,12 @@ export default class Controller extends Section {
}
onAddClick() {
this.addData = {account: this.$params.id};
this.$.dialog.show();
}
onAddSave() {
return this.$http.post(`VnUsers/${this.$params.id}/addAlias`, this.addData)
return this.$http.post(`MailAliasAccounts`, this.addData)
.then(() => this.refresh())
.then(() => this.vnApp.showSuccess(
this.$t('Subscribed to alias!'))
@ -33,12 +34,11 @@ export default class Controller extends Section {
}
onRemove(row) {
const params = {
mailAlias: row.mailAlias
};
return this.$http.post(`VnUsers/${this.$params.id}/removeAlias`, params)
.then(() => this.refresh())
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
return this.$http.delete(`MailAliasAccounts/${row.id}`)
.then(() => {
this.$.data.splice(this.$.data.indexOf(row), 1);
this.vnApp.showSuccess(this.$t('Unsubscribed from alias!'));
});
}
}

View File

@ -25,9 +25,8 @@ describe('component vnUserAliases', () => {
describe('onAddSave()', () => {
it('should add the new row', () => {
controller.addData = {account: 1};
controller.$params = {id: 1};
$httpBackend.expectPOST('VnUsers/1/addAlias').respond();
$httpBackend.expectPOST('MailAliasAccounts').respond();
$httpBackend.expectGET('MailAliasAccounts').respond('foo');
controller.onAddSave();
$httpBackend.flush();
@ -42,14 +41,12 @@ describe('component vnUserAliases', () => {
{id: 1, alias: 'foo'},
{id: 2, alias: 'bar'}
];
controller.$params = {id: 1};
$httpBackend.expectPOST('VnUsers/1/removeAlias').respond();
$httpBackend.expectGET('MailAliasAccounts').respond(controller.$.data[1]);
$httpBackend.expectDELETE('MailAliasAccounts/1').respond();
controller.onRemove(controller.$.data[0]);
$httpBackend.flush();
expect(controller.$.data).toEqual({id: 2, alias: 'bar'});
expect(controller.$.data).toEqual([{id: 2, alias: 'bar'}]);
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});

View File

@ -141,6 +141,7 @@ describe('ticket filter()', () => {
});
it('should return the tickets that are not pending', async() => {
pending('#6010 test intermitente');
const tx = await models.Ticket.beginTransaction({});
try {