From 79e7e7c604944b8ab6ed1ba7b2e4e7ead5337114 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 2 May 2023 15:16:13 +0200 Subject: [PATCH] refs #5472 feat: add change-password section --- back/methods/vn-user/signIn.js | 10 +-- back/models/vn-user.js | 65 ++++++++++++------- .../components/change-password/index.html | 33 ++++++++++ .../salix/components/change-password/index.js | 49 ++++++++++++++ .../components/change-password/locale/en.yml | 4 ++ .../components/change-password/locale/es.yml | 8 +++ .../components/change-password/style.scss | 24 +++++++ front/salix/components/index.js | 1 + front/salix/components/login/index.js | 3 + .../salix/components/reset-password/index.js | 1 + loopback/locale/es.json | 1 - loopback/server/boot/set-password.js | 7 ++ 12 files changed, 176 insertions(+), 30 deletions(-) create mode 100644 front/salix/components/change-password/index.html create mode 100644 front/salix/components/change-password/index.js create mode 100644 front/salix/components/change-password/locale/en.yml create mode 100644 front/salix/components/change-password/locale/es.yml create mode 100644 front/salix/components/change-password/style.scss create mode 100644 loopback/server/boot/set-password.js diff --git a/back/methods/vn-user/signIn.js b/back/methods/vn-user/signIn.js index 5750beaef..36a2fb870 100644 --- a/back/methods/vn-user/signIn.js +++ b/back/methods/vn-user/signIn.js @@ -47,18 +47,18 @@ module.exports = Self => { where }); - const validCredentials = instance - && await instance.hasPassword(password); const today = Date.vnNew(); 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 (!vnUser.active) throw new UserError('User disabled'); - if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) - throw new UserError('Pass expired'); - try { await models.Account.sync(instance.username, password); } catch (err) { diff --git a/back/models/vn-user.js b/back/models/vn-user.js index de3b0e0ba..05102478c 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -108,32 +108,49 @@ module.exports = function(Self) { return email.send(); }); - Self.remoteMethod('setPassword', { - description: 'Reset user\'s password via a password-reset token.', - accepts: [ - {arg: 'id', type: 'any', http: getUserIdFromRequestContext}, - {arg: 'newPassword', type: 'string', required: true, http: {source: 'form'}}, - {arg: 'options', type: 'object', http: 'optionsFromRequest'}, - ], - accessScopes: setPasswordScopes, - http: {verb: 'POST', path: '/reset-password'}, - }, - ); + // FIX THIS + Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { + if (!ctx.args || !ctx.args.data.email) return; + const models = Self.app.models; - function getUserIdFromRequestContext(ctx) { - const token = ctx.req.accessToken; - if (!token) return; + const loopBackContext = LoopBackContext.getCurrentContext(); + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const headers = httpRequest.headers; + const origin = headers.origin; + const url = origin.split(':'); - const hasPrincipalType = 'principalType' in token; - if (hasPrincipalType && token.principalType !== UserModel.modelName) { - // We have multiple user models related to the same access token model - // and the token used to authorize reset-password request was created - // for a different user model. - const err = new Error(g.f('Access Denied')); - err.statusCode = 403; - throw err; + const userId = ctx.instance.id; + const user = await models.VnUser.findById(userId); + + class Mailer { + async send(verifyOptions, cb) { + const params = { + url: verifyOptions.verifyHref, + 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); + }); }; diff --git a/front/salix/components/change-password/index.html b/front/salix/components/change-password/index.html new file mode 100644 index 000000000..8d2726d3d --- /dev/null +++ b/front/salix/components/change-password/index.html @@ -0,0 +1,33 @@ +
Change password
+ + + + + + + + + diff --git a/front/salix/components/change-password/index.js b/front/salix/components/change-password/index.js new file mode 100644 index 000000000..4462b9221 --- /dev/null +++ b/front/salix/components/change-password/index.js @@ -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 +}); diff --git a/front/salix/components/change-password/locale/en.yml b/front/salix/components/change-password/locale/en.yml new file mode 100644 index 000000000..e5419e1c8 --- /dev/null +++ b/front/salix/components/change-password/locale/en.yml @@ -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: $%&.) diff --git a/front/salix/components/change-password/locale/es.yml b/front/salix/components/change-password/locale/es.yml new file mode 100644 index 000000000..30893a152 --- /dev/null +++ b/front/salix/components/change-password/locale/es.yml @@ -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: $%&.) diff --git a/front/salix/components/change-password/style.scss b/front/salix/components/change-password/style.scss new file mode 100644 index 000000000..87e4adc8c --- /dev/null +++ b/front/salix/components/change-password/style.scss @@ -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; + } + } +} diff --git a/front/salix/components/index.js b/front/salix/components/index.js index 8f5724862..0999d9aca 100644 --- a/front/salix/components/index.js +++ b/front/salix/components/index.js @@ -9,6 +9,7 @@ import './login'; import './outLayout'; import './recover-password'; import './reset-password'; +import './change-password'; import './module-card'; import './module-main'; import './side-menu/side-menu'; diff --git a/front/salix/components/login/index.js b/front/salix/components/login/index.js index 150e896a1..d248f56a3 100644 --- a/front/salix/components/login/index.js +++ b/front/salix/components/login/index.js @@ -26,6 +26,9 @@ export default class Controller { this.loading = false; this.password = ''; this.focusUser(); + console.log('hola'); + console.log(err); + console.log(err.error); throw err; }); } diff --git a/front/salix/components/reset-password/index.js b/front/salix/components/reset-password/index.js index a3ca03237..4462b9221 100644 --- a/front/salix/components/reset-password/index.js +++ b/front/salix/components/reset-password/index.js @@ -1,5 +1,6 @@ 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) { diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 6c5d90399..f38678811 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -77,7 +77,6 @@ "This ticket can not be modified": "Este ticket no puede ser modificado", "The introduced hour already exists": "Esta hora ya ha sido introducida", "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", "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", diff --git a/loopback/server/boot/set-password.js b/loopback/server/boot/set-password.js new file mode 100644 index 000000000..ae4dc30ea --- /dev/null +++ b/loopback/server/boot/set-password.js @@ -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); + }; +};