mirror of
https://github.com/HabitRPG/habitica.git
synced 2026-05-23 19:49:28 -05:00
Compare commits
182 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c64d4b0914 | |||
| f94fd0d69d | |||
| 2cd66436bc | |||
| 81a17738b8 | |||
| b6b953ec46 | |||
| ab34c83a9d | |||
| 9cea86f4e0 | |||
| 1b7a705bf9 | |||
| e2c5b9058b | |||
| a2b38ffb02 | |||
| 6395870c00 | |||
| 9562ba432f | |||
| 8a3a83de37 | |||
| 745edd731d | |||
| 53b195931c | |||
| 37ae467fff | |||
| d7d7d64b45 | |||
| e76bdbd62d | |||
| 067e869141 | |||
| 51224a69d9 | |||
| f56018d46a | |||
| b846185f8a | |||
| ff81e55839 | |||
| 9a3cdb5deb | |||
| 47ad7305f5 | |||
| d9b5bbe2a9 | |||
| c2fe04367f | |||
| abcc77b7d6 | |||
| 07cbf45265 | |||
| c035435476 | |||
| 89fdd8a8bb | |||
| d406da4081 | |||
| d74786ef85 | |||
| 64a3d08ce3 | |||
| f635f178da | |||
| 1a7461a8a2 | |||
| cc13c4f28e | |||
| 239f78674b | |||
| d691dee2ca | |||
| 481bd6727d | |||
| d0fc1e0751 | |||
| b07dbb7752 | |||
| 34e7690c38 | |||
| eca7382545 | |||
| be95cd967a | |||
| ce03f837c7 | |||
| 808885425f | |||
| 39a35f44ef | |||
| 2b2e1d4b9a | |||
| 869411c0e9 | |||
| 7484ecf729 | |||
| 3265440bc4 | |||
| acf514e9cb | |||
| 2789d44dbf | |||
| b579f31e9e | |||
| 5e781017ab | |||
| b48f850eac | |||
| 5d6b6ed29a | |||
| 7fbc68511b | |||
| ee2858199b | |||
| b1dd79f75c | |||
| 1ac4dd8171 | |||
| 4f86abd6b2 | |||
| 23b0688abb | |||
| 38efe83cc7 | |||
| 2dadd74097 | |||
| 9f494360ef | |||
| 4122bbdecf | |||
| 256a3abc26 | |||
| b7f3c0f389 | |||
| dca00bf4b7 | |||
| d31c8913d3 | |||
| d839d57299 | |||
| ccc3b4d337 | |||
| 7195ac15b9 | |||
| a5ef6a129e | |||
| 38f5d63d29 | |||
| 43194b71ce | |||
| e4a347a3cb | |||
| 7eaf3e04ab | |||
| b6b03751c4 | |||
| 818d5e4eb6 | |||
| f871c7cf63 | |||
| e9eddec0c4 | |||
| a48a6a292d | |||
| 12aef475c8 | |||
| 112e4e1d76 | |||
| 90eebbcd70 | |||
| 1ad9ba4e71 | |||
| c42b72f8a8 | |||
| 830c8d3104 | |||
| 86ae5f3e44 | |||
| 3922415314 | |||
| 6c71abfac8 | |||
| 6ab08a7d52 | |||
| dc46127fc7 | |||
| b54f031acd | |||
| eafa2f8cdd | |||
| fe45940d46 | |||
| 7dac53867b | |||
| 6f64cb7d9b | |||
| 7d989bcf50 | |||
| 7bd29c2dd7 | |||
| 9e10490102 | |||
| 5792bc0000 | |||
| 06812878b5 | |||
| 8714c7d162 | |||
| e66f4e7812 | |||
| c73f565f65 | |||
| 82e21df943 | |||
| 18ed148320 | |||
| a5fc909f0d | |||
| 30a5192e19 | |||
| 79c0499672 | |||
| dadb752087 | |||
| 37b29d3449 | |||
| bb2ed249b9 | |||
| bb90dde1b6 | |||
| 5299c8d406 | |||
| 8b81e38538 | |||
| 8e05a1b489 | |||
| aafcbe60a3 | |||
| 56d1b77215 | |||
| 61da558a5d | |||
| 490531cc76 | |||
| 8cd4c502bc | |||
| d8cacb653e | |||
| 59436a8bf7 | |||
| 6fade19f27 | |||
| 15d028a281 | |||
| 95b283676a | |||
| 6e7e81206a | |||
| af74cc7c64 | |||
| a9e2a17077 | |||
| 92057dbe17 | |||
| b4ab525be5 | |||
| d3c464d5ea | |||
| 804fe1c6d5 | |||
| 3c5025a78e | |||
| e028232527 | |||
| 192dc26fbe | |||
| 30fd530576 | |||
| f79999fde7 | |||
| 90d6e443ba | |||
| 4ed1082558 | |||
| 00717eda76 | |||
| d1b86e6c14 | |||
| c813afba44 | |||
| d49db6d367 | |||
| d6835aec56 | |||
| 960f7b5886 | |||
| cd9630332d | |||
| ed21a37e5a | |||
| 16256ee190 | |||
| fdecc8ce16 | |||
| 3cc49f6637 | |||
| 47f49f4256 | |||
| 4f4bb52360 | |||
| 3748b3046b | |||
| 5cd0f56811 | |||
| fe5beac91b | |||
| 456c5e57bc | |||
| 185b20995a | |||
| fdf2e590ea | |||
| 994123c387 | |||
| 273590716c | |||
| 6818a094ee | |||
| c99855cef4 | |||
| 6845943ed0 | |||
| 044fe17757 | |||
| ad0ede8d01 | |||
| 23815e89e1 | |||
| cfd19ac694 | |||
| 0897ab5dc9 | |||
| 5c6e8a7331 | |||
| c576c5261e | |||
| bbd98517ff | |||
| 392b54aa7b | |||
| 60b26d4ec0 | |||
| fa1fef11d6 | |||
| 1c51e62e43 | |||
| f049d29d1b |
@@ -89,12 +89,6 @@
|
||||
"USERNAME": "admin",
|
||||
"PASSWORD": "password"
|
||||
},
|
||||
"PUSHER": {
|
||||
"ENABLED": "false",
|
||||
"APP_ID": "appId",
|
||||
"KEY": "key",
|
||||
"SECRET": "secret"
|
||||
},
|
||||
"SLACK": {
|
||||
"FLAGGING_URL": "https://hooks.slack.com/services/id/id/id",
|
||||
"FLAGGING_FOOTER_LINK": "https://habitrpg.github.io/flag-o-rama/",
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
const MIGRATION_NAME = '20181108_username_email.js';
|
||||
const AUTHOR_NAME = 'Sabe'; // in case script author needs to know when their ...
|
||||
const AUTHOR_UUID = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Send emails to eligible users announcing upcoming username changes
|
||||
*/
|
||||
|
||||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
import { sendTxn } from '../../../website/server/libs/email';
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
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: MIGRATION_NAME},
|
||||
'flags.verifiedUsername': {$ne: true},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2018-10-25')},
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
limit: 100,
|
||||
fields: [
|
||||
'_id',
|
||||
'auth',
|
||||
'preferences',
|
||||
'profile',
|
||||
], // 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(() => delay(7000))
|
||||
.then(() => {
|
||||
processUsers(lastUser._id);
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
|
||||
dbUsers.update({_id: user._id}, {$set: {migration: MIGRATION_NAME}});
|
||||
|
||||
sendTxn(
|
||||
user,
|
||||
'username-change-follow-up',
|
||||
[{name: 'LOGIN_NAME', content: user.auth.local.username},
|
||||
{name: 'BASE_URL', content: BASE_URL}]
|
||||
);
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === AUTHOR_UUID) console.warn(`${AUTHOR_NAME} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function delay (t, v) {
|
||||
return new Promise(function batchPause (resolve) {
|
||||
setTimeout(resolve.bind(null, v), t);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -17,7 +17,7 @@ function setUpServer () {
|
||||
setUpServer();
|
||||
|
||||
// Replace this with your migration
|
||||
const processUsers = require('../scripts/gdpr-delete-users.js');
|
||||
const processUsers = require('./users/20181122_turkey_day.js');
|
||||
processUsers()
|
||||
.then(function success () {
|
||||
process.exit(0);
|
||||
|
||||
@@ -2,56 +2,15 @@
|
||||
const MIGRATION_NAME = '20181023_veteran_pet_ladder';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
function processUsers (lastId) {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'flags.verifiedUsername': true,
|
||||
};
|
||||
|
||||
let fields = {
|
||||
'items.pets': 1,
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
return User.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const 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) {
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
let set = {migration: MIGRATION_NAME};
|
||||
const set = {};
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
if (user.items.pets['Bear-Veteran']) {
|
||||
set['items.pets.Fox-Veteran'] = 5;
|
||||
@@ -67,27 +26,41 @@ function updateUser (user) {
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return user.update({_id: user._id}, {$set: set}).exec();
|
||||
return await User.update({_id: user._id}, {$set: set}).exec();
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'flags.verifiedUsername': true,
|
||||
};
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
migration: 1,
|
||||
flags: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
console.log(msg);
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processUsers;
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Award Habitoween ladder items to participants in this month's Habitoween festivities
|
||||
*/
|
||||
|
||||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
const MIGRATION_NAME = '20181030_habitoween_ladder.js'; // Update when running in future years
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
const AUTHOR_NAME = 'Sabe'; // in case script author needs to know when their ...
|
||||
const AUTHOR_UUID = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
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: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2018-10-01')},
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
limit: 250,
|
||||
fields: [
|
||||
'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}`);
|
||||
});
|
||||
}
|
||||
|
||||
const PROGRESS_COUNT = 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 inc = {
|
||||
'items.food.Candy_Skeleton': 1,
|
||||
'items.food.Candy_Base': 1,
|
||||
'items.food.Candy_CottonCandyBlue': 1,
|
||||
'items.food.Candy_CottonCandyPink': 1,
|
||||
'items.food.Candy_Shade': 1,
|
||||
'items.food.Candy_White': 1,
|
||||
'items.food.Candy_Golden': 1,
|
||||
'items.food.Candy_Zombie': 1,
|
||||
'items.food.Candy_Desert': 1,
|
||||
'items.food.Candy_Red': 1,
|
||||
};
|
||||
|
||||
if (user && user.items && user.items.pets && user.items.mounts['JackOLantern-Ghost']) {
|
||||
set['items.pets.JackOLantern-Glow'] = 5;
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Ghost']) {
|
||||
set['items.mounts.JackOLantern-Ghost'] = true;
|
||||
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Base']) {
|
||||
set['items.pets.JackOLantern-Ghost'] = 5;
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Base']) {
|
||||
set['items.mounts.JackOLantern-Base'] = true;
|
||||
} else {
|
||||
set['items.pets.JackOLantern-Base'] = 5;
|
||||
}
|
||||
|
||||
dbUsers.update({_id: user._id}, {$set: set, $inc: inc});
|
||||
|
||||
if (count % PROGRESS_COUNT === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === AUTHOR_UUID) console.warn(`${AUTHOR_NAME} 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;
|
||||
@@ -0,0 +1,109 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20181122_turkey_day';
|
||||
import mongoose from 'mongoose';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
const set = {};
|
||||
let push;
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
if (typeof user.items.gear.owned.armor_special_turkeyArmorBase !== 'undefined') {
|
||||
set['items.gear.owned.head_special_turkeyHelmGilded'] = false;
|
||||
set['items.gear.owned.armor_special_turkeyArmorGilded'] = false;
|
||||
set['items.gear.owned.back_special_turkeyTailGilded'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_turkeyHelmGilded',
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
},
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.armor_special_turkeyArmorGilded',
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
},
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.back_special_turkeyTailGilded',
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
},
|
||||
];
|
||||
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Gilded']) {
|
||||
set['items.gear.owned.head_special_turkeyHelmBase'] = false;
|
||||
set['items.gear.owned.armor_special_turkeyArmorBase'] = false;
|
||||
set['items.gear.owned.back_special_turkeyTailBase'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_turkeyHelmBase',
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
},
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.armor_special_turkeyArmorBase',
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
},
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.back_special_turkeyTailBase',
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
},
|
||||
];
|
||||
} else if (user.items && user.items.pets && user.items.pets['Turkey-Gilded']) {
|
||||
set['items.mounts.Turkey-Gilded'] = true;
|
||||
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Base']) {
|
||||
set['items.pets.Turkey-Gilded'] = 5;
|
||||
} else if (user.items && user.items.pets && user.items.pets['Turkey-Base']) {
|
||||
set['items.mounts.Turkey-Base'] = true;
|
||||
} else {
|
||||
set['items.pets.Turkey-Base'] = 5;
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
if (push) {
|
||||
return await User.update({_id: user._id}, {$set: set, $push: {pinnedItems: {$each: push}}}).exec();
|
||||
} else {
|
||||
return await User.update({_id: user._id}, {$set: set}).exec();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
@@ -8,7 +8,7 @@ const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is do
|
||||
/*
|
||||
* Award this month's mystery items to subscribers
|
||||
*/
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201809', 'head_mystery_201809'];
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201810', 'head_mystery_201810'];
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
Generated
+1816
-2803
File diff suppressed because it is too large
Load Diff
+11
-12
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.66.1",
|
||||
"version": "4.73.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@slack/client": "^3.8.1",
|
||||
@@ -35,7 +35,7 @@
|
||||
"coupon-code": "^0.4.5",
|
||||
"cross-env": "^5.1.5",
|
||||
"css-loader": "^0.28.11",
|
||||
"csv-stringify": "^3.0.0",
|
||||
"csv-stringify": "^4.3.1",
|
||||
"cwait": "^1.1.1",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"express": "^4.16.3",
|
||||
@@ -46,8 +46,8 @@
|
||||
"got": "^9.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel": "^7.0.1",
|
||||
"gulp-imagemin": "^4.1.0",
|
||||
"gulp-nodemon": "^2.2.1",
|
||||
"gulp-imagemin": "^5.0.3",
|
||||
"gulp-nodemon": "^2.4.1",
|
||||
"gulp.spritesmith": "^6.9.0",
|
||||
"habitica-markdown": "^1.3.0",
|
||||
"hellojs": "^1.15.1",
|
||||
@@ -59,16 +59,16 @@
|
||||
"js2xmlparser": "^3.0.0",
|
||||
"lodash": "^4.17.10",
|
||||
"merge-stream": "^1.0.0",
|
||||
"method-override": "^2.3.5",
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.22.1",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^5.1.3",
|
||||
"mongoose": "^5.3.4",
|
||||
"morgan": "^1.7.0",
|
||||
"nconf": "^0.10.0",
|
||||
"node-gcm": "^0.14.4",
|
||||
"node-gcm": "^1.0.2",
|
||||
"node-sass": "^4.9.0",
|
||||
"nodemailer": "^4.6.4",
|
||||
"ora": "^2.1.0",
|
||||
"ora": "^3.0.0",
|
||||
"pageres": "^4.1.1",
|
||||
"passport": "^0.4.0",
|
||||
"passport-facebook": "^2.0.0",
|
||||
@@ -79,14 +79,13 @@
|
||||
"postcss-easy-import": "^3.0.0",
|
||||
"ps-tree": "^1.0.0",
|
||||
"pug": "^2.0.3",
|
||||
"pusher": "^1.3.0",
|
||||
"rimraf": "^2.4.3",
|
||||
"sass-loader": "^7.0.0",
|
||||
"shelljs": "^0.8.2",
|
||||
"short-uuid": "^3.0.0",
|
||||
"smartbanner.js": "^1.9.1",
|
||||
"stripe": "^5.9.0",
|
||||
"superagent": "^3.8.3",
|
||||
"superagent": "^4.0.0",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"svg-url-loader": "^2.3.2",
|
||||
"svgo": "^1.0.5",
|
||||
@@ -163,7 +162,7 @@
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"expect.js": "^0.3.1",
|
||||
"http-proxy-middleware": "^0.18.0",
|
||||
"http-proxy-middleware": "^0.19.0",
|
||||
"istanbul": "^1.1.0-alpha.1",
|
||||
"karma": "^3.0.0",
|
||||
"karma-babel-preprocessor": "^7.0.0",
|
||||
@@ -184,7 +183,7 @@
|
||||
"puppeteer": "^1.4.0",
|
||||
"require-again": "^2.0.0",
|
||||
"selenium-server": "^3.12.0",
|
||||
"sinon": "^4.5.0",
|
||||
"sinon": "^6.3.5",
|
||||
"sinon-chai": "^3.0.0",
|
||||
"sinon-stub-promise": "^4.0.0",
|
||||
"webpack-bundle-analyzer": "^2.12.0",
|
||||
|
||||
@@ -5,10 +5,17 @@ describe('Base model plugin', () => {
|
||||
let schema;
|
||||
|
||||
beforeEach(() => {
|
||||
schema = new mongoose.Schema();
|
||||
schema = new mongoose.Schema({}, {
|
||||
typeKey: '$type',
|
||||
});
|
||||
sandbox.stub(schema, 'add');
|
||||
});
|
||||
|
||||
it('throws if "typeKey" is not set to $type', () => {
|
||||
const schemaWithoutTypeKey = new mongoose.Schema();
|
||||
expect(() => schemaWithoutTypeKey.plugin(baseModel)).to.throw;
|
||||
});
|
||||
|
||||
it('adds a _id field to the schema', () => {
|
||||
schema.plugin(baseModel);
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
|
||||
function expectBillingAggreementDetailSpy () {
|
||||
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.returnsPromise()
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Open'},
|
||||
@@ -80,14 +79,14 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
headers = {};
|
||||
|
||||
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails');
|
||||
getBillingAgreementDetailsSpy.returnsPromise().resolves({
|
||||
getBillingAgreementDetailsSpy.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
},
|
||||
});
|
||||
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription');
|
||||
paymentCancelSubscriptionSpy.returnsPromise().resolves({});
|
||||
paymentCancelSubscriptionSpy.resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@@ -118,7 +117,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should close a user subscription if amazon not closed', async () => {
|
||||
amzLib.getBillingAgreementDetails.restore();
|
||||
expectBillingAggreementDetailSpy();
|
||||
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').returnsPromise().resolves({});
|
||||
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').resolves({});
|
||||
billingAgreementId = user.purchased.plan.customerId;
|
||||
|
||||
await amzLib.cancelSubscription({user, headers});
|
||||
@@ -164,7 +163,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should close a group subscription if amazon not closed', async () => {
|
||||
amzLib.getBillingAgreementDetails.restore();
|
||||
expectBillingAggreementDetailSpy();
|
||||
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').returnsPromise().resolves({});
|
||||
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').resolves({});
|
||||
billingAgreementId = group.purchased.plan.customerId;
|
||||
|
||||
await amzLib.cancelSubscription({user, groupId: group._id, headers});
|
||||
|
||||
@@ -68,22 +68,22 @@ describe('Amazon Payments - Checkout', () => {
|
||||
orderReferenceId = 'orderReferenceId';
|
||||
|
||||
setOrderReferenceDetailsSpy = sinon.stub(amzLib, 'setOrderReferenceDetails');
|
||||
setOrderReferenceDetailsSpy.returnsPromise().resolves({});
|
||||
setOrderReferenceDetailsSpy.resolves({});
|
||||
|
||||
confirmOrderReferenceSpy = sinon.stub(amzLib, 'confirmOrderReference');
|
||||
confirmOrderReferenceSpy.returnsPromise().resolves({});
|
||||
confirmOrderReferenceSpy.resolves({});
|
||||
|
||||
authorizeSpy = sinon.stub(amzLib, 'authorize');
|
||||
authorizeSpy.returnsPromise().resolves({});
|
||||
authorizeSpy.resolves({});
|
||||
|
||||
closeOrderReferenceSpy = sinon.stub(amzLib, 'closeOrderReference');
|
||||
closeOrderReferenceSpy.returnsPromise().resolves({});
|
||||
closeOrderReferenceSpy.resolves({});
|
||||
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems');
|
||||
paymentBuyGemsStub.returnsPromise().resolves({});
|
||||
paymentBuyGemsStub.resolves({});
|
||||
|
||||
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription');
|
||||
paymentCreateSubscritionStub.returnsPromise().resolves({});
|
||||
paymentCreateSubscritionStub.resolves({});
|
||||
|
||||
sinon.stub(common, 'uuid').returns('uuid-generated');
|
||||
});
|
||||
@@ -111,7 +111,7 @@ describe('Amazon Payments - Checkout', () => {
|
||||
}
|
||||
|
||||
it('should purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await amzLib.checkout({user, orderReferenceId, headers});
|
||||
|
||||
expectBuyGemsStub(amzLib.constants.PAYMENT_METHOD);
|
||||
@@ -140,7 +140,7 @@ describe('Amazon Payments - Checkout', () => {
|
||||
});
|
||||
|
||||
it('should error if user cannot get gems gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
await expect(amzLib.checkout({user, orderReferenceId, headers})).to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
|
||||
@@ -46,16 +46,16 @@ describe('Amazon Payments - Subscribe', () => {
|
||||
headers = {};
|
||||
|
||||
amazonSetBillingAgreementDetailsSpy = sinon.stub(amzLib, 'setBillingAgreementDetails');
|
||||
amazonSetBillingAgreementDetailsSpy.returnsPromise().resolves({});
|
||||
amazonSetBillingAgreementDetailsSpy.resolves({});
|
||||
|
||||
amazonConfirmBillingAgreementSpy = sinon.stub(amzLib, 'confirmBillingAgreement');
|
||||
amazonConfirmBillingAgreementSpy.returnsPromise().resolves({});
|
||||
amazonConfirmBillingAgreementSpy.resolves({});
|
||||
|
||||
amazonAuthorizeOnBillingAgreementSpy = sinon.stub(amzLib, 'authorizeOnBillingAgreement');
|
||||
amazonAuthorizeOnBillingAgreementSpy.returnsPromise().resolves({});
|
||||
amazonAuthorizeOnBillingAgreementSpy.resolves({});
|
||||
|
||||
createSubSpy = sinon.stub(payments, 'createSubscription');
|
||||
createSubSpy.returnsPromise().resolves({});
|
||||
createSubSpy.resolves({});
|
||||
|
||||
sinon.stub(common, 'uuid').returns('uuid-generated');
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('#upgradeGroupPlan', () => {
|
||||
await group.save();
|
||||
|
||||
spy = sinon.stub(amzLib, 'authorizeOnBillingAgreement');
|
||||
spy.returnsPromise().resolves([]);
|
||||
spy.resolves([]);
|
||||
|
||||
uuidString = 'uuid-v4';
|
||||
sinon.stub(uuid, 'v4').returns(uuidString);
|
||||
|
||||
@@ -24,16 +24,16 @@ describe('Apple Payments', () => {
|
||||
headers = {};
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
.returnsPromise().resolves();
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
.returnsPromise().resolves({});
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
.returns(true);
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: 'com.habitrpg.ios.Habitica.21gems',
|
||||
transactionId: token,
|
||||
}]);
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').returnsPromise().resolves({});
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -70,7 +70,7 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
it('errors if the user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
await expect(applePayments.verifyGemPurchase(user, receipt, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
@@ -82,7 +82,7 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
it('errors if amount does not exist', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: 'badProduct',
|
||||
@@ -130,7 +130,7 @@ describe('Apple Payments', () => {
|
||||
transactionId: token,
|
||||
}]);
|
||||
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await applePayments.verifyGemPurchase(user, receipt, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
@@ -167,9 +167,9 @@ describe('Apple Payments', () => {
|
||||
nextPaymentProcessing = moment.utc().add({days: 2});
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
.returnsPromise().resolves();
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
.returnsPromise().resolves({});
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
.returns(true);
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
@@ -186,7 +186,7 @@ describe('Apple Payments', () => {
|
||||
productId: sku,
|
||||
transactionId: token,
|
||||
}]);
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -297,9 +297,9 @@ describe('Apple Payments', () => {
|
||||
expirationDate = moment.utc();
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
.returnsPromise().resolves();
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
expirationDate,
|
||||
});
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
@@ -314,7 +314,7 @@ describe('Apple Payments', () => {
|
||||
user.purchased.plan.planId = subKey;
|
||||
user.purchased.plan.additionalData = receipt;
|
||||
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
||||
@@ -24,12 +24,12 @@ describe('Google Payments', () => {
|
||||
headers = {};
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
.returnsPromise().resolves();
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
.returnsPromise().resolves({});
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
.returns(true);
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').returnsPromise().resolves({});
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -64,7 +64,7 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase(user, receipt, signature, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
@@ -77,7 +77,7 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
it('purchases gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await googlePayments.verifyGemPurchase(user, receipt, signature, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
@@ -116,12 +116,12 @@ describe('Google Payments', () => {
|
||||
nextPaymentProcessing = moment.utc().add({days: 2});
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
.returnsPromise().resolves();
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
.returnsPromise().resolves({});
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
.returns(true);
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -193,9 +193,9 @@ describe('Google Payments', () => {
|
||||
expirationDate = moment.utc();
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
.returnsPromise().resolves();
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
expirationDate,
|
||||
});
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
@@ -210,7 +210,7 @@ describe('Google Payments', () => {
|
||||
user.purchased.plan.planId = subKey;
|
||||
user.purchased.plan.additionalData = {data: receipt, signature};
|
||||
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
||||
@@ -69,11 +69,11 @@ describe('Purchasing a group plan for group', () => {
|
||||
};
|
||||
|
||||
let subscriptionId = 'subId';
|
||||
sinon.stub(stripe.customers, 'del').returnsPromise().resolves({});
|
||||
sinon.stub(stripe.customers, 'del').resolves({});
|
||||
|
||||
let currentPeriodEndTimeStamp = moment().add(3, 'months').unix();
|
||||
sinon.stub(stripe.customers, 'retrieve')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
subscriptions: {
|
||||
data: [{id: subscriptionId, current_period_end: currentPeriodEndTimeStamp}], // eslint-disable-line camelcase
|
||||
},
|
||||
@@ -216,7 +216,6 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
it('sends one email to subscribed member of group, stating subscription is cancelled (Amazon)', async () => {
|
||||
sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.returnsPromise()
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
@@ -251,9 +250,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('sends one email to subscribed member of group, stating subscription is cancelled (PayPal)', async () => {
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').returnsPromise().resolves({});
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').resolves({});
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementGet')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
agreement_details: { // eslint-disable-line camelcase
|
||||
next_billing_date: moment().add(3, 'months').toDate(), // eslint-disable-line camelcase
|
||||
cycles_completed: 1, // eslint-disable-line camelcase
|
||||
@@ -449,7 +448,6 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
it('adds months to members with existing recurring subscription (Amazon)', async () => {
|
||||
sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.returnsPromise()
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
@@ -478,9 +476,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription (Paypal)', async () => {
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').returnsPromise().resolves({});
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').resolves({});
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementGet')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
agreement_details: { // eslint-disable-line camelcase
|
||||
next_billing_date: moment().add(3, 'months').toDate(), // eslint-disable-line camelcase
|
||||
cycles_completed: 1, // eslint-disable-line camelcase
|
||||
|
||||
@@ -446,6 +446,19 @@ describe('payments/index', () => {
|
||||
fakeClock.restore();
|
||||
});
|
||||
|
||||
it('does not add a notification for mystery items if none was awarded', async () => {
|
||||
const noMysteryItemTimeframe = 1462183920000; // May 2nd 2016
|
||||
let fakeClock = sinon.useFakeTimers(noMysteryItemTimeframe);
|
||||
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.mysteryItems).to.have.a.lengthOf(0);
|
||||
expect(user.notifications.find(n => n.type === 'NEW_MYSTERY_ITEMS')).to.be.undefined;
|
||||
|
||||
fakeClock.restore();
|
||||
});
|
||||
|
||||
it('does not award mystery item when user already owns the item', async () => {
|
||||
let mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
let fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
|
||||
@@ -13,9 +13,9 @@ describe('checkout success', () => {
|
||||
customerId = 'customerId-test';
|
||||
paymentId = 'paymentId-test';
|
||||
|
||||
paypalPaymentExecuteStub = sinon.stub(paypalPayments, 'paypalPaymentExecute').returnsPromise().resolves({});
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').returnsPromise().resolves({});
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||
paypalPaymentExecuteStub = sinon.stub(paypalPayments, 'paypalPaymentExecute').resolves({});
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('checkout', () => {
|
||||
beforeEach(() => {
|
||||
approvalHerf = 'approval_href';
|
||||
paypalPaymentCreateStub = sinon.stub(paypalPayments, 'paypalPaymentCreate')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
links: [{ rel: 'approval_url', href: approvalHerf }],
|
||||
});
|
||||
});
|
||||
@@ -80,7 +80,7 @@ describe('checkout', () => {
|
||||
|
||||
it('should error if the user cannot get gems', async () => {
|
||||
let user = new User();
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
|
||||
await expect(paypalPayments.checkout({user})).to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
|
||||
@@ -34,8 +34,8 @@ describe('ipn', () => {
|
||||
group.purchased.plan.lastBillingDate = new Date();
|
||||
await group.save();
|
||||
|
||||
ipnVerifyAsyncStub = sinon.stub(paypalPayments, 'ipnVerifyAsync').returnsPromise().resolves({});
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
ipnVerifyAsyncStub = sinon.stub(paypalPayments, 'ipnVerifyAsync').resolves({});
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
||||
@@ -38,15 +38,15 @@ describe('subscribeCancel', () => {
|
||||
|
||||
nextBillingDate = new Date();
|
||||
|
||||
paypalBillingAgreementCancelStub = sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').returnsPromise().resolves({});
|
||||
paypalBillingAgreementCancelStub = sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').resolves({});
|
||||
paypalBillingAgreementGetStub = sinon.stub(paypalPayments, 'paypalBillingAgreementGet')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
agreement_details: {
|
||||
next_billing_date: nextBillingDate,
|
||||
cycles_completed: 1,
|
||||
},
|
||||
});
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
||||
@@ -28,10 +28,10 @@ describe('subscribeSuccess', () => {
|
||||
customerId = 'test-customerId';
|
||||
|
||||
paypalBillingAgreementExecuteStub = sinon.stub(paypalPayments, 'paypalBillingAgreementExecute')
|
||||
.returnsPromise({}).resolves({
|
||||
.resolves({
|
||||
id: customerId,
|
||||
});
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('subscribe', () => {
|
||||
sub = Object.assign({}, common.content.subscriptionBlocks[subKey]);
|
||||
|
||||
paypalBillingAgreementCreateStub = sinon.stub(paypalPayments, 'paypalBillingAgreementCreate')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
links: [{ rel: 'approval_url', href: approvalHerf }],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,12 +82,12 @@ describe('cancel subscription', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
subscriptionId = 'subId';
|
||||
stripeDeleteCustomerStub = sinon.stub(stripe.customers, 'del').returnsPromise().resolves({});
|
||||
paymentsCancelSubStub = sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
stripeDeleteCustomerStub = sinon.stub(stripe.customers, 'del').resolves({});
|
||||
paymentsCancelSubStub = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
|
||||
currentPeriodEndTimeStamp = (new Date()).getTime();
|
||||
stripeRetrieveStub = sinon.stub(stripe.customers, 'retrieve')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
subscriptions: {
|
||||
data: [{id: subscriptionId, current_period_end: currentPeriodEndTimeStamp}], // eslint-disable-line camelcase
|
||||
},
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('checkout with subscription', () => {
|
||||
token = 'test-token';
|
||||
|
||||
spy = sinon.stub(stripe.subscriptions, 'update');
|
||||
spy.returnsPromise().resolves;
|
||||
spy.resolves;
|
||||
|
||||
stripeCreateCustomerSpy = sinon.stub(stripe.customers, 'create');
|
||||
let stripCustomerResponse = {
|
||||
@@ -63,10 +63,10 @@ describe('checkout with subscription', () => {
|
||||
data: [{id: subscriptionId}],
|
||||
},
|
||||
};
|
||||
stripeCreateCustomerSpy.returnsPromise().resolves(stripCustomerResponse);
|
||||
stripeCreateCustomerSpy.resolves(stripCustomerResponse);
|
||||
|
||||
stripePaymentsCreateSubSpy = sinon.stub(payments, 'createSubscription');
|
||||
stripePaymentsCreateSubSpy.returnsPromise().resolves({});
|
||||
stripePaymentsCreateSubSpy.resolves({});
|
||||
|
||||
data.groupId = group._id;
|
||||
data.sub.quantity = 3;
|
||||
|
||||
@@ -26,9 +26,9 @@ describe('checkout', () => {
|
||||
let stripCustomerResponse = {
|
||||
id: customerIdResponse,
|
||||
};
|
||||
stripeChargeStub = sinon.stub(stripe.charges, 'create').returnsPromise().resolves(stripCustomerResponse);
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').returnsPromise().resolves({});
|
||||
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription').returnsPromise().resolves({});
|
||||
stripeChargeStub = sinon.stub(stripe.charges, 'create').resolves(stripCustomerResponse);
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
|
||||
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -82,7 +82,7 @@ describe('checkout', () => {
|
||||
|
||||
it('should error if user cannot get gems', async () => {
|
||||
gift = undefined;
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
|
||||
await expect(stripePayments.checkout({
|
||||
token,
|
||||
@@ -101,7 +101,7 @@ describe('checkout', () => {
|
||||
|
||||
it('should purchase gems', async () => {
|
||||
gift = undefined;
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
|
||||
await stripePayments.checkout({
|
||||
token,
|
||||
|
||||
@@ -98,11 +98,11 @@ describe('edit subscription', () => {
|
||||
beforeEach(() => {
|
||||
subscriptionId = 'subId';
|
||||
stripeListSubscriptionStub = sinon.stub(stripe.customers, 'listSubscriptions')
|
||||
.returnsPromise().resolves({
|
||||
.resolves({
|
||||
data: [{id: subscriptionId}],
|
||||
});
|
||||
|
||||
stripeUpdateSubscriptionStub = sinon.stub(stripe.customers, 'updateSubscription').returnsPromise().resolves({});
|
||||
stripeUpdateSubscriptionStub = sinon.stub(stripe.customers, 'updateSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('Stripe - Webhooks', () => {
|
||||
const eventRetrieved = {type: eventType};
|
||||
|
||||
beforeEach(() => {
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves(eventRetrieved);
|
||||
sinon.stub(stripe.events, 'retrieve').resolves(eventRetrieved);
|
||||
sinon.stub(logger, 'error');
|
||||
});
|
||||
|
||||
@@ -52,8 +52,8 @@ describe('Stripe - Webhooks', () => {
|
||||
const eventType = 'customer.subscription.deleted';
|
||||
|
||||
beforeEach(() => {
|
||||
sinon.stub(stripe.customers, 'del').returnsPromise().resolves({});
|
||||
sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
sinon.stub(stripe.customers, 'del').resolves({});
|
||||
sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -62,7 +62,7 @@ describe('Stripe - Webhooks', () => {
|
||||
});
|
||||
|
||||
it('does not do anything if event.request is null (subscription cancelled manually)', async () => {
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
sinon.stub(stripe.events, 'retrieve').resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
request: 123,
|
||||
@@ -79,7 +79,7 @@ describe('Stripe - Webhooks', () => {
|
||||
describe('user subscription', () => {
|
||||
it('throws an error if the user is not found', async () => {
|
||||
const customerId = 456;
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
sinon.stub(stripe.events, 'retrieve').resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
@@ -113,7 +113,7 @@ describe('Stripe - Webhooks', () => {
|
||||
subscriber.purchased.plan.paymentMethod = 'Stripe';
|
||||
await subscriber.save();
|
||||
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
sinon.stub(stripe.events, 'retrieve').resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
@@ -146,7 +146,7 @@ describe('Stripe - Webhooks', () => {
|
||||
describe('group plan subscription', () => {
|
||||
it('throws an error if the group is not found', async () => {
|
||||
const customerId = 456;
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
sinon.stub(stripe.events, 'retrieve').resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
@@ -185,7 +185,7 @@ describe('Stripe - Webhooks', () => {
|
||||
subscriber.purchased.plan.paymentMethod = 'Stripe';
|
||||
await subscriber.save();
|
||||
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
sinon.stub(stripe.events, 'retrieve').resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
@@ -227,7 +227,7 @@ describe('Stripe - Webhooks', () => {
|
||||
subscriber.purchased.plan.paymentMethod = 'Stripe';
|
||||
await subscriber.save();
|
||||
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
sinon.stub(stripe.events, 'retrieve').resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('Stripe - Upgrade Group Plan', () => {
|
||||
await group.save();
|
||||
|
||||
spy = sinon.stub(stripe.subscriptions, 'update');
|
||||
spy.returnsPromise().resolves([]);
|
||||
spy.resolves([]);
|
||||
data.groupId = group._id;
|
||||
data.sub.quantity = 3;
|
||||
stripePayments.setStripeApi(stripe);
|
||||
|
||||
@@ -477,7 +477,7 @@ describe('Group Model', () => {
|
||||
party.quest.active = false;
|
||||
|
||||
await party.startQuest(questLeader);
|
||||
Group.prototype.sendChat.reset();
|
||||
Group.prototype.sendChat.resetHistory();
|
||||
await party.save();
|
||||
|
||||
await Group.processQuestProgress(participatingMember, progress);
|
||||
@@ -496,7 +496,7 @@ describe('Group Model', () => {
|
||||
party.quest.active = false;
|
||||
|
||||
await party.startQuest(questLeader);
|
||||
Group.prototype.sendChat.reset();
|
||||
Group.prototype.sendChat.resetHistory();
|
||||
await party.save();
|
||||
|
||||
await Group.processQuestProgress(participatingMember, progress);
|
||||
@@ -569,7 +569,7 @@ describe('Group Model', () => {
|
||||
});
|
||||
|
||||
it('throws an error if no uuids or emails are passed in', async () => {
|
||||
await expect(Group.validateInvitations(null, null, res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
@@ -579,7 +579,7 @@ describe('Group Model', () => {
|
||||
});
|
||||
|
||||
it('throws an error if only uuids are passed in, but they are not an array', async () => {
|
||||
await expect(Group.validateInvitations({ uuid: 'user-id'}, null, res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({ uuids: 'user-id'}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
@@ -589,7 +589,7 @@ describe('Group Model', () => {
|
||||
});
|
||||
|
||||
it('throws an error if only emails are passed in, but they are not an array', async () => {
|
||||
await expect(Group.validateInvitations(null, { emails: 'user@example.com'}, res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({emails: 'user@example.com'}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
@@ -599,27 +599,27 @@ describe('Group Model', () => {
|
||||
});
|
||||
|
||||
it('throws an error if emails are not passed in, and uuid array is empty', async () => {
|
||||
await expect(Group.validateInvitations([], null, res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({uuids: []}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMissingUuid');
|
||||
expect(res.t).to.be.calledWith('inviteMustNotBeEmpty');
|
||||
});
|
||||
|
||||
it('throws an error if uuids are not passed in, and email array is empty', async () => {
|
||||
await expect(Group.validateInvitations(null, [], res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({emails: []}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMissingEmail');
|
||||
expect(res.t).to.be.calledWith('inviteMustNotBeEmpty');
|
||||
});
|
||||
|
||||
it('throws an error if uuids and emails are passed in as empty arrays', async () => {
|
||||
await expect(Group.validateInvitations([], [], res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({emails: [], uuids: []}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
@@ -639,7 +639,7 @@ describe('Group Model', () => {
|
||||
|
||||
uuids.push('one-more-uuid'); // to put it over the limit
|
||||
|
||||
await expect(Group.validateInvitations(uuids, emails, res)).to.eventually.be.rejected.and.eql({
|
||||
await expect(Group.validateInvitations({uuids, emails}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
@@ -657,33 +657,33 @@ describe('Group Model', () => {
|
||||
emails.push(`user-${i}@example.com`);
|
||||
}
|
||||
|
||||
await Group.validateInvitations(uuids, emails, res);
|
||||
await Group.validateInvitations({uuids, emails}, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
|
||||
it('does not throw an error if only user ids are passed in', async () => {
|
||||
await Group.validateInvitations(['user-id', 'user-id2'], null, res);
|
||||
await Group.validateInvitations({uuids: ['user-id', 'user-id2']}, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if only emails are passed in', async () => {
|
||||
await Group.validateInvitations(null, ['user1@example.com', 'user2@example.com'], res);
|
||||
await Group.validateInvitations({emails: ['user1@example.com', 'user2@example.com']}, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if both uuids and emails are passed in', async () => {
|
||||
await Group.validateInvitations(['user-id', 'user-id2'], ['user1@example.com', 'user2@example.com'], res);
|
||||
await Group.validateInvitations({uuids: ['user-id', 'user-id2'], emails: ['user1@example.com', 'user2@example.com']}, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if uuids are passed in and emails are an empty array', async () => {
|
||||
await Group.validateInvitations(['user-id', 'user-id2'], [], res);
|
||||
await Group.validateInvitations({uuids: ['user-id', 'user-id2'], emails: []}, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if emails are passed in and uuids are an empty array', async () => {
|
||||
await Group.validateInvitations([], ['user1@example.com', 'user2@example.com'], res);
|
||||
await Group.validateInvitations({uuids: [], emails: ['user1@example.com', 'user2@example.com']}, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
});
|
||||
@@ -1843,6 +1843,62 @@ describe('Group Model', () => {
|
||||
expect(options.chat).to.eql(chat);
|
||||
});
|
||||
|
||||
it('sends webhooks for users with webhooks triggered by system messages', async () => {
|
||||
let guild = new Group({
|
||||
name: 'some guild',
|
||||
type: 'guild',
|
||||
});
|
||||
|
||||
let memberWithWebhook = new User({
|
||||
guilds: [guild._id],
|
||||
webhooks: [{
|
||||
type: 'groupChatReceived',
|
||||
url: 'http://someurl.com',
|
||||
options: {
|
||||
groupId: guild._id,
|
||||
},
|
||||
}],
|
||||
});
|
||||
let memberWithoutWebhook = new User({
|
||||
guilds: [guild._id],
|
||||
});
|
||||
let nonMemberWithWebhooks = new User({
|
||||
webhooks: [{
|
||||
type: 'groupChatReceived',
|
||||
url: 'http://a-different-url.com',
|
||||
options: {
|
||||
groupId: generateUUID(),
|
||||
},
|
||||
}],
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
memberWithWebhook.save(),
|
||||
memberWithoutWebhook.save(),
|
||||
nonMemberWithWebhooks.save(),
|
||||
]);
|
||||
|
||||
guild.leader = memberWithWebhook._id;
|
||||
|
||||
await guild.save();
|
||||
|
||||
const groupMessage = guild.sendChat('Test message.');
|
||||
await groupMessage.save();
|
||||
|
||||
await sleep();
|
||||
|
||||
expect(groupChatReceivedWebhook.send).to.be.calledOnce;
|
||||
|
||||
let args = groupChatReceivedWebhook.send.args[0];
|
||||
let webhooks = args[0].webhooks;
|
||||
let options = args[1];
|
||||
|
||||
expect(webhooks).to.have.a.lengthOf(1);
|
||||
expect(webhooks[0].id).to.eql(memberWithWebhook.webhooks[0].id);
|
||||
expect(options.group).to.eql(guild);
|
||||
expect(options.chat).to.eql(groupMessage);
|
||||
});
|
||||
|
||||
it('sends webhooks for each user with webhooks in group', async () => {
|
||||
let guild = new Group({
|
||||
name: 'some guild',
|
||||
|
||||
@@ -47,6 +47,14 @@ describe('GET /challenges/:challengeId', () => {
|
||||
_id: groupLeader._id,
|
||||
id: groupLeader._id,
|
||||
profile: {name: groupLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: groupLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(chal.group).to.eql({
|
||||
_id: group._id,
|
||||
@@ -105,6 +113,14 @@ describe('GET /challenges/:challengeId', () => {
|
||||
_id: challengeLeader._id,
|
||||
id: challengeLeader._id,
|
||||
profile: {name: challengeLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: challengeLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(chal.group).to.eql({
|
||||
_id: group._id,
|
||||
@@ -131,6 +147,14 @@ describe('GET /challenges/:challengeId', () => {
|
||||
_id: challengeLeader._id,
|
||||
id: challengeLeader._id,
|
||||
profile: {name: challengeLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: challengeLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -179,6 +203,14 @@ describe('GET /challenges/:challengeId', () => {
|
||||
_id: challengeLeader._id,
|
||||
id: challengeLeader._id,
|
||||
profile: {name: challengeLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: challengeLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(chal.group).to.eql({
|
||||
_id: group._id,
|
||||
@@ -205,6 +237,14 @@ describe('GET /challenges/:challengeId', () => {
|
||||
_id: challengeLeader._id,
|
||||
id: challengeLeader._id,
|
||||
profile: {name: challengeLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: challengeLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,6 +60,14 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
_id: groupLeader._id,
|
||||
id: groupLeader._id,
|
||||
profile: {name: groupLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: groupLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,8 +81,16 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
_id: leader._id,
|
||||
id: leader._id,
|
||||
profile: {name: leader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: leader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(res[0]).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(res[0]).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(res[0].profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
@@ -88,8 +104,16 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
_id: anotherUser._id,
|
||||
id: anotherUser._id,
|
||||
profile: {name: anotherUser.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: anotherUser.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(res[0]).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(res[0]).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(res[0].profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
@@ -107,7 +131,7 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
let res = await user.get(`/challenges/${challenge._id}/members?includeAllMembers=not-true`);
|
||||
expect(res.length).to.equal(30);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
@@ -126,7 +150,7 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
let res = await user.get(`/challenges/${challenge._id}/members`);
|
||||
expect(res.length).to.equal(30);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
@@ -145,7 +169,7 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
let res = await user.get(`/challenges/${challenge._id}/members?includeAllMembers=true`);
|
||||
expect(res.length).to.equal(32);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
|
||||
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [{type: 'habit', text: taskText}]);
|
||||
|
||||
let memberProgress = await user.get(`/challenges/${challenge._id}/members/${groupLeader._id}`);
|
||||
expect(memberProgress).to.have.all.keys(['_id', 'id', 'profile', 'tasks']);
|
||||
expect(memberProgress).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile', 'tasks']);
|
||||
expect(memberProgress.profile).to.have.all.keys(['name']);
|
||||
expect(memberProgress.tasks.length).to.equal(1);
|
||||
});
|
||||
|
||||
@@ -39,6 +39,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -46,6 +54,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,6 +74,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -65,6 +89,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,6 +157,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: privateGuild.leader._id,
|
||||
id: privateGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -132,6 +172,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: privateGuild.leader._id,
|
||||
id: privateGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -235,6 +283,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: party.leader._id,
|
||||
id: party.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -242,6 +298,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: party.leader._id,
|
||||
id: party.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -254,6 +318,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: party.leader._id,
|
||||
id: party.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -261,6 +333,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: party.leader._id,
|
||||
id: party.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -288,6 +368,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: user._id,
|
||||
id: user._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -295,6 +383,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: user._id,
|
||||
id: user._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -307,6 +403,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: user._id,
|
||||
id: user._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||
expect(foundChallenge2).to.exist;
|
||||
@@ -314,6 +418,14 @@ describe('GET challenges/groups/:groupId', () => {
|
||||
_id: user._id,
|
||||
id: user._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,6 +40,14 @@ describe('GET challenges/user', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(foundChallenge.group).to.eql({
|
||||
_id: publicGuild._id,
|
||||
@@ -62,6 +70,14 @@ describe('GET challenges/user', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(foundChallenge1.group).to.eql({
|
||||
_id: publicGuild._id,
|
||||
@@ -79,6 +95,14 @@ describe('GET challenges/user', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(foundChallenge2.group).to.eql({
|
||||
_id: publicGuild._id,
|
||||
@@ -101,6 +125,14 @@ describe('GET challenges/user', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(foundChallenge1.group).to.eql({
|
||||
_id: publicGuild._id,
|
||||
@@ -118,6 +150,14 @@ describe('GET challenges/user', () => {
|
||||
_id: publicGuild.leader._id,
|
||||
id: publicGuild.leader._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(foundChallenge2.group).to.eql({
|
||||
_id: publicGuild._id,
|
||||
|
||||
@@ -79,6 +79,14 @@ describe('POST /challenges/:challengeId/join', () => {
|
||||
_id: groupLeader._id,
|
||||
id: groupLeader._id,
|
||||
profile: {name: groupLeader.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: groupLeader.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(res.name).to.equal(challenge.name);
|
||||
});
|
||||
|
||||
@@ -79,6 +79,14 @@ describe('PUT /challenges/:challengeId', () => {
|
||||
_id: member._id,
|
||||
id: member._id,
|
||||
profile: {name: member.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: member.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
expect(res.name).to.equal('New Challenge Name');
|
||||
expect(res.description).to.equal('New challenge description.');
|
||||
|
||||
@@ -203,7 +203,7 @@ describe('GET /groups', () => {
|
||||
let page2 = await expect(user.get('/groups?type=publicGuilds&paginate=true&page=2'))
|
||||
.to.eventually.have.a.lengthOf(1 + 4); // 1 created now, 4 by other tests
|
||||
expect(page2[4].name).to.equal('guild with less members');
|
||||
});
|
||||
}).timeout(10000);
|
||||
});
|
||||
|
||||
it('returns all the user\'s guilds when guilds passed in as query', async () => {
|
||||
|
||||
@@ -50,6 +50,14 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
_id: invited._id,
|
||||
id: invited._id,
|
||||
profile: {name: invited.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: invited.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,7 +66,7 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
let invited = await generateUser();
|
||||
await user.post(`/groups/${group._id}/invite`, {uuids: [invited._id]});
|
||||
let res = await user.get('/groups/party/invites');
|
||||
expect(res[0]).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(res[0]).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(res[0].profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
@@ -76,10 +84,10 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
let res = await leader.get(`/groups/${group._id}/invites`);
|
||||
expect(res.length).to.equal(30);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
it('supports using req.query.lastId to get more invites', async function () {
|
||||
this.timeout(30000); // @TODO: times out after 8 seconds
|
||||
|
||||
@@ -56,13 +56,21 @@ describe('GET /groups/:groupId/members', () => {
|
||||
_id: user._id,
|
||||
id: user._id,
|
||||
profile: {name: user.profile.name},
|
||||
auth: {
|
||||
local: {
|
||||
username: user.auth.local.username,
|
||||
},
|
||||
},
|
||||
flags: {
|
||||
verifiedUsername: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('populates only some fields', async () => {
|
||||
await generateGroup(user, {type: 'party', name: generateUUID()});
|
||||
let res = await user.get('/groups/party/members');
|
||||
expect(res[0]).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(res[0]).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(res[0].profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
@@ -74,7 +82,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
'_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
|
||||
'backer', 'contributor', 'auth', 'items', 'inbox', 'loginIncentives', 'flags',
|
||||
]);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['local', 'timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
@@ -95,7 +103,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
'_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
|
||||
'backer', 'contributor', 'auth', 'items', 'inbox', 'loginIncentives', 'flags',
|
||||
]);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['local', 'timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
@@ -120,7 +128,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
let res = await user.get('/groups/party/members');
|
||||
expect(res.length).to.equal(30);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
@@ -137,7 +145,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
let res = await user.get('/groups/party/members?includeAllMembers=true');
|
||||
expect(res.length).to.equal(30);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,6 +23,73 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('username invites', () => {
|
||||
it('returns an error when invited user is not found', async () => {
|
||||
const fakeID = 'fakeuserid';
|
||||
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [fakeID],
|
||||
}))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('userWithUsernameNotFound', {username: fakeID}),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error when inviting yourself to a group', async () => {
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [inviter.auth.local.lowerCaseUsername],
|
||||
}))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('cannotInviteSelfToGroup'),
|
||||
});
|
||||
});
|
||||
|
||||
it('invites a user to a group by username', async () => {
|
||||
const userToInvite = await generateUser();
|
||||
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [userToInvite.auth.local.lowerCaseUsername],
|
||||
})).to.eventually.deep.equal([{
|
||||
id: group._id,
|
||||
name: groupName,
|
||||
inviter: inviter._id,
|
||||
publicGuild: false,
|
||||
}]);
|
||||
|
||||
await expect(userToInvite.get('/user'))
|
||||
.to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
|
||||
});
|
||||
|
||||
it('invites multiple users to a group by uuid', async () => {
|
||||
const userToInvite = await generateUser();
|
||||
const userToInvite2 = await generateUser();
|
||||
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [userToInvite.auth.local.lowerCaseUsername, userToInvite2.auth.local.lowerCaseUsername],
|
||||
})).to.eventually.deep.equal([
|
||||
{
|
||||
id: group._id,
|
||||
name: groupName,
|
||||
inviter: inviter._id,
|
||||
publicGuild: false,
|
||||
},
|
||||
{
|
||||
id: group._id,
|
||||
name: groupName,
|
||||
inviter: inviter._id,
|
||||
publicGuild: false,
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(userToInvite.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
|
||||
await expect(userToInvite2.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('user id invites', () => {
|
||||
it('returns an error when inviter has no chat privileges', async () => {
|
||||
let inviterMuted = await inviter.update({'flags.chatRevoked': true});
|
||||
@@ -93,7 +160,7 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('inviteMissingUuid'),
|
||||
message: t('inviteMustNotBeEmpty'),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -228,7 +295,7 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('inviteMissingEmail'),
|
||||
message: t('inviteMustNotBeEmpty'),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -417,7 +484,7 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
expect(await inviter.post(`/groups/${group._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
})).to.be.an('array');
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
// @TODO: Add this after we are able to mock the group plan route
|
||||
xit('returns an error when a non-leader invites to a group plan', async () => {
|
||||
@@ -564,7 +631,7 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
expect(await inviter.post(`/groups/${party._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
})).to.be.an('array');
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
it('does not allow 30+ members in a party', async () => {
|
||||
let invitesToGenerate = [];
|
||||
@@ -582,6 +649,6 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
error: 'BadRequest',
|
||||
message: t('partyExceedsMembersLimit', {maxMembersParty: PARTY_LIMIT_MEMBERS}),
|
||||
});
|
||||
});
|
||||
}).timeout(10000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,5 +56,5 @@ describe('GET /hall/patrons', () => {
|
||||
expect(morePatrons.length).to.equal(2);
|
||||
expect(morePatrons[0].backer.tier).to.equal(2);
|
||||
expect(morePatrons[1].backer.tier).to.equal(1);
|
||||
});
|
||||
}).timeout(10000);
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('GET /members/:memberId', () => {
|
||||
'_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
|
||||
'backer', 'contributor', 'auth', 'items', 'inbox', 'loginIncentives', 'flags',
|
||||
]);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['local', 'timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ describe('payments : amazon #subscribeCancel', () => {
|
||||
|
||||
describe('success', () => {
|
||||
beforeEach(() => {
|
||||
amazonSubscribeCancelStub = sinon.stub(amzLib, 'cancelSubscription').returnsPromise().resolves({});
|
||||
amazonSubscribeCancelStub = sinon.stub(amzLib, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('payments - amazon - #checkout', () => {
|
||||
|
||||
describe('success', () => {
|
||||
beforeEach(async () => {
|
||||
amazonCheckoutStub = sinon.stub(amzLib, 'checkout').returnsPromise().resolves({});
|
||||
amazonCheckoutStub = sinon.stub(amzLib, 'checkout').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -27,7 +27,7 @@ describe('payments - amazon - #subscribe', () => {
|
||||
let coupon;
|
||||
|
||||
beforeEach(() => {
|
||||
subscribeWithAmazonStub = sinon.stub(amzLib, 'subscribe').returnsPromise().resolves({});
|
||||
subscribeWithAmazonStub = sinon.stub(amzLib, 'subscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('payments : apple #cancelSubscribe', () => {
|
||||
let cancelStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
cancelStub = sinon.stub(applePayments, 'cancelSubscribe').returnsPromise().resolves({});
|
||||
cancelStub = sinon.stub(applePayments, 'cancelSubscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('payments : apple #verify', () => {
|
||||
let verifyStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
verifyStub = sinon.stub(applePayments, 'verifyGemPurchase').returnsPromise().resolves({});
|
||||
verifyStub = sinon.stub(applePayments, 'verifyGemPurchase').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('payments : apple #subscribe', () => {
|
||||
let subscribeStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeStub = sinon.stub(applePayments, 'subscribe').returnsPromise().resolves({});
|
||||
subscribeStub = sinon.stub(applePayments, 'subscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('payments : google #cancelSubscribe', () => {
|
||||
let cancelStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
cancelStub = sinon.stub(googlePayments, 'cancelSubscribe').returnsPromise().resolves({});
|
||||
cancelStub = sinon.stub(googlePayments, 'cancelSubscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('payments : google #subscribe', () => {
|
||||
let subscribeStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeStub = sinon.stub(googlePayments, 'subscribe').returnsPromise().resolves({});
|
||||
subscribeStub = sinon.stub(googlePayments, 'subscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('payments : google #verify', () => {
|
||||
let verifyStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
verifyStub = sinon.stub(googlePayments, 'verifyGemPurchase').returnsPromise().resolves({});
|
||||
verifyStub = sinon.stub(googlePayments, 'verifyGemPurchase').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('payments : paypal #checkout', () => {
|
||||
let checkoutStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
checkoutStub = sinon.stub(paypalPayments, 'checkout').returnsPromise().resolves('/');
|
||||
checkoutStub = sinon.stub(paypalPayments, 'checkout').resolves('/');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ describe('payments : paypal #checkoutSuccess', () => {
|
||||
let checkoutSuccessStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
checkoutSuccessStub = sinon.stub(paypalPayments, 'checkoutSuccess').returnsPromise().resolves({});
|
||||
checkoutSuccessStub = sinon.stub(paypalPayments, 'checkoutSuccess').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('payments : paypal #subscribe', () => {
|
||||
let subscribeStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeStub = sinon.stub(paypalPayments, 'subscribe').returnsPromise().resolves('/');
|
||||
subscribeStub = sinon.stub(paypalPayments, 'subscribe').resolves('/');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ describe('payments : paypal #subscribeCancel', () => {
|
||||
let subscribeCancelStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeCancelStub = sinon.stub(paypalPayments, 'subscribeCancel').returnsPromise().resolves('/');
|
||||
subscribeCancelStub = sinon.stub(paypalPayments, 'subscribeCancel').resolves('/');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ describe('payments : paypal #subscribeSuccess', () => {
|
||||
let subscribeSuccessStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeSuccessStub = sinon.stub(paypalPayments, 'subscribeSuccess').returnsPromise().resolves({});
|
||||
subscribeSuccessStub = sinon.stub(paypalPayments, 'subscribeSuccess').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('payments - paypal - #ipn', () => {
|
||||
let ipnStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
ipnStub = sinon.stub(paypalPayments, 'ipn').returnsPromise().resolves({});
|
||||
ipnStub = sinon.stub(paypalPayments, 'ipn').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ describe('payments - stripe - #subscribeCancel', () => {
|
||||
|
||||
describe('success', () => {
|
||||
beforeEach(async () => {
|
||||
stripeCancelSubscriptionStub = sinon.stub(stripePayments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
stripeCancelSubscriptionStub = sinon.stub(stripePayments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('payments - stripe - #checkout', () => {
|
||||
let stripeCheckoutSubscriptionStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
stripeCheckoutSubscriptionStub = sinon.stub(stripePayments, 'checkout').returnsPromise().resolves({});
|
||||
stripeCheckoutSubscriptionStub = sinon.stub(stripePayments, 'checkout').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('payments - stripe - #subscribeEdit', () => {
|
||||
let stripeEditSubscriptionStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
stripeEditSubscriptionStub = sinon.stub(stripePayments, 'editSubscription').returnsPromise().resolves({});
|
||||
stripeEditSubscriptionStub = sinon.stub(stripePayments, 'editSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
describe('POST /user/auth/pusher', () => {
|
||||
let user;
|
||||
let endpoint = '/user/auth/pusher';
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('requires authentication', async () => {
|
||||
let api = requester();
|
||||
|
||||
await expect(api.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('missingAuthHeaders'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.body.socket_id is missing', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.body.channel_name is missing', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.body.channel_name is badly formatted', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: '123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher channel type.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if an invalid channel type is passed', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: 'invalid-group-123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher channel type.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if an invalid resource type is passed', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: 'presence-user-123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher resource type.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if an invalid resource id is passed', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: 'presence-group-123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher resource id, must be a UUID.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if the passed resource id doesn\'t match the user\'s party', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: `presence-group-${generateUUID()}`,
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: 'Resource id must be the user\'s party.',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12,14 +12,14 @@ const ENDPOINT = '/user/auth/update-username';
|
||||
|
||||
describe('PUT /user/auth/update-username', async () => {
|
||||
let user;
|
||||
let newUsername = 'new-username';
|
||||
let password = 'password'; // from habitrpg/test/helpers/api-integration/v3/object-generators.js
|
||||
let password = 'password'; // from habitrpg/test/helpers/api-integration/v4/object-generators.js
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('successfully changes username', async () => {
|
||||
it('successfully changes username with password', async () => {
|
||||
let newUsername = 'new-username';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
password,
|
||||
@@ -29,6 +29,38 @@ describe('PUT /user/auth/update-username', async () => {
|
||||
expect(user.auth.local.username).to.eql(newUsername);
|
||||
});
|
||||
|
||||
it('successfully changes username without password', async () => {
|
||||
let newUsername = 'new-username-nopw';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(newUsername);
|
||||
});
|
||||
|
||||
it('successfully changes username containing number and underscore', async () => {
|
||||
let newUsername = 'new_username9';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(newUsername);
|
||||
});
|
||||
|
||||
it('sets verifiedUsername when changing username', async () => {
|
||||
user.flags.verifiedUsername = false;
|
||||
await user.sync();
|
||||
let newUsername = 'new-username-verify';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.flags.verifiedUsername).to.eql(true);
|
||||
});
|
||||
|
||||
it('converts user with SHA1 encrypted password to bcrypt encryption', async () => {
|
||||
let myNewUsername = 'my-new-username';
|
||||
let textPassword = 'mySecretPassword';
|
||||
@@ -80,6 +112,7 @@ describe('PUT /user/auth/update-username', async () => {
|
||||
});
|
||||
|
||||
it('errors if password is wrong', async () => {
|
||||
let newUsername = 'new-username';
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
password: 'wrong-password',
|
||||
@@ -90,19 +123,6 @@ describe('PUT /user/auth/update-username', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('prevents social-only user from changing username', async () => {
|
||||
let socialUser = await generateUser({ 'auth.local': { ok: true } });
|
||||
|
||||
await expect(socialUser.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('userHasNoLocalRegistration'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is not provided', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
password,
|
||||
@@ -112,5 +132,93 @@ describe('PUT /user/auth/update-username', async () => {
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is a slur', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'TESTPLACEHOLDERSLURWORDHERE',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username contains a slur', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'TESTPLACEHOLDERSLURWORDHERE_otherword',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'something_TESTPLACEHOLDERSLURWORDHERE',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'somethingTESTPLACEHOLDERSLURWORDHEREotherword',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is not allowed', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'support',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueForbidden'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is not allowed regardless of casing', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'SUppORT',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueForbidden'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if username has incorrect length', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'thisisaverylongusernameover20characters',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueLength'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username contains invalid characters', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'Eichhörnchen',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueInvalidCharacters'),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'test.name',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueInvalidCharacters'),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: '🤬',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueInvalidCharacters'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,4 +53,15 @@ describe('POST /user/buy-gear/:key', () => {
|
||||
message: 'You need to purchase a lower level gear before this one.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if tries to buy gear from a different class', async () => {
|
||||
let key = 'armor_rogue_1';
|
||||
|
||||
return expect(user.post(`/user/buy-gear/${key}`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: 'You can\'t buy this item.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v4';
|
||||
|
||||
const ENDPOINT = '/user/auth/verify-display-name';
|
||||
|
||||
describe('POST /user/auth/verify-display-name', async () => {
|
||||
let user;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('successfully verifies display name including funky characters', async () => {
|
||||
let newDisplayName = 'Sabé 🤬';
|
||||
let response = await user.post(ENDPOINT, {
|
||||
displayName: newDisplayName,
|
||||
});
|
||||
expect(response).to.eql({ isUsable: true });
|
||||
});
|
||||
|
||||
context('errors', async () => {
|
||||
it('errors if display name is not provided', async () => {
|
||||
await expect(user.post(ENDPOINT, {
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if display name is a slur', async () => {
|
||||
await expect(user.post(ENDPOINT, {
|
||||
displayName: 'TESTPLACEHOLDERSLURWORDHERE',
|
||||
})).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueSlur')] });
|
||||
});
|
||||
|
||||
it('errors if display name contains a slur', async () => {
|
||||
await expect(user.post(ENDPOINT, {
|
||||
displayName: 'TESTPLACEHOLDERSLURWORDHERE_otherword',
|
||||
})).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueLength'), t('displaynameIssueSlur')] });
|
||||
await expect(user.post(ENDPOINT, {
|
||||
displayName: 'something_TESTPLACEHOLDERSLURWORDHERE',
|
||||
})).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueLength'), t('displaynameIssueSlur')] });
|
||||
await expect(user.post(ENDPOINT, {
|
||||
displayName: 'somethingTESTPLACEHOLDERSLURWORDHEREotherword',
|
||||
})).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueLength'), t('displaynameIssueSlur')] });
|
||||
});
|
||||
|
||||
it('errors if display name has incorrect length', async () => {
|
||||
await expect(user.post(ENDPOINT, {
|
||||
displayName: 'this is a very long display name over 30 characters',
|
||||
})).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueLength')] });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,224 +0,0 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v4';
|
||||
import {
|
||||
bcryptCompare,
|
||||
sha1MakeSalt,
|
||||
sha1Encrypt as sha1EncryptPassword,
|
||||
} from '../../../../../website/server/libs/password';
|
||||
|
||||
const ENDPOINT = '/user/auth/update-username';
|
||||
|
||||
describe('PUT /user/auth/update-username', async () => {
|
||||
let user;
|
||||
let password = 'password'; // from habitrpg/test/helpers/api-integration/v4/object-generators.js
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('successfully changes username with password', async () => {
|
||||
let newUsername = 'new-username';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
password,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(newUsername);
|
||||
});
|
||||
|
||||
it('successfully changes username without password', async () => {
|
||||
let newUsername = 'new-username-nopw';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(newUsername);
|
||||
});
|
||||
|
||||
it('successfully changes username containing number and underscore', async () => {
|
||||
let newUsername = 'new_username9';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.auth.local.username).to.eql(newUsername);
|
||||
});
|
||||
|
||||
it('sets verifiedUsername when changing username', async () => {
|
||||
user.flags.verifiedUsername = false;
|
||||
await user.sync();
|
||||
let newUsername = 'new-username-verify';
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
});
|
||||
expect(response).to.eql({ username: newUsername });
|
||||
await user.sync();
|
||||
expect(user.flags.verifiedUsername).to.eql(true);
|
||||
});
|
||||
|
||||
it('converts user with SHA1 encrypted password to bcrypt encryption', async () => {
|
||||
let myNewUsername = 'my-new-username';
|
||||
let textPassword = 'mySecretPassword';
|
||||
let salt = sha1MakeSalt();
|
||||
let sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
|
||||
await user.update({
|
||||
'auth.local.hashed_password': sha1HashedPassword,
|
||||
'auth.local.passwordHashMethod': 'sha1',
|
||||
'auth.local.salt': salt,
|
||||
});
|
||||
|
||||
await user.sync();
|
||||
expect(user.auth.local.passwordHashMethod).to.equal('sha1');
|
||||
expect(user.auth.local.salt).to.equal(salt);
|
||||
expect(user.auth.local.hashed_password).to.equal(sha1HashedPassword);
|
||||
|
||||
// update email
|
||||
let response = await user.put(ENDPOINT, {
|
||||
username: myNewUsername,
|
||||
password: textPassword,
|
||||
});
|
||||
expect(response).to.eql({ username: myNewUsername });
|
||||
|
||||
await user.sync();
|
||||
|
||||
expect(user.auth.local.username).to.eql(myNewUsername);
|
||||
expect(user.auth.local.passwordHashMethod).to.equal('bcrypt');
|
||||
expect(user.auth.local.salt).to.be.undefined;
|
||||
expect(user.auth.local.hashed_password).not.to.equal(sha1HashedPassword);
|
||||
|
||||
let isValidPassword = await bcryptCompare(textPassword, user.auth.local.hashed_password);
|
||||
expect(isValidPassword).to.equal(true);
|
||||
});
|
||||
|
||||
context('errors', async () => {
|
||||
it('prevents username update if new username is already taken', async () => {
|
||||
let existingUsername = 'existing-username';
|
||||
await generateUser({'auth.local.username': existingUsername, 'auth.local.lowerCaseUsername': existingUsername });
|
||||
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: existingUsername,
|
||||
password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameTaken'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if password is wrong', async () => {
|
||||
let newUsername = 'new-username';
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: newUsername,
|
||||
password: 'wrong-password',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('wrongPassword'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is not provided', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
password,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is a slur', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'TESTPLACEHOLDERSLURWORDHERE',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username contains a slur', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'TESTPLACEHOLDERSLURWORDHERE_otherword',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'something_TESTPLACEHOLDERSLURWORDHERE',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'somethingTESTPLACEHOLDERSLURWORDHEREotherword',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: [t('usernameIssueLength'), t('usernameIssueSlur')].join(' '),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is not allowed', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'support',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueForbidden'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username is not allowed regardless of casing', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'SUppORT',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueForbidden'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if username has incorrect length', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'thisisaverylongusernameover20characters',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueLength'),
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if new username contains invalid characters', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'Eichhörnchen',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueInvalidCharacters'),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: 'test.name',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueInvalidCharacters'),
|
||||
});
|
||||
await expect(user.put(ENDPOINT, {
|
||||
username: '🤬',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('usernameIssueInvalidCharacters'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@ require('babel-polyfill');
|
||||
|
||||
// Automatically setup SinonJS' sandbox for each test
|
||||
beforeEach(() => {
|
||||
global.sandbox = sinon.sandbox.create();
|
||||
global.sandbox = sinon.createSandbox();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import taskDefaults from '../../../website/common/script/libs/taskDefaults';
|
||||
import { generateUser } from '../../helpers/common.helper';
|
||||
|
||||
describe('taskDefaults', () => {
|
||||
it('applies defaults to undefined type or habit', () => {
|
||||
let task = taskDefaults();
|
||||
let task = taskDefaults({}, generateUser());
|
||||
expect(task.type).to.eql('habit');
|
||||
expect(task._id).to.exist;
|
||||
expect(task.text).to.eql(task._id);
|
||||
@@ -18,7 +21,7 @@ describe('taskDefaults', () => {
|
||||
});
|
||||
|
||||
it('applies defaults to a daily', () => {
|
||||
let task = taskDefaults({ type: 'daily' });
|
||||
let task = taskDefaults({ type: 'daily' }, generateUser());
|
||||
expect(task.type).to.eql('daily');
|
||||
expect(task._id).to.exist;
|
||||
expect(task.text).to.eql(task._id);
|
||||
@@ -42,7 +45,7 @@ describe('taskDefaults', () => {
|
||||
});
|
||||
|
||||
it('applies defaults a reward', () => {
|
||||
let task = taskDefaults({ type: 'reward' });
|
||||
let task = taskDefaults({ type: 'reward' }, generateUser());
|
||||
expect(task.type).to.eql('reward');
|
||||
expect(task._id).to.exist;
|
||||
expect(task.text).to.eql(task._id);
|
||||
@@ -52,7 +55,7 @@ describe('taskDefaults', () => {
|
||||
});
|
||||
|
||||
it('applies defaults a todo', () => {
|
||||
let task = taskDefaults({ type: 'todo' });
|
||||
let task = taskDefaults({ type: 'todo' }, generateUser());
|
||||
expect(task.type).to.eql('todo');
|
||||
expect(task._id).to.exist;
|
||||
expect(task.text).to.eql(task._id);
|
||||
@@ -61,4 +64,18 @@ describe('taskDefaults', () => {
|
||||
expect(task.priority).to.eql(1);
|
||||
expect(task.completed).to.eql(false);
|
||||
});
|
||||
|
||||
it('starts a task yesterday if user cron is later today', () => {
|
||||
// Configure to have a day start that's *always* tomorrow.
|
||||
let user = generateUser({'preferences.dayStart': 25});
|
||||
let task = taskDefaults({ type: 'daily' }, user);
|
||||
|
||||
expect(task.startDate).to.eql(
|
||||
moment()
|
||||
.zone(user.preferences.timezoneOffset, 'hour')
|
||||
.startOf('day')
|
||||
.subtract(1, 'day')
|
||||
.toDate()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -246,5 +246,14 @@ describe('shared.ops.buyMarketGear', () => {
|
||||
|
||||
expect(user.items.gear.owned).to.have.property('head_special_2', true);
|
||||
});
|
||||
|
||||
it('does buyGear equipment if it is an armoire item that an user previously lost', () => {
|
||||
user.stats.gp = 200;
|
||||
user.items.gear.owned.shield_armoire_ramHornShield = false;
|
||||
|
||||
buyGear(user, {params: {key: 'shield_armoire_ramHornShield'}});
|
||||
|
||||
expect(user.items.gear.owned).to.have.property('shield_armoire_ramHornShield', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -228,7 +228,7 @@ describe('shouldDo', () => {
|
||||
options.timezoneOffset = 0;
|
||||
options.nextDue = true;
|
||||
|
||||
day = moment('2017-05-01').toDate();
|
||||
day = moment.utc('2017-05-01').toDate();
|
||||
dailyTask.frequency = 'daily';
|
||||
dailyTask.everyX = 2;
|
||||
dailyTask.startDate = day;
|
||||
@@ -391,7 +391,7 @@ describe('shouldDo', () => {
|
||||
options.timezoneOffset = 0;
|
||||
options.nextDue = true;
|
||||
|
||||
day = moment('2017-05-01').toDate();
|
||||
day = moment.utc('2017-05-01').toDate();
|
||||
dailyTask.frequency = 'weekly';
|
||||
dailyTask.everyX = 1;
|
||||
dailyTask.repeat = {
|
||||
@@ -780,7 +780,7 @@ describe('shouldDo', () => {
|
||||
options.timezoneOffset = 0;
|
||||
options.nextDue = true;
|
||||
|
||||
day = moment('2017-05-01').toDate();
|
||||
day = moment.utc('2017-05-01').toDate();
|
||||
|
||||
dailyTask.frequency = 'monthly';
|
||||
dailyTask.everyX = 3;
|
||||
@@ -817,7 +817,7 @@ describe('shouldDo', () => {
|
||||
expect(moment(nextDue[4]).toDate()).to.eql(moment.utc('2017-10-02').toDate());
|
||||
expect(moment(nextDue[5]).toDate()).to.eql(moment.utc('2017-11-06').toDate());
|
||||
|
||||
day = moment('2017-05-08').toDate();
|
||||
day = moment.utc('2017-05-08').toDate();
|
||||
|
||||
dailyTask.daysOfMonth = [];
|
||||
dailyTask.weeksOfMonth = [1];
|
||||
@@ -841,7 +841,7 @@ describe('shouldDo', () => {
|
||||
expect(moment(nextDue[4]).toDate()).to.eql(moment.utc('2017-10-09').toDate());
|
||||
expect(moment(nextDue[5]).toDate()).to.eql(moment.utc('2017-11-13').toDate());
|
||||
|
||||
day = moment('2017-05-29').toDate();
|
||||
day = moment.utc('2017-05-29').toDate();
|
||||
|
||||
dailyTask.daysOfMonth = [];
|
||||
dailyTask.weeksOfMonth = [4];
|
||||
@@ -1143,7 +1143,7 @@ describe('shouldDo', () => {
|
||||
options.timezoneOffset = 0;
|
||||
options.nextDue = true;
|
||||
|
||||
day = moment('2017-05-01').toDate();
|
||||
day = moment.utc('2017-05-01').toDate();
|
||||
|
||||
dailyTask.frequency = 'yearly';
|
||||
dailyTask.everyX = 5;
|
||||
|
||||
@@ -13,7 +13,7 @@ global.expect = chai.expect;
|
||||
global.sinon = require('sinon');
|
||||
let sinonStubPromise = require('sinon-stub-promise');
|
||||
sinonStubPromise(global.sinon);
|
||||
global.sandbox = sinon.sandbox.create();
|
||||
global.sandbox = sinon.createSandbox();
|
||||
|
||||
import setupNconf from '../../website/server/libs/setupNconf';
|
||||
setupNconf('./config.json.example');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.achievement-costumeContest6x {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1013px -798px;
|
||||
background-position: -1136px -169px;
|
||||
width: 144px;
|
||||
height: 156px;
|
||||
}
|
||||
@@ -12,44 +12,20 @@
|
||||
}
|
||||
.promo_animal_tails {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1013px -208px;
|
||||
background-position: -994px 0px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_armoire_backgrounds_201810 {
|
||||
.promo_armoire_backgrounds_201811 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -848px -1009px;
|
||||
background-position: -481px -568px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_fall_avatar_customizations {
|
||||
.promo_frost_potions {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1013px 0px;
|
||||
width: 336px;
|
||||
height: 207px;
|
||||
}
|
||||
.promo_fall_festival_2017 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px -453px;
|
||||
width: 414px;
|
||||
height: 210px;
|
||||
}
|
||||
.promo_fall_festival_2018 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -367px -723px;
|
||||
width: 393px;
|
||||
height: 213px;
|
||||
}
|
||||
.promo_forest_friends_bundle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -1009px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_ghost_potions {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -424px -1009px;
|
||||
width: 423px;
|
||||
background-position: -421px -723px;
|
||||
width: 417px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_ios {
|
||||
@@ -58,51 +34,51 @@
|
||||
width: 375px;
|
||||
height: 361px;
|
||||
}
|
||||
.promo_mystery_201809 {
|
||||
.promo_mystery_201810 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1013px -650px;
|
||||
width: 306px;
|
||||
background-position: -1136px 0px;
|
||||
width: 294px;
|
||||
height: 168px;
|
||||
}
|
||||
.promo_oddballs_bundle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px -420px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_seasonal_shop {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1155px -503px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
.promo_spooky_sparkles {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1155px -208px;
|
||||
width: 140px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_take_this {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1158px -798px;
|
||||
background-position: -1281px -169px;
|
||||
width: 96px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_turkey_day_2018 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -723px;
|
||||
width: 420px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_veteran_pets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -1157px;
|
||||
background-position: 0px -871px;
|
||||
width: 363px;
|
||||
height: 141px;
|
||||
}
|
||||
.scene_nametag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px -244px;
|
||||
background-position: -481px 0px;
|
||||
width: 512px;
|
||||
height: 208px;
|
||||
}
|
||||
.scene_positivity {
|
||||
.scene_sleep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px 0px;
|
||||
width: 531px;
|
||||
height: 243px;
|
||||
background-position: -481px -209px;
|
||||
width: 390px;
|
||||
height: 210px;
|
||||
}
|
||||
.scene_tools {
|
||||
.scene_veteran_pets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -723px;
|
||||
width: 366px;
|
||||
height: 285px;
|
||||
background-position: -1136px -326px;
|
||||
width: 242px;
|
||||
height: 62px;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,48 +4,72 @@
|
||||
width: 221px;
|
||||
height: 39px;
|
||||
}
|
||||
.quest_dilatory {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dilatoryDistress1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -1085px;
|
||||
width: 210px;
|
||||
height: 210px;
|
||||
}
|
||||
.quest_dilatoryDistress2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -570px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_dilatoryDistress3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dustbunnies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_egg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -537px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
}
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1198px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_evilsanta2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_falcon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_ferret {
|
||||
.quest_dilatory_derby {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dustbunnies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_egg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -362px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
}
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1174px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_evilsanta2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_falcon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_ferret {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_frog {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -1112px;
|
||||
@@ -54,19 +78,19 @@
|
||||
}
|
||||
.quest_ghost_stag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -220px;
|
||||
background-position: -880px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -452px;
|
||||
background-position: -880px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -251px -1546px;
|
||||
background-position: 0px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
@@ -78,19 +102,19 @@
|
||||
}
|
||||
.quest_gryphon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1322px -1112px;
|
||||
background-position: -1314px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_guineapig {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px 0px;
|
||||
background-position: -440px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_harpy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -220px;
|
||||
background-position: -660px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -102,67 +126,67 @@
|
||||
}
|
||||
.quest_hippo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -672px;
|
||||
background-position: -1100px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_horse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -672px;
|
||||
background-position: -1100px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_kangaroo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -672px;
|
||||
background-position: -1100px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_kraken {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1531px -1332px;
|
||||
background-position: -663px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_lostMasterclasser1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -672px;
|
||||
background-position: 0px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -672px;
|
||||
background-position: -220px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px 0px;
|
||||
background-position: -440px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -896px;
|
||||
background-position: -1757px -872px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_mayhemMistiflying2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -440px;
|
||||
background-position: -880px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -660px;
|
||||
background-position: -1100px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_monkey {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -892px;
|
||||
background-position: -1320px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -174,37 +198,37 @@
|
||||
}
|
||||
.quest_moon2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -892px;
|
||||
background-position: -1320px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -892px;
|
||||
background-position: -220px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -892px;
|
||||
background-position: -1320px -880px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -892px;
|
||||
background-position: 0px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -892px;
|
||||
background-position: -220px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_nudibranch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -651px;
|
||||
background-position: -1540px 0px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
@@ -216,73 +240,73 @@
|
||||
}
|
||||
.quest_owl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -440px;
|
||||
background-position: -660px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_peacock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px 0px;
|
||||
background-position: -1540px -868px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_penguin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -353px;
|
||||
background-position: -1757px -178px;
|
||||
width: 190px;
|
||||
height: 183px;
|
||||
}
|
||||
.quest_pterodactyl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -880px;
|
||||
background-position: -440px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rat {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1112px;
|
||||
background-position: -1320px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -868px;
|
||||
background-position: -1540px -434px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_rooster {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px 0px;
|
||||
background-position: -1531px -1332px;
|
||||
width: 213px;
|
||||
height: 174px;
|
||||
}
|
||||
.quest_sabretooth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -1112px;
|
||||
background-position: -660px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_seaserpent {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -1112px;
|
||||
background-position: -1100px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sheep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px 0px;
|
||||
background-position: -880px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_slime {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -1112px;
|
||||
background-position: -220px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sloth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -1112px;
|
||||
background-position: -880px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -294,55 +318,55 @@
|
||||
}
|
||||
.quest_snake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1314px -1332px;
|
||||
background-position: -1322px -1112px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_spider {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1546px;
|
||||
background-position: -251px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_squirrel {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -660px;
|
||||
background-position: -660px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -745px;
|
||||
background-position: -1757px -721px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_stoikalmCalamity2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -220px;
|
||||
background-position: -660px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -220px;
|
||||
background-position: -660px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_taskwoodsTerror1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1047px;
|
||||
background-position: -1757px -1023px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_taskwoodsTerror2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -434px;
|
||||
background-position: -1540px -651px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_taskwoodsTerror3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -440px;
|
||||
background-position: 0px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -354,49 +378,25 @@
|
||||
}
|
||||
.quest_trex {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -175px;
|
||||
background-position: -1757px 0px;
|
||||
width: 204px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_trex_undead {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -663px -1332px;
|
||||
background-position: -880px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_triceratops {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -452px;
|
||||
background-position: -440px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_turtle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -452px;
|
||||
background-position: -880px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_unicorn {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_vice1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -1085px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_vice2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_vice3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user