Compare commits

..

1 Commits

Author SHA1 Message Date
Keith Holliday
f72b503abd 4.41.6 2018-05-06 22:12:39 -05:00
1346 changed files with 36964 additions and 51961 deletions

View File

@@ -1,7 +1,7 @@
[//]: # (Note: See http://habitica.wikia.com/wiki/Using_Your_Local_Install_to_Modify_Habitica%27s_Website_and_API for more info)
[//]: # (Put Issue # here, if applicable. This will automatically close the issue if your PR is merged in)
Fixes put_#_and_issue_numer_here
[//]: # (Put Issue # or URL here, if applicable. This will automatically close the issue if your PR is merged in)
Fixes put_issue_url_here
### Changes
[//]: # (Describe the changes that were made in detail here. Include pictures if necessary)

1
.gitignore vendored
View File

@@ -39,7 +39,6 @@ dist-client
test/client/unit/coverage
test/client/e2e/reports
test/client-old/spec/mocks/translations.js
yarn.lock
# Elastic Beanstalk Files
.elasticbeanstalk/*

View File

@@ -20,9 +20,8 @@ env:
- DISABLE_REQUEST_LOGGING=true
matrix:
- TEST="lint"
- TEST="test:api:unit" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:api-v3:unit" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:api-v3:integration" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:api-v4:integration" REQUIRES_SERVER=true COVERAGE=true
- TEST="test:sanity"
- TEST="test:content" COVERAGE=true
- TEST="test:common" COVERAGE=true

View File

@@ -1,29 +1,18 @@
FROM node:8
ENV ADMIN_EMAIL admin@habitica.com
ENV AMAZON_PAYMENTS_CLIENT_ID amzn1.application-oa2-client.68ed9e6904ef438fbc1bf86bf494056e
ENV AMAZON_PAYMENTS_SELLER_ID AMQ3SB4SG5E91
ENV AMPLITUDE_KEY e8d4c24b3d6ef3ee73eeba715023dd43
ENV BASE_URL https://habitica.com
ENV FACEBOOK_KEY 128307497299777
ENV GA_ID UA-33510635-1
ENV GOOGLE_CLIENT_ID 1035232791481-32vtplgnjnd1aufv3mcu1lthf31795fq.apps.googleusercontent.com
ENV NODE_ENV production
ENV STRIPE_PUB_KEY pk_85fQ0yMECHNfHTSsZoxZXlPSwSNfA
# Install global packages
RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg
RUN git clone --branch release https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN npm install
RUN gulp build:prod --force
# Create Build dir
RUN mkdir -p ./website/build
# Start Habitica
EXPOSE 3000
CMD ["node", "./website/transpiled-babel/index.js"]
FROM node:8
# Install global packages
RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg
RUN git clone https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN cp config.json.example config.json
RUN npm install
# Create Build dir
RUN mkdir -p ./website/build
# Start Habitica
EXPOSE 3000
CMD ["npm", "start"]

View File

@@ -1,18 +0,0 @@
FROM node:8
# Install global packages
RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg
RUN git clone https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN cp config.json.example config.json
RUN npm install
# Create Build dir
RUN mkdir -p ./website/build
# Start Habitica
EXPOSE 3000
CMD ["npm", "start"]

29
Dockerfile-Production Normal file
View File

@@ -0,0 +1,29 @@
FROM node:8
ENV ADMIN_EMAIL admin@habitica.com
ENV AMAZON_PAYMENTS_CLIENT_ID amzn1.application-oa2-client.68ed9e6904ef438fbc1bf86bf494056e
ENV AMAZON_PAYMENTS_SELLER_ID AMQ3SB4SG5E91
ENV AMPLITUDE_KEY e8d4c24b3d6ef3ee73eeba715023dd43
ENV BASE_URL https://habitica.com
ENV FACEBOOK_KEY 128307497299777
ENV GA_ID UA-33510635-1
ENV GOOGLE_CLIENT_ID 1035232791481-32vtplgnjnd1aufv3mcu1lthf31795fq.apps.googleusercontent.com
ENV NODE_ENV production
ENV STRIPE_PUB_KEY pk_85fQ0yMECHNfHTSsZoxZXlPSwSNfA
# Install global packages
RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg
RUN git clone --branch v4.41.0 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN npm install
RUN gulp build:prod --force
# Create Build dir
RUN mkdir -p ./website/build
# Start Habitica
EXPOSE 3000
CMD ["node", "./website/transpiled-babel/index.js"]

View File

@@ -78,9 +78,6 @@
"PUSH_CONFIGS": {
"GCM_SERVER_API_KEY": "",
"APN_ENABLED": "false",
"APN_KEY_ID": "xxxxxxxxxx",
"APN_KEY": "xxxxxxxxxx",
"APN_TEAM_ID": "aaabbbcccd",
"FCM_SERVER_API_KEY": ""
},
"SITE_HTTP_AUTH": {
@@ -115,6 +112,5 @@
"CLOUDKARAFKA_USERNAME": "",
"CLOUDKARAFKA_PASSWORD": "",
"CLOUDKARAFKA_TOPIC_PREFIX": ""
},
"MIGRATION_CONNECT_STRING": "mongodb://localhost:27017/habitrpg?auto_reconnect=true"
}
}

View File

@@ -1,100 +0,0 @@
import max from 'lodash/max';
import mean from 'lodash/mean';
import monk from 'monk';
import round from 'lodash/round';
import sum from 'lodash/sum';
/*
* Output data on subscribers' task histories, formatted for CSV.
* User ID,Count of Dailies,Count of Habits,Total History Size,Max History Size,Mean History Size,Median History Size
*/
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
let dbUsers = monk(connectionString).get('users', { castIds: false });
let dbTasks = monk(connectionString).get('tasks', { castIds: false });
function usersReport () {
let allHistoryLengths = [];
console.info('User ID,Count of Dailies,Count of Habits,Total History Size,Max History Size,Mean History Size,Median History Size');
dbUsers.find(
{
$and:
[
{'purchased.plan.planId': {$ne:null}},
{'purchased.plan.planId': {$ne:''}},
],
$or:
[
{'purchased.plan.dateTerminated': null},
{'purchased.plan.dateTerminated': ''},
{'purchased.plan.dateTerminated': {$gt:new Date()}},
],
},
{
fields: {_id: 1},
}
).each((user, {close, pause, resume}) => {
let historyLengths = [];
let habitCount = 0;
let dailyCount = 0;
pause();
return dbTasks.find(
{
userId: user._id,
$or:
[
{type: 'habit'},
{type: 'daily'},
],
},
{
fields: {
type: 1,
history: 1,
},
}
).each((task) => {
if (task.type === 'habit') {
habitCount++;
}
if (task.type === 'daily') {
dailyCount++;
}
if (task.history.length > 0) {
allHistoryLengths.push(task.history.length);
historyLengths.push(task.history.length);
}
}).then(() => {
const totalHistory = sum(historyLengths);
const maxHistory = historyLengths.length > 0 ? max(historyLengths) : 0;
const meanHistory = historyLengths.length > 0 ? round(mean(historyLengths)) : 0;
const medianHistory = historyLengths.length > 0 ? median(historyLengths) : 0;
console.info(`${user._id},${dailyCount},${habitCount},${totalHistory},${maxHistory},${meanHistory},${medianHistory}`);
resume();
});
}).then(() => {
console.info(`Total Subscriber History Entries: ${sum(allHistoryLengths)}`);
console.info(`Largest History Size: ${max(allHistoryLengths)}`);
console.info(`Mean History Size: ${round(mean(allHistoryLengths))}`);
console.info(`Median History Size: ${median(allHistoryLengths)}`);
return process.exit(0);
});
}
function median(values) { // https://gist.github.com/caseyjustus/1166258
values.sort( function(a,b) {return a - b;} );
var half = Math.floor(values.length/2);
if (values.length % 2) {
return values[half];
}
else {
return (values[half-1] + values[half]) / 2.0;
}
}
module.exports = usersReport;

View File

@@ -165,9 +165,9 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
pipe(runner);
}));
gulp.task('test:api:unit', (done) => {
gulp.task('test:api-v3:unit', (done) => {
let runner = exec(
testBin('node_modules/.bin/istanbul cover --dir coverage/api-unit node_modules/mocha/bin/_mocha -- test/api/unit --recursive --require ./test/helpers/start-server'),
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-unit --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/unit --recursive --require ./test/helpers/start-server'),
(err) => {
if (err) {
process.exit(1);
@@ -179,8 +179,8 @@ gulp.task('test:api:unit', (done) => {
pipe(runner);
});
gulp.task('test:api:unit:watch', () => {
return gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit', done => done()));
gulp.task('test:api-v3:unit:watch', () => {
return gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api-v3:unit', done => done()));
});
gulp.task('test:api-v3:integration', (done) => {
@@ -215,43 +215,17 @@ gulp.task('test:api-v3:integration:separate-server', (done) => {
pipe(runner);
});
gulp.task('test:api-v4:integration', (done) => {
let runner = exec(
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v4-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v4 --recursive --require ./test/helpers/start-server'),
{maxBuffer: 500 * 1024},
(err) => {
if (err) {
process.exit(1);
}
done();
}
);
pipe(runner);
});
gulp.task('test:api-v4:integration:separate-server', (done) => {
let runner = exec(
testBin('mocha test/api/v4 --recursive --require ./test/helpers/start-server', 'LOAD_SERVER=0'),
{maxBuffer: 500 * 1024},
(err) => done(err)
);
pipe(runner);
});
gulp.task('test', gulp.series(
'test:sanity',
'test:content',
'test:common',
'test:api:unit',
'test:api-v3:unit',
'test:api-v3:integration',
'test:api-v4:integration',
done => done()
));
gulp.task('test:api-v3', gulp.series(
'test:api:unit',
'test:api-v3:unit',
'test:api-v3:integration',
done => done()
));
));

View File

@@ -1,107 +0,0 @@
import monk from 'monk';
import nconf from 'nconf';
import stripePayments from '../../website/server/libs/payments/stripe';
/*
* Ensure that group plan billing is accurate by doing the following:
* 1. Correct the memberCount in all paid groups whose counts are wrong
* 2. Where the above uses Stripe, update their subscription counts in Stripe
*
* Provides output on what groups were fixed, which can be piped to CSV.
*/
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
let dbGroups = monk(CONNECTION_STRING).get('groups', { castIds: false });
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
async function fixGroupPlanMembers () {
console.info('Group ID, Customer ID, Plan ID, Quantity, Recorded Member Count, Actual Member Count');
let groupPlanCount = 0;
let fixedGroupCount = 0;
dbGroups.find(
{
$and:
[
{'purchased.plan.planId': {$ne: null}},
{'purchased.plan.planId': {$ne: ''}},
{'purchased.plan.customerId': {$ne: 'cus_9f0DV4g7WHRzpM'}}, // Demo groups
{'purchased.plan.customerId': {$ne: 'cus_9maalqDOFTrvqx'}},
],
$or:
[
{'purchased.plan.dateTerminated': null},
{'purchased.plan.dateTerminated': ''},
],
},
{
fields: {
memberCount: 1,
'purchased.plan': 1,
},
}
).each(async (group, {close, pause, resume}) => { // eslint-disable-line no-unused-vars
pause();
groupPlanCount++;
const canonicalMemberCount = await dbUsers.count(
{
$or:
[
{'party._id': group._id},
{guilds: group._id},
],
}
);
const incorrectMemberCount = group.memberCount !== canonicalMemberCount;
const isMonthlyPlan = group.purchased.plan.planId === 'group_monthly';
const quantityMismatch = group.purchased.plan.quantity !== group.memberCount + 2;
const incorrectQuantity = isMonthlyPlan && quantityMismatch;
if (!incorrectMemberCount && !incorrectQuantity) {
resume();
return;
}
console.info(`${group._id}, ${group.purchased.plan.customerId}, ${group.purchased.plan.planId}, ${group.purchased.plan.quantity}, ${group.memberCount}, ${canonicalMemberCount}`);
const groupUpdate = await dbGroups.update(
{ _id: group._id },
{
$set: {
memberCount: canonicalMemberCount,
},
}
);
if (!groupUpdate) return;
fixedGroupCount++;
if (group.purchased.plan.paymentMethod === 'Stripe') {
await stripePayments.chargeForAdditionalGroupMember(group);
await dbGroups.update(
{_id: group._id},
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
);
}
if (incorrectQuantity) {
await dbGroups.update(
{_id: group._id},
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
);
}
resume();
}).then(() => {
console.info(`Fixed ${fixedGroupCount} out of ${groupPlanCount} active Group Plans`);
return process.exit(0);
}).catch((err) => {
console.log(err);
return process.exit(1);
});
}
module.exports = fixGroupPlanMembers;

View File

@@ -17,5 +17,5 @@ function setUpServer () {
setUpServer();
// Replace this with your migration
const processUsers = require('./users/takeThis.js');
const processUsers = require('./groups/migrate-chat.js');
processUsers();

View File

@@ -1,4 +1,4 @@
let migrationName = '20180801_takeThis.js'; // Update per month
let migrationName = '20180102_takeThis.js'; // Update per month
let authorName = 'Sabe'; // in case script author needs to know when their ...
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
@@ -6,16 +6,15 @@ let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
* Award Take This ladder items to participants in this month's challenge
*/
import monk from 'monk';
import nconf from 'nconf';
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING'); // FOR TEST DATABASE
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
let monk = require('monk');
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
let dbUsers = monk(connectionString).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
challenges: {$in: ['081f8912-3526-47d5-984f-f71bbeec77fc']}, // Update per month
challenges: {$in: ['5f70ce5b-2d82-4114-8e44-ca65615aae62']}, // Update per month
};
if (lastId) {

View File

@@ -1,138 +0,0 @@
// const migrationName = 'habits-one-history-entry-per-day';
// const authorName = 'paglias'; // in case script author needs to know when their ...
// const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
/*
* Iterates over all habits and condense multiple history entries for the same day into a single entry
*/
const monk = require('monk');
const _ = require('lodash');
const moment = require('moment');
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
const dbTasks = monk(connectionString).get('tasks', { castIds: false });
function processChallengeHabits (lastId) {
let query = {
'challenge.id': {$exists: true},
userId: {$exists: false},
type: 'habit',
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbTasks.find(query, {
sort: {_id: 1},
limit: 500,
})
.then(updateChallengeHabits)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateChallengeHabits (habits) {
if (!habits || habits.length === 0) {
console.warn('All appropriate challenge habits found and modified.');
displayData();
return;
}
let habitsPromises = habits.map(updateChallengeHabit);
let lastHabit = habits[habits.length - 1];
return Promise.all(habitsPromises)
.then(() => {
return processChallengeHabits(lastHabit._id);
});
}
function updateChallengeHabit (habit) {
count++;
if (habit && habit.history && habit.history.length > 0) {
// First remove missing entries
habit.history = habit.history.filter(entry => Boolean(entry));
habit.history = _.chain(habit.history)
// processes all entries to identify an up or down score
.forEach((entry, index) => {
if (index === 0) { // first entry doesn't have a previous one
// first value < 0 identifies a negative score as the first action
entry.scoreDirection = entry.value >= 0 ? 'up' : 'down';
} else {
// could be missing if the previous entry was null and thus excluded
const previousEntry = habit.history[index - 1];
const previousValue = previousEntry.value;
entry.scoreDirection = entry.value > previousValue ? 'up' : 'down';
}
})
.groupBy(entry => { // group entries by aggregateBy
return moment(entry.date).format('YYYYMMDD');
})
.toPairs() // [key, entry]
.sortBy(([key]) => key) // sort by date
.map(keyEntryPair => {
let entries = keyEntryPair[1]; // 1 is entry, 0 is key
let scoredUp = 0;
let scoredDown = 0;
entries.forEach(entry => {
if (entry.scoreDirection === 'up') {
scoredUp += 1;
} else {
scoredDown += 1;
}
// delete the unnecessary scoreDirection and scoreNotes prop
delete entry.scoreDirection;
delete entry.scoreNotes;
});
return {
date: Number(entries[entries.length - 1].date), // keep last value
value: entries[entries.length - 1].value, // keep last value,
scoredUp,
scoredDown,
};
})
.value();
return dbTasks.update({_id: habit._id}, {
$set: {history: habit.history},
});
}
if (count % progressCount === 0) console.warn(`${count } habits processed`);
}
function displayData () {
console.warn(`\n${ count } tasks processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processChallengeHabits;

View File

@@ -1,163 +0,0 @@
const migrationName = 'habits-one-history-entry-per-day';
const authorName = 'paglias'; // in case script author needs to know when their ...
const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
/*
* Iterates over all habits and condense multiple history entries for the same day into a single entry
*/
const monk = require('monk');
const _ = require('lodash');
const moment = require('moment');
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
const dbTasks = monk(connectionString).get('tasks', { castIds: false });
const dbUsers = monk(connectionString).get('users', { castIds: false });
function processUsers (lastId) {
let query = {
migration: {$ne: migrationName},
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 50, // just 50 users per time since we have to process all their habits as well
fields: ['_id', 'preferences.timezoneOffset', 'preferences.dayStart'],
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users and their tasks found and modified.');
displayData();
return;
}
let usersPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(usersPromises)
.then(() => {
return processUsers(lastUser._id);
});
}
function updateHabit (habit, timezoneOffset, dayStart) {
if (habit && habit.history && habit.history.length > 0) {
// First remove missing entries
habit.history = habit.history.filter(entry => Boolean(entry));
habit.history = _.chain(habit.history)
// processes all entries to identify an up or down score
.forEach((entry, index) => {
if (index === 0) { // first entry doesn't have a previous one
// first value < 0 identifies a negative score as the first action
entry.scoreDirection = entry.value >= 0 ? 'up' : 'down';
} else {
// could be missing if the previous entry was null and thus excluded
const previousEntry = habit.history[index - 1];
const previousValue = previousEntry.value;
entry.scoreDirection = entry.value > previousValue ? 'up' : 'down';
}
})
.groupBy(entry => { // group entries by aggregateBy
const entryDate = moment(entry.date).zone(timezoneOffset || 0);
if (entryDate.hour() < dayStart) entryDate.subtract(1, 'day');
return entryDate.format('YYYYMMDD');
})
.toPairs() // [key, entry]
.sortBy(([key]) => key) // sort by date
.map(keyEntryPair => {
let entries = keyEntryPair[1]; // 1 is entry, 0 is key
let scoredUp = 0;
let scoredDown = 0;
entries.forEach(entry => {
if (entry.scoreDirection === 'up') {
scoredUp += 1;
} else {
scoredDown += 1;
}
// delete the unnecessary scoreDirection and scoreNotes prop
delete entry.scoreDirection;
delete entry.scoreNotes;
});
return {
date: Number(entries[entries.length - 1].date), // keep last value
value: entries[entries.length - 1].value, // keep last value,
scoredUp,
scoredDown,
};
})
.value();
return dbTasks.update({_id: habit._id}, {
$set: {history: habit.history},
});
}
}
function updateUser (user) {
count++;
const timezoneOffset = user.preferences.timezoneOffset;
const dayStart = user.preferences.dayStart;
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } being processed`);
return dbTasks.find({
type: 'habit',
userId: user._id,
})
.then(habits => {
return Promise.all(habits.map(habit => updateHabit(habit, timezoneOffset, dayStart)));
})
.then(() => {
return dbUsers.update({_id: user._id}, {
$set: {migration: migrationName},
});
})
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
function displayData () {
console.warn(`\n${ count } tasks processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processUsers;

View File

@@ -7,7 +7,7 @@ let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
*/
let monk = require('monk');
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true';
let connectionString = 'mongodb://sabrecat:z8e8jyRA8CTofMQ@ds013393-a0.mlab.com:13393/habitica?auto_reconnect=true';
let dbTasks = monk(connectionString).get('tasks', { castIds: false });
function processTasks (lastId) {

View File

@@ -1,17 +1,15 @@
import monk from 'monk';
import nconf from 'nconf';
const migrationName = 'mystery-items-201807.js'; // Update per month
const migrationName = 'mystery-items-201802.js'; // Update per month
const authorName = 'Sabe'; // in case script author needs to know when their ...
const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
/*
* Award this month's mystery items to subscribers
*/
const MYSTERY_ITEMS = ['armor_mystery_201807', 'head_mystery_201807'];
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
const MYSTERY_ITEMS = ['back_mystery_201804', 'headAccessory_mystery_201804'];
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
let monk = require('monk');
let dbUsers = monk(connectionString).get('users', { castIds: false });
let UserNotification = require('../../website/server/models/userNotification').model;
function processUsers (lastId) {

View File

@@ -1,123 +0,0 @@
let migrationName = '20180731_naming-day.js'; // Update when running in future years
let authorName = 'Sabe'; // in case script author needs to know when their ...
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
/*
* Award Naming Day ladder items to participants in this month's Naming Day festivities
*/
import monk from 'monk';
import nconf from 'nconf';
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING'); // FOR TEST DATABASE
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 250,
fields: [
'items.gear.owned',
'items.mounts',
'items.pets',
], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users found and modified.');
displayData();
return;
}
let userPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(userPromises)
.then(() => {
processUsers(lastUser._id);
});
}
function updateUser (user) {
count++;
let set = {};
let push;
const inc = {
'items.food.Cake_Base': 1,
'items.food.Cake_CottonCandyBlue': 1,
'items.food.Cake_CottonCandyPink': 1,
'items.food.Cake_Desert': 1,
'items.food.Cake_Golden': 1,
'items.food.Cake_Red': 1,
'items.food.Cake_Shade': 1,
'items.food.Cake_Skeleton': 1,
'items.food.Cake_White': 1,
'items.food.Cake_Zombie': 1,
'achievements.habiticaDays': 1,
};
if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.head_special_namingDay2017 !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.body_special_namingDay2018': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.body_special_namingDay2018', _id: monk.id()}};
} else if (user && user.items && user.items.pets && typeof user.items.pets['Gryphon-RoyalPurple'] !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.head_special_namingDay2017': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.head_special_namingDay2017', _id: monk.id()}};
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Gryphon-RoyalPurple'] !== 'undefined') {
set = {migration: migrationName, 'items.pets.Gryphon-RoyalPurple': 5};
} else {
set = {migration: migrationName, 'items.mounts.Gryphon-RoyalPurple': true};
}
if (push) {
dbUsers.update({_id: user._id}, {$set: set, $push: push, $inc: inc});
} else {
dbUsers.update({_id: user._id}, {$set: set, $inc: inc});
}
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } processed`);
}
function displayData () {
console.warn(`\n${ count } users processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processUsers;

View File

@@ -1,109 +0,0 @@
const migrationName = 'remove-social-users-extra-data.js';
const authorName = 'paglias'; // in case script author needs to know when their ...
const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
/*
* Remove not needed data from social profiles
*/
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
const monk = require('monk');
const dbUsers = monk(connectionString).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
$or: [
{ 'auth.facebook.id': { $exists: true } },
{ 'auth.google.id': { $exists: true } },
],
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 250,
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users found and modified.');
displayData();
return;
}
let userPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(userPromises)
.then(() => {
processUsers(lastUser._id);
});
}
function updateUser (user) {
count++;
const isFacebook = user.auth.facebook && user.auth.facebook.id;
const isGoogle = user.auth.google && user.auth.google.id;
const update = { $set: {} };
if (isFacebook) {
update.$set['auth.facebook'] = {
id: user.auth.facebook.id,
emails: user.auth.facebook.emails,
};
}
if (isGoogle) {
update.$set['auth.google'] = {
id: user.auth.google.id,
emails: user.auth.google.emails,
};
}
dbUsers.update({
_id: user._id,
}, update);
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } processed`);
}
function displayData () {
console.warn(`\n${ count } users processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processUsers;

View File

@@ -1,99 +0,0 @@
let migrationName = '20180724_summer-splash-orcas.js'; // Update per month
let authorName = 'Sabe'; // in case script author needs to know when their ...
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
/*
* Award ladder items to participants in this year's Summer Splash festivities
*/
import monk from 'monk';
import nconf from 'nconf';
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
'auth.timestamps.loggedin': {$gt: new Date('2018-07-01')}, // rerun without date restriction after initial run
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 250,
fields: [
'items.mounts',
], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users found and modified.');
displayData();
return;
}
let userPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(userPromises)
.then(() => {
processUsers(lastUser._id);
});
}
function updateUser (user) {
count++;
let set = {};
if (user && user.items && user.items.pets && typeof user.items.pets['Orca-Base'] !== 'undefined') {
set = {migration: migrationName};
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Orca-Base'] !== 'undefined') {
set = {migration: migrationName, 'items.pets.Orca-Base': 5};
} else {
set = {migration: migrationName, 'items.mounts.Orca-Base': true};
}
dbUsers.update({_id: user._id}, {$set: set});
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } processed`);
}
function displayData () {
console.warn(`\n${ count } users processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processUsers;

11523
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,16 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.56.2",
"version": "4.41.6",
"main": "./website/server/index.js",
"dependencies": {
"@slack/client": "^3.8.1",
"accepts": "^1.3.5",
"amazon-payments": "^0.2.7",
"amazon-payments": "^0.2.6",
"amplitude": "^3.5.0",
"apidoc": "^0.17.5",
"autoprefixer": "^8.5.0",
"aws-sdk": "^2.239.1",
"apn": "^2.2.0",
"autoprefixer": "^8.4.1",
"aws-sdk": "^2.230.1",
"axios": "^0.18.0",
"axios-progress-bar": "^1.2.0",
"babel-core": "^6.26.3",
@@ -27,20 +26,20 @@
"babel-register": "^6.6.0",
"babel-runtime": "^6.11.6",
"bcrypt": "^2.0.0",
"body-parser": "^1.18.3",
"body-parser": "^1.15.0",
"bootstrap": "^4.1.1",
"bootstrap-vue": "^2.0.0-rc.9",
"compression": "^1.7.2",
"cookie-session": "^1.2.0",
"coupon-code": "^0.4.5",
"cross-env": "^5.1.5",
"cross-env": "^5.1.4",
"css-loader": "^0.28.11",
"csv-stringify": "^2.1.0",
"cwait": "^1.1.1",
"domain-middleware": "~0.1.0",
"express": "^4.16.3",
"express-basic-auth": "^1.1.5",
"express-validator": "^5.2.0",
"express-validator": "^5.1.2",
"extract-text-webpack-plugin": "^3.0.2",
"glob": "^7.1.2",
"got": "^8.3.1",
@@ -53,7 +52,7 @@
"hellojs": "^1.15.1",
"html-webpack-plugin": "^3.2.0",
"image-size": "^0.6.2",
"in-app-purchase": "^1.9.4",
"in-app-purchase": "^1.9.3",
"intro.js": "^2.9.3",
"jquery": ">=3.0.0",
"js2xmlparser": "^3.0.0",
@@ -62,7 +61,7 @@
"method-override": "^2.3.5",
"moment": "^2.22.1",
"moment-recur": "^1.0.7",
"mongoose": "^5.1.2",
"mongoose": "^5.0.17",
"morgan": "^1.7.0",
"nconf": "^0.10.0",
"node-gcm": "^0.14.4",
@@ -79,19 +78,18 @@
"postcss-easy-import": "^3.0.0",
"ps-tree": "^1.0.0",
"pug": "^2.0.3",
"push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
"pusher": "^1.3.0",
"rimraf": "^2.4.3",
"sass-loader": "^7.0.0",
"shelljs": "^0.8.2",
"stripe": "^5.9.0",
"shelljs": "^0.8.1",
"stripe": "^5.8.0",
"superagent": "^3.8.3",
"svg-inline-loader": "^0.8.0",
"svg-url-loader": "^2.3.2",
"svgo": "^1.0.5",
"svgo-loader": "^2.1.0",
"universal-analytics": "^0.4.16",
"update": "^0.7.4",
"upgrade": "^1.1.0",
"url-loader": "^1.0.0",
"useragent": "^2.1.9",
"uuid": "^3.0.1",
@@ -105,7 +103,7 @@
"vue-template-compiler": "^2.5.16",
"vuedraggable": "^2.15.0",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
"webpack": "^3.12.0",
"webpack": "^3.11.0",
"webpack-merge": "^4.0.0",
"winston": "^2.4.2",
"winston-loggly-bulk": "^2.0.2",
@@ -121,11 +119,9 @@
"test": "npm run lint && gulp test && gulp apidoc",
"test:build": "gulp test:prepare:build",
"test:api-v3": "gulp test:api-v3",
"test:api:unit": "gulp test:api:unit",
"test:api-v3:unit": "gulp test:api-v3:unit",
"test:api-v3:integration": "gulp test:api-v3:integration",
"test:api-v3:integration:separate-server": "NODE_ENV=test gulp test:api-v3:integration:separate-server",
"test:api-v4:integration": "gulp test:api-v4:integration",
"test:api-v4:integration:separate-server": "NODE_ENV=test gulp test:api-v4:integration:separate-server",
"test:sanity": "istanbul cover --dir coverage/sanity --report lcovonly node_modules/mocha/bin/_mocha -- test/sanity --recursive",
"test:common": "istanbul cover --dir coverage/common --report lcovonly node_modules/mocha/bin/_mocha -- test/common --recursive",
"test:content": "istanbul cover --dir coverage/content --report lcovonly node_modules/mocha/bin/_mocha -- test/content --recursive",
@@ -143,15 +139,15 @@
"apidoc": "gulp apidoc"
},
"devDependencies": {
"@vue/test-utils": "^1.0.0-beta.16",
"@vue/test-utils": "^1.0.0-beta.15",
"babel-plugin-istanbul": "^4.1.6",
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chalk": "^2.4.1",
"chromedriver": "^2.38.3",
"chromedriver": "^2.38.2",
"connect-history-api-fallback": "^1.1.0",
"coveralls": "^3.0.1",
"coveralls": "^3.0.0",
"cross-spawn": "^6.0.5",
"eslint": "^4.19.1",
"eslint-config-habitrpg": "^4.0.0",
@@ -167,7 +163,7 @@
"karma-babel-preprocessor": "^7.0.0",
"karma-chai-plugins": "^0.9.0",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage": "^1.1.2",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-sinon-chai": "^1.3.4",
@@ -177,17 +173,17 @@
"karma-webpack": "^3.0.0",
"lcov-result-merger": "^2.0.0",
"mocha": "^5.1.1",
"monk": "^6.0.6",
"monk": "^6.0.5",
"nightwatch": "^0.9.21",
"puppeteer": "^1.4.0",
"puppeteer": "^1.3.0",
"require-again": "^2.0.0",
"selenium-server": "^3.12.0",
"selenium-server": "^3.11.0",
"sinon": "^4.5.0",
"sinon-chai": "^3.0.0",
"sinon-stub-promise": "^4.0.0",
"webpack-bundle-analyzer": "^2.12.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-dev-middleware": "^2.0.5",
"webpack-hot-middleware": "^2.22.2"
"webpack-hot-middleware": "^2.22.1"
},
"optionalDependencies": {
"memwatch-next": "^0.3.0",

View File

@@ -5,7 +5,7 @@ import {
sleep,
checkExistence,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('DELETE /challenges/:challengeId', () => {
@@ -41,7 +41,6 @@ describe('DELETE /challenges/:challengeId', () => {
group = populatedGroup.group;
challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [
{type: 'habit', text: taskText},

View File

@@ -3,7 +3,7 @@ import {
createAndPopulateGroup,
generateChallenge,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId', () => {
@@ -33,11 +33,9 @@ describe('GET /challenges/:challengeId', () => {
group = populatedGroup.group;
challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
});
it('should return challenge data', async () => {
await challenge.sync();
let chal = await user.get(`/challenges/${challenge._id}`);
expect(chal.memberCount).to.equal(challenge.memberCount);
expect(chal.name).to.equal(challenge.name);
@@ -82,7 +80,6 @@ describe('GET /challenges/:challengeId', () => {
challenge = await generateChallenge(groupLeader, group);
await members[0].post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/challenges/${challenge._id}/join`);
});
it('fails if user doesn\'t have access to the challenge', async () => {
@@ -137,7 +134,6 @@ describe('GET /challenges/:challengeId', () => {
challenge = await generateChallenge(groupLeader, group);
await members[0].post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/challenges/${challenge._id}/join`);
});
it('fails if user doesn\'t have access to the challenge', async () => {

View File

@@ -4,7 +4,7 @@ import {
generateChallenge,
translate as t,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId/export/csv', () => {
@@ -24,7 +24,6 @@ describe('GET /challenges/:challengeId/export/csv', () => {
members = populatedGroup.members;
challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
await members[0].post(`/challenges/${challenge._id}/join`);
await members[1].post(`/challenges/${challenge._id}/join`);
await members[2].post(`/challenges/${challenge._id}/join`);

View File

@@ -3,7 +3,7 @@ import {
generateGroup,
generateChallenge,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId/members', () => {
@@ -45,7 +45,6 @@ describe('GET /challenges/:challengeId/members', () => {
let leader = await generateUser({balance: 4});
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});
let challenge = await generateChallenge(leader, group);
await leader.post(`/challenges/${challenge._id}/join`);
let res = await user.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({
_id: leader._id,
@@ -60,7 +59,6 @@ describe('GET /challenges/:challengeId/members', () => {
let anotherUser = await generateUser({balance: 3});
let group = await generateGroup(anotherUser, {type: 'guild', privacy: 'public', name: generateUUID()});
let challenge = await generateChallenge(anotherUser, group);
await anotherUser.post(`/challenges/${challenge._id}/join`);
let res = await user.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({
_id: anotherUser._id,
@@ -74,7 +72,6 @@ describe('GET /challenges/:challengeId/members', () => {
it('returns only first 30 members if req.query.includeAllMembers is not true', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = [];
for (let i = 0; i < 31; i++) {
@@ -93,7 +90,6 @@ describe('GET /challenges/:challengeId/members', () => {
it('returns only first 30 members if req.query.includeAllMembers is not defined', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = [];
for (let i = 0; i < 31; i++) {
@@ -112,7 +108,6 @@ describe('GET /challenges/:challengeId/members', () => {
it('returns all members if req.query.includeAllMembers is true', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = [];
for (let i = 0; i < 31; i++) {
@@ -128,11 +123,9 @@ describe('GET /challenges/:challengeId/members', () => {
});
});
it('supports using req.query.lastId to get more members', async function () {
this.timeout(30000); // @TODO: times out after 8 seconds
it('supports using req.query.lastId to get more members', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = [];
for (let i = 0; i < 57; i++) {
@@ -153,7 +146,6 @@ describe('GET /challenges/:challengeId/members', () => {
it('supports using req.query.search to get search members', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let usersToGenerate = [];
for (let i = 0; i < 3; i++) {

View File

@@ -3,7 +3,7 @@ import {
generateChallenge,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /challenges/:challengeId/members/:memberId', () => {
@@ -50,7 +50,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('fails if user doesn\'t have access to the challenge', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let anotherUser = await generateUser();
let member = await generateUser();
await expect(anotherUser.get(`/challenges/${challenge._id}/members/${member._id}`)).to.eventually.be.rejected.and.eql({
@@ -63,7 +62,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('fails if member is not part of the challenge', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let member = await generateUser();
await expect(user.get(`/challenges/${challenge._id}/members/${member._id}`)).to.eventually.be.rejected.and.eql({
code: 404,
@@ -76,7 +74,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
let groupLeader = await generateUser({balance: 4});
let group = await generateGroup(groupLeader, {type: 'guild', privacy: 'public', name: generateUUID()});
let challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
let taskText = 'Test Text';
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: taskText}]);
@@ -89,7 +86,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('returns the member tasks for the challenges', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
await user.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: 'Test Text'}]);
let memberProgress = await user.get(`/challenges/${challenge._id}/members/${user._id}`);
@@ -102,7 +98,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
it('returns the tasks without the tags and checklist', async () => {
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
let taskText = 'Test Text';
await user.post(`/tasks/challenge/${challenge._id}`, [{
type: 'todo',

View File

@@ -3,7 +3,7 @@ import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { TAVERN_ID } from '../../../../../website/common/script/constants';
describe('GET challenges/groups/:groupId', () => {
@@ -25,9 +25,7 @@ describe('GET challenges/groups/:groupId', () => {
nonMember = await generateUser();
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should return group challenges for non member with populated leader', async () => {
@@ -75,7 +73,6 @@ describe('GET challenges/groups/:groupId', () => {
expect(foundChallengeIndex).to.eql(0);
let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
@@ -102,9 +99,7 @@ describe('GET challenges/groups/:groupId', () => {
nonMember = await generateUser();
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should prevent non-member from seeing challenges', async () => {
@@ -161,12 +156,9 @@ describe('GET challenges/groups/:groupId', () => {
slug: 'habitica_official',
}],
});
await user.post(`/challenges/${officialChallenge._id}/join`);
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should return official challenges first', async () => {
@@ -186,7 +178,6 @@ describe('GET challenges/groups/:groupId', () => {
expect(foundChallengeIndex).to.eql(1);
let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
@@ -212,9 +203,7 @@ describe('GET challenges/groups/:groupId', () => {
nonMember = await generateUser();
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should prevent non-member from seeing challenges', async () => {
@@ -274,9 +263,7 @@ describe('GET challenges/groups/:groupId', () => {
tavern = await user.get(`/groups/${TAVERN_ID}`);
challenge = await generateChallenge(user, tavern, {prize: 1});
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, tavern, {prize: 1});
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should return tavern challenges with populated leader', async () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser,
generateChallenge,
createAndPopulateGroup,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET challenges/user', () => {
context('no official challenges', () => {
@@ -24,9 +24,7 @@ describe('GET challenges/user', () => {
nonMember = await generateUser();
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should return challenges user has joined', async () => {
@@ -148,7 +146,6 @@ describe('GET challenges/user', () => {
expect(foundChallengeIndex).to.eql(0);
let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user');
@@ -167,7 +164,6 @@ describe('GET challenges/user', () => {
});
let privateChallenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${privateChallenge._id}/join`);
let challenges = await nonMember.get('/challenges/user');
@@ -202,12 +198,9 @@ describe('GET challenges/user', () => {
slug: 'habitica_official',
}],
});
await user.post(`/challenges/${officialChallenge._id}/join`);
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should return official challenges first', async () => {
@@ -227,7 +220,6 @@ describe('GET challenges/user', () => {
expect(foundChallengeIndex).to.eql(1);
let newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user');
@@ -260,14 +252,12 @@ describe('GET challenges/user', () => {
await user.update({balance: 20});
for (let i = 0; i < 11; i += 1) {
let challenge = await generateChallenge(user, group); // eslint-disable-line
await user.post(`/challenges/${challenge._id}/join`); // eslint-disable-line
await generateChallenge(user, group); // eslint-disable-line
}
});
it('returns public guilds filtered by category', async () => {
const categoryChallenge = await generateChallenge(user, guild, {categories});
await user.post(`/challenges/${categoryChallenge._id}/join`);
const challenges = await user.get(`/challenges/user?categories=${categories[0].slug}`);
expect(challenges[0]._id).to.eql(categoryChallenge._id);

View File

@@ -2,7 +2,7 @@ import {
generateUser,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /challenges', () => {
@@ -242,6 +242,7 @@ describe('POST /challenges', () => {
it('returns an error when challenge validation fails; doesn\'s save user or group', async () => {
let oldChallengeCount = group.challengeCount;
let oldUserBalance = groupLeader.balance;
let oldUserChallenges = groupLeader.challenges;
let oldGroupBalance = group.balance;
await expect(groupLeader.post('/challenges', {
@@ -259,6 +260,7 @@ describe('POST /challenges', () => {
expect(group.challengeCount).to.eql(oldChallengeCount);
expect(group.balance).to.eql(oldGroupBalance);
expect(groupLeader.balance).to.eql(oldUserBalance);
expect(groupLeader.challenges).to.eql(oldUserChallenges);
});
it('sets all properites of the challenge as passed', async () => {
@@ -289,29 +291,28 @@ describe('POST /challenges', () => {
name: group.name,
type: group.type,
});
expect(challenge.memberCount).to.eql(0);
expect(challenge.memberCount).to.eql(1);
expect(challenge.prize).to.eql(prize);
});
it('does not add challenge to creator\'s challenges', async () => {
await groupLeader.post('/challenges', {
it('adds challenge to creator\'s challenges', async () => {
let challenge = await groupLeader.post('/challenges', {
group: group._id,
name: 'Test Challenge',
shortName: 'TC Label',
});
await groupLeader.sync();
expect(groupLeader.challenges.length).to.equal(0);
await expect(groupLeader.sync()).to.eventually.have.property('challenges').to.include(challenge._id);
});
it('does not award joinedChallenge achievement for creating a challenge', async () => {
it('awards achievement if this is creator\'s first challenge', async () => {
await groupLeader.post('/challenges', {
group: group._id,
name: 'Test Challenge',
shortName: 'TC Label',
});
groupLeader = await groupLeader.sync();
expect(groupLeader.achievements.joinedChallenge).to.not.be.true;
expect(groupLeader.achievements.joinedChallenge).to.be.true;
});
it('sets summary to challenges name when not supplied', async () => {

View File

@@ -3,7 +3,7 @@ import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /challenges/:challengeId/join', () => {
@@ -43,7 +43,6 @@ describe('POST /challenges/:challengeId/join', () => {
authorizedUser = populatedGroup.members[0];
challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
});
it('returns an error when user doesn\'t have permissions to access the challenge', async () => {
@@ -92,7 +91,6 @@ describe('POST /challenges/:challengeId/join', () => {
});
it('increases memberCount of challenge', async () => {
await challenge.sync();
let oldMemberCount = challenge.memberCount;
await authorizedUser.post(`/challenges/${challenge._id}/join`);

View File

@@ -3,7 +3,7 @@ import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /challenges/:challengeId/leave', () => {
@@ -48,7 +48,6 @@ describe('POST /challenges/:challengeId/leave', () => {
notInGroupLeavingUser = populatedGroup.members[2];
challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
taskText = 'A challenge task text';

View File

@@ -5,7 +5,7 @@ import {
sleep,
checkExistence,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /challenges/:challengeId/winner/:winnerId', () => {
@@ -58,7 +58,6 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
challenge = await generateChallenge(groupLeader, group, {
prize: 1,
});
await groupLeader.post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [
{type: 'habit', text: taskText},

View File

@@ -1,7 +1,7 @@
import {
generateUser,
generateGroup,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /challenges/:challengeId/clone', () => {
it('clones a challenge', async () => {

View File

@@ -3,7 +3,7 @@ import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('PUT /challenges/:challengeId', () => {
let privateGuild, user, nonMember, challenge, member;
@@ -25,7 +25,6 @@ describe('PUT /challenges/:challengeId', () => {
member = members[0];
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
await member.post(`/challenges/${challenge._id}/join`);
});

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('DELETE /groups/:groupId/chat/:chatId', () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /groups/:groupId/chat', () => {
let user;

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { find } from 'lodash';
describe('POST /chat/:chatId/flag', () => {

View File

@@ -1,7 +1,7 @@
import {
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { find } from 'lodash';
describe('POST /chat/:chatId/like', () => {

View File

@@ -4,7 +4,7 @@ import {
translate as t,
sleep,
server,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import {
SPAM_MESSAGE_LIMIT,
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
@@ -388,23 +388,6 @@ describe('POST /chat', () => {
expect(groupMessages[0].id).to.exist;
});
it('creates a chat with a max length of 3000 chars', async () => {
const veryLongMessage = `
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789.
THIS PART WON'T BE IN THE MESSAGE (over 3000)
`;
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: veryLongMessage});
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
expect(newMessage.message.id).to.exist;
expect(groupMessages[0].id).to.exist;
expect(newMessage.message.text.length).to.eql(3000);
expect(newMessage.message.text).to.not.contain('MESSAGE');
expect(groupMessages[0].text.length).to.eql(3000);
});
it('creates a chat with user styles', async () => {
const mount = 'test-mount';
const pet = 'test-pet';

View File

@@ -1,7 +1,7 @@
import {
createAndPopulateGroup,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /groups/:id/chat/seen', () => {
context('Guild', () => {

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import config from '../../../../../config.json';
import { v4 as generateUUID } from 'uuid';

View File

@@ -1,7 +1,7 @@
import {
requester,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import i18n from '../../../../../website/common/script/i18n';
describe('GET /content', () => {

View File

@@ -1,8 +1,8 @@
import {
generateUser,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
import apiError from '../../../../../website/server/libs/apiError';
} from '../../../../helpers/api-v3-integration.helper';
import apiMessages from '../../../../../website/server/libs/apiMessages';
describe('GET /coupons/', () => {
let user;
@@ -19,7 +19,7 @@ describe('GET /coupons/', () => {
await expect(user.get('/coupons')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: apiError('noSudoAccess'),
message: apiMessages('noSudoAccess'),
});
});

View File

@@ -2,7 +2,7 @@ import {
generateUser,
translate as t,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /coupons/enter/:code', () => {
let user;

View File

@@ -2,9 +2,9 @@ import {
generateUser,
translate as t,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import couponCode from 'coupon-code';
import apiError from '../../../../../website/server/libs/apiError';
import apiMessages from '../../../../../website/server/libs/apiMessages';
describe('POST /coupons/generate/:event', () => {
let user;
@@ -26,7 +26,7 @@ describe('POST /coupons/generate/:event', () => {
await expect(user.post('/coupons/generate/aaa')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: apiError('noSudoAccess'),
message: apiMessages('noSudoAccess'),
});
});

View File

@@ -2,7 +2,7 @@ import {
generateUser,
requester,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /coupons/validate/:code', () => {
let api = requester();

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
xdescribe('GET /export/avatar-:memberId.html', () => {

View File

@@ -1,6 +1,6 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import {
updateDocument,
} from '../../../../helpers/mongo';

View File

@@ -1,6 +1,6 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /export/inbox.html', () => {
let user;

View File

@@ -1,6 +1,6 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /export/userdata.json', () => {
it('should return a valid JSON file with user data', async () => {

View File

@@ -1,6 +1,6 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import xml2js from 'xml2js';
import util from 'util';
@@ -23,17 +23,6 @@ describe('GET /export/userdata.xml', () => {
]);
// add pinnedItem
await user.get('/user/toggle-pinned-item/marketGear/gear.flat.shield_rogue_5');
// add a private message
let receiver = await generateUser();
user.post('/members/send-private-message', {
message: 'Your first message, hi!',
toUserId: receiver._id,
});
let response = await user.get('/export/userdata.xml');
let {user: res} = await parseStringAsync(response, {explicitArray: false});

View File

@@ -1,7 +1,7 @@
import nconf from 'nconf';
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /debug/add-hourglass', () => {
let userToGetHourGlass;

View File

@@ -1,7 +1,7 @@
import nconf from 'nconf';
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /debug/add-ten-gems', () => {
let userToGainTenGems;

View File

@@ -1,7 +1,7 @@
import nconf from 'nconf';
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /debug/make-admin (pended for v3 prod testing)', () => {
let user;

View File

@@ -3,7 +3,7 @@
import nconf from 'nconf';
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /debug/modify-inventory', () => {
let user, originalItems;

View File

@@ -1,7 +1,7 @@
import nconf from 'nconf';
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /debug/quest-progress', () => {
let user;

View File

@@ -1,7 +1,7 @@
import nconf from 'nconf';
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /debug/set-cron', () => {
let user;

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { encrypt } from '../../../../../website/server/libs/encryption';
import { v4 as generateUUID } from 'uuid';

View File

@@ -1,7 +1,7 @@
import {
generateUser,
generateGroup,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /group-plans', () => {
let user;

View File

@@ -3,11 +3,11 @@ import {
resetHabiticaDB,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import {
TAVERN_ID,
} from '../../../../../website/server/models/group';
import apiError from '../../../../../website/server/libs/apiError';
import apiMessages from '../../../../../website/server/libs/apiMessages';
describe('GET /groups', () => {
let user;
@@ -167,7 +167,7 @@ describe('GET /groups', () => {
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: apiError('guildsOnlyPaginate'),
message: apiMessages('guildsOnlyPaginate'),
});
});

View File

@@ -2,7 +2,7 @@ import {
generateUser,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /groups/:groupId/invites', () => {
@@ -81,8 +81,7 @@ describe('GET /groups/:groupId/invites', () => {
});
});
it('supports using req.query.lastId to get more invites', async function () {
this.timeout(30000); // @TODO: times out after 8 seconds
it('supports using req.query.lastId to get more invites', async () => {
let leader = await generateUser({balance: 4});
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});

View File

@@ -2,7 +2,7 @@ import {
generateUser,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import common from '../../../../../website/common';
@@ -77,7 +77,7 @@ describe('GET /groups/:groupId/members', () => {
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
expect(Object.keys(memberRes.preferences).sort()).to.eql([
'size', 'hair', 'skin', 'shirt',
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
'chair', 'costume', 'sleep', 'background', 'tasks',
].sort());
expect(memberRes.stats.maxMP).to.exist;
@@ -98,7 +98,7 @@ describe('GET /groups/:groupId/members', () => {
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
expect(Object.keys(memberRes.preferences).sort()).to.eql([
'size', 'hair', 'skin', 'shirt',
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
'chair', 'costume', 'sleep', 'background', 'tasks',
].sort());
expect(memberRes.stats.maxMP).to.exist;
@@ -142,8 +142,7 @@ describe('GET /groups/:groupId/members', () => {
});
});
it('supports using req.query.lastId to get more members', async function () {
this.timeout(30000); // @TODO: times out after 8 seconds
it('supports using req.query.lastId to get more members', async () => {
let leader = await generateUser({balance: 4});
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});

View File

@@ -2,7 +2,7 @@ import {
generateUser,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import {

View File

@@ -1,7 +1,7 @@
import {
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { find } from 'lodash';
describe('POST /group/:groupId/remove-manager', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /group', () => {
let user;

View File

@@ -3,7 +3,7 @@ import {
createAndPopulateGroup,
checkExistence,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /group/:groupId/join', () => {

View File

@@ -5,7 +5,7 @@ import {
sleep,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import {
each,
@@ -93,7 +93,6 @@ describe('POST /groups/:groupId/leave', () => {
beforeEach(async () => {
challenge = await generateChallenge(leader, groupToLeave);
await leader.post(`/challenges/${challenge._id}/join`);
await leader.post(`/tasks/challenge/${challenge._id}`, {
text: 'test habit',

View File

@@ -2,7 +2,7 @@ import {
generateUser,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /group/:groupId/reject-invite', () => {
context('Rejecting a public guild invite', () => {

View File

@@ -3,7 +3,7 @@ import {
createAndPopulateGroup,
translate as t,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import * as email from '../../../../../website/server/libs/email';
describe('POST /groups/:groupId/removeMember/:memberId', () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import nconf from 'nconf';
@@ -114,19 +114,6 @@ describe('Post /groups/:groupId/invite', () => {
});
});
it('returns error when recipient has blocked the senders', async () => {
const inviterNoBlocks = await inviter.update({'inbox.blocks': []});
let userWithBlockedInviter = await generateUser({'inbox.blocks': [inviter._id]});
await expect(inviterNoBlocks.post(`/groups/${group._id}/invite`, {
uuids: [userWithBlockedInviter._id],
}))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('notAuthorizedToSendMessageToThisUser'),
});
});
it('invites a user to a group by uuid', async () => {
let userToInvite = await generateUser();

View File

@@ -2,7 +2,7 @@ import {
generateUser,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /group/:groupId/add-manager', () => {
let leader, nonLeader, groupToUpdate;

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('PUT /group', () => {
let leader, nonLeader, groupToUpdate, adminUser;

View File

@@ -1,7 +1,7 @@
import {
generateUser,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /hall/heroes', () => {
it('returns all heroes sorted by -contributor.level and with correct fields', async () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /heroes/:heroId', () => {

View File

@@ -2,7 +2,7 @@ import {
generateUser,
translate as t,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { times } from 'lodash';
describe('GET /hall/patrons', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('PUT /heroes/:heroId', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /members/:memberId/achievements', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import common from '../../../../../website/common';
@@ -37,7 +37,7 @@ describe('GET /members/:memberId', () => {
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
expect(Object.keys(memberRes.preferences).sort()).to.eql([
'size', 'hair', 'skin', 'shirt',
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
'chair', 'costume', 'sleep', 'background', 'tasks',
].sort());
expect(memberRes.stats.maxMP).to.exist;

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('GET /members/:toUserId/objections/:interaction', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /members/send-private-message', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
function findMessage (messages, receiverId) {

View File

@@ -1,6 +1,6 @@
import {
requester,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /news', () => {
let api;

View File

@@ -1,6 +1,6 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('POST /news/tell-me-later', () => {
let user;

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /notifications/:notificationId/read', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /notifications/:notificationId/see', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /notifications/read', () => {

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /notifications/see', () => {

View File

@@ -1,39 +0,0 @@
import {
createAndPopulateGroup,
} from '../../../../helpers/api-integration/v3';
describe('Prevent multiple notifications', () => {
let partyLeader, partyMembers, party;
before(async () => {
let { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
type: 'party',
privacy: 'private',
},
members: 4,
});
party = group;
partyLeader = groupLeader;
partyMembers = members;
});
it('does not add the same notification twice', async () => {
const multipleChatMessages = [];
for (let i = 0; i < 4; i++) {
for (let memberIndex = 0; memberIndex < partyMembers.length; memberIndex++) {
multipleChatMessages.push(
partyMembers[memberIndex].post(`/groups/${party._id}/chat`, { message: `Message ${i}_${memberIndex}`}),
);
}
}
await Promise.all(multipleChatMessages);
const userWithNotification = await partyLeader.get('/user');
expect(userWithNotification.notifications.length).to.be.eq(1);
});
});

View File

@@ -1,8 +1,8 @@
import {
generateUser,
translate as t,
} from '../../../../../helpers/api-integration/v3';
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import apiError from '../../../../../../website/server/libs/apiError';
describe('payments : paypal #checkoutSuccess', () => {
let endpoint = '/paypal/checkout/success';
@@ -17,7 +17,7 @@ describe('payments : paypal #checkoutSuccess', () => {
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: apiError('missingPaymentId'),
message: t('missingPaymentId'),
});
});
@@ -26,7 +26,7 @@ describe('payments : paypal #checkoutSuccess', () => {
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: apiError('missingCustomerId'),
message: t('missingCustomerId'),
});
});

View File

@@ -1,9 +1,9 @@
import {
generateUser,
translate as t,
} from '../../../../../helpers/api-integration/v3';
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
import shared from '../../../../../../website/common';
import apiError from '../../../../../../website/server/libs/apiError';
describe('payments : paypal #subscribe', () => {
let endpoint = '/paypal/subscribe';
@@ -17,7 +17,7 @@ describe('payments : paypal #subscribe', () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: apiError('missingSubKey'),
message: t('missingSubKey'),
});
});

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../../helpers/api-integration/v3';
import apiError from '../../../../../../website/server/libs/apiError';
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
describe('payments : paypal #subscribeSuccess', () => {
@@ -16,7 +16,7 @@ describe('payments : paypal #subscribeSuccess', () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: apiError('missingPaypalBlock'),
message: t('missingPaypalBlock'),
});
});

View File

@@ -1,7 +1,7 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import superagent from 'superagent';
import nconf from 'nconf';

View File

@@ -3,7 +3,7 @@ import {
translate as t,
generateUser,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { model as Chat } from '../../../../../website/server/models/chat';
describe('POST /groups/:groupId/quests/accept', () => {

View File

@@ -3,7 +3,7 @@ import {
translate as t,
generateUser,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { model as Chat } from '../../../../../website/server/models/chat';
describe('POST /groups/:groupId/quests/force-start', () => {

View File

@@ -2,11 +2,10 @@ import {
createAndPopulateGroup,
translate as t,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import { quests as questScrolls } from '../../../../../website/common/script/content';
import { model as Chat } from '../../../../../website/server/models/chat';
import apiError from '../../../../../website/server/libs/apiError';
describe('POST /groups/:groupId/quests/invite/:questKey', () => {
let questingGroup;
@@ -70,7 +69,7 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${FAKE_QUEST}`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: apiError('questNotFound', {key: FAKE_QUEST}),
message: t('questNotFound', {key: FAKE_QUEST}),
});
});

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup,
translate as t,
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import { model as Group } from '../../../../../website/server/models/group';

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup,
translate as t,
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /groups/:groupId/quests/cancel', () => {

View File

@@ -2,7 +2,7 @@ import {
createAndPopulateGroup,
translate as t,
generateUser,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
describe('POST /groups/:groupId/quests/leave', () => {

View File

@@ -3,7 +3,7 @@ import {
translate as t,
generateUser,
sleep,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
import { v4 as generateUUID } from 'uuid';
import { model as Chat } from '../../../../../website/server/models/chat';

View File

@@ -1,6 +1,6 @@
import {
requester,
} from '../../../../helpers/api-integration/v3';
} from '../../../../helpers/api-v3-integration.helper';
describe('GET /status', () => {
it('returns status: up', async () => {

Some files were not shown because too many files have changed in this diff Show More