Field ACL part one #689 (vn-model) beforeRemote() wrapper

This commit is contained in:
Joan Sanchez 2018-10-23 11:25:51 +02:00
parent 9f7be6364c
commit f2d5e6afee
35 changed files with 272 additions and 566 deletions

View File

@ -164,6 +164,7 @@
"state": "client.card.credit.create",
"component": "vn-client-credit-create",
"description": "New credit",
"acl": ["teamBoss"],
"params": {
"client": "$ctrl.client"
}
@ -191,6 +192,7 @@
"state": "client.card.greuge.create",
"component": "vn-client-greuge-create",
"description": "New greuge",
"acl": ["salesAssistant"],
"params": {
"client": "$ctrl.client"
}

View File

@ -1,4 +1,4 @@
<mg-ajax path="/client/api/Clients/{{patch.params.id}}/updateBasicData" options="vnPatch"></mg-ajax>
<mg-ajax path="/client/api/Clients/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.client"
@ -34,8 +34,7 @@
show-field="firstName"
value-field="id"
label="Salesperson"
vn-acl="salesAssistant, employee"
acl-conditional-to-employee="{{!$ctrl.client.isTaxDataChecked}}">
vn-acl="salesAssistant">
<tpl-item>{{firstName}} {{name}}</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one

View File

@ -1,9 +1,9 @@
<mg-ajax path="/client/api/Clients/{{post.params.id}}/updateBillingData" options="vnPost"></mg-ajax>
<mg-ajax path="/client/api/Clients/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.client"
form="form"
save="post">
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()">
<vn-card pad-large>
@ -36,9 +36,9 @@
label="Swift / BIC"
url="/client/api/BankEntities"
field="$ctrl.client.bankEntityFk"
select-fields="['name']"
fields="['name']"
initial-data="$ctrl.client.bankEntityFk"
where="{or: [{bic: {regexp: 'search'}}, {name: {regexp: 'search'}}]}"
search-function="{or: [{bic: {regexp: $search}}, {name: {regexp: $search}}]}"
value-field="id"
show-field="bic"
vn-acl="salesAssistant">

View File

@ -37,7 +37,11 @@
</vn-pagination>
</vn-card>
</vn-vertical>
<a ui-sref="client.card.credit.create" vn-tooltip="New credit"
vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-float-button icon="add" fixed-bottom-right
ui-sref="client.card.credit.create"
vn-acl="teamBoss"
vn-acl-action="remove"
vn-tooltip="New credit"
vn-bind="+">
</vn-float-button>

View File

@ -1,4 +1,4 @@
<mg-ajax path="/client/api/Clients/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<mg-ajax path="/client/api/Clients/{{patch.params.id}}/updateFiscalData" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.client"
@ -13,41 +13,31 @@
vn-two
vn-focus
label="Social name"
field="$ctrl.client.socialName"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.socialName">
</vn-textfield>
<vn-textfield
vn-one
label="Tax number"
field="$ctrl.client.fi"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.fi">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-two
label="Street"
field="$ctrl.client.street"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.street">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Postcode"
field="$ctrl.client.postcode"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.postcode">
</vn-textfield>
<vn-textfield
vn-one
label="City"
field="$ctrl.client.city"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.city">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
@ -58,9 +48,7 @@
url="/client/api/Countries"
show-field="country"
value-field="id"
label="Country"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
label="Country">
</vn-autocomplete>
<vn-autocomplete
vn-one
@ -69,80 +57,61 @@
url="/client/api/Provinces"
show-field="name"
value-field="id"
label="Province"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
label="Province">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-check
vn-one
label="Active"
field="$ctrl.client.isActive"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.isActive">
</vn-check>
<vn-check
vn-one
label="Frozen"
field="$ctrl.client.isFreezed"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.isFreezed">
</vn-check>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-check
vn-one
label="Has to invoice"
field="$ctrl.client.hasToInvoice"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.hasToInvoice">
</vn-check>
<vn-check
vn-one
label="Vies"
field="$ctrl.client.isVies"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.isVies">
</vn-check>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-check
vn-one
label="Invoice by mail"
field="$ctrl.client.isToBeMailed"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.isToBeMailed">
</vn-check>
<vn-check
vn-one
label="Invoice by address"
field="$ctrl.client.hasToInvoiceByAddress"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.hasToInvoiceByAddress">
</vn-check>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-check
vn-one
label="Is equalizated"
field="$ctrl.client.isEqualizated"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
field="$ctrl.client.isEqualizated">
</vn-check>
<vn-check
vn-one
label="Verified data"
field="$ctrl.client.isTaxDataChecked"
vn-acl="administrative, salesAssistant, salesAssistant">
vn-acl="administrative">
</vn-check>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit
label="Save"
vn-acl="administrative, salesAssistant, salesPerson"
acl-conditional-to-salesPerson="{{!$ctrl.client.isTaxDataChecked}}">
<vn-submit label="Save">
</vn-submit>
</vn-button-bar>
</form>

View File

@ -51,8 +51,11 @@
</vn-pagination>
</vn-card>
</vn-vertical>
<a ui-sref="client.card.greuge.create" vn-tooltip="New greuge"
vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-float-button icon="add" fixed-bottom-right
ui-sref="client.card.greuge.create"
vn-tooltip="New greuge"
vn-acl="salesAssistant"
vn-acl-action="remove"
vn-bind="+">
</vn-float-button>

View File

@ -68,7 +68,7 @@
</vn-autocomplete>
<vn-check
vn-one
label="Is active"
label="Active"
field="$ctrl.item.isActive">
</vn-check>
</vn-horizontal>

View File

@ -195,7 +195,7 @@ export default {
expenceSelect: `vn-autocomplete[field="$ctrl.item.expenceFk"] input`,
expenceSelectOptionThree: `vn-autocomplete[field="$ctrl.item.expenceFk"] vn-drop-down ul > li:nth-child(3)`,
longNameInput: `vn-textfield[label="Full name"] input`,
isActiveCheckbox: `vn-check[label='Is active'] > label > input`,
isActiveCheckbox: `vn-check[label='Active'] > label > input`,
submitBasicDataButton: `${components.vnSubmit}`
},
itemTags: {

View File

@ -75,7 +75,7 @@ describe('Client Edit fiscalData path', () => {
});
});
it(`should click on the fiscal data button to start editing`, () => {
it(`should click on the fiscal data button`, () => {
return nightmare
.waitToClick(selectors.clientFiscalData.fiscalDataButton)
.waitForURL('fiscal-data')
@ -85,161 +85,6 @@ describe('Client Edit fiscalData path', () => {
});
});
it('should not be able to edit the social name', done => {
return nightmare
.wait(selectors.clientFiscalData.socialNameInput)
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.socialNameInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the fiscal id', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.fiscalIdInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the address', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.addressInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the postcode', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.postcodeInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the city', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.cityInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the country', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.countryInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the province', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.provinceInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the active checkbox', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.activeCheckboxInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the frozen checkbox', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.frozenCheckboxInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the has to invoice checkbox', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.hasToInvoiceCheckboxInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the vies checkbox', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.viesCheckboxInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the invoice by mail checkbox', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.invoiceByMailCheckboxInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the invoice by address', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.invoiceByAddressCheckboxInput)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the equalization tax checkbox', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.equalizationTaxCheckboxLabel)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
it('should not be able to edit the verified data checkbox', done => {
return nightmare
.evaluate(selector => {
@ -250,17 +95,6 @@ describe('Client Edit fiscalData path', () => {
done();
}).catch(done.fail);
});
it('should not be able to use the submit button', done => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.saveButton)
.then(value => {
expect(value).toBeTruthy();
done();
}).catch(done.fail);
});
});
describe('as administrative', () => {

View File

@ -7,7 +7,7 @@ describe('Client', () => {
beforeAll(() => {
return nightmare
.waitForLogin('employee');
.waitForLogin('salesAssistant');
});
it('should click on the Clients button of the top bar menu', done => {

View File

@ -290,14 +290,15 @@ describe('Client lock verified data path', () => {
}).catch(done.fail);
});
it('should confirm the form have been disabled for salesPerson', done => {
it('should not be able to save change throwing a verified data error', done => {
return nightmare
.wait(selectors.clientFiscalData.socialNameInput)
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, 'vn-textfield[field="$ctrl.client.socialName"] input')
.clearInput(selectors.clientFiscalData.socialNameInput)
.type(selectors.clientFiscalData.socialNameInput, 'salesPerson was here')
.click(selectors.clientFiscalData.saveButton)
.waitForSnackbar()
.then(result => {
expect(result).toEqual(true);
expect(result).toEqual(jasmine.arrayContaining([`You can't make changes on a client with verified data`]));
done();
}).catch(done.fail);
});
@ -360,40 +361,14 @@ describe('Client lock verified data path', () => {
}).catch(done.fail);
});
it('should confirm verified data button is enabled for salesAssistant', done => {
it('should confirm verified data button is disabled for salesAssistant', done => {
return nightmare
.wait(selectors.clientFiscalData.verifiedDataCheckboxInput)
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.verifiedDataCheckbox)
.then(result => {
expect(result).not.toBe(true);
done();
}).catch(done.fail);
});
it('should uncheck the Verified data checkbox', done => {
return nightmare
.waitToClick(selectors.clientFiscalData.verifiedDataCheckboxInput)
.waitToClick(selectors.clientFiscalData.saveButton)
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual('Data saved!');
done();
}).catch(done.fail);
});
it('should confirm Verified data checkbox is unchecked', done => {
return nightmare
.waitToClick(selectors.clientBasicData.basicDataButton)
.wait(selectors.clientBasicData.nameInput)
.waitToClick(selectors.clientFiscalData.fiscalDataButton)
.wait(selectors.clientFiscalData.verifiedDataCheckboxInput)
.evaluate(selector => {
return document.querySelector(selector).checked;
}, selectors.clientFiscalData.verifiedDataCheckboxInput)
.then(value => {
expect(value).toBeFalsy();
expect(result).toBeTruthy();
done();
}).catch(done.fail);
});

View File

@ -0,0 +1,71 @@
USE `vn`;
CREATE TABLE `salix`.`fieldAcl` (
`id` INT NOT NULL AUTO_INCREMENT,
`model` VARCHAR(255) NULL,
`property` VARCHAR(255) NULL,
`actionType` SET('insert', 'update', '*') NULL DEFAULT '*',
`role` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'name', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'contact', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'email', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'phone', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'mobile', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'contactChannelFk', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'socialName', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'fi', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'street', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'postcode', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'city', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'countryFk', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'provinceFk', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'isActive', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'salesPersonFk', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'hasToInvoice', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'isToBeMailed', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'isEqualizated', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'isFreezed', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'isVies', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'hasToInvoiceByAddress', 'update', 'salesPerson');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'isTaxDataChecked', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'payMethodFk', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'dueDay', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'iban', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'bankEntityFk', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'hasLcr', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'hasCoreVnl', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'hasSepaVnl', 'update', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Client', 'credit', 'update', 'teamBoss');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('BankEntity', '*', 'insert', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'isDefaultAddress', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'nickname', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'postalCode', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'provinceFk', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'agencyModeFk', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'phone', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'mobile', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'street', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'city', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'isActive', '*', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'isEqualizated', '*', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Address', 'clientFk', 'insert', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('ClientObservation', '*', 'insert', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Recovery', '*', 'insert', 'administrative');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Recovery', 'finished', 'update', 'administrative');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('CreditClassification', 'finished', 'update', 'creditInsurance');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Account', '*', 'update', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Greuge', '*', 'insert', 'salesAssistant');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('ClientSample', '*', 'insert', 'employee');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Item', '*', '*', 'buyer');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Item', '*', '*', 'marketingBoss');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('ItemBotanical', '*', '*', 'buyer');
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('ClaimEnd', '*', '*', 'salesAssistant');
DELETE FROM `salix`.`ACL` WHERE `id`='28';
UPDATE `salix`.`ACL` SET `accessType`='*' WHERE `id`='60';
DELETE FROM `salix`.`ACL` WHERE `id`='59';
DELETE FROM `salix`.`ACL` WHERE `id`='57';
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (116, 'BankEntity', '*', '*', 'ALLOW', 'role', 'employee');
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (117, 'ClientSample', '*', '*', 'ALLOW', 'role', 'employee');

View File

@ -34,5 +34,8 @@
"The new quantity should be smaller than the old one": "The new quantity should be smaller than the old one",
"Package cannot be blank": "Package cannot be blank",
"The sales of this ticket can't be modified": "The sales of this ticket can't be modified",
"You don't have enough privileges to do that": "You don't have enough privileges to do that"
"You don't have enough privileges to do that": "You don't have enough privileges to do that",
"You don't have enough privileges to change that field": "You don't have enough privileges to change that field",
"You don't have enough privileges": "You don't have enough privileges",
"You can't make changes on a client with verified data": "You can't make changes on a client with verified data"
}

View File

@ -51,9 +51,12 @@
"You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo",
"Warehouse cannot be blank": "El almacén no puede quedar en blanco",
"Agency cannot be blank": "La agencia no puede quedar en blanco",
"You don't have enough privileges to do that": "No tienes permisos para para hacer esto",
"You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados",
"This address doesn't exist": "Este consignatario no existe",
"The sales of this ticket can't be modified": "Los movimientos de este tiquet no pueden ser modificadas",
"You can't create an order for a inactive client": "You can't create an order for a inactive client",
"You can't create an order for a client that doesn't has tax data verified": "You can't create an order for a client that doesn't has tax data verified"
"You can't create an order for a client that doesn't has tax data verified": "You can't create an order for a client that doesn't has tax data verified",
"You haven't enought privileges": "You haven't enought privileges",
"You don't have enought privileges": "You don't have enought privileges",
"You don't have enough privileges": "You don't have enough privileges"
}

View File

@ -1,52 +0,0 @@
const app = require(`${servicesDir}/client/server/server`);
describe('Client updateBasicData', () => {
afterAll(async() => {
let id = 101;
let ctx = {req: {accessToken: {userId: 1}}};
let validparams = {email: 'BruceWayne@verdnatura.es'};
await app.models.Client.updateBasicData(ctx, validparams, id);
});
it('should return an error if the params aint valid', async() => {
let error;
let ctx = {req: {accessToken: {userId: 1}}};
let id = 101;
let invalidparams = {invalid: 'param for update'};
await app.models.Client.updateBasicData(ctx, invalidparams, id)
.catch(e => {
error = e;
});
expect(error.toString()).toContain(`You don't have enough privileges to do that`);
});
it('should return an error if the client has isTaxDataChecked and employee try to change his salesPerson', async() => {
let error;
let ctx = {req: {accessToken: {userId: 1}}};
let id = 101;
let params = {salesPerson: 3};
await app.models.Client.updateBasicData(ctx, params, id)
.catch(e => {
error = e;
});
expect(error.toString()).toContain(`You don't have enough privileges to do that`);
});
it('should update the client fiscal data and return the count if changes made', async() => {
let id = 101;
let client = await app.models.Client.findById(id);
expect(client.email).toEqual('BruceWayne@verdnatura.es');
let validparams = {email: 'myNewEmail@myDomain.es'};
let ctx = {req: {accessToken: {userId: 1}}};
let result = await app.models.Client.updateBasicData(ctx, validparams, id);
expect(result.email).toEqual('myNewEmail@myDomain.es');
});
});

View File

@ -1,82 +0,0 @@
const app = require(`${servicesDir}/client/server/server`);
describe('Client updateBillingData', () => {
afterAll(async() => {
let ctxOfAdmin = {req: {accessToken: {userId: 5}}};
let validparams = {
phone: 1111111111,
payMethodFk: 5,
dueDay: 0,
iban: null,
hasLcr: 0,
hasCoreVnl: 1,
hasSepaVnl: 1
};
let idWithDataChecked = 101;
await app.models.Client.updateBillingData(ctxOfAdmin, validparams, idWithDataChecked);
});
it('should return an error if the user is not administrative and the isTaxDataChecked value is true', async() => {
let error;
let ctxOfNoAdmin = {req: {accessToken: {userId: 1}}};
let params = {iban: null};
let idWithDataChecked = 101;
await app.models.Client.updateBillingData(ctxOfNoAdmin, params, idWithDataChecked)
.catch(e => {
error = e;
});
expect(error.message).toEqual(`You don't have enough privileges to do that`);
});
it('should update the billing data and check if the changes were made', async() => {
let ctxOfAdmin = {req: {accessToken: {userId: 5}}};
let params = {
phone: 2222222222,
payMethodFk: 4,
bankEntityFk: 128,
dueDay: 30,
iban: 'ES91 2100 0418 4502 0005 1332',
hasLcr: 1,
hasCoreVnl: 0,
hasSepaVnl: 0
};
let idWithDataChecked = 101;
await app.models.Client.updateBillingData(ctxOfAdmin, params, idWithDataChecked);
let client = await app.models.Client.findById(idWithDataChecked);
expect(client.phone).not.toEqual(params.phone);
expect(client.payMethodFk).toEqual(params.payMethodFk);
expect(client.dueDay).toEqual(params.dueDay);
expect(client.iban).toEqual(params.iban);
expect(client.hasLcr).toBeTruthy();
expect(client.hasCoreVnl).toBeFalsy();
expect(client.hasSepaVnl).toBeFalsy();
});
it('should return an error if the given IBAN is an invalid one', async() => {
let ctxOfAdmin = {req: {accessToken: {userId: 5}}};
let validparams = {
payMethodFk: 5,
iban: null};
let idWithDataChecked = 101;
await app.models.Client.updateBillingData(ctxOfAdmin, validparams, idWithDataChecked);
validparams = {iban: 12345};
try {
await app.models.Client.updateBillingData(ctxOfAdmin, validparams, idWithDataChecked);
} catch (error) {
expect(error.toString()).toContain('The IBAN does not have the correct format');
}
let client = await app.models.Client.findById(idWithDataChecked);
expect(client.iban).toBeFalsy();
});
});

View File

@ -21,7 +21,7 @@ describe('Client updateFiscalData', () => {
error = e;
});
expect(error.toString()).toContain(`You don't have enough privileges to do that`);
expect(error.toString()).toContain(`You can't make changes on a client with verified data`);
});
it('should return an error if the user is administrative and the isTaxDataChecked value is true BUT the params aint valid', async() => {

View File

@ -1,54 +0,0 @@
let UserError = require('../../helpers').UserError;
module.exports = Self => {
Self.remoteMethodCtx('updateBasicData', {
description: 'Updates billing data of a client',
accessType: 'WRITE',
accepts: [{
arg: 'data',
type: 'Object',
required: true,
description: 'Params to update',
http: {source: 'body'}
}, {
arg: 'id',
type: 'string',
required: true,
description: 'Model id',
http: {source: 'path'}
}],
returns: {
arg: 'data',
type: 'Worker',
root: true
},
http: {
path: `/:id/updateBasicData`,
verb: 'PATCH'
}
});
Self.updateBasicData = async(ctx, params, id) => {
let userId = ctx.req.accessToken.userId;
let validUpdateParams = [
'contact',
'name',
'email',
'phone',
'mobile',
'salesPersonFk',
'contactChannelFk'
];
let isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant');
let client = await Self.app.models.Client.findById(id);
for (const key in params) {
if (validUpdateParams.indexOf(key) === -1 || key == 'salesPersonFk' && client.isTaxDataChecked && !isSalesAssistant)
throw new UserError(`You don't have enough privileges to do that`);
}
return await client.updateAttributes(params);
};
};

View File

@ -1,64 +0,0 @@
let UserError = require('../../helpers').UserError;
module.exports = Self => {
Self.remoteMethodCtx('updateBillingData', {
description: 'Updates billing data of a client',
accessType: 'WRITE',
accepts: [{
arg: 'data',
type: 'Object',
required: true,
description: 'Params to update',
http: {source: 'body'}
}, {
arg: 'id',
type: 'string',
required: true,
description: 'Model id',
http: {source: 'path'}
}],
returns: {
arg: 'data',
type: 'Worker',
root: true
},
http: {
path: `/:id/updateBillingData`,
verb: 'POST'
}
});
Self.updateBillingData = async(ctx, params, id) => {
let userId = ctx.req.accessToken.userId;
let data = filterAttributes(params, [
'payMethodFk',
'bankEntityFk',
'dueDay',
'iban',
'hasLcr',
'hasCoreVnl',
'hasSepaVnl']);
if (!Object.keys(data).length) return;
let isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant');
let client = await Self.app.models.Client.findOne({where: {id: id}});
if (!isSalesAssistant)
throw new UserError(`You don't have enough privileges to do that`);
return client.updateAttributes(data);
};
function filterAttributes(params, allowed) {
let newParams = {};
Object.keys(params).forEach(attribute => {
if (allowed.indexOf(attribute) > -1)
newParams[attribute] = params[attribute];
});
return newParams;
}
};

View File

@ -30,11 +30,11 @@ module.exports = Self => {
Self.updateFiscalData = async(ctx, params, id) => {
let userId = ctx.req.accessToken.userId;
let isAdministrative = await Self.app.models.Account.hasRole(userId, 'administrative');
let isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant');
let [taxData] = await Self.app.models.Client.find({where: {id: id}, fields: ['isTaxDataChecked']});
if (!isAdministrative && taxData.isTaxDataChecked)
throw new UserError(`You don't have enough privileges to do that`);
if (!isSalesAssistant && taxData.isTaxDataChecked)
throw new UserError(`You can't make changes on a client with verified data`);
let validUpdateParams = [
'socialName',

View File

@ -47,19 +47,36 @@ module.exports = Self => {
* Checks if user has a role.
*
* @param {Integer} userId The user id
* @param {String} role The role name
* @param {String} name The role name
* @return {Boolean} %true if user has the role, %false otherwise
*/
Self.hasRole = async function(userId, role) {
Self.hasRole = async function(userId, name) {
let roles = await Self.getRoles(userId);
return roles.find(role => {
return role.toLowerCase() == name.toLowerCase();
});
};
/**
* Get all user roles.
*
* @param {Integer} userId The user id
* @return {Object} User role list
*/
Self.getRoles = async function(userId) {
let result = await Self.rawSql(
`SELECT COUNT(*) AS roleCount
`SELECT r.name
FROM account.user u
JOIN account.roleRole rr ON rr.role = u.role
JOIN account.role r ON r.id = rr.inheritsFrom
WHERE u.id = ?
AND r.name = ?`,
[userId, role]
);
return result[0].roleCount > 0;
WHERE u.id = ?`, [userId]);
let roles = [];
for (role of result) {
roles.push(role.name);
}
return roles;
};
};

View File

@ -17,8 +17,6 @@ module.exports = Self => {
require('../methods/client/getAverageInvoiced')(Self);
require('../methods/client/summary')(Self);
require('../methods/client/updateFiscalData')(Self);
require('../methods/client/updateBillingData')(Self);
require('../methods/client/updateBasicData')(Self);
require('../methods/client/getTransactions')(Self);
require('../methods/client/confirmTransaction')(Self);
@ -102,8 +100,6 @@ module.exports = Self => {
});
}
// Hooks
Self.observe('before save', async function(ctx) {
let changes = ctx.data || ctx.instance;
let orgData = ctx.currentInstance;

View File

@ -0,0 +1,27 @@
{
"name": "FieldAcl",
"base": "VnModel",
"options": {
"mysql": {
"table": "fieldAcl"
}
},
"properties": {
"id": {
"id": true,
"type": "Number"
},
"model": {
"type": "String"
},
"property":{
"type": "String"
},
"actionType":{
"type": "String"
},
"role":{
"type": "String"
}
}
}

View File

@ -1,4 +1,4 @@
module.exports = Self => {
require('../methods/userConfig/setUserConfig')(Self);
require('../methods/userConfig/getUserConfig')(Self);
require('../methods/user-config/setUserConfig')(Self);
require('../methods/user-config/getUserConfig')(Self);
};

View File

@ -1,34 +1,20 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const UserError = require('../helpers').UserError;
module.exports = function(Self) {
Self.ParameterizedSQL = ParameterizedSQL;
Self.setup = function() {
Self.super_.setup.call(this);
/*
let disableMethods = {
create: true,
replaceOrCreate: true,
patchOrCreate: true,
upsert: true,
updateOrCreate: true,
exists: true,
find: true,
findOne: true,
findById: true,
deleteById: true,
replaceById: true,
updateAttributes: false,
createChangeStream: true,
updateAll: true,
upsertWithWhere: true,
count: true
};
for (let method in disableMethods) {
// this.disableRemoteMethod(method, disableMethods[method]);
}
*/
// Register field ACL validation
this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx));
this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx));
this.beforeRemote('patchOrCreate', ctx => this.checkInsertAcls(ctx));
this.beforeRemote('create', ctx => this.checkInsertAcls(ctx));
this.beforeRemote('replaceById', ctx => this.checkInsertAcls(ctx));
this.beforeRemote('replaceOrCreate', ctx => this.checkInsertAcls(ctx));
this.remoteMethod('crud', {
description: 'Create, update or/and delete instances from model with a single request',
@ -298,6 +284,72 @@ module.exports = function(Self) {
]);
};
Self.checkAcls = async function(ctx, actionType) {
let userId = ctx.req.accessToken.userId;
let models = this.app.models;
let userRoles = await models.Account.getRoles(userId);
let data = ctx.args.data;
let modelAcls;
function modifiedProperties(data) {
let properties = [];
for (property in data) {
properties.push(property);
}
return properties;
}
modelAcls = await models.FieldAcl.find({
where: {
and: [
{model: this.modelName},
{role: {inq: userRoles}},
{property: '*'},
{or: [{actionType: '*'}, {actionType: actionType}]}
]
}
});
let allowedAll = modelAcls.find(acl => {
return acl.property == '*';
});
if (allowedAll)
return;
modelAcls = await models.FieldAcl.find({
where: {
and: [
{model: this.modelName},
{role: {inq: userRoles}},
{property: {inq: modifiedProperties(data)}},
{or: [{actionType: '*'}, {actionType: actionType}]}
]
}
});
let propsHash = {};
for (let acl of modelAcls)
propsHash[acl.property] = true;
let allowedProperties = Object.keys(data).every(property => {
return propsHash[property];
});
if (!allowedProperties)
throw new UserError(`You don't have enough privileges`);
};
Self.checkUpdateAcls = function(ctx) {
return this.checkAcls(ctx, 'update');
};
Self.checkInsertAcls = function(ctx) {
return this.checkAcls(ctx, 'insert');
};
// Action bindings
require('../methods/vn-model/validateBinded')(Self);
// Handle MySql errors

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/worker-mana/getCurrentWorkerMana')(Self);
};

View File

@ -1,3 +0,0 @@
module.exports = Self => {
require('../methods/workerMana/getCurrentWorkerMana')(Self);
};

View File

@ -15,6 +15,9 @@
"ACL": {
"dataSource": "salix"
},
"FieldAcl": {
"dataSource": "salix"
},
"ObservationType": {
"dataSource": "vn"
},