4077-login_recover-password & account_verifyEmail #1063
|
@ -38,11 +38,21 @@ module.exports = Self => {
|
|||
userId: user.id
|
||||
});
|
||||
|
||||
const title = $t('Recover password');
|
||||
const body = `
|
||||
alexm marked this conversation as resolved
Outdated
|
||||
<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
juan
commented
No gastes la BD per enviar correus, gasta (i defineix) un model 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
juan
commented
Aquest return no fa falta ficarlo. Aquest return no fa falta ficarlo.
|
||||
|
|
|
@ -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
juan
commented
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
juan
commented
Cridar al métode 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: [
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"emailVerified": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('Account', 'recoverPassword', 'READ', 'ALLOW', 'ROLE', 'account');
|
|
@ -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"
|
||||
}
|
|
@ -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."
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -30,7 +30,7 @@ class Controller extends Descriptor {
|
|||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.$location.$$search.access_token)
|
||||
if (this.$params.access_token)
|
||||
this.onChangePassClick(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Gasta una plantilla ejs com ací, no fa falta afegir dependencies: