feat(canEdit): use checkAccess
gitea/salix/pipeline/head This commit is unstable Details

This commit is contained in:
Alex Moreno 2022-10-31 14:13:06 +01:00
parent 36c0cc1a38
commit b37c257885
6 changed files with 281 additions and 203 deletions

View File

@ -1,3 +1,5 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production');
('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'),
('Sale', 'editFloramondo', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'editWeekly', 'WRITE', 'DENY', 'ROLE', '$authenticated');

View File

@ -0,0 +1,22 @@
module.exports = function(app) {
app.models.ACL.checkAccess = async(ctx, modelId, property, accessType = '*') => {
const models = app.models;
const context = {
accessToken: ctx.req.accessToken,
model: models[modelId],
property: property,
modelId: modelId,
accessType: accessType,
sharedMethod: {
name: property,
aliases: [],
sharedClass: true
}
};
const acl = await models.ACL.checkAccessForContext(context);
return acl.permission == 'ALLOW';
};
};

View File

@ -1,5 +1,4 @@
const UserError = require('vn-loopback/util/user-error');
const loopBackCtx = require('vn-loopback/server/server');
module.exports = Self => {
Self.remoteMethodCtx('canEdit', {
@ -7,7 +6,7 @@ module.exports = Self => {
accessType: 'READ',
accepts: [{
arg: 'sales',
type: ['object'],
type: ['number'],
required: true
}],
returns: {
@ -16,7 +15,7 @@ module.exports = Self => {
},
http: {
path: `/canEdit`,
verb: 'get'
verb: 'GET'
}
});
@ -27,64 +26,39 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
console.log(ctx.req.accessToken);
const token = ctx.req.accessToken;
let canEditTracked = await models.ACL.checkAccessForToken(token, models.Sale, null, 'refund');
// const newCtx = ctx;
// newCtx.property = 'refund';
// newCtx.accessType = 'WRITE';
// newCtx.methodNames = ['refund'];
// newCtx.model = await models.Sale;
const salesData = await models.Sale.find({
fields: ['id', 'itemFk', 'ticketFk'],
where: {id: {inq: sales}},
include:
{
relation: 'item',
scope: {
fields: ['id', 'isFloramondo'],
}
}
}, myOptions);
// let canEditTracked = await models.ACL.checkAccessForContext(newCtx);
console.log(canEditTracked);
const ticketId = salesData[0].ticketFk;
// let canEditTracked2 = await models.ACL.checkPermission('USER', 'developer', 'Sale', 'editTracked', 'READ');
/* const array = ['editTracked'];
const AccessContext = loopBackCtx.AccessContext;
const toFind = {
principals: [{
type: 'ROLE',
id: 'employee'
}],
model: 'Sale',
property: 'editTracked',
methodNames: ['editTracked'],
accessType: 'WRITE'
};
const newContext = new AccessContext(toFind);
newContext.methodNames = ['editTracked'];
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);
if (!isTicketEditable)
throw new UserError(`The sales of this ticket can't be modified`);
let canEditTracked3 = await models.ACL.checkAccessForContext(newContext);
const hasSaleTracking = await models.SaleTracking.findOne({where: {saleFk: {inq: sales}}}, myOptions);
const hasSaleCloned = await models.SaleCloned.findOne({where: {saleClonedFk: {inq: sales}}}, myOptions);
const isTicketWeekly = await models.TicketWeekly.findOne({where: {ticketFk: ticketId}}, myOptions);
const hasSaleFloramondo = salesData.find(sale => sale.item().isFloramondo);
let canEditTracked4 = await models.ACL.checkAccessForContext({
principals: [{
type: 'ROLE',
id: 'developer'
}],
model: 'Sale',
property: 'editTracked',
methodName: 'editTracked',
methodNames: ['editTracked'],
accessType: 'WRITE'
});
// console.log(canEditTracked);
// canEditTracked = await models.ACL.resolvePermission(canEditTracked);
// let canEditCloned = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'editCloned', '*');
// let canEditWeekly = await models.ACL.checkPermission('ROLE', 'employee', 'Ticket', 'editWeekly', '*');
const canEditTracked = await models.ACL.checkAccess(ctx, 'Sale', 'editTracked');
const canEditCloned = await models.ACL.checkAccess(ctx, 'Sale', 'editCloned');
const canEditWeekly = await models.ACL.checkAccess(ctx, 'Ticket', 'editWeekly');
const canEditFloramondo = await models.ACL.checkAccess(ctx, 'Sale', 'editFloramondo');
// console.log(canEditTracked, canEditTracked2);
console.log('DENY: ', canEditTracked3.permission);
console.log('ALLOW: ', canEditTracked4.permission);
const shouldEditTracked = canEditTracked || !hasSaleTracking;
const shouldEditCloned = canEditCloned || !hasSaleCloned;
const shouldEditWeekly = canEditWeekly || !isTicketWeekly;
const shouldEditFloramondo = canEditFloramondo || !hasSaleFloramondo;
const canEdit = shouldEditTracked && shouldEditCloned && shouldEditWeekly;
if (canEdit)
return true;
return false;*/
return shouldEditTracked && shouldEditCloned && shouldEditWeekly && shouldEditFloramondo;
};
};

View File

@ -1,179 +1,253 @@
const models = require('vn-loopback/server/server').models;
describe('sale canEdit()', () => {
it('should return true if the role is production regardless of the saleTrackings', async() => {
const tx = await models.Sale.beginTransaction({});
const employeeId = 1;
try {
const options = {transaction: tx};
describe('sale editTracked', () => {
it('should return true if the role is production regardless of the saleTrackings', async() => {
const tx = await models.Sale.beginTransaction({});
const productionUserID = 49;
const ctx = {req: {accessToken: {userId: productionUserID}}};
try {
const options = {transaction: tx};
const sales = [25];
const productionUserID = 49;
const ctx = {req: {accessToken: {userId: productionUserID}}};
const result = await models.Sale.canEdit(ctx, sales, options);
const sales = [25];
expect(result).toEqual(true);
const result = await models.Sale.canEdit(ctx, sales, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
expect(result).toEqual(true);
it('should return true if the role is not production and none of the sales has saleTracking', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const salesPersonUserID = 18;
const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
const sales = [10];
const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return false if any of the sales has a saleTracking record', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const buyerId = 35;
const ctx = {req: {accessToken: {userId: buyerId}}};
const sales = [31];
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 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 = [27];
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({});
const roleEnabled = await models.ACL.findOne({
where: {
model: 'Sale',
property: 'editCloned'
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
if (!roleEnabled || !roleEnabled.principalId) return;
try {
const options = {transaction: tx};
it('should return true if the role is not production and none of the sales has saleTracking', async() => {
const tx = await models.Sale.beginTransaction({});
const roleId = await models.Role.findOne({
where: {
name: roleEnabled.principalId
}
});
const ctx = {req: {accessToken: {userId: roleId}}};
try {
const options = {transaction: tx};
const sales = [27];
const salesPersonUserID = 18;
const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
const result = await models.Sale.canEdit(ctx, sales, options);
const sales = [10];
expect(result).toEqual(true);
const result = await models.Sale.canEdit(ctx, sales, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
expect(result).toEqual(true);
it('should return false if any of the sales is of ticket weekly', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const employeeId = 1;
const ctx = {req: {accessToken: {userId: employeeId}}};
const sales = [33];
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 of ticketWeekly and has the correct role', async() => {
const tx = await models.Sale.beginTransaction({});
const roleEnabled = await models.ACL.findOne({
where: {
model: 'Sale',
property: 'editWeekly'
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
if (!roleEnabled || !roleEnabled.principalId) return;
try {
const options = {transaction: tx};
it('should return false if any of the sales has a saleTracking record', async() => {
const tx = await models.Sale.beginTransaction({});
const roleId = await models.Role.findOne({
try {
const options = {transaction: tx};
const buyerId = 35;
const ctx = {req: {accessToken: {userId: buyerId}}};
const sales = [31];
const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(false);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
describe('sale editCloned', () => {
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 = [27];
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({});
const roleEnabled = await models.ACL.findOne({
where: {
name: roleEnabled.principalId
model: 'Sale',
property: 'editCloned',
permission: 'ALLOW'
}
});
const ctx = {req: {accessToken: {userId: roleId}}};
if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback();
try {
const options = {transaction: tx};
const role = await models.Role.findOne({
where: {
name: roleEnabled.principalId
}
});
const ctx = {req: {accessToken: {userId: role.id}}};
const sales = [27];
const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
describe('ticket editWeekly', () => {
it('should return false if any of the sales is of ticket weekly', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: employeeId}}};
const sales = [33];
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 of ticketWeekly and has the correct role', async() => {
const tx = await models.Sale.beginTransaction({});
const roleEnabled = await models.ACL.findOne({
where: {
model: 'Ticket',
property: 'editWeekly',
permission: 'ALLOW'
}
});
if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback();
try {
const options = {transaction: tx};
const role = await models.Role.findOne({
where: {
name: roleEnabled.principalId
}
});
const ctx = {req: {accessToken: {userId: role.id}}};
const sales = [33];
const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
describe('sale editFloramondo', () => {
it('should return false if any of the sales isFloramondo', async() => {
const tx = await models.Sale.beginTransaction({});
const sales = [33];
const result = await models.Sale.canEdit(ctx, sales, options);
try {
const options = {transaction: tx};
expect(result).toEqual(true);
const ctx = {req: {accessToken: {userId: employeeId}}};
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
// For test
const saleToEdit = await models.Sale.findById(sales[0], null, options);
await saleToEdit.updateAttribute('itemFk', 9, options);
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 of isFloramondo and has the correct role', async() => {
const tx = await models.Sale.beginTransaction({});
const sales = [32];
const roleEnabled = await models.ACL.findOne({
where: {
model: 'Sale',
property: 'editFloramondo',
permission: 'ALLOW'
}
});
if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback();
try {
const options = {transaction: tx};
const role = await models.Role.findOne({
where: {
name: roleEnabled.principalId
}
});
const ctx = {req: {accessToken: {userId: role.id}}};
// For test
const saleToEdit = await models.Sale.findById(sales[0], null, options);
await saleToEdit.updateAttribute('itemFk', 9, options);
const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
});

View File

@ -1,6 +1,6 @@
const models = require('vn-loopback/server/server').models;
fdescribe('sale reserve()', () => {
describe('sale reserve()', () => {
const ctx = {
req: {
accessToken: {userId: 1},
@ -31,7 +31,7 @@ fdescribe('sale reserve()', () => {
expect(error).toEqual(new Error(`The sales of this ticket can't be modified`));
});
fit('should update the given sales of a ticket to reserved', async() => {
it('should update the given sales of a ticket to reserved', async() => {
const tx = await models.Sale.beginTransaction({});
try {

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('ticket componentUpdate()', () => {
const userID = 1101;
@ -175,10 +176,15 @@ describe('ticket componentUpdate()', () => {
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: ctx.req
});
const oldTicket = await models.Ticket.findById(ticketID, null, options);
await models.Ticket.componentUpdate(ctx, options);
const [newTicketID] = await models.Ticket.rawSql('SELECT MAX(id) as id FROM ticket', null, options);
const oldTicket = await models.Ticket.findById(ticketID, null, options);
const newTicket = await models.Ticket.findById(newTicketID.id, null, options);
const newTicketSale = await models.Sale.findOne({where: {ticketFk: args.id}}, options);