feat(account): send verifyEmail when change email and tests
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
This commit is contained in:
parent
c79f884526
commit
fc5460dc9e
|
@ -38,11 +38,21 @@ module.exports = Self => {
|
||||||
userId: user.id
|
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(?,?,?,?)`, [
|
await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [
|
||||||
email,
|
email,
|
||||||
null,
|
null,
|
||||||
$t('Recovery password'),
|
title,
|
||||||
`${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`
|
body
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
/* eslint max-len: ["error", { "code": 150 }]*/
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/account/login')(Self);
|
require('../methods/account/login')(Self);
|
||||||
|
@ -27,6 +29,40 @@ module.exports = Self => {
|
||||||
ctx.data.password = md5(ctx.data.password);
|
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', {
|
Self.remoteMethod('getCurrentUserData', {
|
||||||
description: 'Gets the current user data',
|
description: 'Gets the current user data',
|
||||||
accepts: [
|
accepts: [
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"emailVerified": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"created": {
|
"created": {
|
||||||
"type": "date"
|
"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', () => {
|
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() => {
|
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();
|
expect(result).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if the user doesnt have the given role', async() => {
|
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();
|
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.",
|
"Descanso diario 12h.": "Daily rest 12h.",
|
||||||
"Fichadas impares": "Odd signs",
|
"Fichadas impares": "Odd signs",
|
||||||
"Descanso diario 9h.": "Daily rest 9h.",
|
"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.",
|
"Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.",
|
||||||
"Dirección incorrecta": "Dirección incorrecta",
|
"Dirección incorrecta": "Dirección incorrecta",
|
||||||
"This email does not belong to a user": "Este correo electrónico no pertenece a un usuario.",
|
"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';
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
export default class Controller extends 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() {
|
onSubmit() {
|
||||||
this.$.watcher.submit()
|
this.$.watcher.submit()
|
||||||
.then(() => this.card.reload());
|
.then(() => this.card.reload());
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Controller extends Descriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
if (this.$location.$$search.access_token)
|
if (this.$params.access_token)
|
||||||
this.onChangePassClick(false);
|
this.onChangePassClick(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ describe('component vnUserDescriptor', () => {
|
||||||
|
|
||||||
describe('onInit()', () => {
|
describe('onInit()', () => {
|
||||||
it('should open onChangePassClick popup', () => {
|
it('should open onChangePassClick popup', () => {
|
||||||
controller.$location = {$$search: {access_token: 'RANDOM_TOKEN'}};
|
controller.$params = {access_token: 'RANDOM_TOKEN'};
|
||||||
jest.spyOn(controller, 'onChangePassClick');
|
jest.spyOn(controller, 'onChangePassClick');
|
||||||
|
|
||||||
controller.$onInit();
|
controller.$onInit();
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "/basic-data",
|
"url": "/basic-data?access_token&emailVerified",
|
||||||
"state": "account.card.basicData",
|
"state": "account.card.basicData",
|
||||||
"component": "vn-user-basic-data",
|
"component": "vn-user-basic-data",
|
||||||
"description": "Basic data",
|
"description": "Basic data",
|
||||||
|
|
Loading…
Reference in New Issue