refs #5472 feat: add change-password section
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alex Moreno 2023-05-02 15:16:13 +02:00
parent 48be8b9fe0
commit 79e7e7c604
12 changed files with 176 additions and 30 deletions

View File

@ -47,18 +47,18 @@ module.exports = Self => {
where where
}); });
const validCredentials = instance
&& await instance.hasPassword(password);
const today = Date.vnNew(); const today = Date.vnNew();
today.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0);
if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime())
throw new UserError('Pass expired');
const validCredentials = instance
&& await instance.hasPassword(password);
if (validCredentials) { if (validCredentials) {
if (!vnUser.active) if (!vnUser.active)
throw new UserError('User disabled'); throw new UserError('User disabled');
if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime())
throw new UserError('Pass expired');
try { try {
await models.Account.sync(instance.username, password); await models.Account.sync(instance.username, password);
} catch (err) { } catch (err) {

View File

@ -108,32 +108,49 @@ module.exports = function(Self) {
return email.send(); return email.send();
}); });
Self.remoteMethod('setPassword', { // FIX THIS
description: 'Reset user\'s password via a password-reset token.', Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {
accepts: [ if (!ctx.args || !ctx.args.data.email) return;
{arg: 'id', type: 'any', http: getUserIdFromRequestContext}, const models = Self.app.models;
{arg: 'newPassword', type: 'string', required: true, http: {source: 'form'}},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
accessScopes: setPasswordScopes,
http: {verb: 'POST', path: '/reset-password'},
},
);
function getUserIdFromRequestContext(ctx) { const loopBackContext = LoopBackContext.getCurrentContext();
const token = ctx.req.accessToken; const httpCtx = {req: loopBackContext.active};
if (!token) return; const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const url = origin.split(':');
const hasPrincipalType = 'principalType' in token; const userId = ctx.instance.id;
if (hasPrincipalType && token.principalType !== UserModel.modelName) { const user = await models.VnUser.findById(userId);
// We have multiple user models related to the same access token model
// and the token used to authorize reset-password request was created class Mailer {
// for a different user model. async send(verifyOptions, cb) {
const err = new Error(g.f('Access Denied')); const params = {
err.statusCode = 403; url: verifyOptions.verifyHref,
throw err; recipient: verifyOptions.to,
lang: ctx.req.getLocale()
};
const email = new Email('email-verify', params);
email.send();
cb(null, verifyOptions.to);
}
} }
return token.userId; const options = {
} type: 'email',
to: instance.email,
from: {},
redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`,
template: false,
mailer: new Mailer,
host: url[1].split('/')[2],
port: url[2],
protocol: url[0],
user: Self
};
await user.verify(options);
});
}; };

View File

@ -0,0 +1,33 @@
<h5 class="vn-mb-md vn-mt-lg" translate>Change password</h5>
<vn-textfield
label="Old password"
ng-model="$ctrl.oldPassword"
type="password"
info="{{'Password requirements' | translate:$ctrl.passRequirements}}"
vn-focus>
</vn-textfield>
<vn-textfield
label="New password"
ng-model="$ctrl.newPassword"
type="password"
info="{{'Password requirements' | translate:$ctrl.passRequirements}}"
vn-focus>
</vn-textfield>
<vn-textfield
label="New password"
ng-model="$ctrl.newPassword"
type="password"
info="{{'Password requirements' | translate:$ctrl.passRequirements}}"
vn-focus>
</vn-textfield>
<vn-textfield
label="Repeat password"
ng-model="$ctrl.repeatPassword"
type="password">
</vn-textfield>
<div class="footer">
<vn-submit label="Reset password" ng-click="$ctrl.submit()"></vn-submit>
<div class="spinner-wrapper">
<vn-spinner enable="$ctrl.loading"></vn-spinner>
</div>
</div>

View File

@ -0,0 +1,49 @@
import ngModule from '../../module';
import './style.scss';
const UserError = require('vn-loopback/util/user-error');
export default class Controller {
constructor($scope, $element, $http, vnApp, $translate, $state, $location) {
Object.assign(this, {
$scope,
$element,
$http,
vnApp,
$translate,
$state,
$location
});
}
$onInit() {
this.$http.get('UserPasswords/findOne')
.then(res => {
this.passRequirements = res.data;
});
}
submit() {
if (!this.newPassword)
throw new UserError(`You must enter a new password`);
if (this.newPassword != this.repeatPassword)
throw new UserError(`Passwords don't match`);
const headers = {
Authorization: this.$location.$$search.access_token
};
const newPassword = this.newPassword;
this.$http.post('VnUsers/reset-password', {newPassword}, {headers})
.then(() => {
this.vnApp.showSuccess(this.$translate.instant('Password changed!'));
this.$state.go('login');
});
}
}
Controller.$inject = ['$scope', '$element', '$http', 'vnApp', '$translate', '$state', '$location'];
ngModule.vnComponent('vnResetPassword', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,4 @@
Password requirements: >
The password must have at least {{ length }} length characters,
{{nAlpha}} alphabetic characters, {{nUpper}} capital letters, {{nDigits}}
digits and {{nPunct}} symbols (Ex: $%&.)

View File

@ -0,0 +1,8 @@
Reset password: Restrablecer contraseña
New password: Nueva contraseña
Repeat password: Repetir contraseña
Password changed!: ¡Contraseña cambiada!
Password requirements: >
La contraseña debe tener al menos {{ length }} caracteres de longitud,
{{nAlpha}} caracteres alfabéticos, {{nUpper}} letras mayúsculas, {{nDigits}}
dígitos y {{nPunct}} símbolos (Ej: $%&.)

View File

@ -0,0 +1,24 @@
@import "variables";
vn-reset-password{
.footer {
margin-top: 32px;
text-align: center;
position: relative;
& > .vn-submit {
display: block;
& > input {
display: block;
width: 100%;
}
}
& > .spinner-wrapper {
position: absolute;
width: 0;
top: 3px;
right: -8px;
overflow: visible;
}
}
}

View File

@ -9,6 +9,7 @@ import './login';
import './outLayout'; import './outLayout';
import './recover-password'; import './recover-password';
import './reset-password'; import './reset-password';
import './change-password';
import './module-card'; import './module-card';
import './module-main'; import './module-main';
import './side-menu/side-menu'; import './side-menu/side-menu';

View File

@ -26,6 +26,9 @@ export default class Controller {
this.loading = false; this.loading = false;
this.password = ''; this.password = '';
this.focusUser(); this.focusUser();
console.log('hola');
console.log(err);
console.log(err.error);
throw err; throw err;
}); });
} }

View File

@ -1,5 +1,6 @@
import ngModule from '../../module'; import ngModule from '../../module';
import './style.scss'; import './style.scss';
const UserError = require('vn-loopback/util/user-error');
export default class Controller { export default class Controller {
constructor($scope, $element, $http, vnApp, $translate, $state, $location) { constructor($scope, $element, $http, vnApp, $translate, $state, $location) {

View File

@ -77,7 +77,6 @@
"This ticket can not be modified": "Este ticket no puede ser modificado", "This ticket can not be modified": "Este ticket no puede ser modificado",
"The introduced hour already exists": "Esta hora ya ha sido introducida", "The introduced hour already exists": "Esta hora ya ha sido introducida",
"INFINITE_LOOP": "Existe una dependencia entre dos Jefes", "INFINITE_LOOP": "Existe una dependencia entre dos Jefes",
"The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas", "The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas",
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros", "NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado", "ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",

View File

@ -0,0 +1,7 @@
// SET IN VN_USER
module.exports = async function(app) {
const _setPassword = app.models.VnUser.setPassword;
app.models.VnUser.setPassword = function(newPassword, options, cb) {
return _setPassword.call(this, newPassword, options, cb);
};
};