test(ticket): fix tests and add funcionalityAcl
gitea/salix/pipeline/head This commit is unstable
Details
gitea/salix/pipeline/head This commit is unstable
Details
This commit is contained in:
parent
8b636497a4
commit
9d482f7dfd
|
@ -1,33 +0,0 @@
|
||||||
module.exports = Self => {
|
|
||||||
Self.remoteMethodCtx('aclFunc', {
|
|
||||||
description: 'Get the user information and permissions',
|
|
||||||
accepts: [
|
|
||||||
{
|
|
||||||
arg: 'property',
|
|
||||||
type: 'String',
|
|
||||||
description: 'The user name or email',
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
returns: {
|
|
||||||
type: 'Object',
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/aclFunc`,
|
|
||||||
verb: 'GET'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.aclFunc = async function(ctx, property) {
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const models = Self.app.models;
|
|
||||||
|
|
||||||
const [acl] = await Self.rawSql(
|
|
||||||
`SELECT a.principalId
|
|
||||||
FROM salix.ACL a
|
|
||||||
WHERE a.property = ?`, [property]);
|
|
||||||
|
|
||||||
return await models.Account.hasRole(userId, acl.principalId);
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('funcionalityAcl', {
|
||||||
|
description: 'Return if user has permissions',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'model',
|
||||||
|
type: 'String',
|
||||||
|
description: 'The model',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'property',
|
||||||
|
type: 'String',
|
||||||
|
description: 'The property',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/funcionalityAcl`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.funcionalityAcl = async function(ctx, model, property) {
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const models = Self.app.models;
|
||||||
|
|
||||||
|
const [acl] = await Self.rawSql(
|
||||||
|
`SELECT f.role
|
||||||
|
FROM salix.funcionalityAcl f
|
||||||
|
WHERE f.model = ?
|
||||||
|
AND f.property = ?`, [model, property]);
|
||||||
|
|
||||||
|
return await models.Account.hasRole(userId, acl.role);
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "FuncionalityAcl",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "salix.funcionalityAcl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
CREATE TABLE `funcionalityAcl` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`model` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`property` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`role` varchar(45) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci
|
|
@ -14,10 +14,10 @@ INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
|
||||||
('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
|
('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
|
||||||
|
|
||||||
INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
|
INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'it@gotamcity.com', 'incidences@gotamcity.com');
|
(1, 'it@gotamcity.com', 'incidences@gotamcity.com');
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`)
|
INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`)
|
||||||
VALUES
|
VALUES
|
||||||
('1', '6');
|
('1', '6');
|
||||||
|
|
||||||
|
@ -1146,10 +1146,11 @@ INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`)
|
||||||
|
|
||||||
INSERT INTO `vn`.`saleTracking`(`saleFk`, `isChecked`, `created`, `originalQuantity`, `workerFk`, `actionFk`, `id`, `stateFk`)
|
INSERT INTO `vn`.`saleTracking`(`saleFk`, `isChecked`, `created`, `originalQuantity`, `workerFk`, `actionFk`, `id`, `stateFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 0, util.VN_CURDATE(), 5, 55, 3, 1, 14),
|
(1, 0, util.VN_CURDATE(), 5, 55, 3, 1, 14),
|
||||||
(1, 1, util.VN_CURDATE(), 5, 54, 3, 2, 8),
|
(1, 1, util.VN_CURDATE(), 5, 54, 3, 2, 8),
|
||||||
(2, 1, util.VN_CURDATE(), 10, 40, 4, 3, 8),
|
(2, 1, util.VN_CURDATE(), 10, 40, 4, 3, 8),
|
||||||
(3, 1, util.VN_CURDATE(), 2, 40, 4, 4, 8);
|
(3, 1, util.VN_CURDATE(), 2, 40, 4, 4, 8),
|
||||||
|
(31, 1, util.VN_CURDATE(), -5, 40, 4, 5, 8);
|
||||||
|
|
||||||
INSERT INTO `vn`.`itemBarcode`(`id`, `itemFk`, `code`)
|
INSERT INTO `vn`.`itemBarcode`(`id`, `itemFk`, `code`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2664,8 +2665,11 @@ INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `lev
|
||||||
VALUES
|
VALUES
|
||||||
(9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL);
|
(9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
INSERT INTO salix.ACL
|
INSERT INTO `salix`.`funcionalityAcl` (`model`, `property`, `role`)
|
||||||
(model, property, accessType, permission, principalType, principalId)
|
VALUES
|
||||||
VALUES
|
('Sale', 'editTracked', 'production'),
|
||||||
('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'),
|
('Sale', 'editCloned', 'production');
|
||||||
('Sale', 'editCloned', 'WRITE', 'ALLOW', 'ROLE', 'production');
|
|
||||||
|
INSERT INTO `vn`.`saleCloned` (`saleClonedFk`, `saleOriginalFk`)
|
||||||
|
VALUES
|
||||||
|
('26', '25');
|
||||||
|
|
|
@ -37,8 +37,8 @@ module.exports = Self => {
|
||||||
const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions);
|
const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions);
|
||||||
const hasSaleCloned = saleCloned.length;
|
const hasSaleCloned = saleCloned.length;
|
||||||
|
|
||||||
const canEditTracked = await models.Account.aclFunc(ctx, 'editTracked');
|
const canEditTracked = await models.Account.funcionalityAcl(ctx, 'Sale', 'editTracked');
|
||||||
const canEditCloned = await models.Account.aclFunc(ctx, 'editCloned');
|
const canEditCloned = await models.Account.funcionalityAcl(ctx, 'Sale', 'editCloned');
|
||||||
|
|
||||||
const canEdit = (canEditTracked || !hasSaleTracking) && (canEditCloned || !hasSaleCloned);
|
const canEdit = (canEditTracked || !hasSaleTracking) && (canEditCloned || !hasSaleCloned);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ describe('sale canEdit()', () => {
|
||||||
const productionUserID = 49;
|
const productionUserID = 49;
|
||||||
const ctx = {req: {accessToken: {userId: productionUserID}}};
|
const ctx = {req: {accessToken: {userId: productionUserID}}};
|
||||||
|
|
||||||
const sales = [3];
|
const sales = [25];
|
||||||
|
|
||||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
|
@ -51,10 +51,10 @@ describe('sale canEdit()', () => {
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const salesPersonUserID = 18;
|
const buyerId = 35;
|
||||||
const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
|
const ctx = {req: {accessToken: {userId: buyerId}}};
|
||||||
|
|
||||||
const sales = [3];
|
const sales = [31];
|
||||||
|
|
||||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
|
@ -66,4 +66,48 @@ describe('sale canEdit()', () => {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return false if any of the sales is cloned', async() => {
|
||||||
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const buyerId = 35;
|
||||||
|
const ctx = {req: {accessToken: {userId: buyerId}}};
|
||||||
|
|
||||||
|
const sales = [26];
|
||||||
|
|
||||||
|
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
|
expect(result).toEqual(false);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if any of the sales is cloned and has the correct role', async() => {
|
||||||
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
// modify?
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const productionId = 49;
|
||||||
|
const ctx = {req: {accessToken: {userId: productionId}}};
|
||||||
|
|
||||||
|
const sales = [26];
|
||||||
|
|
||||||
|
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('sale updateConcept()', () => {
|
describe('sale updateConcept()', () => {
|
||||||
const ctx = {req: {accessToken: {userId: 9}}};
|
const ctx = {req: {accessToken: {userId: 9}}};
|
||||||
const saleId = 1;
|
const saleId = 25;
|
||||||
|
|
||||||
it('should throw if ID was undefined', async() => {
|
it('should throw if ID was undefined', async() => {
|
||||||
const tx = await models.Sale.beginTransaction({});
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
|
|
@ -28,13 +28,20 @@ describe('sale updateQuantity()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if the quantity is greater than it should be', async() => {
|
it('should throw an error if the quantity is greater than it should be', async() => {
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: 1},
|
||||||
|
headers: {origin: 'localhost:5000'},
|
||||||
|
__: () => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
const tx = await models.Sale.beginTransaction({});
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
|
||||||
let error;
|
let error;
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
await models.Sale.updateQuantity(ctx, 1, 99, options);
|
await models.Sale.updateQuantity(ctx, 17, 99, options);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -45,21 +52,60 @@ describe('sale updateQuantity()', () => {
|
||||||
expect(error).toEqual(new Error('The new quantity should be smaller than the old one'));
|
expect(error).toEqual(new Error('The new quantity should be smaller than the old one'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the quantity of a given sale current line', async() => {
|
it('should add quantity if the quantity is greater than it should be and is role advanced', async() => {
|
||||||
const tx = await models.Sale.beginTransaction({});
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
const saleId = 17;
|
||||||
|
const buyerId = 35;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: buyerId},
|
||||||
|
headers: {origin: 'localhost:5000'},
|
||||||
|
__: () => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const originalLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options);
|
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, options);
|
||||||
|
|
||||||
expect(originalLine.quantity).toEqual(5);
|
expect(isRoleAdvanced).toEqual(true);
|
||||||
|
|
||||||
await models.Sale.updateQuantity(ctx, 1, 4, options);
|
const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||||
|
|
||||||
const modifiedLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options);
|
expect(originalLine.quantity).toEqual(30);
|
||||||
|
|
||||||
expect(modifiedLine.quantity).toEqual(4);
|
const newQuantity = originalLine.quantity + 1;
|
||||||
|
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||||
|
|
||||||
|
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||||
|
|
||||||
|
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the quantity of a given sale current line', async() => {
|
||||||
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
const saleId = 25;
|
||||||
|
const newQuantity = 4;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||||
|
|
||||||
|
expect(originalLine.quantity).toEqual(20);
|
||||||
|
|
||||||
|
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||||
|
|
||||||
|
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||||
|
|
||||||
|
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -41,14 +41,13 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions);
|
|
||||||
|
|
||||||
if (!canEditSale)
|
|
||||||
throw new UserError(`Sale(s) blocked, please contact production`);
|
|
||||||
|
|
||||||
if (isNaN(newQuantity))
|
if (isNaN(newQuantity))
|
||||||
throw new UserError(`The value should be a number`);
|
throw new UserError(`The value should be a number`);
|
||||||
|
|
||||||
|
const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions);
|
||||||
|
if (!canEditSale)
|
||||||
|
throw new UserError(`Sale(s) blocked, please contact production`);
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
include: {
|
include: {
|
||||||
relation: 'ticket',
|
relation: 'ticket',
|
||||||
|
@ -70,7 +69,8 @@ module.exports = Self => {
|
||||||
|
|
||||||
const sale = await models.Sale.findById(id, filter, myOptions);
|
const sale = await models.Sale.findById(id, filter, myOptions);
|
||||||
|
|
||||||
if (newQuantity > sale.quantity)
|
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions);
|
||||||
|
if (newQuantity > sale.quantity && !isRoleAdvanced)
|
||||||
throw new UserError('The new quantity should be smaller than the old one');
|
throw new UserError('The new quantity should be smaller than the old one');
|
||||||
|
|
||||||
const oldQuantity = sale.quantity;
|
const oldQuantity = sale.quantity;
|
||||||
|
|
|
@ -33,4 +33,5 @@ module.exports = function(Self) {
|
||||||
require('../methods/ticket/closeByTicket')(Self);
|
require('../methods/ticket/closeByTicket')(Self);
|
||||||
require('../methods/ticket/closeByAgency')(Self);
|
require('../methods/ticket/closeByAgency')(Self);
|
||||||
require('../methods/ticket/closeByRoute')(Self);
|
require('../methods/ticket/closeByRoute')(Self);
|
||||||
|
require('../methods/ticket/isRoleAdvanced')(Self);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue