refs #4797 fix test, add getList
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alexandre Riera 2023-05-09 11:34:32 +02:00
parent b37bde2ba7
commit e7d16dc8ba
6 changed files with 240 additions and 83 deletions

View File

@ -0,0 +1,80 @@
module.exports = Self => {
Self.remoteMethod('getList', {
description: 'Get list of the available and active notification subscriptions',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'number',
description: 'User to modify',
http: {source: 'path'}
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/getList`,
verb: 'GET'
}
});
Self.getList = async(id, options) => {
const notifications = [];
const models = Self.app.models;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const activeNotifications = await models.NotificationSubscription.find({
include: {relation: 'notification'},
where: {userFk: id}
}, myOptions);
const roles = await models.RoleMapping.find({
fields: ['roleId'],
where: {principalId: id}
}, myOptions);
const availableNotifications = await models.NotificationAcl.find({
include: {relation: 'notification'},
where: {
roleFk: {
inq: roles.map(role => {
return role.roleId;
}),
},
}
}, myOptions);
activeNotifications.forEach(subscription => {
notifications.push({
id: subscription.id,
notificationFk: subscription.notificationFk,
name: subscription.notification().name,
description: subscription.notification().description,
active: true
});
});
availableNotifications.forEach(acl => {
const activeNotif = notifications.find(
notif => notif.notificationFk === acl.notificationFk
);
if (!activeNotif) {
notifications.push({
id: null,
notificationFk: acl.notificationFk,
name: acl.notification().name,
description: acl.notification().description,
active: false,
});
}
});
return notifications;
};
};

View File

@ -0,0 +1,38 @@
const models = require('vn-loopback/server/server').models;
describe('NotificationSubscription getList()', () => {
it('should return a list of available and active notifications of a user', async() => {
const userId = 1109;
const activeNotifications = await models.NotificationSubscription.find({
where: {userFk: userId}
});
const roles = await models.RoleMapping.find({
fields: ['roleId'],
where: {principalId: userId}
});
const availableNotifications = await models.NotificationAcl.find({
where: {
roleFk: {
inq: roles.map(role => {
return role.roleId;
}),
},
}
});
const result = await models.NotificationSubscription.getList(userId);
expect(result.filter(notification => notification.active == true).length)
.toEqual(activeNotifications.length);
expect(result.filter(notification => notification.active == false).length)
.toEqual(availableNotifications.length - activeNotifications.length);
});
it('should return empty from a non existent user', async() => {
const userId = 123456789;
const result = await models.NotificationSubscription.getList(userId);
expect(result.length).toEqual(0);
});
});

View File

@ -1,62 +1,40 @@
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.observe('before delete', async function(ctx) {
await checkModifyPermission(ctx);
});
async function checkModifyPermission(ctx) {
const models = Self.app.models;
const instance = ctx.instance;
const userId = ctx.options.accessToken.userId;
const user = await ctx.instance.userFk;
const modifiedUser = await getUserToModify(null, user, models);
if (userId != modifiedUser.id && userId != modifiedUser.bossFk)
throw new UserError('You dont have permission to modify this user');
});
let notificationFk;
let workerId;
Self.remoteMethod('deleteNotification', {
description: 'Deletes a notification subscription',
accepts: [
{
arg: 'ctx',
type: 'object',
http: {source: 'context'}
},
{
arg: 'notificationId',
type: 'number',
required: true
},
],
returns: {
type: 'object',
root: true
},
http: {
verb: 'POST',
path: '/deleteNotification'
if (instance) {
notificationFk = instance.notificationFk;
workerId = instance.userFk;
} else {
const notificationSubscription = await models.NotificationSubscription.findById(ctx.where.id);
notificationFk = notificationSubscription.notificationFk;
workerId = notificationSubscription.userFk;
}
});
Self.deleteNotification = async function(ctx, notificationId) {
const models = Self.app.models;
const user = ctx.req.accessToken.userId;
const modifiedUser = await getUserToModify(notificationId, null, models);
if (user != modifiedUser.id && user != modifiedUser.bossFk)
throw new UserError('You dont have permission to modify this user');
await models.NotificationSubscription.destroyById(notificationId);
};
async function getUserToModify(notificationId, userFk, models) {
let userToModify = userFk;
if (notificationId) {
const subscription = await models.NotificationSubscription.findById(notificationId);
userToModify = subscription.userFk;
}
return await models.Worker.findOne({
fields: ['id', 'bossFk'],
where: {
id: userToModify
}
const worker = await models.Worker.findById(workerId, {fields: ['id', 'bossFk']});
const notificationsAvailables = await models.NotificationSubscription.getList(workerId);
const hasAcl = notificationsAvailables.some(function(available) {
return available.notificationFk === notificationFk;
});
if (!hasAcl || (userId != worker.id && userId != worker.bossFk))
throw new UserError('The notification subscription of this worker cant be modified');
}
};

View File

@ -1,69 +1,126 @@
const models = require('vn-loopback/server/server').models;
describe('loopback model NotificationSubscription', () => {
it('should fail to delete a notification if the user is not editing itself or a subordinate', async() => {
it('should fail to add a notification subscription if the worker doesnt have ACLs', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const user = 9;
const notificationSubscriptionId = 2;
const ctx = {req: {accessToken: {userId: user}}};
const notification = await models.NotificationSubscription.findById(notificationSubscriptionId);
const options = {transaction: tx, accessToken: {userId: 9}};
await models.NotificationSubscription.create({notificationFk: 1, userFk: 62}, options);
await models.NotificationSubscription.deleteNotification(ctx, notification.id, options);
expect(error.message).toContain('You dont have permission to modify this user');
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
await tx.rollback();
}
expect(error.message).toEqual('The notification subscription of this worker cant be modified');
});
it('should delete a notification if the user is editing itself', async() => {
it('should fail to add a notification subscription if the user isnt editing itself or subordinate', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const user = 9;
const options = {transaction: tx, accessToken: {userId: 1}};
await models.NotificationSubscription.create({notificationFk: 1, userFk: 9}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual('The notification subscription of this worker cant be modified');
});
it('should fail to delete a notification subscription if the user isnt editing itself or subordinate', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 9}};
const notificationSubscriptionId = 2;
await models.NotificationSubscription.destroyAll({id: notificationSubscriptionId}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual('The notification subscription of this worker cant be modified');
});
it('should add a notification subscription if the user is editing itself', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 9}};
await models.NotificationSubscription.create({notificationFk: 2, userFk: 9}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toBeUndefined();
});
it('should delete a notification subscription if the user is editing itself', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 9}};
const notificationSubscriptionId = 6;
const ctx = {req: {accessToken: {userId: user}}};
const notification = await models.NotificationSubscription.findById(notificationSubscriptionId);
await models.NotificationSubscription.destroyAll({id: notificationSubscriptionId}, options);
await models.NotificationSubscription.deleteNotification(ctx, notification.id, options);
const deletedNotification = await models.NotificationSubscription.findById(notificationSubscriptionId);
expect(deletedNotification).toBeNull();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
error = e;
}
expect(error).toBeUndefined();
});
it('should delete a notification if the user is editing a subordinate', async() => {
it('should add a notification subscription if the user is editing a subordinate', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const user = 19;
const notificationSubscriptionId = 4;
const ctx = {req: {accessToken: {userId: user}}};
const notification = await models.NotificationSubscription.findById(notificationSubscriptionId);
const options = {transaction: tx, accessToken: {userId: 9}};
await models.NotificationSubscription.create({notificationFk: 1, userFk: 5}, options);
await models.NotificationSubscription.deleteNotification(ctx, notification.id, options);
const deletedNotification = await models.NotificationSubscription.findById(notificationSubscriptionId);
expect(deletedNotification).toBeNull();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
error = e;
}
expect(error).toBeUndefined();
});
it('should delete a notification subscription if the user is editing a subordinate', async() => {
const tx = await models.NotificationSubscription.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 19}};
const notificationSubscriptionId = 4;
await models.NotificationSubscription.destroyAll({id: notificationSubscriptionId}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toBeUndefined();
});
});

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('NotificationSubscription', 'getList', 'READ', 'ALLOW', 'ROLE', 'employee');

View File

@ -290,5 +290,6 @@
"isTaxDataChecked": "Datos comprobados",
"comercialId": "Id comercial",
"comercialName": "Comercial",
"Invalid NIF for VIES": "Invalid NIF for VIES"
"Invalid NIF for VIES": "Invalid NIF for VIES",
"The notification subscription of this worker cant be modified": "La subscripción a la notificación de este trabajador no puede ser modificada"
}