diff --git a/server/config/config.js b/server/config/config.js
index a3efaf32d..6f409e1b4 100644
--- a/server/config/config.js
+++ b/server/config/config.js
@@ -74,4 +74,6 @@ module.exports = {
api_key: 'b0JDZW56RnV6aEthb0RGPXVEcUI'
},
jwtSecret: 'b0JDZW56RnV6aEthb0RGPXVEcUI',
+ contactUsMail: 'support@bigcapital.ly',
+ baseURL: 'https://bigcapital.ly',
};
diff --git a/server/src/http/controllers/Authentication.ts b/server/src/http/controllers/Authentication.ts
index 9b0d1537c..83f74d632 100644
--- a/server/src/http/controllers/Authentication.ts
+++ b/server/src/http/controllers/Authentication.ts
@@ -76,14 +76,15 @@ export default class AuthenticationController extends BaseController{
*/
get resetPasswordSchema(): ValidationChain[] {
return [
- check('password').exists().isLength({ min: 5 }).custom((value, { req }) => {
- if (value !== req.body.confirm_password) {
- throw new Error("Passwords don't match");
- } else {
- return value;
- }
- }),
- ]
+ check('password').exists().isLength({ min: 5 })
+ .custom((value, { req }) => {
+ if (value !== req.body.confirm_password) {
+ throw new Error("Passwords don't match");
+ } else {
+ return value;
+ }
+ }),
+ ];
}
/**
@@ -111,7 +112,7 @@ export default class AuthenticationController extends BaseController{
return res.status(200).send({ token, user });
} catch (error) {
if (error instanceof ServiceError) {
- if (error.errorType === 'invalid_details') {
+ if (['invalid_details', 'invalid_password'].indexOf(error.errorType) !== -1) {
return res.boom.badRequest(null, {
errors: [{ type: 'INVALID_DETAILS', code: 100 }],
});
@@ -201,8 +202,6 @@ export default class AuthenticationController extends BaseController{
type: 'RESET_PASSWORD_SUCCESS',
})
} catch(error) {
- console.log(error);
-
if (error instanceof ServiceError) {
if (error.errorType === 'token_invalid') {
return res.boom.badRequest(null, {
diff --git a/server/src/jobs/ResetPasswordMail.ts b/server/src/jobs/ResetPasswordMail.ts
index baf7076a4..0cc99523c 100644
--- a/server/src/jobs/ResetPasswordMail.ts
+++ b/server/src/jobs/ResetPasswordMail.ts
@@ -2,8 +2,17 @@ import { Container, Inject } from 'typedi';
import AuthenticationService from '@/services/Authentication';
export default class WelcomeEmailJob {
- @Inject()
- authService: AuthenticationService;
+ /**
+ * Constructor method.
+ * @param {Agenda} agenda
+ */
+ constructor(agenda) {
+ agenda.define(
+ 'reset-password-mail',
+ { priority: 'high' },
+ this.handler.bind(this),
+ );
+ }
/**
* Handle send welcome mail job.
@@ -11,17 +20,18 @@ export default class WelcomeEmailJob {
* @param {Function} done
*/
public async handler(job, done: Function): Promise {
- const { email, organizationName, firstName } = job.attrs.data;
+ const { user, token } = job.attrs.data;
const Logger = Container.get('logger');
+ const authService = Container.get(AuthenticationService);
- Logger.info(`Send reset password mail - started: ${job.attrs.data}`);
+ Logger.info(`[send_reset_password] started: ${job.attrs.data}`);
try {
- await this.authService.mailMessages.sendResetPasswordMessage();
- Logger.info(`Send reset password mail - finished: ${job.attrs.data}`);
+ await authService.mailMessages.sendResetPasswordMessage(user, token);
+ Logger.info(`[send_reset_password] finished: ${job.attrs.data}`);
done()
} catch (error) {
- Logger.info(`Send reset password mail - error: ${job.attrs.data}, error: ${error}`);
+ Logger.info(`[send_reset_password] error: ${job.attrs.data}, error: ${error}`);
done(error);
}
}
diff --git a/server/src/jobs/welcomeEmail.ts b/server/src/jobs/welcomeEmail.ts
index c257f6cae..8c741c82f 100644
--- a/server/src/jobs/welcomeEmail.ts
+++ b/server/src/jobs/welcomeEmail.ts
@@ -2,8 +2,18 @@ import { Container, Inject } from 'typedi';
import AuthenticationService from '@/services/Authentication';
export default class WelcomeEmailJob {
- @Inject()
- authService: AuthenticationService;
+ /**
+ * Constructor method.
+ * @param {Agenda} agenda -
+ */
+ constructor(agenda) {
+ // Welcome mail and SMS message.
+ agenda.define(
+ 'welcome-email',
+ { priority: 'high' },
+ this.handler.bind(this),
+ );
+ }
/**
* Handle send welcome mail job.
@@ -11,17 +21,18 @@ export default class WelcomeEmailJob {
* @param {Function} done
*/
public async handler(job, done: Function): Promise {
- const { email, organizationName, firstName } = job.attrs.data;
+ const { organizationName, user } = job.attrs.data;
const Logger = Container.get('logger');
+ const authService = Container.get(AuthenticationService);
+
+ Logger.info(`[welcome_mail] send welcome mail message - started: ${job.attrs.data}`);
- Logger.info(`Send welcome mail message - started: ${job.attrs.data}`);
-
try {
- await this.authService.mailMessages.sendWelcomeMessage();
- Logger.info(`Send welcome mail message - finished: ${job.attrs.data}`);
- done()
+ await authService.mailMessages.sendWelcomeMessage(user, organizationName);
+ Logger.info(`[welcome_mail] send welcome mail message - finished: ${job.attrs.data}`);
+ done();
} catch (error) {
- Logger.info(`Send welcome mail message - error: ${job.attrs.data}, error: ${error}`);
+ Logger.info(`[welcome_mail] send welcome mail message - error: ${job.attrs.data}, error: ${error}`);
done(error);
}
}
diff --git a/server/src/loaders/jobs.ts b/server/src/loaders/jobs.ts
index 4909dae85..c1095af2f 100644
--- a/server/src/loaders/jobs.ts
+++ b/server/src/loaders/jobs.ts
@@ -13,23 +13,15 @@ import SendMailNotificationTrialEnd from '@/jobs/MailNotificationTrialEnd';
import UserInviteMailJob from '@/jobs/UserInviteMail';
export default ({ agenda }: { agenda: Agenda }) => {
- // Welcome mail and SMS message.
- agenda.define(
- 'welcome-email',
- { priority: 'high' },
- new WelcomeEmailJob().handler,
- );
+ new WelcomeEmailJob(agenda);
+ new ResetPasswordMailJob(agenda);
+
agenda.define(
'welcome-sms',
{ priority: 'high' },
new WelcomeSMSJob().handler
);
- // Reset password mail.
- agenda.define(
- 'reset-password-mail',
- { priority: 'high' },
- new ResetPasswordMailJob().handler,
- );
+
// User invite mail.
agenda.define(
'user-invite-mail',
diff --git a/server/src/services/Authentication/AuthenticationMailMessages.ts b/server/src/services/Authentication/AuthenticationMailMessages.ts
index f9461a1fd..e74585971 100644
--- a/server/src/services/Authentication/AuthenticationMailMessages.ts
+++ b/server/src/services/Authentication/AuthenticationMailMessages.ts
@@ -1,35 +1,78 @@
-import { Service } from "typedi";
+import fs from 'fs';
+import { Service, Container } from "typedi";
+import Mustache from 'mustache';
+import path from 'path';
+import { ISystemUser } from '@/interfaces';
+import config from '@/../config/config';
+import { ISystemUser } from 'src/interfaces';
@Service()
export default class AuthenticationMailMesssages {
-
- sendWelcomeMessage() {
- const Logger = Container.get('logger');
+ /**
+ * Sends welcome message.
+ * @param {ISystemUser} user - The system user.
+ * @param {string} organizationName -
+ * @return {Promise}
+ */
+ sendWelcomeMessage(user: ISystemUser, organizationName: string): Promise {
const Mail = Container.get('mail');
-
+
const filePath = path.join(global.rootPath, 'views/mail/Welcome.html');
const template = fs.readFileSync(filePath, 'utf8');
const rendered = Mustache.render(template, {
- email, organizationName, firstName,
+ email: user.email,
+ firstName: user.firstName,
+ organizationName,
});
const mailOptions = {
- to: email,
+ to: user.email,
from: `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`,
subject: 'Welcome to Bigcapital',
html: rendered,
};
- Mail.sendMail(mailOptions, (error) => {
- if (error) {
- Logger.error('Failed send welcome mail', { error, form });
- done(error);
- return;
- }
- Logger.info('User has been sent welcome email successfuly.', { form });
- done();
- });
+ return new Promise((resolve, reject) => {
+ Mail.sendMail(mailOptions, (error) => {
+ if (error) {
+ resolve(error);
+ return;
+ }
+ reject();
+ });
+ });
}
- sendResetPasswordMessage() {
+ /**
+ * Sends reset password message.
+ *
+ * @param {ISystemUser} user - The system user.
+ * @param {string} token - Reset password token.
+ * @return {Promise}
+ */
+ sendResetPasswordMessage(user: ISystemUser, token: string): Promise {
+ const Mail = Container.get('mail');
+ const filePath = path.join(global.rootPath, 'views/mail/ResetPassword.html');
+ const template = fs.readFileSync(filePath, 'utf8');
+ const rendered = Mustache.render(template, {
+ resetPasswordUrl: `${config.baseURL}/reset/${token}`,
+ first_name: user.firstName,
+ last_name: user.lastName,
+ contact_us_email: config.contactUsMail,
+ });
+ const mailOptions = {
+ to: user.email,
+ from: `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`,
+ subject: 'Bigcapital - Password Reset',
+ html: rendered,
+ };
+ return new Promise((resolve, reject) => {
+ Mail.sendMail(mailOptions, (error) => {
+ if (error) {
+ reject(error);
+ return;
+ }
+ resolve();
+ });
+ });
}
}
\ No newline at end of file
diff --git a/server/src/services/Authentication/index.ts b/server/src/services/Authentication/index.ts
index c14f36d02..b391b58c5 100644
--- a/server/src/services/Authentication/index.ts
+++ b/server/src/services/Authentication/index.ts
@@ -65,7 +65,7 @@ export default class AuthenticationService {
this.logger.info('[login] check password validation.');
if (!user.verifyPassword(password)) {
- throw new ServiceError('password_invalid');
+ throw new ServiceError('invalid_password');
}
if (!user.active) {
@@ -133,8 +133,10 @@ export default class AuthenticationService {
tenant_id: tenant.id,
});
- this.eventDispatcher.dispatch(events.auth.register, { registerDTO });
-
+ // Triggers `onRegister` event.
+ this.eventDispatcher.dispatch(events.auth.register, {
+ registerDTO, user: registeredUser
+ });
return registeredUser;
}
@@ -194,9 +196,12 @@ export default class AuthenticationService {
await this.validateEmailExistance(email);
// Delete all stored tokens of reset password that associate to the give email.
+ this.logger.info('[send_reset_password] trying to delete all tokens by email.');
await PasswordReset.query().where('email', email).delete();
const token = uniqid();
+
+ this.logger.info('[send_reset_password] insert the generated token.');
const passwordReset = await PasswordReset.query().insert({ email, token });
const user = await SystemUser.query().findOne('email', email);
diff --git a/server/src/services/Subscription/MailMessages.ts b/server/src/services/Subscription/MailMessages.ts
index 572fc84d2..4c50a5243 100644
--- a/server/src/services/Subscription/MailMessages.ts
+++ b/server/src/services/Subscription/MailMessages.ts
@@ -2,7 +2,11 @@ import { Service } from "typedi";
@Service()
export default class SubscriptionMailMessages {
-
+ /**
+ *
+ * @param phoneNumber
+ * @param remainingDays
+ */
public async sendRemainingSubscriptionPeriod(phoneNumber: string, remainingDays: number) {
const message: string = `
Your remaining subscription is ${remainingDays} days,
@@ -11,6 +15,11 @@ export default class SubscriptionMailMessages {
this.smsClient.sendMessage(phoneNumber, message);
}
+ /**
+ *
+ * @param phoneNumber
+ * @param remainingDays
+ */
public async sendRemainingTrialPeriod(phoneNumber: string, remainingDays: number) {
const message: string = `
Your remaining free trial is ${remainingDays} days,
diff --git a/server/src/services/Subscription/Subscription.ts b/server/src/services/Subscription/Subscription.ts
index c63861a25..8949667d6 100644
--- a/server/src/services/Subscription/Subscription.ts
+++ b/server/src/services/Subscription/Subscription.ts
@@ -1,3 +1,4 @@
+import { Inject } from 'typedi';
import { Tenant, Plan } from '@/system/models';
import { IPaymentContext } from '@/interfaces';
import { NotAllowedChangeSubscriptionPlan } from '@/exceptions';
@@ -5,6 +6,9 @@ import { NotAllowedChangeSubscriptionPlan } from '@/exceptions';
export default class Subscription {
paymentContext: IPaymentContext|null;
+ @Inject('logger')
+ logger: any;
+
/**
* Constructor method.
* @param {IPaymentContext}
diff --git a/server/src/subscribers/authentication.ts b/server/src/subscribers/authentication.ts
index a2e2da00f..26b0d468e 100644
--- a/server/src/subscribers/authentication.ts
+++ b/server/src/subscribers/authentication.ts
@@ -3,7 +3,6 @@ import { pick } from 'lodash';
import { EventSubscriber, On } from 'event-dispatch';
import events from '@/subscribers/events';
-
@EventSubscriber()
export class AuthenticationSubscriber {
@@ -14,13 +13,14 @@ export class AuthenticationSubscriber {
@On(events.auth.register)
public onRegister(payload) {
- const { registerDTO } = payload;
+ const { registerDTO, user } = payload;
const agenda = Container.get('agenda');
// Send welcome mail to the user.
agenda.now('welcome-email', {
- ...pick(registerDTO, ['email', 'organizationName', 'firstName']),
+ ...pick(registerDTO, ['organizationName']),
+ user,
});
}
@@ -32,7 +32,6 @@ export class AuthenticationSubscriber {
@On(events.auth.sendResetPassword)
public onSendResetPassword (payload) {
const { user, token } = payload;
-
const agenda = Container.get('agenda');
// Send reset password mail.
diff --git a/server/src/subscribers/organization.ts b/server/src/subscribers/organization.ts
new file mode 100644
index 000000000..670505ede
--- /dev/null
+++ b/server/src/subscribers/organization.ts
@@ -0,0 +1,16 @@
+import { Container } from 'typedi';
+import { On, EventSubscriber } from "event-dispatch";
+import events from '@/subscribers/events';
+
+@EventSubscriber()
+export class OrganizationSubscriber {
+
+ @On(events.organization.build)
+ public onBuild(payload) {
+ const agenda = Container.get('agenda');
+
+ agenda.now('welcome-sms', {
+ email, organizationName, firstName,
+ });
+ }
+}
\ No newline at end of file
diff --git a/server/views/mail/ResetPassword.html b/server/views/mail/ResetPassword.html
index 1bdc23ffc..fb4c6bd25 100644
--- a/server/views/mail/ResetPassword.html
+++ b/server/views/mail/ResetPassword.html
@@ -184,8 +184,8 @@
}
.btn-primary a {
- background-color: #2d95fd;
- border-color: #2d95fd;
+ background-color: #1968F0;
+ border-color: #1968F0;
color: #ffffff;
}
@@ -374,8 +374,8 @@
Reset Your Password
- Hi {{ first_name }} {{ last_name }},
- Click On The link blow to reset your password.
+ Hi {{ first_name }} {{ last_name }},
+ Click on the link blow to reset your password.
@@ -384,7 +384,7 @@
diff --git a/server/views/mail/Welcome.html b/server/views/mail/Welcome.html
index bde1211fe..2f610316a 100644
--- a/server/views/mail/Welcome.html
+++ b/server/views/mail/Welcome.html
@@ -335,8 +335,6 @@
border-color: #004dd0 !important;
}
}
-
-
[data-icon="bigcapital"] path {
fill: #004dd0;
}