mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
Upgrade server deps (#10017)
* remove unused apn lib and upgrade moment-recur * upgrade validator * upgrade got * request -> got * fix validation * fix tests * upgrade nodemailer * fix unit tests * fix webhook tests, upgrade express-validator (using legacy api) * upgrade js2xmlparser * update misc packages * fix linting * update packages
This commit is contained in:
776
package-lock.json
generated
776
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@@ -9,14 +9,13 @@
|
|||||||
"amazon-payments": "^0.2.6",
|
"amazon-payments": "^0.2.6",
|
||||||
"amplitude": "^3.5.0",
|
"amplitude": "^3.5.0",
|
||||||
"apidoc": "^0.17.5",
|
"apidoc": "^0.17.5",
|
||||||
"apn": "^1.7.6",
|
|
||||||
"autoprefixer": "^8.0.0",
|
"autoprefixer": "^8.0.0",
|
||||||
"aws-sdk": "^2.0.25",
|
"aws-sdk": "^2.200.0",
|
||||||
"axios": "^0.17.1",
|
"axios": "^0.18.0",
|
||||||
"axios-progress-bar": "^1.1.8",
|
"axios-progress-bar": "^1.1.8",
|
||||||
"babel-core": "^6.0.0",
|
"babel-core": "^6.0.0",
|
||||||
|
"babel-eslint": "^8.2.2",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-eslint": "^8.2.1",
|
|
||||||
"babel-plugin-syntax-async-functions": "^6.13.0",
|
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||||
"babel-plugin-transform-async-to-module-method": "^6.8.0",
|
"babel-plugin-transform-async-to-module-method": "^6.8.0",
|
||||||
@@ -31,20 +30,20 @@
|
|||||||
"body-parser": "^1.15.0",
|
"body-parser": "^1.15.0",
|
||||||
"bootstrap": "^4.0.0",
|
"bootstrap": "^4.0.0",
|
||||||
"bootstrap-vue": "^2.0.0-rc.1",
|
"bootstrap-vue": "^2.0.0-rc.1",
|
||||||
"compression": "^1.6.1",
|
"compression": "^1.7.2",
|
||||||
"cookie-session": "^1.2.0",
|
"cookie-session": "^1.2.0",
|
||||||
"coupon-code": "^0.4.5",
|
"coupon-code": "^0.4.5",
|
||||||
"cross-env": "^5.1.3",
|
"cross-env": "^5.1.3",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
"csv-stringify": "^2.0.1",
|
"csv-stringify": "^2.0.4",
|
||||||
"cwait": "^1.1.1",
|
"cwait": "^1.1.1",
|
||||||
"domain-middleware": "~0.1.0",
|
"domain-middleware": "~0.1.0",
|
||||||
"express": "^4.16.2",
|
"express": "^4.16.2",
|
||||||
"express-basic-auth": "^1.0.1",
|
"express-basic-auth": "^1.1.4",
|
||||||
"express-validator": "^2.18.0",
|
"express-validator": "^5.0.1",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"got": "^6.1.1",
|
"got": "^8.2.0",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.0",
|
||||||
"gulp-babel": "^7.0.1",
|
"gulp-babel": "^7.0.1",
|
||||||
"gulp-imagemin": "^4.1.0",
|
"gulp-imagemin": "^4.1.0",
|
||||||
@@ -57,19 +56,19 @@
|
|||||||
"in-app-purchase": "^1.1.6",
|
"in-app-purchase": "^1.1.6",
|
||||||
"intro.js": "^2.6.0",
|
"intro.js": "^2.6.0",
|
||||||
"jquery": ">=3.0.0",
|
"jquery": ">=3.0.0",
|
||||||
"js2xmlparser": "~1.0.0",
|
"js2xmlparser": "^3.0.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"merge-stream": "^1.0.0",
|
"merge-stream": "^1.0.0",
|
||||||
"method-override": "^2.3.5",
|
"method-override": "^2.3.5",
|
||||||
"moment": "^2.13.0",
|
"moment": "^2.13.0",
|
||||||
"moment-recur": "git://github.com/habitrpg/moment-recur.git#f147ef27bbc26ca67638385f3db4a44084c76626",
|
"moment-recur": "^1.0.7",
|
||||||
"mongoose": "^4.13.10",
|
"mongoose": "^4.13.11",
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
"nconf": "^0.10.0",
|
"nconf": "^0.10.0",
|
||||||
"node-gcm": "^0.14.4",
|
"node-gcm": "^0.14.4",
|
||||||
"node-sass": "^4.5.0",
|
"node-sass": "^4.5.0",
|
||||||
"nodemailer": "^2.3.2",
|
"nodemailer": "^4.5.0",
|
||||||
"ora": "^1.1.0",
|
"ora": "^2.0.0",
|
||||||
"pageres": "^4.1.1",
|
"pageres": "^4.1.1",
|
||||||
"passport": "^0.4.0",
|
"passport": "^0.4.0",
|
||||||
"passport-facebook": "^2.0.0",
|
"passport-facebook": "^2.0.0",
|
||||||
@@ -82,11 +81,10 @@
|
|||||||
"pug": "^2.0.0-rc.4",
|
"pug": "^2.0.0-rc.4",
|
||||||
"push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
|
"push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
|
||||||
"pusher": "^1.3.0",
|
"pusher": "^1.3.0",
|
||||||
"request": "^2.83.0",
|
|
||||||
"rimraf": "^2.4.3",
|
"rimraf": "^2.4.3",
|
||||||
"sass-loader": "^6.0.2",
|
"sass-loader": "^6.0.2",
|
||||||
"shelljs": "^0.8.1",
|
"shelljs": "^0.8.1",
|
||||||
"stripe": "^5.4.0",
|
"stripe": "^5.5.0",
|
||||||
"superagent": "^3.4.3",
|
"superagent": "^3.4.3",
|
||||||
"svg-inline-loader": "^0.8.0",
|
"svg-inline-loader": "^0.8.0",
|
||||||
"svg-url-loader": "^2.0.2",
|
"svg-url-loader": "^2.0.2",
|
||||||
@@ -96,13 +94,13 @@
|
|||||||
"url-loader": "^0.6.2",
|
"url-loader": "^0.6.2",
|
||||||
"useragent": "^2.1.9",
|
"useragent": "^2.1.9",
|
||||||
"uuid": "^3.0.1",
|
"uuid": "^3.0.1",
|
||||||
"validator": "^4.9.0",
|
"validator": "^9.4.1",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vue": "^2.5.2",
|
"vue": "^2.5.2",
|
||||||
"vue-loader": "^14.1.1",
|
"vue-loader": "^14.1.1",
|
||||||
"vue-mugen-scroll": "^0.2.1",
|
"vue-mugen-scroll": "^0.2.1",
|
||||||
"vue-router": "^3.0.0",
|
"vue-router": "^3.0.0",
|
||||||
"vue-style-loader": "^3.0.0",
|
"vue-style-loader": "^4.0.2",
|
||||||
"vue-template-compiler": "^2.5.2",
|
"vue-template-compiler": "^2.5.2",
|
||||||
"vuedraggable": "^2.15.0",
|
"vuedraggable": "^2.15.0",
|
||||||
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
|
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
|
||||||
@@ -145,12 +143,12 @@
|
|||||||
"babel-plugin-istanbul": "^4.0.0",
|
"babel-plugin-istanbul": "^4.0.0",
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"chai-as-promised": "^7.1.1",
|
"chai-as-promised": "^7.1.1",
|
||||||
"chalk": "^2.3.0",
|
"chalk": "^2.3.1",
|
||||||
"chromedriver": "^2.27.2",
|
"chromedriver": "^2.27.2",
|
||||||
"connect-history-api-fallback": "^1.1.0",
|
"connect-history-api-fallback": "^1.1.0",
|
||||||
"coveralls": "^3.0.0",
|
"coveralls": "^3.0.0",
|
||||||
"cross-spawn": "^6.0.4",
|
"cross-spawn": "^6.0.4",
|
||||||
"eslint": "^4.17.0",
|
"eslint": "^4.18.1",
|
||||||
"eslint-config-habitrpg": "^4.0.0",
|
"eslint-config-habitrpg": "^4.0.0",
|
||||||
"eslint-friendly-formatter": "^3.0.0",
|
"eslint-friendly-formatter": "^3.0.0",
|
||||||
"eslint-loader": "^1.3.0",
|
"eslint-loader": "^1.3.0",
|
||||||
@@ -173,13 +171,13 @@
|
|||||||
"karma-spec-reporter": "0.0.32",
|
"karma-spec-reporter": "0.0.32",
|
||||||
"karma-webpack": "^2.0.2",
|
"karma-webpack": "^2.0.2",
|
||||||
"lcov-result-merger": "^2.0.0",
|
"lcov-result-merger": "^2.0.0",
|
||||||
"mocha": "^5.0.0",
|
"mocha": "^5.0.1",
|
||||||
"monk": "^6.0.5",
|
"monk": "^6.0.5",
|
||||||
"nightwatch": "^0.9.12",
|
"nightwatch": "^0.9.12",
|
||||||
"puppeteer": "^1.0.0",
|
"puppeteer": "^1.1.0",
|
||||||
"require-again": "^2.0.0",
|
"require-again": "^2.0.0",
|
||||||
"selenium-server": "^3.0.1",
|
"selenium-server": "^3.9.1",
|
||||||
"sinon": "^4.2.2",
|
"sinon": "^4.3.0",
|
||||||
"sinon-chai": "^2.8.0",
|
"sinon-chai": "^2.8.0",
|
||||||
"sinon-stub-promise": "^4.0.0",
|
"sinon-stub-promise": "^4.0.0",
|
||||||
"webpack-bundle-analyzer": "^2.2.1",
|
"webpack-bundle-analyzer": "^2.2.1",
|
||||||
|
|||||||
@@ -478,8 +478,8 @@ describe('POST /chat', () => {
|
|||||||
context('Spam prevention', () => {
|
context('Spam prevention', () => {
|
||||||
it('Returns an error when the user has been posting too many messages', async () => {
|
it('Returns an error when the user has been posting too many messages', async () => {
|
||||||
// Post as many messages are needed to reach the spam limit
|
// Post as many messages are needed to reach the spam limit
|
||||||
for (let i = 0; i < SPAM_MESSAGE_LIMIT; i++) { // eslint-disable-line no-await-in-loop
|
for (let i = 0; i < SPAM_MESSAGE_LIMIT; i++) {
|
||||||
let result = await additionalMember.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage });
|
let result = await additionalMember.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage }); // eslint-disable-line no-await-in-loop
|
||||||
expect(result.message.id).to.exist;
|
expect(result.message.id).to.exist;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,8 +494,8 @@ describe('POST /chat', () => {
|
|||||||
let userSocialite = await member.update({'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL, 'flags.chatRevoked': false});
|
let userSocialite = await member.update({'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL, 'flags.chatRevoked': false});
|
||||||
|
|
||||||
// Post 1 more message than the spam limit to ensure they do not reach the limit
|
// Post 1 more message than the spam limit to ensure they do not reach the limit
|
||||||
for (let i = 0; i < SPAM_MESSAGE_LIMIT + 1; i++) { // eslint-disable-line no-await-in-loop
|
for (let i = 0; i < SPAM_MESSAGE_LIMIT + 1; i++) {
|
||||||
let result = await userSocialite.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage });
|
let result = await userSocialite.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage }); // eslint-disable-line no-await-in-loop
|
||||||
expect(result.message.id).to.exist;
|
expect(result.message.id).to.exist;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -113,10 +113,10 @@ describe('GET /tasks/user', () => {
|
|||||||
await user.sync();
|
await user.sync();
|
||||||
let initialTodoCount = user.tasksOrder.todos.length;
|
let initialTodoCount = user.tasksOrder.todos.length;
|
||||||
|
|
||||||
for (let i = 0; i < numberOfTodos; i++) { // eslint-disable-line no-await-in-loop
|
for (let i = 0; i < numberOfTodos; i++) {
|
||||||
let id = todos[i]._id;
|
let id = todos[i]._id;
|
||||||
|
|
||||||
await user.post(`/tasks/${id}/score/up`);
|
await user.post(`/tasks/${id}/score/up`); // eslint-disable-line no-await-in-loop
|
||||||
}
|
}
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ describe('POST /tasks/clearCompletedTodos', () => {
|
|||||||
let tasks = await user.get('/tasks/user?type=todos');
|
let tasks = await user.get('/tasks/user?type=todos');
|
||||||
expect(tasks.length).to.equal(initialTodoCount + 7);
|
expect(tasks.length).to.equal(initialTodoCount + 7);
|
||||||
|
|
||||||
for (let task of tasks) { // eslint-disable-line no-await-in-loop
|
for (let task of tasks) {
|
||||||
if (['todo 2', 'todo 3', 'todo 6'].indexOf(task.text) !== -1) {
|
if (['todo 2', 'todo 3', 'todo 6'].indexOf(task.text) !== -1) {
|
||||||
await user.post(`/tasks/${task._id}/score/up`);
|
await user.post(`/tasks/${task._id}/score/up`); // eslint-disable-line no-await-in-loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ describe('PUT /user/webhook/:id', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns an error if validation fails', async () => {
|
it('returns an error if validation fails', async () => {
|
||||||
await expect(user.put(`/user/webhook/${webhookToUpdate.id}`, { url: 'foo', enabled: true })).to.eventually.be.rejected.and.eql({
|
await expect(user.put(`/user/webhook/${webhookToUpdate.id}`, { url: 'foo_invalid', enabled: true })).to.eventually.be.rejected.and.eql({
|
||||||
code: 400,
|
code: 400,
|
||||||
error: 'BadRequest',
|
error: 'BadRequest',
|
||||||
message: 'User validation failed',
|
message: 'User validation failed',
|
||||||
|
|||||||
@@ -1,27 +1,11 @@
|
|||||||
/* eslint-disable global-require */
|
/* eslint-disable global-require */
|
||||||
import request from 'request';
|
import got from 'got';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import nodemailer from 'nodemailer';
|
import nodemailer from 'nodemailer';
|
||||||
import Bluebird from 'bluebird';
|
|
||||||
import requireAgain from 'require-again';
|
import requireAgain from 'require-again';
|
||||||
import logger from '../../../../../website/server/libs/logger';
|
import logger from '../../../../../website/server/libs/logger';
|
||||||
import { TAVERN_ID } from '../../../../../website/server/models/group';
|
import { TAVERN_ID } from '../../../../../website/server/models/group';
|
||||||
|
import { defer } from '../../../../helpers/api-unit.helper';
|
||||||
function defer () {
|
|
||||||
let resolve;
|
|
||||||
let reject;
|
|
||||||
|
|
||||||
let promise = new Bluebird((resolveParam, rejectParam) => {
|
|
||||||
resolve = resolveParam;
|
|
||||||
reject = rejectParam;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
resolve,
|
|
||||||
reject,
|
|
||||||
promise,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUser () {
|
function getUser () {
|
||||||
return {
|
return {
|
||||||
@@ -158,7 +142,7 @@ describe('emails', () => {
|
|||||||
|
|
||||||
describe('sendTxnEmail', () => {
|
describe('sendTxnEmail', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
sandbox.stub(request, 'post');
|
sandbox.stub(got, 'post').returns(defer().promise);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -176,8 +160,9 @@ describe('emails', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
sendTxnEmail(mailingInfo, emailType);
|
sendTxnEmail(mailingInfo, emailType);
|
||||||
expect(request.post).to.be.calledWith(sinon.match({
|
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||||
json: {
|
json: true,
|
||||||
|
body: {
|
||||||
data: {
|
data: {
|
||||||
emailType: sinon.match.same(emailType),
|
emailType: sinon.match.same(emailType),
|
||||||
to: sinon.match((value) => {
|
to: sinon.match((value) => {
|
||||||
@@ -199,7 +184,7 @@ describe('emails', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
sendTxnEmail(mailingInfo, emailType);
|
sendTxnEmail(mailingInfo, emailType);
|
||||||
expect(request.post).not.to.be.called;
|
expect(got.post).not.to.be.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses getUserInfo in case of user data', () => {
|
it('uses getUserInfo in case of user data', () => {
|
||||||
@@ -210,8 +195,9 @@ describe('emails', () => {
|
|||||||
let mailingInfo = getUser();
|
let mailingInfo = getUser();
|
||||||
|
|
||||||
sendTxnEmail(mailingInfo, emailType);
|
sendTxnEmail(mailingInfo, emailType);
|
||||||
expect(request.post).to.be.calledWith(sinon.match({
|
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||||
json: {
|
json: true,
|
||||||
|
body: {
|
||||||
data: {
|
data: {
|
||||||
emailType: sinon.match.same(emailType),
|
emailType: sinon.match.same(emailType),
|
||||||
to: sinon.match(val => val[0]._id === mailingInfo._id),
|
to: sinon.match(val => val[0]._id === mailingInfo._id),
|
||||||
@@ -232,8 +218,9 @@ describe('emails', () => {
|
|||||||
let variables = [1, 2, 3];
|
let variables = [1, 2, 3];
|
||||||
|
|
||||||
sendTxnEmail(mailingInfo, emailType, variables);
|
sendTxnEmail(mailingInfo, emailType, variables);
|
||||||
expect(request.post).to.be.calledWith(sinon.match({
|
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||||
json: {
|
json: true,
|
||||||
|
body: {
|
||||||
data: {
|
data: {
|
||||||
variables: sinon.match((value) => {
|
variables: sinon.match((value) => {
|
||||||
return value[0].name === 'BASE_URL';
|
return value[0].name === 'BASE_URL';
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import request from 'request';
|
import got from 'got';
|
||||||
import {
|
import {
|
||||||
WebhookSender,
|
WebhookSender,
|
||||||
taskScoredWebhook,
|
taskScoredWebhook,
|
||||||
groupChatReceivedWebhook,
|
groupChatReceivedWebhook,
|
||||||
taskActivityWebhook,
|
taskActivityWebhook,
|
||||||
} from '../../../../../website/server/libs/webhook';
|
} from '../../../../../website/server/libs/webhook';
|
||||||
|
import { defer } from '../../../../helpers/api-unit.helper';
|
||||||
|
|
||||||
describe('webhooks', () => {
|
describe('webhooks', () => {
|
||||||
let webhooks;
|
let webhooks;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
sandbox.stub(request, 'post');
|
sandbox.stub(got, 'post').returns(defer().promise);
|
||||||
|
|
||||||
webhooks = [{
|
webhooks = [{
|
||||||
id: 'taskActivity',
|
id: 'taskActivity',
|
||||||
@@ -59,8 +60,9 @@ describe('webhooks', () => {
|
|||||||
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
|
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
|
||||||
|
|
||||||
expect(WebhookSender.defaultTransformData).to.be.calledOnce;
|
expect(WebhookSender.defaultTransformData).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
|
||||||
|
json: true,
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -81,8 +83,9 @@ describe('webhooks', () => {
|
|||||||
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
|
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
|
||||||
|
|
||||||
expect(WebhookSender.defaultTransformData).to.not.be.called;
|
expect(WebhookSender.defaultTransformData).to.not.be.called;
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
|
||||||
|
json: true,
|
||||||
body: {
|
body: {
|
||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
baz: 'biz',
|
baz: 'biz',
|
||||||
@@ -117,7 +120,7 @@ describe('webhooks', () => {
|
|||||||
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
|
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: true, type: 'custom'}], body);
|
||||||
|
|
||||||
expect(WebhookSender.defaultWebhookFilter).to.not.be.called;
|
expect(WebhookSender.defaultWebhookFilter).to.not.be.called;
|
||||||
expect(request.post).to.not.be.called;
|
expect(got.post).to.not.be.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can pass in a webhook filter function that filters on data', () => {
|
it('can pass in a webhook filter function that filters on data', () => {
|
||||||
@@ -136,10 +139,8 @@ describe('webhooks', () => {
|
|||||||
{ id: 'other-custom-webhook', url: 'http://other-custom-url.com', enabled: true, type: 'custom', options: { foo: 'foo' }},
|
{ id: 'other-custom-webhook', url: 'http://other-custom-url.com', enabled: true, type: 'custom', options: { foo: 'foo' }},
|
||||||
], body);
|
], body);
|
||||||
|
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch('http://custom-url.com');
|
||||||
url: 'http://custom-url.com',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores disabled webhooks', () => {
|
it('ignores disabled webhooks', () => {
|
||||||
@@ -151,7 +152,7 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: false, type: 'custom'}], body);
|
sendWebhook.send([{id: 'custom-webhook', url: 'http://custom-url.com', enabled: false, type: 'custom'}], body);
|
||||||
|
|
||||||
expect(request.post).to.not.be.called;
|
expect(got.post).to.not.be.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores webhooks with invalid urls', () => {
|
it('ignores webhooks with invalid urls', () => {
|
||||||
@@ -163,7 +164,7 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
sendWebhook.send([{id: 'custom-webhook', url: 'httxp://custom-url!!', enabled: true, type: 'custom'}], body);
|
sendWebhook.send([{id: 'custom-webhook', url: 'httxp://custom-url!!', enabled: true, type: 'custom'}], body);
|
||||||
|
|
||||||
expect(request.post).to.not.be.called;
|
expect(got.post).to.not.be.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores webhooks of other types', () => {
|
it('ignores webhooks of other types', () => {
|
||||||
@@ -178,9 +179,8 @@ describe('webhooks', () => {
|
|||||||
{ id: 'other-webhook', url: 'http://other-url.com', enabled: true, type: 'other'},
|
{ id: 'other-webhook', url: 'http://other-url.com', enabled: true, type: 'other'},
|
||||||
], body);
|
], body);
|
||||||
|
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
|
||||||
url: 'http://custom-url.com',
|
|
||||||
body,
|
body,
|
||||||
json: true,
|
json: true,
|
||||||
});
|
});
|
||||||
@@ -198,14 +198,12 @@ describe('webhooks', () => {
|
|||||||
{ id: 'other-custom-webhook', url: 'http://other-url.com', enabled: true, type: 'custom'},
|
{ id: 'other-custom-webhook', url: 'http://other-url.com', enabled: true, type: 'custom'},
|
||||||
], body);
|
], body);
|
||||||
|
|
||||||
expect(request.post).to.be.calledTwice;
|
expect(got.post).to.be.calledTwice;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch('http://custom-url.com', {
|
||||||
url: 'http://custom-url.com',
|
|
||||||
body,
|
body,
|
||||||
json: true,
|
json: true,
|
||||||
});
|
});
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch('http://other-url.com', {
|
||||||
url: 'http://other-url.com',
|
|
||||||
body,
|
body,
|
||||||
json: true,
|
json: true,
|
||||||
});
|
});
|
||||||
@@ -252,8 +250,9 @@ describe('webhooks', () => {
|
|||||||
it('sends task and stats data', () => {
|
it('sends task and stats data', () => {
|
||||||
taskScoredWebhook.send(webhooks, data);
|
taskScoredWebhook.send(webhooks, data);
|
||||||
|
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch(webhooks[0].url, {
|
||||||
|
json: true,
|
||||||
body: {
|
body: {
|
||||||
type: 'scored',
|
type: 'scored',
|
||||||
user: {
|
user: {
|
||||||
@@ -283,7 +282,7 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
taskScoredWebhook.send(webhooks, data);
|
taskScoredWebhook.send(webhooks, data);
|
||||||
|
|
||||||
expect(request.post).to.not.be.called;
|
expect(got.post).to.not.be.called;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -304,8 +303,9 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
taskActivityWebhook.send(webhooks, data);
|
taskActivityWebhook.send(webhooks, data);
|
||||||
|
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch(webhooks[0].url, {
|
||||||
|
json: true,
|
||||||
body: {
|
body: {
|
||||||
type,
|
type,
|
||||||
task: data.task,
|
task: data.task,
|
||||||
@@ -319,7 +319,7 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
taskActivityWebhook.send(webhooks, data);
|
taskActivityWebhook.send(webhooks, data);
|
||||||
|
|
||||||
expect(request.post).to.not.be.called;
|
expect(got.post).to.not.be.called;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -340,8 +340,9 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
groupChatReceivedWebhook.send(webhooks, data);
|
groupChatReceivedWebhook.send(webhooks, data);
|
||||||
|
|
||||||
expect(request.post).to.be.calledOnce;
|
expect(got.post).to.be.calledOnce;
|
||||||
expect(request.post).to.be.calledWithMatch({
|
expect(got.post).to.be.calledWithMatch(webhooks[webhooks.length - 1].url, {
|
||||||
|
json: true,
|
||||||
body: {
|
body: {
|
||||||
group: {
|
group: {
|
||||||
id: 'group-id',
|
id: 'group-id',
|
||||||
@@ -370,7 +371,7 @@ describe('webhooks', () => {
|
|||||||
|
|
||||||
groupChatReceivedWebhook.send(webhooks, data);
|
groupChatReceivedWebhook.send(webhooks, data);
|
||||||
|
|
||||||
expect(request.post).to.not.be.called;
|
expect(got.post).to.not.be.called;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -108,3 +108,19 @@ export function generateDaily (user) {
|
|||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function defer () {
|
||||||
|
let resolve;
|
||||||
|
let reject;
|
||||||
|
|
||||||
|
let promise = new Promise((resolveParam, rejectParam) => {
|
||||||
|
resolve = resolveParam;
|
||||||
|
reject = rejectParam;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
resolve,
|
||||||
|
reject,
|
||||||
|
promise,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function fetch (store, options = {}) { // eslint-disable-line no-shadow
|
|||||||
export async function set (store, changes) {
|
export async function set (store, changes) {
|
||||||
const user = store.state.user.data;
|
const user = store.state.user.data;
|
||||||
|
|
||||||
for (let key in changes) { // eslint-disable-line no-await-in-loop
|
for (let key in changes) {
|
||||||
if (key === 'tags') {
|
if (key === 'tags') {
|
||||||
// Keep challenge and group tags
|
// Keep challenge and group tags
|
||||||
const oldTags = user.tags.filter(t => {
|
const oldTags = user.tags.filter(t => {
|
||||||
@@ -31,7 +31,7 @@ export async function set (store, changes) {
|
|||||||
user.tags = changes[key].concat(oldTags);
|
user.tags = changes[key].concat(oldTags);
|
||||||
|
|
||||||
// Remove deleted tags from tasks
|
// Remove deleted tags from tasks
|
||||||
const userTasksByType = (await store.dispatch('tasks:fetchUserTasks')).data;
|
const userTasksByType = (await store.dispatch('tasks:fetchUserTasks')).data; // eslint-disable-line no-await-in-loop
|
||||||
|
|
||||||
Object.keys(userTasksByType).forEach(taskType => {
|
Object.keys(userTasksByType).forEach(taskType => {
|
||||||
userTasksByType[taskType].forEach(task => {
|
userTasksByType[taskType].forEach(task => {
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ api.loginLocal = {
|
|||||||
let username = req.body.username;
|
let username = req.body.username;
|
||||||
let password = req.body.password;
|
let password = req.body.password;
|
||||||
|
|
||||||
if (validator.isEmail(username)) {
|
if (validator.isEmail(String(username))) {
|
||||||
login = {'auth.local.email': username.toLowerCase()}; // Emails are stored lowercase
|
login = {'auth.local.email': username.toLowerCase()}; // Emails are stored lowercase
|
||||||
} else {
|
} else {
|
||||||
login = {'auth.local.username': username};
|
login = {'auth.local.username': username};
|
||||||
@@ -410,7 +410,7 @@ api.pusherAuth = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resourceId = resourceId.join('-'); // the split at the beginning had split resourceId too
|
resourceId = resourceId.join('-'); // the split at the beginning had split resourceId too
|
||||||
if (!validator.isUUID(resourceId)) {
|
if (!validator.isUUID(String(resourceId))) {
|
||||||
throw new BadRequest('Invalid Pusher resource id, must be a UUID.');
|
throw new BadRequest('Invalid Pusher resource id, must be a UUID.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,7 +144,12 @@ api.exportUserDataXml = {
|
|||||||
'Content-Type': 'text/xml',
|
'Content-Type': 'text/xml',
|
||||||
'Content-disposition': 'attachment; filename=habitica-user-data.xml',
|
'Content-disposition': 'attachment; filename=habitica-user-data.xml',
|
||||||
});
|
});
|
||||||
res.status(200).send(js2xml('user', userData));
|
res.status(200).send(js2xml.parse('user', userData, {
|
||||||
|
cdataInvalidChars: true,
|
||||||
|
declaration: {
|
||||||
|
include: false,
|
||||||
|
},
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,16 +33,16 @@ api.verifyGemPurchase = async function verifyGemPurchase (user, receipt, headers
|
|||||||
let correctReceipt = false;
|
let correctReceipt = false;
|
||||||
|
|
||||||
// Purchasing one item at a time (processing of await(s) below is sequential not parallel)
|
// Purchasing one item at a time (processing of await(s) below is sequential not parallel)
|
||||||
for (let index in purchaseDataList) { // eslint-disable-line no-await-in-loop
|
for (let index in purchaseDataList) {
|
||||||
let purchaseData = purchaseDataList[index];
|
let purchaseData = purchaseDataList[index];
|
||||||
let token = purchaseData.transactionId;
|
let token = purchaseData.transactionId;
|
||||||
|
|
||||||
let existingReceipt = await IapPurchaseReceipt.findOne({
|
let existingReceipt = await IapPurchaseReceipt.findOne({ // eslint-disable-line no-await-in-loop
|
||||||
_id: token,
|
_id: token,
|
||||||
}).exec();
|
}).exec();
|
||||||
|
|
||||||
if (!existingReceipt) {
|
if (!existingReceipt) {
|
||||||
await IapPurchaseReceipt.create({
|
await IapPurchaseReceipt.create({ // eslint-disable-line no-await-in-loop
|
||||||
_id: token,
|
_id: token,
|
||||||
consumed: true,
|
consumed: true,
|
||||||
userId: user._id,
|
userId: user._id,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { createTransport } from 'nodemailer';
|
import nodemailer from 'nodemailer';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import { TAVERN_ID } from '../models/group';
|
import { TAVERN_ID } from '../models/group';
|
||||||
import { encrypt } from './encryption';
|
import { encrypt } from './encryption';
|
||||||
import request from 'request';
|
import got from 'got';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
import common from '../../common';
|
import common from '../../common';
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ const EMAIL_SERVER = {
|
|||||||
};
|
};
|
||||||
const BASE_URL = nconf.get('BASE_URL');
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
|
||||||
let smtpTransporter = createTransport({
|
let smtpTransporter = nodemailer.createTransport({
|
||||||
service: nconf.get('SMTP_SERVICE'),
|
service: nconf.get('SMTP_SERVICE'),
|
||||||
auth: {
|
auth: {
|
||||||
user: nconf.get('SMTP_USER'),
|
user: nconf.get('SMTP_USER'),
|
||||||
@@ -150,13 +150,10 @@ export function sendTxn (mailingInfoArray, emailType, variables, personalVariabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IS_PROD && mailingInfoArray.length > 0) {
|
if (IS_PROD && mailingInfoArray.length > 0) {
|
||||||
request.post({
|
got.post(`${EMAIL_SERVER.url}/job`, {
|
||||||
url: `${EMAIL_SERVER.url}/job`,
|
auth: `${EMAIL_SERVER.auth.user}:${EMAIL_SERVER.auth.password}`,
|
||||||
auth: {
|
json: true,
|
||||||
user: EMAIL_SERVER.auth.user,
|
body: {
|
||||||
pass: EMAIL_SERVER.auth.password,
|
|
||||||
},
|
|
||||||
json: {
|
|
||||||
type: 'email',
|
type: 'email',
|
||||||
data: {
|
data: {
|
||||||
emailType,
|
emailType,
|
||||||
@@ -170,6 +167,6 @@ export function sendTxn (mailingInfoArray, emailType, variables, personalVariabl
|
|||||||
backoff: {delay: 10 * 60 * 1000, type: 'fixed'},
|
backoff: {delay: 10 * 60 * 1000, type: 'fixed'},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, (err) => logger.error(err));
|
}).catch((err) => logger.error(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
// TODO remove this lib and use directly the apn module
|
// @TODO remove this lib and use directly the apn module
|
||||||
import pushNotify from 'push-notify';
|
import pushNotify from 'push-notify';
|
||||||
import apnLib from 'apn';
|
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
import Bluebird from 'bluebird';
|
import Bluebird from 'bluebird';
|
||||||
import {
|
import {
|
||||||
@@ -44,21 +43,9 @@ if (APN_ENABLED) {
|
|||||||
apn.on('transmissionError', (errorCode, notification, device) => {
|
apn.on('transmissionError', (errorCode, notification, device) => {
|
||||||
logger.error('APN transmissionError', errorCode, notification, device);
|
logger.error('APN transmissionError', errorCode, notification, device);
|
||||||
});
|
});
|
||||||
|
|
||||||
let feedback = new apnLib.Feedback({
|
|
||||||
key,
|
|
||||||
cert,
|
|
||||||
batchFeedback: true,
|
|
||||||
interval: 3600, // Check for feedback once an hour
|
|
||||||
});
|
|
||||||
|
|
||||||
feedback.on('feedback', (devices) => {
|
|
||||||
if (devices && devices.length > 0) {
|
|
||||||
logger.info('Delivery of push notifications failed for some Apple devices.', devices);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNotification (user, details = {}) {
|
function sendNotification (user, details = {}) {
|
||||||
if (!user) throw new Error('User is required.');
|
if (!user) throw new Error('User is required.');
|
||||||
if (user.preferences.pushNotifications.unsubscribeFromAll === true) return;
|
if (user.preferences.pushNotifications.unsubscribeFromAll === true) return;
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { post } from 'request';
|
import got from 'got';
|
||||||
import { isURL } from 'validator';
|
import { isURL } from 'validator';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const IS_PRODUCTION = nconf.get('IS_PROD');
|
||||||
|
|
||||||
function sendWebhook (url, body) {
|
function sendWebhook (url, body) {
|
||||||
post({
|
got.post(url, {
|
||||||
url,
|
|
||||||
body,
|
body,
|
||||||
json: true,
|
json: true,
|
||||||
}, (err) => {
|
}).catch(err => logger.error(err));
|
||||||
if (err) {
|
|
||||||
logger.error(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidWebhook (hook) {
|
function isValidWebhook (hook) {
|
||||||
return hook.enabled && isURL(hook.url);
|
return hook.enabled && isURL(hook.url, {
|
||||||
|
require_tld: IS_PRODUCTION ? true : false, // eslint-disable-line camelcase
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebhookSender {
|
export class WebhookSender {
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ TaskSchema.statics.findByIdOrAlias = async function findByIdOrAlias (identifier,
|
|||||||
|
|
||||||
let query = _.cloneDeep(additionalQueries);
|
let query = _.cloneDeep(additionalQueries);
|
||||||
|
|
||||||
if (validator.isUUID(identifier)) {
|
if (validator.isUUID(String(identifier))) {
|
||||||
query._id = identifier;
|
query._id = identifier;
|
||||||
} else {
|
} else {
|
||||||
query.userId = userId;
|
query.userId = userId;
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import shared from '../../common';
|
|||||||
import {v4 as uuid} from 'uuid';
|
import {v4 as uuid} from 'uuid';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { BadRequest } from '../libs/errors';
|
import { BadRequest } from '../libs/errors';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const IS_PRODUCTION = nconf.get('IS_PROD');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
const TASK_ACTIVITY_DEFAULT_OPTIONS = Object.freeze({
|
const TASK_ACTIVITY_DEFAULT_OPTIONS = Object.freeze({
|
||||||
@@ -36,7 +38,11 @@ export let schema = new Schema({
|
|||||||
url: {
|
url: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
validate: [validator.isURL, shared.i18n.t('invalidUrl')],
|
validate: [(v) => {
|
||||||
|
return validator.isURL(v, {
|
||||||
|
require_tld: IS_PRODUCTION ? true : false, // eslint-disable-line camelcase
|
||||||
|
});
|
||||||
|
}, shared.i18n.t('invalidUrl')],
|
||||||
},
|
},
|
||||||
enabled: { type: Boolean, required: true, default: true },
|
enabled: { type: Boolean, required: true, default: true },
|
||||||
options: {
|
options: {
|
||||||
@@ -72,7 +78,7 @@ schema.methods.formatOptions = function formatOptions (res) {
|
|||||||
} else if (this.type === 'groupChatReceived') {
|
} else if (this.type === 'groupChatReceived') {
|
||||||
this.options = _.pick(this.options, 'groupId');
|
this.options = _.pick(this.options, 'groupId');
|
||||||
|
|
||||||
if (!validator.isUUID(this.options.groupId)) {
|
if (!validator.isUUID(String(this.options.groupId))) {
|
||||||
throw new BadRequest(res.t('groupIdRequired'));
|
throw new BadRequest(res.t('groupIdRequired'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user