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) {