Merge pull request '#6744 fix worker setPassword' (!2027) from 6744-fixWorkerSetPassword into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #2027 Reviewed-by: Javi Gallego <jgallego@verdnatura.es> Reviewed-by: Juan Ferrer <juan@verdnatura.es>
This commit is contained in:
commit
5341818473
|
@ -220,5 +220,7 @@
|
||||||
"Shelving not valid": "Shelving not valid",
|
"Shelving not valid": "Shelving not valid",
|
||||||
"printerNotExists": "The printer does not exist",
|
"printerNotExists": "The printer does not exist",
|
||||||
"There are not picking tickets": "There are not picking tickets",
|
"There are not picking tickets": "There are not picking tickets",
|
||||||
"ticketCommercial": "The ticket {{ ticket }} for the salesperson {{ salesMan }} is in preparation. (automatically generated message)"
|
"ticketCommercial": "The ticket {{ ticket }} for the salesperson {{ salesMan }} is in preparation. (automatically generated message)",
|
||||||
|
"This password can only be changed by the user themselves": "This password can only be changed by the user themselves",
|
||||||
|
"They're not your subordinate": "They're not your subordinate"
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,5 +346,7 @@
|
||||||
"CountryFK cannot be empty": "El país no puede estar vacío",
|
"CountryFK cannot be empty": "El país no puede estar vacío",
|
||||||
"Cmr file does not exist": "El archivo del cmr no existe",
|
"Cmr file does not exist": "El archivo del cmr no existe",
|
||||||
"You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
|
"You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
|
||||||
"The address of the customer must have information about Incoterms and Customs Agent": "El consignatario del cliente debe tener informado Incoterms y Agente de aduanas"
|
"The address of the customer must have information about Incoterms and Customs Agent": "El consignatario del cliente debe tener informado Incoterms y Agente de aduanas",
|
||||||
}
|
"This password can only be changed by the user themselves": "Esta contraseña solo puede ser modificada por el propio usuario",
|
||||||
|
"They're not your subordinate": "No es tu subordinado/a."
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
|
||||||
|
const ForbiddenError = require('vn-loopback/util/forbiddenError');
|
||||||
|
const {models} = require('vn-loopback/server/server');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/account/sync')(Self);
|
require('../methods/account/sync')(Self);
|
||||||
require('../methods/account/sync-by-id')(Self);
|
require('../methods/account/sync-by-id')(Self);
|
||||||
|
@ -7,4 +10,11 @@ module.exports = Self => {
|
||||||
require('../methods/account/logout')(Self);
|
require('../methods/account/logout')(Self);
|
||||||
require('../methods/account/change-password')(Self);
|
require('../methods/account/change-password')(Self);
|
||||||
require('../methods/account/set-password')(Self);
|
require('../methods/account/set-password')(Self);
|
||||||
|
|
||||||
|
Self.setUnverifiedPassword = async(id, pass, options) => {
|
||||||
|
const {emailVerified} = await models.VnUser.findById(id, {fields: ['emailVerified']}, options);
|
||||||
|
if (emailVerified) throw new ForbiddenError('This password can only be changed by the user themselves');
|
||||||
|
|
||||||
|
await models.VnUser.setPassword(id, pass, options);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,31 +1,29 @@
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
const ForbiddenError = require('vn-loopback/util/forbiddenError');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('setPassword', {
|
Self.remoteMethodCtx('setPassword', {
|
||||||
description: 'Set a new password',
|
description: 'Set a new password',
|
||||||
accepts: [
|
accepts: [{
|
||||||
{
|
arg: 'id',
|
||||||
arg: 'workerFk',
|
type: 'number',
|
||||||
type: 'number',
|
required: true,
|
||||||
required: true,
|
description: 'The worker id',
|
||||||
description: 'The worker id',
|
http: {source: 'path'}
|
||||||
},
|
}, {
|
||||||
{
|
arg: 'newPass',
|
||||||
arg: 'newPass',
|
type: 'String',
|
||||||
type: 'String',
|
required: true,
|
||||||
required: true,
|
description: 'The new worker password'
|
||||||
description: 'The new worker password'
|
}],
|
||||||
}
|
|
||||||
],
|
|
||||||
http: {
|
http: {
|
||||||
path: `/:id/setPassword`,
|
path: `/:id/setPassword`,
|
||||||
verb: 'PATCH'
|
verb: 'PATCH'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Self.setPassword = async(ctx, options) => {
|
Self.setPassword = async(ctx, id, newPass, options) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
const {args} = ctx;
|
|
||||||
let tx;
|
let tx;
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
if (!myOptions.transaction) {
|
if (!myOptions.transaction) {
|
||||||
|
@ -33,11 +31,10 @@ module.exports = Self => {
|
||||||
myOptions.transaction = tx;
|
myOptions.transaction = tx;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const isSubordinate = await models.Worker.isSubordinate(ctx, args.workerFk, myOptions);
|
const isSubordinate = await Self.isSubordinate(ctx, id, myOptions);
|
||||||
if (!isSubordinate) throw new UserError('You don\'t have enough privileges.');
|
if (!isSubordinate) throw new ForbiddenError('They\'re not your subordinate');
|
||||||
|
|
||||||
await models.VnUser.setPassword(args.workerFk, args.newPass, myOptions);
|
await models.Account.setUnverifiedPassword(id, newPass, myOptions);
|
||||||
await models.VnUser.updateAll({id: args.workerFk}, {emailVerified: true}, myOptions);
|
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,31 +1,30 @@
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
const {models} = require('vn-loopback/server/server');
|
||||||
|
|
||||||
const models = require('vn-loopback/server/server').models;
|
|
||||||
|
|
||||||
describe('worker setPassword()', () => {
|
describe('worker setPassword()', () => {
|
||||||
let ctx;
|
let ctx;
|
||||||
|
const newPass = 'H3rn4d3z#';
|
||||||
|
const employeeId = 1;
|
||||||
|
const managerId = 20;
|
||||||
|
const administrativeId = 5;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
ctx = {
|
ctx = {
|
||||||
req: {
|
req: {
|
||||||
accessToken: {},
|
accessToken: {userId: managerId},
|
||||||
headers: {origin: 'http://localhost'}
|
headers: {origin: 'http://localhost'}
|
||||||
},
|
},
|
||||||
args: {workerFk: 9}
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
it('should change the password if it is a subordinate and the email is not verified', async() => {
|
||||||
ctx.req.accessToken.userId = 20;
|
|
||||||
ctx.args.newPass = 'H3rn4d3z#';
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should change the password', async() => {
|
|
||||||
const tx = await models.Worker.beginTransaction({});
|
const tx = await models.Worker.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
await models.Worker.setPassword(ctx, options);
|
await models.Worker.setPassword(ctx, employeeId, newPass, options);
|
||||||
|
const isNewPass = await passHasBeenChanged(employeeId, newPass, options);
|
||||||
|
|
||||||
|
expect(isNewPass).toBeTrue();
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
@ -33,29 +32,48 @@ describe('worker setPassword()', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error: Password does not meet requirements', async() => {
|
it('should not change the password if it is a subordinate and the email is verified', async() => {
|
||||||
const tx = await models.Collection.beginTransaction({});
|
const tx = await models.Worker.beginTransaction({});
|
||||||
ctx.args.newPass = 'Hi';
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
await models.Worker.setPassword(ctx, options);
|
await models.VnUser.updateAll({id: employeeId}, {emailVerified: true}, options);
|
||||||
|
await models.Worker.setPassword(ctx, employeeId, newPass, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toEqual(`This password can only be changed by the user themselves`);
|
||||||
|
await tx.rollback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change the password if it is not a subordinate', async() => {
|
||||||
|
const tx = await models.Worker.beginTransaction({});
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
await models.Worker.setPassword(ctx, administrativeId, newPass, options);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toEqual(`They're not your subordinate`);
|
||||||
|
await tx.rollback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error: Password does not meet requirements', async() => {
|
||||||
|
const tx = await models.Worker.beginTransaction({});
|
||||||
|
const newPass = 'Hi';
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
await models.Worker.setPassword(ctx, employeeId, newPass, options);
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.sqlMessage).toEqual('Password does not meet requirements');
|
expect(e.sqlMessage).toEqual('Password does not meet requirements');
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error: You don\'t have enough privileges.', async() => {
|
|
||||||
ctx.req.accessToken.userId = 5;
|
|
||||||
const tx = await models.Collection.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
await models.Worker.setPassword(ctx, options);
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
expect(e).toEqual(new UserError(`You don't have enough privileges.`));
|
|
||||||
await tx.rollback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const passHasBeenChanged = async(userId, pass, options) => {
|
||||||
|
const user = await models.VnUser.findById(userId, null, options);
|
||||||
|
return user.hasPassword(pass);
|
||||||
|
};
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
? 'Click to allow the user to be disabled'
|
? 'Click to allow the user to be disabled'
|
||||||
: 'Click to exclude the user from getting disabled'}}
|
: 'Click to exclude the user from getting disabled'}}
|
||||||
</vn-item>
|
</vn-item>
|
||||||
<vn-item ng-if="!$ctrl.worker.user.emailVerified" ng-click="setPassword.show()" translate>
|
<vn-item ng-if="!$ctrl.worker.user.emailVerified && $ctrl.vnConfig.storage.currentUserWorkerId !=$ctrl.worker.id" ng-click="setPassword.show()" translate>
|
||||||
Change password
|
Change password
|
||||||
</vn-item>
|
</vn-item>
|
||||||
</slot-menu>
|
</slot-menu>
|
||||||
<slot-body>
|
<slot-body>
|
||||||
|
|
|
@ -69,6 +69,7 @@ class Controller extends Descriptor {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.getData(`Workers/${this.id}`, {filter})
|
return this.getData(`Workers/${this.id}`, {filter})
|
||||||
.then(res => this.entity = res.data);
|
.then(res => this.entity = res.data);
|
||||||
}
|
}
|
||||||
|
@ -86,15 +87,14 @@ class Controller extends Descriptor {
|
||||||
if (this.newPassword != this.repeatPassword)
|
if (this.newPassword != this.repeatPassword)
|
||||||
throw new UserError(`Passwords don't match`);
|
throw new UserError(`Passwords don't match`);
|
||||||
this.$http.patch(
|
this.$http.patch(
|
||||||
`Workers/${this.entity.id}/setPassword`,
|
`Workers/${this.entity.id}/setPassword`, {newPass: this.newPassword}
|
||||||
{workerFk: this.entity.id, newPass: this.newPassword}
|
|
||||||
) .then(() => {
|
) .then(() => {
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Password changed!'));
|
this.vnApp.showSuccess(this.$translate.instant('Password changed!'));
|
||||||
});
|
}).then(() => this.loadData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', '$rootScope'];
|
Controller.$inject = ['$element', '$scope', '$rootScope', 'vnConfig'];
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerDescriptor', {
|
ngModule.vnComponent('vnWorkerDescriptor', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
|
|
|
@ -16,6 +16,7 @@ describe('vnWorkerDescriptor', () => {
|
||||||
const id = 1;
|
const id = 1;
|
||||||
const response = 'foo';
|
const response = 'foo';
|
||||||
|
|
||||||
|
$httpBackend.whenGET('UserConfigs/getUserConfig').respond({});
|
||||||
$httpBackend.expectRoute('GET', `Workers/${id}`).respond(response);
|
$httpBackend.expectRoute('GET', `Workers/${id}`).respond(response);
|
||||||
controller.id = id;
|
controller.id = id;
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
Loading…
Reference in New Issue