4077-login_recover-password & account_verifyEmail #1063
|
@ -38,11 +38,21 @@ module.exports = Self => {
|
|||
userId: user.id
|
||||
});
|
||||
|
||||
const title = $t('Recover password');
|
||||
const body = `
|
||||
<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(?,?,?,?)`, [
|
||||
email,
|
||||
null,
|
||||
$t('Recovery password'),
|
||||
`${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`
|
||||
title,
|
||||
body
|
||||
]);
|
||||
|
||||
return;
|
||||
|
|
|
@ -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 = `
|
||||
<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(?,?,?,?)`, [
|
||||
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