diff --git a/config.json.example b/config.json.example index 2c5e30fdf1..ae805b0561 100644 --- a/config.json.example +++ b/config.json.example @@ -67,12 +67,6 @@ "SLACK_FLAGGING_URL": "https://hooks.slack.com/services/id/id/id", "SLACK_SUBSCRIPTIONS_URL": "https://hooks.slack.com/services/id/id/id", "SLACK_URL": "https://hooks.slack.com/services/some-url", - "SMTP_HOST": "example.com", - "SMTP_PASS": "password", - "SMTP_PORT": 587, - "SMTP_SERVICE": "Gmail", - "SMTP_TLS": "true", - "SMTP_USER": "user@example.com", "STRIPE_API_KEY": "aaaabbbbccccddddeeeeffff00001111", "STRIPE_PUB_KEY": "22223333444455556666777788889999", "TEST_DB_URI": "mongodb://localhost/habitrpg_test", diff --git a/migrations/archive/2019/20190717_groups_fix_2.js b/migrations/archive/2019/20190717_groups_fix_2.js index e717c04b97..cb96ba63a3 100644 --- a/migrations/archive/2019/20190717_groups_fix_2.js +++ b/migrations/archive/2019/20190717_groups_fix_2.js @@ -13,28 +13,30 @@ const questScrolls = shared.content.quests; const progressCount = 1000; let count = 0; -let backupUsers; async function updateGroup (group) { count++; - if (group && group.quest && group.quest.leader) { + if (group && group.quest && group.quest.key && group.quest.leader) { const quest = questScrolls[group.quest.key]; const leader = await User.findOne({_id: group.quest.leader}).exec(); - if (!leader) return; + if (leader && quest) { + await User.update({ + _id: leader._id, + migration: {$ne: MIGRATION_NAME}, + }, { + $set: {migration: MIGRATION_NAME}, + $inc: { + balance: 1, + [`items.quests.${group.quest.key}`]: 1, + }, + }).exec(); - await User.update({ _id: leader._id }, { - $set: {migration: MIGRATION_NAME}, - $inc: { - balance: 1, - [`items.quests.${group.quest.key}`]: 1, - }, - }).exec(); - - // unsubscribe from all is already checked by sendTxnEmail - if (leader.preferences && leader.preferences.emailNotifications && leader.preferences.emailNotifications.majorUpdates !== false) { - sendTxnEmail(leader, 'groups-outage'); + // unsubscribe from all is already checked by sendTxnEmail + if (leader.preferences && leader.preferences.emailNotifications && leader.preferences.emailNotifications.majorUpdates !== false) { + sendTxnEmail(leader, 'groups-outage'); + } } } @@ -58,7 +60,7 @@ module.exports = async function processUsers () { while (true) { // eslint-disable-line no-constant-condition const groupsPromise = new Promise((resolve, reject) => { backupGroups - .find(query, { + .find(query, { limit: 250, sort: {_id: 1} }) @@ -66,7 +68,7 @@ module.exports = async function processUsers () { resolve(foundGroupInBackup); }).catch(e => { reject(e); - }) + }); }); const groups = await groupsPromise; @@ -77,7 +79,7 @@ module.exports = async function processUsers () { break; } else { query._id = { - $gt: groups[groups.length - 1], + $gt: groups[groups.length - 1]._id, }; } diff --git a/package-lock.json b/package-lock.json index 76ae6159ea..1a90652886 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.104.1", + "version": "4.104.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b5af464833..fcf569922e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.104.1", + "version": "4.104.2", "main": "./website/server/index.js", "dependencies": { "@google-cloud/trace-agent": "^4.0.0", @@ -69,7 +69,6 @@ "nconf": "^0.10.0", "node-gcm": "^1.0.2", "node-sass": "^4.9.0", - "nodemailer": "^6.0.0", "ora": "^3.2.0", "pageres": "^5.1.0", "passport": "^0.4.0", diff --git a/test/api/unit/libs/email.test.js b/test/api/unit/libs/email.test.js index fe2fafd08e..6b4d368aa6 100644 --- a/test/api/unit/libs/email.test.js +++ b/test/api/unit/libs/email.test.js @@ -1,9 +1,7 @@ /* eslint-disable global-require */ import got from 'got'; import nconf from 'nconf'; -import nodemailer from 'nodemailer'; import requireAgain from 'require-again'; -import logger from '../../../../website/server/libs/logger'; import { TAVERN_ID } from '../../../../website/server/models/group'; import { defer } from '../../../helpers/api-unit.helper'; @@ -35,42 +33,6 @@ function getUser () { describe('emails', () => { let pathToEmailLib = '../../../../website/server/libs/email'; - describe('sendEmail', () => { - let sendMailSpy; - - beforeEach(() => { - sendMailSpy = sandbox.stub().returns(defer().promise); - sandbox.stub(nodemailer, 'createTransport').returns({ - sendMail: sendMailSpy, - }); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it('can send an email using the default transport', () => { - let attachEmail = requireAgain(pathToEmailLib); - attachEmail.send(); - expect(sendMailSpy).to.be.calledOnce; - }); - - it('logs errors', (done) => { - sandbox.stub(logger, 'error'); - - let attachEmail = requireAgain(pathToEmailLib); - attachEmail.send(); - expect(sendMailSpy).to.be.calledOnce; - defer().reject(); - - // wait for unhandledRejection event to fire - setTimeout(() => { - expect(logger.error).to.be.calledOnce; - done(); - }, 20); - }); - }); - describe('getUserInfo', () => { it('returns an empty object if no field request', () => { let attachEmail = requireAgain(pathToEmailLib); @@ -84,7 +46,7 @@ describe('emails', () => { let user = getUser(); let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); - expect(data).to.have.property('name', user.profile.name); + expect(data).to.have.property('name', user.auth.local.username); expect(data).to.have.property('email', user.auth.local.email); expect(data).to.have.property('_id', user._id); expect(data).to.have.property('canSend', true); @@ -95,11 +57,11 @@ describe('emails', () => { let getUserInfo = attachEmail.getUserInfo; let user = getUser(); delete user.profile.name; - delete user.auth.local; + delete user.auth.local.email; let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); - expect(data).to.have.property('name', user.profile.name); + expect(data).to.have.property('name', user.auth.local.username); expect(data).to.have.property('email', user.auth.facebook.emails[0].value); expect(data).to.have.property('_id', user._id); expect(data).to.have.property('canSend', true); @@ -114,7 +76,7 @@ describe('emails', () => { let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); - expect(data).to.have.property('name', user.profile.name); + expect(data).to.have.property('name', user.auth.local.username); expect(data).not.to.have.property('email'); expect(data).to.have.property('_id', user._id); expect(data).to.have.property('canSend', true); diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 82fb3dabad..f37c5c511b 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -16,6 +16,7 @@ describe('payments/index', () => { beforeEach(async () => { user = new User(); user.profile.name = 'sender'; + user.auth.local.username = 'sender'; await user.save(); group = generateGroup({ diff --git a/website/common/locales/en/front.json b/website/common/locales/en/front.json index 0d547cedd8..ccb45f30a0 100644 --- a/website/common/locales/en/front.json +++ b/website/common/locales/en/front.json @@ -278,9 +278,6 @@ "passwordConfirmationMatch": "Password confirmation doesn't match password.", "passwordResetPage": "Reset Password", "passwordReset": "If we have your email on file, instructions for setting a new password have been sent to your email.", - "passwordResetEmailSubject": "Password Reset for Habitica", - "passwordResetEmailText": "If you requested a password reset for <%= username %> on Habitica, head to <%= passwordResetLink %> to set a new one. The link will expire after 24 hours. If you haven't requested a password reset, please ignore this email.", - "passwordResetEmailHtml": "If you requested a password reset for <%= username %> on Habitica, \">click here to set a new one. The link will expire after 24 hours.

If you haven't requested a password reset, please ignore this email.", "invalidLoginCredentialsLong": "Uh-oh - your email address / username or password is incorrect.\n- Make sure they are typed correctly. Your username and password are case-sensitive.\n- You may have signed up with Facebook or Google-sign-in, not email so double-check by trying them.\n- If you forgot your password, click \"Forgot Password\".", "invalidCredentials": "There is no account that uses those credentials.", "accountSuspended": "This account, User ID \"<%= userId %>\", has been blocked for breaking the Community Guidelines (https://habitica.com/static/community-guidelines) or Terms of Service (https://habitica.com/static/terms). For details or to ask to be unblocked, please email our Community Manager at <%= communityManagerEmail %> or ask your parent or guardian to email them. Please include your @Username in the email.", diff --git a/website/server/controllers/api-v3/auth.js b/website/server/controllers/api-v3/auth.js index 04e7e9f316..9d5d2a4977 100644 --- a/website/server/controllers/api-v3/auth.js +++ b/website/server/controllers/api-v3/auth.js @@ -11,7 +11,7 @@ import { BadRequest, } from '../../libs/errors'; import * as passwordUtils from '../../libs/password'; -import { send as sendEmail } from '../../libs/email'; +import { sendTxn as sendTxnEmail } from '../../libs/email'; import { validatePasswordResetCodeAndFindUser, convertToBcrypt} from '../../libs/password'; import { encrypt } from '../../libs/encryption'; import { @@ -303,19 +303,9 @@ api.resetPassword = { user.auth.local.passwordResetCode = passwordResetCode; - sendEmail({ - from: 'Habitica ', - to: email, - subject: res.t('passwordResetEmailSubject'), - text: res.t('passwordResetEmailText', { - username: user.auth.local.username, - passwordResetLink: link, - }), - html: res.t('passwordResetEmailHtml', { - username: user.auth.local.username, - passwordResetLink: link, - }), - }); + sendTxnEmail(user, 'reset-password', [ + {name: 'PASSWORD_RESET_LINK', content: link}, + ]); await user.save(); } diff --git a/website/server/libs/email.js b/website/server/libs/email.js index 42ec7387a4..02e236fe60 100644 --- a/website/server/libs/email.js +++ b/website/server/libs/email.js @@ -1,4 +1,3 @@ -import nodemailer from 'nodemailer'; import nconf from 'nconf'; import { TAVERN_ID } from '../models/group'; import { encrypt } from './encryption'; @@ -16,25 +15,11 @@ const EMAIL_SERVER = { }; const BASE_URL = nconf.get('BASE_URL'); -let smtpTransporter = nodemailer.createTransport({ - service: nconf.get('SMTP_SERVICE'), - auth: { - user: nconf.get('SMTP_USER'), - pass: nconf.get('SMTP_PASS'), - }, -}); - -// Send email directly from the server using the smtpTransporter, -// used only to send password reset emails because users unsubscribed on Mandrill wouldn't get them -export function send (mailData) { - return smtpTransporter.sendMail(mailData); // promise -} - export function getUserInfo (user, fields = []) { let info = {}; if (fields.indexOf('name') !== -1) { - info.name = user.profile && user.profile.name; + info.name = user.auth && user.auth.local.username; } if (fields.indexOf('email') !== -1) {