Merge branch 'dev' into 5749-autoincrement-zoneIncluded
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Pablo Natek 2023-10-19 10:49:31 +00:00
commit 71182d8630
9 changed files with 197 additions and 6 deletions

View File

@ -38,6 +38,12 @@
"active": {
"type": "boolean"
},
"email": {
"type": "string"
},
"emailVerified": {
"type": "boolean"
},
"created": {
"type": "date"
},
@ -137,7 +143,8 @@
"image",
"hasGrant",
"realm",
"email"
"email",
"emailVerified"
]
}
}

View File

@ -0,0 +1,4 @@
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
VALUES ('Worker','setPassword','*','ALLOW','ROLE','employee');

View File

@ -0,0 +1,48 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('setPassword', {
description: 'Set a new password',
accepts: [
{
arg: 'workerFk',
type: 'number',
required: true,
description: 'The worker id',
},
{
arg: 'newPass',
type: 'String',
required: true,
description: 'The new worker password'
}
],
http: {
path: `/:id/setPassword`,
verb: 'PATCH'
}
});
Self.setPassword = async(ctx, options) => {
const models = Self.app.models;
const myOptions = {};
const {args} = ctx;
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const isSubordinate = await models.Worker.isSubordinate(ctx, args.workerFk, myOptions);
if (!isSubordinate) throw new UserError('You don\'t have enough privileges.');
await models.VnUser.setPassword(args.workerFk, args.newPass, myOptions);
await models.VnUser.updateAll({id: args.workerFk}, {emailVerified: true}, myOptions);
if (tx) await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -0,0 +1,61 @@
const UserError = require('vn-loopback/util/user-error');
const models = require('vn-loopback/server/server').models;
describe('worker setPassword()', () => {
let ctx;
beforeAll(() => {
ctx = {
req: {
accessToken: {},
headers: {origin: 'http://localhost'}
},
args: {workerFk: 9}
};
});
beforeEach(() => {
ctx.req.accessToken.userId = 20;
ctx.args.newPass = 'H3rn4d3z#';
});
it('should change the password', async() => {
const tx = await models.Worker.beginTransaction({});
try {
const options = {transaction: tx};
await models.Worker.setPassword(ctx, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should throw an error: Password does not meet requirements', async() => {
const tx = await models.Collection.beginTransaction({});
ctx.args.newPass = 'Hi';
try {
const options = {transaction: tx};
await models.Worker.setPassword(ctx, options);
await tx.rollback();
} catch (e) {
expect(e.sqlMessage).toEqual('Password does not meet requirements');
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();
}
});
});

View File

@ -18,6 +18,7 @@ module.exports = Self => {
require('../methods/worker/allocatePDA')(Self);
require('../methods/worker/search')(Self);
require('../methods/worker/isAuthorized')(Self);
require('../methods/worker/setPassword')(Self);
Self.validatesUniquenessOf('locker', {
message: 'This locker has already been assigned'

View File

@ -8,7 +8,7 @@ class Controller extends ModuleCard {
{
relation: 'user',
scope: {
fields: ['name'],
fields: ['name', 'emailVerified'],
include: {
relation: 'emailUser',
scope: {

View File

@ -11,6 +11,9 @@
? 'Click to allow the user to be disabled'
: 'Click to exclude the user from getting disabled'}}
</vn-item>
<vn-item ng-if="!$ctrl.worker.user.emailVerified" ng-click="setPassword.show()" translate>
Change password
</vn-item>
</slot-menu>
<slot-body>
<div class="attributes">
@ -72,4 +75,29 @@
<vn-popup vn-id="summary">
<vn-worker-summary worker="$ctrl.worker"></vn-worker-summary>
</vn-popup>
<vn-dialog
vn-id="setPassword"
on-accept="$ctrl.setPassword($ctrl.worker.password)"
message="Reset password"
>
<tpl-body>
<vn-textfield
vn-one
label="New password"
required="true"
ng-model="$ctrl.newPassword"
type="password"
info="{{'Password requirements' | translate:$ctrl.passRequirements}}"
>
</vn-textfield>
<vn-textfield
label="Repeat password"
ng-model="$ctrl.repeatPassword"
type="password">
</vn-textfield>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button>
</tpl-buttons>
</vn-dialog>

View File

@ -1,5 +1,6 @@
import ngModule from '../module';
import Descriptor from 'salix/components/descriptor';
const UserError = require('vn-loopback/util/user-error');
class Controller extends Descriptor {
constructor($element, $, $rootScope) {
super($element, $);
@ -12,9 +13,11 @@ class Controller extends Descriptor {
set worker(value) {
this.entity = value;
if (value)
this.getIsExcluded();
if (this.entity && !this.entity.user.emailVerified)
this.getPassRequirements();
}
getIsExcluded() {
@ -38,7 +41,7 @@ class Controller extends Descriptor {
{
relation: 'user',
scope: {
fields: ['name'],
fields: ['name', 'emailVerified'],
include: {
relation: 'emailUser',
scope: {
@ -66,10 +69,29 @@ class Controller extends Descriptor {
}
]
};
return this.getData(`Workers/${this.id}`, {filter})
.then(res => this.entity = res.data);
}
getPassRequirements() {
this.$http.get('UserPasswords/findOne')
.then(res => {
this.passRequirements = res.data;
});
}
setPassword() {
if (!this.newPassword)
throw new UserError(`You must enter a new password`);
if (this.newPassword != this.repeatPassword)
throw new UserError(`Passwords don't match`);
this.$http.patch(
`Workers/${this.entity.id}/setPassword`,
{workerFk: this.entity.id, newPass: this.newPassword}
) .then(() => {
this.vnApp.showSuccess(this.$translate.instant('Password changed!'));
});
}
}
Controller.$inject = ['$element', '$scope', '$rootScope'];

View File

@ -23,4 +23,24 @@ describe('vnWorkerDescriptor', () => {
expect(controller.worker).toEqual(response);
});
});
describe('setPassword()', () => {
it('should throw an error: You must enter a new password', () => {
try {
controller.setPassword();
} catch (error) {
expect(error.message).toEqual('You must enter a new password');
}
});
it('should throw an error: Passwords don\'t match', () => {
controller.newPassword = 'aaa';
controller.repeatPassword = 'bbb';
try {
controller.setPassword();
} catch (error) {
expect(error.message).toEqual('Passwords don\'t match');
}
});
});
});