Merge branch 'dev' into 5174-refactor-ticket-weekly
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
af1e68675f
|
@ -6,6 +6,16 @@
|
||||||
"table": "util.notificationAcl"
|
"table": "util.notificationAcl"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"properties":{
|
||||||
|
"notificationFk": {
|
||||||
|
"id": true,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"roleFk":{
|
||||||
|
"id": true,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
"notification": {
|
"notification": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.observe('before save', async function(ctx) {
|
||||||
|
const models = Self.app.models;
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -7,15 +7,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"notificationFk": {
|
"id": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"id": true,
|
"id": true,
|
||||||
"description": "Identifier"
|
"description": "Primary key"
|
||||||
|
},
|
||||||
|
"notificationFk": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Foreign key to Notification"
|
||||||
},
|
},
|
||||||
"userFk": {
|
"userFk": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"id": true,
|
"description": "Foreign key to Account"
|
||||||
"description": "Identifier"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
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() => {
|
||||||
|
const tx = await models.NotificationSubscription.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const user = 9;
|
||||||
|
const notificationSubscriptionId = 2;
|
||||||
|
const ctx = {req: {accessToken: {userId: user}}};
|
||||||
|
const notification = await models.NotificationSubscription.findById(notificationSubscriptionId);
|
||||||
|
|
||||||
|
let error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await models.NotificationSubscription.deleteNotification(ctx, notification.id, options);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toContain('You dont have permission to modify this user');
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should delete a notification if the user is editing itself', async() => {
|
||||||
|
const tx = await models.NotificationSubscription.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const user = 9;
|
||||||
|
const notificationSubscriptionId = 4;
|
||||||
|
const ctx = {req: {accessToken: {userId: user}}};
|
||||||
|
const notification = await models.NotificationSubscription.findById(notificationSubscriptionId);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should delete a notification if the user is editing a subordinate', async() => {
|
||||||
|
const tx = await models.NotificationSubscription.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const user = 9;
|
||||||
|
const notificationSubscriptionId = 5;
|
||||||
|
const ctx = {req: {accessToken: {userId: user}}};
|
||||||
|
const notification = await models.NotificationSubscription.findById(notificationSubscriptionId);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model,property,accessType,principalId)
|
||||||
|
VALUES
|
||||||
|
('NotificationSubscription','*','*','employee'),
|
||||||
|
('NotificationAcl','*','READ','employee');
|
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE
|
||||||
|
`util`.`notificationSubscription`
|
||||||
|
ADD
|
||||||
|
CONSTRAINT `notificationSubscription_UN` UNIQUE KEY (`notificationFk`, `userFk`);
|
|
@ -0,0 +1,7 @@
|
||||||
|
ALTER TABLE `util`.`notificationSubscription`
|
||||||
|
ADD `id` int(11) auto_increment NULL,
|
||||||
|
DROP PRIMARY KEY,
|
||||||
|
ADD CONSTRAINT PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
ALTER TABLE `util`.`notificationSubscription`
|
||||||
|
ADD KEY `notificationSubscription_ibfk_1` (`notificationFk`);
|
|
@ -1954,10 +1954,6 @@ INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`
|
||||||
(100, 'INDEFINIDO A TIEMPO COMPLETO', 1, 1, 1),
|
(100, 'INDEFINIDO A TIEMPO COMPLETO', 1, 1, 1),
|
||||||
(109, 'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO', 1, 1, 1);
|
(109, 'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO', 1, 1, 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`businessCategory` (`id`, `description`, `rate`)
|
|
||||||
VALUES
|
|
||||||
(1, 'basic employee', 1);
|
|
||||||
|
|
||||||
UPDATE `vn`.`business` b
|
UPDATE `vn`.`business` b
|
||||||
SET `rate` = 7,
|
SET `rate` = 7,
|
||||||
`workerBusinessCategoryFk` = 1,
|
`workerBusinessCategoryFk` = 1,
|
||||||
|
@ -2705,7 +2701,10 @@ INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1109),
|
(1, 1109),
|
||||||
(1, 1110),
|
(1, 1110),
|
||||||
(3, 1109);
|
(3, 1109),
|
||||||
|
(1,9),
|
||||||
|
(1,3);
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
|
INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -478,8 +478,8 @@ export default class SmartTable extends Component {
|
||||||
|
|
||||||
const params = {q: JSON.stringify(stateFilter)};
|
const params = {q: JSON.stringify(stateFilter)};
|
||||||
|
|
||||||
this.$state.go(this.$state.current.name, params, {location: 'replace'});
|
this.$state.go(this.$state.current.name, params, {location: 'replace'})
|
||||||
this.refresh();
|
.then(() => this.refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
applySort() {
|
applySort() {
|
||||||
|
@ -499,8 +499,8 @@ export default class SmartTable extends Component {
|
||||||
stateFilter.tableOrder = order;
|
stateFilter.tableOrder = order;
|
||||||
|
|
||||||
const params = {q: JSON.stringify(stateFilter)};
|
const params = {q: JSON.stringify(stateFilter)};
|
||||||
this.$state.go(this.$state.current.name, params, {location: 'replace'});
|
this.$state.go(this.$state.current.name, params, {location: 'replace'})
|
||||||
this.refresh();
|
.then(() => this.refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
filterSanitizer(field) {
|
filterSanitizer(field) {
|
||||||
|
@ -589,7 +589,7 @@ export default class SmartTable extends Component {
|
||||||
refresh() {
|
refresh() {
|
||||||
this.isRefreshing = true;
|
this.isRefreshing = true;
|
||||||
this.model.refresh()
|
this.model.refresh()
|
||||||
.then(() => this.isRefreshing = false);
|
.finally(() => this.isRefreshing = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,7 @@ describe('Component smartTable', () => {
|
||||||
describe('applySort()', () => {
|
describe('applySort()', () => {
|
||||||
it('should call the $state go and model refresh without making changes on the model order', () => {
|
it('should call the $state go and model refresh without making changes on the model order', () => {
|
||||||
controller.$state = {
|
controller.$state = {
|
||||||
go: jest.fn(),
|
go: jest.fn().mockReturnValue(new Promise(resolve => resolve())),
|
||||||
current: {
|
current: {
|
||||||
name: 'section'
|
name: 'section'
|
||||||
}
|
}
|
||||||
|
@ -171,13 +171,12 @@ describe('Component smartTable', () => {
|
||||||
|
|
||||||
expect(controller.model.order).toBeUndefined();
|
expect(controller.model.order).toBeUndefined();
|
||||||
expect(controller.$state.go).toHaveBeenCalled();
|
expect(controller.$state.go).toHaveBeenCalled();
|
||||||
expect(controller.refresh).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the $state go and model refresh after setting model order according to the controller sortCriteria', () => {
|
it('should call the $state go and model refresh after setting model order according to the controller sortCriteria', () => {
|
||||||
const orderBy = {field: 'myField', sortType: 'ASC'};
|
const orderBy = {field: 'myField', sortType: 'ASC'};
|
||||||
controller.$state = {
|
controller.$state = {
|
||||||
go: jest.fn(),
|
go: jest.fn().mockReturnValue(new Promise(resolve => resolve())),
|
||||||
current: {
|
current: {
|
||||||
name: 'section'
|
name: 'section'
|
||||||
}
|
}
|
||||||
|
@ -190,7 +189,6 @@ describe('Component smartTable', () => {
|
||||||
|
|
||||||
expect(controller.model.order).toEqual(`${orderBy.field} ${orderBy.sortType}`);
|
expect(controller.model.order).toEqual(`${orderBy.field} ${orderBy.sortType}`);
|
||||||
expect(controller.$state.go).toHaveBeenCalled();
|
expect(controller.$state.go).toHaveBeenCalled();
|
||||||
expect(controller.refresh).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -293,12 +291,10 @@ describe('Component smartTable', () => {
|
||||||
controller.$inputsScope = {
|
controller.$inputsScope = {
|
||||||
searchProps: {}
|
searchProps: {}
|
||||||
};
|
};
|
||||||
jest.spyOn(controller, 'refresh');
|
|
||||||
|
|
||||||
controller.defaultFilter();
|
controller.defaultFilter();
|
||||||
|
|
||||||
expect(controller.model.addFilter).toHaveBeenCalled();
|
expect(controller.model.addFilter).toHaveBeenCalled();
|
||||||
expect(controller.refresh).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue