const Boom = require('boom'); const BaseController = require('../../core/abstract/BaseApiController'); class UsersController extends BaseController { constructor(...args) { super(...args); this.User = this.server.plugins.users.User; this.UserService = this.server.plugins.users.UserService; } findById(req, reply) { return Promise.resolve() .then(() => { return this.User.findOne({ where: { id: req.params.id }, include: ['Shops'] }); }) .then(reply); } findAll(req, reply) { return Promise.resolve() .then(() => { const q = req.query; const options = { limit: q.limit || 100, offset: q.offset || 0, order: this.UtilityService.getOrderClause(q.sort), where: this.UtilityService.getSearchClause(q.search, {Model: this.User}), }; return this.User.scope('role:user').findAndCountAll(options); }) .then(reply); } create(req, reply) { return Promise.resolve() .then(() => { return this.UserService.create(req.payload); }) .then(reply); } update(req, reply) { return Promise.resolve() .then(() => { const where = { id: req.auth.credentials.id, }; if (req.auth.credentials.isAdmin) { where.id = req.params.id; } let emailChanged; let phoneChanged; return this.User.findOne({ where }) .then((user) => { if (!user) throw Boom.notFound('Record not found'); user.set(req.payload); emailChanged = user.changed('email'); phoneChanged = user.changed('phone'); return user.save(); }) .tap((user) => { if (!emailChanged) return; this.EmailVerificationService.sendVerificationEmail(user.email) .catch((err) => { this.logger.error(err); }); }) // .tap((user) => { // if (!phoneChanged) return; // // this.PhoneVerificationService.sendVerificationMessage(user) // .catch((err) => { // this.logger.error(err); // }); // }) .then((user) => { return this.User.scope('public').findById(user.id); }); }) .then(reply); } register(req, reply) { return Promise.resolve() .then(() => { return this.RecaptchaService.validate(req.payload.recaptcha, req.info.remoteAddress); }) .then(() => this.User.findOne({where: {email: req.payload.user.email}})) .then((existingUser) => { if(existingUser) { throw Boom.badData('This email is already registered.'); } }) .then(() => this.UserService.create(req.payload.user)) .then(() => { // We're capturing errors on this because this is not critical return this.EmailVerificationService.getVerificationLink(req.payload.user.email) .then((emailVerificationLink) => { const tplParams = { emailVerificationLink }; const html = this.MailTemplateService.getCompiledTemplate('welcomeAndVerifyEmail', tplParams); return this.MailService.send({ to: req.payload.user.email, subject: 'Verify account email', html }); }) .catch((err) => { this.logger.error(err); }); }) .then(() => reply.ok()); } login(req, reply) { return this.UserService.login(req.payload) .then(reply); } getCurrentUser(req, reply) { return this.User.scope('public').findOne({ where: { id: req.auth.credentials.id }, include: [{ model: this.server.plugins.shops.Shop.scope(['active']), required: false, }], }) .then(reply); } verifyEmail(req, reply) { return Promise.resolve() .then(() => { const hash = req.query.h; return this.EmailVerificationService.verify(hash); }) .then((user) => { user.emailVerified = true; return user.save(); }) .then(() => reply.ok()); } resendVerification(req, reply) { const type = req.params.type; return Promise.resolve() .then(() => { const where = { id: req.auth.credentials.id, }; if (req.auth.credentials.isAdmin) { delete where.id; where.id = req.params.id; } return this.User.findOne({ where }); }) .then((user) => { if (!user) throw Boom.notFound('Record not found'); if (type === 'email') { if (user.emailVerified) throw Boom.conflict('Email already verified'); return this.EmailVerificationService.sendVerificationEmail(user.email); } if (type === 'phone') { // TODO: Implement resend verification for phone numbers throw new Error('Not implemented'); } }) .then(reply); } loginAs(req, reply) { return Promise.resolve() .then(() => { return this.User.findOne({ where: { id: req.params.id }, include: [{ model: this.server.plugins.shops.Shop.scope(['active']), required: false }], }) .then((user) => { if (!user) throw Boom.notFound('User not found'); return this.UserService.generateJWTToken(user) .then((token) => { return { token, user }; }); }); }) .then(reply); } resetPasswordRequest(req, reply) { return Promise.resolve() .then(() => { return this.RecaptchaService.validate(req.payload.recaptcha, req.info.remoteAddress); }) .then(() => this.User.findOne({ where: { email: req.payload.email } })) .then((user) => { if (!user) { throw Boom.badRequest('Unknown email.'); } user.setResetPasswordToken(); return user.save(); }) .then((user) => { const tplParams = { resetPasswordLink: this.UtilityService.getResetPasswordLink(user), user }; const html = this.MailTemplateService.getCompiledTemplate('resetPassword', tplParams); return this.MailService.send({ to: user.email, subject: 'Reset account password', html }); }) .then(() => reply.ok()); } resetPasswordSubmit(req, reply) { return Promise.resolve() .then(() => { return this.RecaptchaService.validate(req.payload.recaptcha, req.info.remoteAddress); }) .then(() => this.User.findOne({ where: { resetPasswordToken: req.payload.token } })) .then((user) => { if (!user) { throw Boom.badRequest('Invalid token'); } user.validateResetToken(req.payload.token); user.password = req.payload.password; return user.save(); }) .catch((err) => { throw err.isBoom ? err : Boom.badRequest(err); }) .then(() => reply.ok()); } destroy(req, reply) { return Promise.resolve() .then(() => { return this.User.findById(req.params.id) .then((user) => { if (!user) { throw Boom.notFound('Record not found'); } return user.destroy(); }); }) .then(reply); } } module.exports = (server) => new UsersController(server);