mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
Merge branch 'release' into develop
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "4.104.1",
|
||||
"version": "4.104.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 <strong><%= username %></strong> on Habitica, <a href=\"<%= passwordResetLink %>\">click here</a> to set a new one. The link will expire after 24 hours.<br/><br>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.",
|
||||
|
||||
@@ -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 <admin@habitica.com>',
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user