4077-login_recover-password & account_verifyEmail #1063

Merged
alexm merged 52 commits from 4077-login_recover-password into dev 2022-11-28 11:34:03 +00:00
11 changed files with 123 additions and 14 deletions
Showing only changes of commit fc5460dc9e - Show all commits

View File

@ -38,11 +38,21 @@ module.exports = Self => {
userId: user.id
});
const title = $t('Recover password');
const body = `
alexm marked this conversation as resolved Outdated
Outdated
Review

Gasta una plantilla ejs com ací, no fa falta afegir dependencies:

Gasta una plantilla *ejs* com ací, no fa falta afegir dependencies: * https://gitea.verdnatura.es/juan/hedera-web/src/branch/master/back/common/models/user.js#L52
<p>
${$t('Click on the following link to change your password')}:
</p>
</b>
<a href="${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}">
${title}
</a>`;
await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [
alexm marked this conversation as resolved Outdated
Outdated
Review
No gastes la BD per enviar correus, gasta (i defineix) un model `Email` com s'ha fet ací👍 * https://gitea.verdnatura.es/juan/hedera-web/src/branch/master/back/common/models/user.js#L57 * https://gitea.verdnatura.es/juan/hedera-web/src/branch/master/back/server/model-config.json#L58 * https://loopback.io/doc/en/lb3/Email-connector.html
email,
null,
$t('Recovery password'),
`${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`
title,
body
]);
return;
alexm marked this conversation as resolved Outdated
Outdated
Review

Aquest return no fa falta ficarlo.

Aquest return no fa falta ficarlo.

View File

@ -1,4 +1,6 @@
/* eslint max-len: ["error", { "code": 150 }]*/
const md5 = require('md5');
const LoopBackContext = require('loopback-context');
module.exports = Self => {
require('../methods/account/login')(Self);
@ -27,6 +29,40 @@ module.exports = Self => {
ctx.data.password = md5(ctx.data.password);
});
Self.observe('before save', async ctx => {
const models = Self.app.models;
const loopBackContext = LoopBackContext.getCurrentContext();
const changes = ctx.data || ctx.instance;
if (ctx.isNewInstance || !changes.email) return;
const userId = ctx.currentInstance.id;
const user = await models.Account.findById(userId);
if (user.email == changes.email) return;
const httpCtx = {req: loopBackContext.active};
const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const $t = httpRequest.__;
const title = $t('Verify email');
const body = `
alexm marked this conversation as resolved Outdated
Outdated
Review

Plantilla ejs

Plantilla *ejs*
<p>
${$t(`Click on the following link to verify this email. If you haven't requested this email, just ignore it`)}:
</p>
</b>
<a href="${origin}/#!/account/${userId}/basic-data?emailVerified">
${title}
</a>`;
result = await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [
alexm marked this conversation as resolved Outdated
Outdated
Review
Cridar al métode `User.verify()` com ací: * https://gitea.verdnatura.es/juan/hedera-web/src/branch/master/back/common/models/user.js#L22 * https://loopback.io/doc/en/lb2/Registering-users.html
changes.email,
null,
title,
body
], ctx.options);
});
Self.remoteMethod('getCurrentUserData', {
description: 'Gets the current user data',
accepts: [

View File

@ -40,6 +40,9 @@
"email": {
"type": "string"
},
"emailVerified": {
"type": "boolean"
},
"created": {
"type": "date"
},

View File

@ -1,15 +1,61 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('loopback model Account', () => {
const userId = 1105;
const activeCtx = {
accessToken: {userId: userId},
http: {
req: {
headers: {origin: 'http://localhost'},
[`__`]: value => {
return value;
}
}
}
};
beforeEach(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should return true if the user has the given role', async() => {
let result = await app.models.Account.hasRole(1, 'employee');
let result = await models.Account.hasRole(1, 'employee');
expect(result).toBeTruthy();
});
it('should return false if the user doesnt have the given role', async() => {
let result = await app.models.Account.hasRole(1, 'administrator');
let result = await models.Account.hasRole(1, 'administrator');
expect(result).toBeFalsy();
});
it('should send email when change email', async() => {
const tx = await models.Account.beginTransaction({});
const newEmail = 'emailNotVerified@mydomain.com';
let lastEmail;
try {
const options = {transaction: tx};
const account = await models.Account.findById(userId, null, options);
await account.updateAttribute('email', newEmail, options);
[lastEmail] = await models.Mail.find({
where: {
receiver: newEmail
}
}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(lastEmail.receiver).toEqual(newEmail);
});
});

View File

@ -1,3 +0,0 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Account', 'recoverPassword', 'READ', 'ALLOW', 'ROLE', 'account');

View File

@ -130,5 +130,7 @@
"Descanso diario 12h.": "Daily rest 12h.",
"Fichadas impares": "Odd signs",
"Descanso diario 9h.": "Daily rest 9h.",
"Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h."
"Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.",
"Verify email": "Verify email",
"Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Click on the following link to verify this email. If you haven't requested this email, just ignore it"
}

View File

@ -234,5 +234,8 @@
"Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.",
"Dirección incorrecta": "Dirección incorrecta",
"This email does not belong to a user": "Este correo electrónico no pertenece a un usuario.",
"Recovery password": "Recuperar contraseña"
"Recover password": "Recuperar contraseña",
"Click on the following link to change your password.": "Pulsa en el siguiente link para cambiar tu contraseña.",
"Verify email": "Verificar correo",
"Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo."
}

View File

@ -2,6 +2,18 @@ import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
$onInit() {
if (this.$params.emailVerified) {
const params = {
emailVerified: true
};
return this.$http.patch(`Accounts/${this.$params.id}`, params)
.then(() => {
this.vnApp.showSuccess(this.$t('Data saved!'));
});
}
}
onSubmit() {
this.$.watcher.submit()
.then(() => this.card.reload());

View File

@ -30,7 +30,7 @@ class Controller extends Descriptor {
}
$onInit() {
if (this.$location.$$search.access_token)
if (this.$params.access_token)
this.onChangePassClick(false);
}

View File

@ -108,7 +108,7 @@ describe('component vnUserDescriptor', () => {
describe('onInit()', () => {
it('should open onChangePassClick popup', () => {
controller.$location = {$$search: {access_token: 'RANDOM_TOKEN'}};
controller.$params = {access_token: 'RANDOM_TOKEN'};
jest.spyOn(controller, 'onChangePassClick');
controller.$onInit();

View File

@ -73,7 +73,7 @@
}
},
{
"url": "/basic-data",
"url": "/basic-data?access_token&emailVerified",
"state": "account.card.basicData",
"component": "vn-user-basic-data",
"description": "Basic data",
@ -249,4 +249,4 @@
"acl": ["developer"]
}
]
}
}