Merge branch 'develop' into release
|
|
@ -14,7 +14,7 @@ files:
|
||||||
owner: root
|
owner: root
|
||||||
group: users
|
group: users
|
||||||
content: |
|
content: |
|
||||||
$(ls -td /opt/elasticbeanstalk/node-install/node-* | head -1)/bin/npm install -g npm@4
|
$(ls -td /opt/elasticbeanstalk/node-install/node-* | head -1)/bin/npm install -g npm@5
|
||||||
container_commands:
|
container_commands:
|
||||||
01_makeBabel:
|
01_makeBabel:
|
||||||
command: "touch /tmp/.babel.json"
|
command: "touch /tmp/.babel.json"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ addons:
|
||||||
- g++-4.8
|
- g++-4.8
|
||||||
before_install:
|
before_install:
|
||||||
- $CXX --version
|
- $CXX --version
|
||||||
- npm install -g npm@4
|
- npm install -g npm@5
|
||||||
- if [ $REQUIRES_SERVER ]; then sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10; echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list; sudo apt-get update; sudo apt-get install mongodb-org-server; fi
|
- if [ $REQUIRES_SERVER ]; then sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10; echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list; sudo apt-get update; sudo apt-get install mongodb-org-server; fi
|
||||||
install:
|
install:
|
||||||
- npm install &> npm.install.log || (cat npm.install.log; false)
|
- npm install &> npm.install.log || (cat npm.install.log; false)
|
||||||
|
|
@ -34,6 +34,5 @@ env:
|
||||||
- TEST="test:sanity"
|
- TEST="test:sanity"
|
||||||
- TEST="test:content" COVERAGE=true
|
- TEST="test:content" COVERAGE=true
|
||||||
- TEST="test:common" COVERAGE=true
|
- TEST="test:common" COVERAGE=true
|
||||||
- TEST="test:karma" COVERAGE=true
|
|
||||||
- TEST="client:unit" COVERAGE=true
|
- TEST="client:unit" COVERAGE=true
|
||||||
- TEST="apidoc"
|
- TEST="apidoc"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
FROM node:boron
|
FROM node:boron
|
||||||
|
|
||||||
|
# Upgrade NPM to v5 (Yarn is needed because of this bug https://github.com/npm/npm/issues/16807)
|
||||||
|
# The used solution is suggested here https://github.com/npm/npm/issues/16807#issuecomment-313591975
|
||||||
|
RUN yarn global add npm@5
|
||||||
# Install global packages
|
# Install global packages
|
||||||
RUN npm install -g gulp grunt-cli bower mocha
|
RUN npm install -g gulp grunt-cli bower mocha
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
FROM node:boron
|
FROM node:boron
|
||||||
|
|
||||||
|
# Upgrade NPM to v5 (Yarn is needed because of this bug https://github.com/npm/npm/issues/16807)
|
||||||
|
# The used solution is suggested here https://github.com/npm/npm/issues/16807#issuecomment-313591975
|
||||||
|
RUN yarn global add npm@5
|
||||||
# Install global packages
|
# Install global packages
|
||||||
RUN npm install -g gulp grunt-cli bower mocha
|
RUN npm install -g gulp grunt-cli bower mocha
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import gulp from 'gulp';
|
import gulp from 'gulp';
|
||||||
import runSequence from 'run-sequence';
|
import runSequence from 'run-sequence';
|
||||||
import babel from 'gulp-babel';
|
import babel from 'gulp-babel';
|
||||||
|
import webpackProductionBuild from '../webpack/build';
|
||||||
require('gulp-grunt')(gulp);
|
require('gulp-grunt')(gulp);
|
||||||
|
|
||||||
gulp.task('build', () => {
|
gulp.task('build', () => {
|
||||||
|
|
@ -25,6 +26,14 @@ gulp.task('build:common', () => {
|
||||||
|
|
||||||
gulp.task('build:server', ['build:src', 'build:common']);
|
gulp.task('build:server', ['build:src', 'build:common']);
|
||||||
|
|
||||||
|
// Client Production Build
|
||||||
|
gulp.task('build:client', ['bootstrap'], (done) => {
|
||||||
|
webpackProductionBuild((err, output) => {
|
||||||
|
if (err) return done(err);
|
||||||
|
console.log(output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('build:dev', ['browserify', 'prepare:staticNewStuff'], (done) => {
|
gulp.task('build:dev', ['browserify', 'prepare:staticNewStuff'], (done) => {
|
||||||
gulp.start('grunt-build:dev', done);
|
gulp.start('grunt-build:dev', done);
|
||||||
});
|
});
|
||||||
|
|
@ -33,7 +42,12 @@ gulp.task('build:dev:watch', ['build:dev'], () => {
|
||||||
gulp.watch(['website/client-old/**/*.styl', 'website/common/script/*']);
|
gulp.watch(['website/client-old/**/*.styl', 'website/common/script/*']);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build:prod', ['browserify', 'build:server', 'prepare:staticNewStuff'], (done) => {
|
gulp.task('build:prod', [
|
||||||
|
'browserify',
|
||||||
|
'build:server',
|
||||||
|
'prepare:staticNewStuff',
|
||||||
|
'build:client',
|
||||||
|
], (done) => {
|
||||||
runSequence(
|
runSequence(
|
||||||
'grunt-build:prod',
|
'grunt-build:prod',
|
||||||
'apidoc',
|
'apidoc',
|
||||||
|
|
|
||||||
97
migrations/20170928_redesign_guilds.js
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
var migrationName = '20170928_redesign_guilds.js';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy Guild Leader messages to end of Guild descriptions
|
||||||
|
* Copy Guild logos to beginning of Guild descriptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
var monk = require('monk');
|
||||||
|
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
|
var dbGroups = monk(connectionString).get('groups', { castIds: false });
|
||||||
|
|
||||||
|
function processGroups(lastId) {
|
||||||
|
// specify a query to limit the affected groups (empty for all groups):
|
||||||
|
var query = {
|
||||||
|
};
|
||||||
|
|
||||||
|
var fields = {
|
||||||
|
'description': 1,
|
||||||
|
'logo': 1,
|
||||||
|
'leaderMessage': 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastId) {
|
||||||
|
query._id = {
|
||||||
|
$gt: lastId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbGroups.find(query, {
|
||||||
|
fields: fields,
|
||||||
|
sort: {_id: 1},
|
||||||
|
limit: 250,
|
||||||
|
})
|
||||||
|
.then(updateGroups)
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
return exiting(1, 'ERROR! ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function updateGroups (groups) {
|
||||||
|
if (!groups || groups.length === 0) {
|
||||||
|
console.warn('All appropriate groups found and modified.');
|
||||||
|
displayData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var groupPromises = groups.map(updateGroup);
|
||||||
|
var lastGroup = groups[groups.length - 1];
|
||||||
|
|
||||||
|
return Promise.all(groupPromises)
|
||||||
|
.then(function () {
|
||||||
|
processGroups(lastGroup._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGroup (group) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
var description = group.description;
|
||||||
|
|
||||||
|
if (group.logo) {
|
||||||
|
description = '\n\n \n\n' + description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.leaderMessage) {
|
||||||
|
description = description + '\n\n \n\n' + group.leaderMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
var set = {
|
||||||
|
description: description,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (count % progressCount == 0) console.warn(count + ' ' + group._id);
|
||||||
|
|
||||||
|
return dbGroups.update({_id: group._id}, {$set:set});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayData() {
|
||||||
|
console.warn('\n' + count + ' groups 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 = processGroups;
|
||||||
127
migrations/20170928_redesign_launch.js
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
var updateStore = require('../website/common/script/libs/updateStore');
|
||||||
|
var getItemInfo = require('../website/common/script/libs/getItemInfo');
|
||||||
|
|
||||||
|
var migrationName = '20170928_redesign_launch.js';
|
||||||
|
var authorName = 'paglias'; // in case script author needs to know when their ...
|
||||||
|
var authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; //... own data is done
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Migrate existing in app rewards lists to pinned items
|
||||||
|
* Award Veteran Pets
|
||||||
|
*/
|
||||||
|
|
||||||
|
var monk = require('monk');
|
||||||
|
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
|
var dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||||
|
|
||||||
|
function processUsers(lastId) {
|
||||||
|
// specify a query to limit the affected users (empty for all users):
|
||||||
|
var query = {
|
||||||
|
'migration': {$ne:migrationName},
|
||||||
|
'auth.timestamps.loggedin': {$gt: new Date('2017-09-21')},
|
||||||
|
};
|
||||||
|
|
||||||
|
var fields = {
|
||||||
|
'items.pets': 1,
|
||||||
|
'items.gear': 1,
|
||||||
|
'stats.class': 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastId) {
|
||||||
|
query._id = {
|
||||||
|
$gt: lastId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbUsers.find(query, {
|
||||||
|
fields: fields,
|
||||||
|
sort: {_id: 1},
|
||||||
|
limit: 250,
|
||||||
|
})
|
||||||
|
.then(updateUsers)
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
return exiting(1, 'ERROR! ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function updateUsers (users) {
|
||||||
|
if (!users || users.length === 0) {
|
||||||
|
console.warn('All appropriate users found and modified.');
|
||||||
|
displayData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userPromises = users.map(updateUser);
|
||||||
|
var lastUser = users[users.length - 1];
|
||||||
|
|
||||||
|
return Promise.all(userPromises)
|
||||||
|
.then(function () {
|
||||||
|
processUsers(lastUser._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUser (user) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
var set = {'migration': migrationName};
|
||||||
|
|
||||||
|
var oldRewardsList = updateStore(user);
|
||||||
|
var newPinnedItems = [
|
||||||
|
{
|
||||||
|
type: 'armoire',
|
||||||
|
path: 'armoire',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'potion',
|
||||||
|
path: 'potion',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
oldRewardsList.forEach(item => {
|
||||||
|
var type = 'marketGear';
|
||||||
|
|
||||||
|
var itemInfo = getItemInfo(user, 'marketGear', item);
|
||||||
|
newPinnedItems.push({
|
||||||
|
type,
|
||||||
|
path: itemInfo.path,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
set.pinnedItems = newPinnedItems;
|
||||||
|
|
||||||
|
if (user.items.pets['Lion-Veteran']) {
|
||||||
|
set['items.pets.Bear-Veteran'] = 5;
|
||||||
|
} else if (user.items.pets['Tiger-Veteran']) {
|
||||||
|
set['items.pets.Lion-Veteran'] = 5;
|
||||||
|
} else if (user.items.pets['Wolf-Veteran']) {
|
||||||
|
set['items.pets.Tiger-Veteran'] = 5;
|
||||||
|
} else {
|
||||||
|
set['items.pets.Wolf-Veteran'] = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count % progressCount == 0) console.warn(count + ' ' + user._id);
|
||||||
|
if (user._id == authorUuid) console.warn(authorName + ' processed');
|
||||||
|
|
||||||
|
return dbUsers.update({_id: user._id}, {$set:set});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
98
migrations/s3-upload.js
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
let Bluebird = require('bluebird');
|
||||||
|
let request = require('superagent');
|
||||||
|
let last = require('lodash/last');
|
||||||
|
let AWS = require('aws-sdk');
|
||||||
|
|
||||||
|
let config = require('../config');
|
||||||
|
const S3_DIRECTORY = 'mobileApp/images'; //config.S3.SPRITES_DIRECTORY;
|
||||||
|
|
||||||
|
AWS.config.update({
|
||||||
|
accessKeyId: config.S3.accessKeyId,
|
||||||
|
secretAccessKey: config.S3.secretAccessKey,
|
||||||
|
// region: config.get('S3_REGION'),
|
||||||
|
});
|
||||||
|
|
||||||
|
let BUCKET_NAME = config.S3.bucket;
|
||||||
|
let s3 = new AWS.S3();
|
||||||
|
|
||||||
|
// Adapted from http://stackoverflow.com/a/22210077/2601552
|
||||||
|
function uploadFile (buffer, fileName) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
s3.putObject({
|
||||||
|
Body: buffer,
|
||||||
|
Key: fileName,
|
||||||
|
Bucket: BUCKET_NAME,
|
||||||
|
}, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
// console.info(`${fileName} uploaded to ${BUCKET_NAME} succesfully.`);
|
||||||
|
resolve(fileName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileName (file) {
|
||||||
|
let piecesOfPath = file.split('/');
|
||||||
|
let name = last(piecesOfPath);
|
||||||
|
let fullName = S3_DIRECTORY + name;
|
||||||
|
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileFromUrl (url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request.get(url).end((err, res) => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
let file = res.body;
|
||||||
|
resolve(file);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let commit = '78f94e365c72cc58f66857d5941105638db7d35c';
|
||||||
|
commit = 'df0dbaba636c9ce424cc7040f7bd7fc1aa311015';
|
||||||
|
let gihuburl = `https://api.github.com/repos/HabitRPG/habitica/commits/${commit}`
|
||||||
|
|
||||||
|
|
||||||
|
let currentIndex = 0;
|
||||||
|
|
||||||
|
function uploadToS3(start, end, filesUrls) {
|
||||||
|
let urls = filesUrls.slice(start, end);
|
||||||
|
|
||||||
|
if (urls.length === 0) {
|
||||||
|
console.log("done");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let promises = urls.map(fullUrl => {
|
||||||
|
return getFileFromUrl(fullUrl)
|
||||||
|
.then((buffer) => {
|
||||||
|
return uploadFile(buffer, getFileName(fullUrl));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
console.log(promises.length)
|
||||||
|
|
||||||
|
return Bluebird.all(promises)
|
||||||
|
.then(() => {
|
||||||
|
currentIndex += 50;
|
||||||
|
uploadToS3(currentIndex, currentIndex + 50, filesUrls);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
request.get(gihuburl)
|
||||||
|
.end((err, res) => {
|
||||||
|
console.log(err);
|
||||||
|
let files = res.body.files;
|
||||||
|
|
||||||
|
let filesUrls = [''];
|
||||||
|
filesUrls = files.map(file => {
|
||||||
|
return file.raw_url;
|
||||||
|
})
|
||||||
|
|
||||||
|
uploadToS3(currentIndex, currentIndex + 50, filesUrls);
|
||||||
|
});
|
||||||
13885
npm-shrinkwrap.json
generated
21115
package-lock.json
generated
Normal file
25
package.json
|
|
@ -30,14 +30,15 @@
|
||||||
"bcrypt": "^1.0.2",
|
"bcrypt": "^1.0.2",
|
||||||
"bluebird": "^3.3.5",
|
"bluebird": "^3.3.5",
|
||||||
"body-parser": "^1.15.0",
|
"body-parser": "^1.15.0",
|
||||||
"bootstrap": "^4.0.0-alpha.6",
|
"bootstrap": "4.0.0-alpha.6",
|
||||||
"bootstrap-vue": "^0.18.0",
|
"bootstrap-vue": "^1.0.0-beta.6",
|
||||||
"bower": "~1.3.12",
|
"bower": "~1.3.12",
|
||||||
"browserify": "~12.0.1",
|
"browserify": "~12.0.1",
|
||||||
"compression": "^1.6.1",
|
"compression": "^1.6.1",
|
||||||
"connect-ratelimit": "0.0.7",
|
"connect-ratelimit": "0.0.7",
|
||||||
"cookie-session": "^1.2.0",
|
"cookie-session": "^1.2.0",
|
||||||
"coupon-code": "^0.4.5",
|
"coupon-code": "^0.4.5",
|
||||||
|
"cross-env": "^4.0.0",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
"csv-stringify": "^1.0.2",
|
"csv-stringify": "^1.0.2",
|
||||||
"cwait": "~1.0.1",
|
"cwait": "~1.0.1",
|
||||||
|
|
@ -59,7 +60,7 @@
|
||||||
"grunt-contrib-stylus": "~0.20.0",
|
"grunt-contrib-stylus": "~0.20.0",
|
||||||
"grunt-contrib-uglify": "~0.6.0",
|
"grunt-contrib-uglify": "~0.6.0",
|
||||||
"grunt-contrib-watch": "~0.6.1",
|
"grunt-contrib-watch": "~0.6.1",
|
||||||
"grunt-hashres": "habitrpg/grunt-hashres#v0.4.2",
|
"grunt-hashres": "git://github.com/habitrpg/grunt-hashres#dc85db6d3002e29e1b7c5ee186b80d708d2f0e0b",
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^3.9.0",
|
||||||
"gulp-babel": "^6.1.2",
|
"gulp-babel": "^6.1.2",
|
||||||
"gulp-grunt": "^0.5.2",
|
"gulp-grunt": "^0.5.2",
|
||||||
|
|
@ -75,13 +76,13 @@
|
||||||
"in-app-purchase": "^1.1.6",
|
"in-app-purchase": "^1.1.6",
|
||||||
"intro.js": "^2.6.0",
|
"intro.js": "^2.6.0",
|
||||||
"jade": "~1.11.0",
|
"jade": "~1.11.0",
|
||||||
"jquery": "^3.1.1",
|
"jquery": ">=3.0.0",
|
||||||
"js2xmlparser": "~1.0.0",
|
"js2xmlparser": "~1.0.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"merge-stream": "^1.0.0",
|
"merge-stream": "^1.0.0",
|
||||||
"method-override": "^2.3.5",
|
"method-override": "^2.3.5",
|
||||||
"moment": "^2.13.0",
|
"moment": "^2.13.0",
|
||||||
"moment-recur": "habitrpg/moment-recur#v1.0.6",
|
"moment-recur": "git://github.com/habitrpg/moment-recur#f147ef27bbc26ca67638385f3db4a44084c76626",
|
||||||
"mongoose": "~4.8.6",
|
"mongoose": "~4.8.6",
|
||||||
"mongoose-id-autoinc": "~2013.7.14-4",
|
"mongoose-id-autoinc": "~2013.7.14-4",
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
|
|
@ -98,11 +99,12 @@
|
||||||
"passport-google-oauth20": "1.0.0",
|
"passport-google-oauth20": "1.0.0",
|
||||||
"paypal-ipn": "3.0.0",
|
"paypal-ipn": "3.0.0",
|
||||||
"paypal-rest-sdk": "^1.2.1",
|
"paypal-rest-sdk": "^1.2.1",
|
||||||
|
"popper.js": "^1.11.0",
|
||||||
"postcss-easy-import": "^2.0.0",
|
"postcss-easy-import": "^2.0.0",
|
||||||
"pretty-data": "^0.40.0",
|
"pretty-data": "^0.40.0",
|
||||||
"ps-tree": "^1.0.0",
|
"ps-tree": "^1.0.0",
|
||||||
"pug": "^2.0.0-beta.12",
|
"pug": "^2.0.0-beta.12",
|
||||||
"push-notify": "habitrpg/push-notify#v1.2.0",
|
"push-notify": "git://github.com/habitrpg/push-notify#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
|
||||||
"pusher": "^1.3.0",
|
"pusher": "^1.3.0",
|
||||||
"request": "~2.74.0",
|
"request": "~2.74.0",
|
||||||
"rimraf": "^2.4.3",
|
"rimraf": "^2.4.3",
|
||||||
|
|
@ -111,6 +113,7 @@
|
||||||
"sass-loader": "^6.0.2",
|
"sass-loader": "^6.0.2",
|
||||||
"serve-favicon": "^2.3.0",
|
"serve-favicon": "^2.3.0",
|
||||||
"shelljs": "^0.7.6",
|
"shelljs": "^0.7.6",
|
||||||
|
"sortablejs": "^1.6.1",
|
||||||
"stripe": "^4.2.0",
|
"stripe": "^4.2.0",
|
||||||
"superagent": "^3.4.3",
|
"superagent": "^3.4.3",
|
||||||
"svg-inline-loader": "^0.7.1",
|
"svg-inline-loader": "^0.7.1",
|
||||||
|
|
@ -126,11 +129,10 @@
|
||||||
"vue": "^2.1.0",
|
"vue": "^2.1.0",
|
||||||
"vue-loader": "^11.0.0",
|
"vue-loader": "^11.0.0",
|
||||||
"vue-mugen-scroll": "^0.2.1",
|
"vue-mugen-scroll": "^0.2.1",
|
||||||
"vue-notification": "^1.3.2",
|
|
||||||
"vue-router": "^2.0.0-rc.5",
|
"vue-router": "^2.0.0-rc.5",
|
||||||
"vue-style-loader": "^3.0.0",
|
"vue-style-loader": "^3.0.0",
|
||||||
"vue-template-compiler": "^2.1.10",
|
"vue-template-compiler": "^2.1.10",
|
||||||
"vuejs-datepicker": "^0.9.4",
|
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker#45e607a7bccf4e3e089761b3b7b33e3f2c5dc21f",
|
||||||
"webpack": "^2.2.1",
|
"webpack": "^2.2.1",
|
||||||
"webpack-merge": "^4.0.0",
|
"webpack-merge": "^4.0.0",
|
||||||
"winston": "^2.1.0",
|
"winston": "^2.1.0",
|
||||||
|
|
@ -140,7 +142,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^6.9.1",
|
"node": "^6.9.1",
|
||||||
"npm": "^4.0.2"
|
"npm": "^5.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint --ext .js,.vue .",
|
"lint": "eslint --ext .js,.vue .",
|
||||||
|
|
@ -162,13 +164,13 @@
|
||||||
"coverage": "COVERAGE=true mocha --require register-handlers.js --reporter html-cov > coverage.html; open coverage.html",
|
"coverage": "COVERAGE=true mocha --require register-handlers.js --reporter html-cov > coverage.html; open coverage.html",
|
||||||
"sprites": "gulp sprites:compile",
|
"sprites": "gulp sprites:compile",
|
||||||
"client:dev": "gulp bootstrap && node webpack/dev-server.js",
|
"client:dev": "gulp bootstrap && node webpack/dev-server.js",
|
||||||
"client:build": "gulp bootstrap && node webpack/build.js",
|
"client:build": "gulp build:client",
|
||||||
"client:unit": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js --single-run",
|
"client:unit": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js --single-run",
|
||||||
"client:unit:watch": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js",
|
"client:unit:watch": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js",
|
||||||
"client:e2e": "node test/client/e2e/runner.js",
|
"client:e2e": "node test/client/e2e/runner.js",
|
||||||
"client:test": "npm run client:unit && npm run client:e2e",
|
"client:test": "npm run client:unit && npm run client:e2e",
|
||||||
"start": "gulp run:dev",
|
"start": "gulp run:dev",
|
||||||
"postinstall": "bower --config.interactive=false install -f && gulp build && npm run client:build",
|
"postinstall": "gulp build",
|
||||||
"apidoc": "gulp apidoc"
|
"apidoc": "gulp apidoc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -179,7 +181,6 @@
|
||||||
"chromedriver": "^2.27.2",
|
"chromedriver": "^2.27.2",
|
||||||
"connect-history-api-fallback": "^1.1.0",
|
"connect-history-api-fallback": "^1.1.0",
|
||||||
"coveralls": "^2.11.2",
|
"coveralls": "^2.11.2",
|
||||||
"cross-env": "^4.0.0",
|
|
||||||
"cross-spawn": "^5.0.1",
|
"cross-spawn": "^5.0.1",
|
||||||
"csv": "~0.3.6",
|
"csv": "~0.3.6",
|
||||||
"deep-diff": "~0.1.4",
|
"deep-diff": "~0.1.4",
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,10 @@ describe('GET /challenges/:challengeId', () => {
|
||||||
});
|
});
|
||||||
expect(chal.group).to.eql({
|
expect(chal.group).to.eql({
|
||||||
_id: group._id,
|
_id: group._id,
|
||||||
|
categories: [],
|
||||||
id: group.id,
|
id: group.id,
|
||||||
name: group.name,
|
name: group.name,
|
||||||
|
summary: group.name,
|
||||||
type: group.type,
|
type: group.type,
|
||||||
privacy: group.privacy,
|
privacy: group.privacy,
|
||||||
leader: groupLeader.id,
|
leader: groupLeader.id,
|
||||||
|
|
@ -100,8 +102,10 @@ describe('GET /challenges/:challengeId', () => {
|
||||||
});
|
});
|
||||||
expect(chal.group).to.eql({
|
expect(chal.group).to.eql({
|
||||||
_id: group._id,
|
_id: group._id,
|
||||||
|
categories: [],
|
||||||
id: group.id,
|
id: group.id,
|
||||||
name: group.name,
|
name: group.name,
|
||||||
|
summary: group.name,
|
||||||
type: group.type,
|
type: group.type,
|
||||||
privacy: group.privacy,
|
privacy: group.privacy,
|
||||||
leader: groupLeader.id,
|
leader: groupLeader.id,
|
||||||
|
|
@ -153,7 +157,9 @@ describe('GET /challenges/:challengeId', () => {
|
||||||
expect(chal.group).to.eql({
|
expect(chal.group).to.eql({
|
||||||
_id: group._id,
|
_id: group._id,
|
||||||
id: group.id,
|
id: group.id,
|
||||||
|
categories: [],
|
||||||
name: group.name,
|
name: group.name,
|
||||||
|
summary: group.name,
|
||||||
type: group.type,
|
type: group.type,
|
||||||
privacy: group.privacy,
|
privacy: group.privacy,
|
||||||
leader: groupLeader.id,
|
leader: groupLeader.id,
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,12 @@ describe('GET challenges/user', () => {
|
||||||
});
|
});
|
||||||
expect(foundChallenge.group).to.eql({
|
expect(foundChallenge.group).to.eql({
|
||||||
_id: publicGuild._id,
|
_id: publicGuild._id,
|
||||||
|
categories: [],
|
||||||
id: publicGuild._id,
|
id: publicGuild._id,
|
||||||
type: publicGuild.type,
|
type: publicGuild.type,
|
||||||
privacy: publicGuild.privacy,
|
privacy: publicGuild.privacy,
|
||||||
name: publicGuild.name,
|
name: publicGuild.name,
|
||||||
|
summary: publicGuild.name,
|
||||||
leader: publicGuild.leader._id,
|
leader: publicGuild.leader._id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -61,10 +63,12 @@ describe('GET challenges/user', () => {
|
||||||
});
|
});
|
||||||
expect(foundChallenge1.group).to.eql({
|
expect(foundChallenge1.group).to.eql({
|
||||||
_id: publicGuild._id,
|
_id: publicGuild._id,
|
||||||
|
categories: [],
|
||||||
id: publicGuild._id,
|
id: publicGuild._id,
|
||||||
type: publicGuild.type,
|
type: publicGuild.type,
|
||||||
privacy: publicGuild.privacy,
|
privacy: publicGuild.privacy,
|
||||||
name: publicGuild.name,
|
name: publicGuild.name,
|
||||||
|
summary: publicGuild.name,
|
||||||
leader: publicGuild.leader._id,
|
leader: publicGuild.leader._id,
|
||||||
});
|
});
|
||||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||||
|
|
@ -76,10 +80,12 @@ describe('GET challenges/user', () => {
|
||||||
});
|
});
|
||||||
expect(foundChallenge2.group).to.eql({
|
expect(foundChallenge2.group).to.eql({
|
||||||
_id: publicGuild._id,
|
_id: publicGuild._id,
|
||||||
|
categories: [],
|
||||||
id: publicGuild._id,
|
id: publicGuild._id,
|
||||||
type: publicGuild.type,
|
type: publicGuild.type,
|
||||||
privacy: publicGuild.privacy,
|
privacy: publicGuild.privacy,
|
||||||
name: publicGuild.name,
|
name: publicGuild.name,
|
||||||
|
summary: publicGuild.name,
|
||||||
leader: publicGuild.leader._id,
|
leader: publicGuild.leader._id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -96,10 +102,12 @@ describe('GET challenges/user', () => {
|
||||||
});
|
});
|
||||||
expect(foundChallenge1.group).to.eql({
|
expect(foundChallenge1.group).to.eql({
|
||||||
_id: publicGuild._id,
|
_id: publicGuild._id,
|
||||||
|
categories: [],
|
||||||
id: publicGuild._id,
|
id: publicGuild._id,
|
||||||
type: publicGuild.type,
|
type: publicGuild.type,
|
||||||
privacy: publicGuild.privacy,
|
privacy: publicGuild.privacy,
|
||||||
name: publicGuild.name,
|
name: publicGuild.name,
|
||||||
|
summary: publicGuild.name,
|
||||||
leader: publicGuild.leader._id,
|
leader: publicGuild.leader._id,
|
||||||
});
|
});
|
||||||
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||||
|
|
@ -111,14 +119,26 @@ describe('GET challenges/user', () => {
|
||||||
});
|
});
|
||||||
expect(foundChallenge2.group).to.eql({
|
expect(foundChallenge2.group).to.eql({
|
||||||
_id: publicGuild._id,
|
_id: publicGuild._id,
|
||||||
|
categories: [],
|
||||||
id: publicGuild._id,
|
id: publicGuild._id,
|
||||||
type: publicGuild.type,
|
type: publicGuild.type,
|
||||||
privacy: publicGuild.privacy,
|
privacy: publicGuild.privacy,
|
||||||
name: publicGuild.name,
|
name: publicGuild.name,
|
||||||
|
summary: publicGuild.name,
|
||||||
leader: publicGuild.leader._id,
|
leader: publicGuild.leader._id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return not return challenges in user groups if we send member true param', async () => {
|
||||||
|
let challenges = await member.get(`/challenges/user?member=${true}`);
|
||||||
|
|
||||||
|
let foundChallenge1 = _.find(challenges, { _id: challenge._id });
|
||||||
|
expect(foundChallenge1).to.not.exist;
|
||||||
|
|
||||||
|
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
|
||||||
|
expect(foundChallenge2).to.not.exist;
|
||||||
|
});
|
||||||
|
|
||||||
it('should return newest challenges first', async () => {
|
it('should return newest challenges first', async () => {
|
||||||
let challenges = await user.get('/challenges/user');
|
let challenges = await user.get('/challenges/user');
|
||||||
|
|
||||||
|
|
@ -137,6 +157,7 @@ describe('GET challenges/user', () => {
|
||||||
let { group, groupLeader } = await createAndPopulateGroup({
|
let { group, groupLeader } = await createAndPopulateGroup({
|
||||||
groupDetails: {
|
groupDetails: {
|
||||||
name: 'TestPrivateGuild',
|
name: 'TestPrivateGuild',
|
||||||
|
summary: 'summary for TestPrivateGuild',
|
||||||
type: 'guild',
|
type: 'guild',
|
||||||
privacy: 'private',
|
privacy: 'private',
|
||||||
},
|
},
|
||||||
|
|
@ -158,6 +179,7 @@ describe('GET challenges/user', () => {
|
||||||
let { group, groupLeader } = await createAndPopulateGroup({
|
let { group, groupLeader } = await createAndPopulateGroup({
|
||||||
groupDetails: {
|
groupDetails: {
|
||||||
name: 'TestGuild',
|
name: 'TestGuild',
|
||||||
|
summary: 'summary for TestGuild',
|
||||||
type: 'guild',
|
type: 'guild',
|
||||||
privacy: 'public',
|
privacy: 'public',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ describe('POST /chat', () => {
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
author_name: `${user.profile.name} - ${user.auth.local.email} - ${user._id}`,
|
author_name: `${user.profile.name} - ${user.auth.local.email} - ${user._id}`,
|
||||||
title: 'Slur in Test Guild',
|
title: 'Slur in Test Guild',
|
||||||
title_link: `${BASE_URL}/#/options/groups/guilds/${groupWithChat.id}`,
|
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
|
||||||
text: testSlurMessage,
|
text: testSlurMessage,
|
||||||
// footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
|
// footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
|
||||||
mrkdwn_in: [
|
mrkdwn_in: [
|
||||||
|
|
|
||||||
32
test/api/v3/integration/groups/GET-group-plans.test.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
} from '../../../../helpers/api-v3-integration.helper';
|
||||||
|
|
||||||
|
describe('GET /group-plans', () => {
|
||||||
|
let user;
|
||||||
|
let groupPlan;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
user = await generateUser({balance: 4});
|
||||||
|
groupPlan = await generateGroup(user,
|
||||||
|
{
|
||||||
|
name: 'public guild - is member',
|
||||||
|
type: 'guild',
|
||||||
|
privacy: 'public',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
purchased: {
|
||||||
|
plan: {
|
||||||
|
customerId: 'existings',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns group plans for the user', async () => {
|
||||||
|
let groupPlans = await user.get('/group-plans');
|
||||||
|
|
||||||
|
expect(groupPlans[0]._id).to.eql(groupPlan._id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -6,7 +6,7 @@ import superagent from 'superagent';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
|
|
||||||
const API_TEST_SERVER_PORT = nconf.get('PORT');
|
const API_TEST_SERVER_PORT = nconf.get('PORT');
|
||||||
describe('GET /qr-code/user/:memberId', () => {
|
xdescribe('GET /qr-code/user/:memberId', () => {
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ describe('GET /tasks/user', () => {
|
||||||
it('returns all user\'s tasks', async () => {
|
it('returns all user\'s tasks', async () => {
|
||||||
let createdTasks = await user.post('/tasks/user', [{text: 'test habit', type: 'habit'}, {text: 'test todo', type: 'todo'}]);
|
let createdTasks = await user.post('/tasks/user', [{text: 'test habit', type: 'habit'}, {text: 'test todo', type: 'todo'}]);
|
||||||
let tasks = await user.get('/tasks/user');
|
let tasks = await user.get('/tasks/user');
|
||||||
expect(tasks.length).to.equal(createdTasks.length + 1); // + 1 because 1 is a default task
|
expect(tasks.length).to.equal(createdTasks.length + 1); // Plus one for generated todo
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns only a type of user\'s tasks if req.query.type is specified', async () => {
|
it('returns only a type of user\'s tasks if req.query.type is specified', async () => {
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ describe('POST /tasks/unlink-all/:challengeId', () => {
|
||||||
// Have the leader delete the challenge and unlink the tasks
|
// Have the leader delete the challenge and unlink the tasks
|
||||||
await user.del(`/challenges/${challenge._id}`);
|
await user.del(`/challenges/${challenge._id}`);
|
||||||
await user.post(`/tasks/unlink-all/${challenge._id}?keep=keep-all`);
|
await user.post(`/tasks/unlink-all/${challenge._id}?keep=keep-all`);
|
||||||
// Get the second task for the second user
|
// Get the task for the second user
|
||||||
const [, anotherUserTask] = await anotherUser.get('/tasks/user');
|
const [, anotherUserTask] = await anotherUser.get('/tasks/user');
|
||||||
// Expect the second user to still have the task, but unlinked
|
// Expect the second user to still have the task, but unlinked
|
||||||
expect(anotherUserTask.challenge).to.eql({
|
expect(anotherUserTask.challenge).to.eql({
|
||||||
|
|
@ -106,4 +106,4 @@ describe('POST /tasks/unlink-all/:challengeId', () => {
|
||||||
winner: null,
|
winner: null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ describe('POST /tasks/user', () => {
|
||||||
expect(task.updatedAt).not.to.equal('tomorrow');
|
expect(task.updatedAt).not.to.equal('tomorrow');
|
||||||
expect(task.challenge).not.to.equal('no');
|
expect(task.challenge).not.to.equal('no');
|
||||||
expect(task.completed).to.equal(false);
|
expect(task.completed).to.equal(false);
|
||||||
expect(task.streak).not.to.equal('never');
|
expect(task.dateCompleted).not.to.equal('never');
|
||||||
expect(task.value).not.to.equal(324);
|
expect(task.value).not.to.equal(324);
|
||||||
expect(task.yesterDaily).to.equal(true);
|
expect(task.yesterDaily).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,12 @@ describe('DELETE /user', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deletes the user\'s tasks', async () => {
|
it('deletes the user\'s tasks', async () => {
|
||||||
|
await user.post('/tasks/user', {
|
||||||
|
text: 'test habit',
|
||||||
|
type: 'habit',
|
||||||
|
});
|
||||||
|
await user.sync();
|
||||||
|
|
||||||
// gets the user's tasks ids
|
// gets the user's tasks ids
|
||||||
let ids = [];
|
let ids = [];
|
||||||
each(user.tasksOrder, (idsForOrder) => {
|
each(user.tasksOrder, (idsForOrder) => {
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ describe('GET /user/anonymized', () => {
|
||||||
});
|
});
|
||||||
// tasks
|
// tasks
|
||||||
expect(tasks2).to.exist;
|
expect(tasks2).to.exist;
|
||||||
expect(tasks2.length).to.eql(5); // +1 because generateUser() assigns one todo
|
expect(tasks2.length).to.eql(5);
|
||||||
expect(tasks2[0].checklist).to.exist;
|
expect(tasks2[0].checklist).to.exist;
|
||||||
_.forEach(tasks2, (task) => {
|
_.forEach(tasks2, (task) => {
|
||||||
expect(task.text).to.eql('task text');
|
expect(task.text).to.eql('task text');
|
||||||
|
|
|
||||||
|
|
@ -10,43 +10,31 @@ import nconf from 'nconf';
|
||||||
|
|
||||||
const API_TEST_SERVER_PORT = nconf.get('PORT');
|
const API_TEST_SERVER_PORT = nconf.get('PORT');
|
||||||
|
|
||||||
describe('GET /user/auth/local/reset-password-set-new-one', () => {
|
// @TODO skipped because on travis the client isn't available and the redirect fails
|
||||||
|
xdescribe('GET /user/auth/local/reset-password-set-new-one', () => {
|
||||||
let endpoint = `http://localhost:${API_TEST_SERVER_PORT}/static/user/auth/local/reset-password-set-new-one`;
|
let endpoint = `http://localhost:${API_TEST_SERVER_PORT}/static/user/auth/local/reset-password-set-new-one`;
|
||||||
|
|
||||||
// Tests to validate the validatePasswordResetCodeAndFindUser function
|
// Tests to validate the validatePasswordResetCodeAndFindUser function
|
||||||
|
|
||||||
it('renders an error page if the code is missing', async () => {
|
it('renders an error page if the code is missing', async () => {
|
||||||
try {
|
const res = await superagent.get(endpoint);
|
||||||
await superagent.get(endpoint);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code is invalid json', async () => {
|
it('renders an error page if the code is invalid json', async () => {
|
||||||
try {
|
const res = await superagent.get(`${endpoint}?code=invalid`);
|
||||||
await superagent.get(`${endpoint}?code=invalid`);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code cannot be decrypted', async () => {
|
it('renders an error page if the code cannot be decrypted', async () => {
|
||||||
let user = await generateUser();
|
let user = await generateUser();
|
||||||
|
|
||||||
try {
|
let code = JSON.stringify({ // not encrypted
|
||||||
let code = JSON.stringify({ // not encrypted
|
userId: user._id,
|
||||||
userId: user._id,
|
expiresAt: new Date(),
|
||||||
expiresAt: new Date(),
|
});
|
||||||
});
|
const res = await superagent.get(`${endpoint}?code=${code}`);
|
||||||
await superagent.get(`${endpoint}?code=${code}`);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
|
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code is expired', async () => {
|
it('renders an error page if the code is expired', async () => {
|
||||||
|
|
@ -60,12 +48,8 @@ describe('GET /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
const res = await superagent.get(`${endpoint}?code=${code}`);
|
||||||
await superagent.get(`${endpoint}?code=${code}`);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the user does not exist', async () => {
|
it('renders an error page if the user does not exist', async () => {
|
||||||
|
|
@ -74,12 +58,8 @@ describe('GET /user/auth/local/reset-password-set-new-one', () => {
|
||||||
expiresAt: moment().add({days: 1}),
|
expiresAt: moment().add({days: 1}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
try {
|
const res = await superagent.get(`${endpoint}?code=${code}`);
|
||||||
await superagent.get(`${endpoint}?code=${code}`);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the user has no local auth', async () => {
|
it('renders an error page if the user has no local auth', async () => {
|
||||||
|
|
@ -93,12 +73,8 @@ describe('GET /user/auth/local/reset-password-set-new-one', () => {
|
||||||
auth: 'not an object with valid fields',
|
auth: 'not an object with valid fields',
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
const res = await superagent.get(`${endpoint}?code=${code}`);
|
||||||
await superagent.get(`${endpoint}?code=${code}`);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code doesn\'t match the one saved at user.auth.passwordResetCode', async () => {
|
it('renders an error page if the code doesn\'t match the one saved at user.auth.passwordResetCode', async () => {
|
||||||
|
|
@ -112,12 +88,8 @@ describe('GET /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': 'invalid',
|
'auth.local.passwordResetCode': 'invalid',
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
const res = await superagent.get(`${endpoint}?code=${code}`);
|
||||||
await superagent.get(`${endpoint}?code=${code}`);
|
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
|
||||||
throw new Error('Request should fail.');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -134,7 +106,8 @@ describe('GET /user/auth/local/reset-password-set-new-one', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
let res = await superagent.get(`${endpoint}?code=${code}`);
|
let res = await superagent.get(`${endpoint}?code=${code}`);
|
||||||
expect(res.status).to.equal(200);
|
expect(res.req.path.indexOf('hasError=false') !== -1).to.equal(true);
|
||||||
|
expect(res.req.path.indexOf('code=') !== -1).to.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,49 +10,46 @@ import {
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
|
requester,
|
||||||
|
translate as t,
|
||||||
} from '../../../../../helpers/api-integration/v3';
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
import superagent from 'superagent';
|
|
||||||
import nconf from 'nconf';
|
|
||||||
|
|
||||||
const API_TEST_SERVER_PORT = nconf.get('PORT');
|
describe('POST /user/auth/reset-password-set-new-one', () => {
|
||||||
|
const endpoint = '/user/auth/reset-password-set-new-one';
|
||||||
describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
const api = requester();
|
||||||
let endpoint = `http://localhost:${API_TEST_SERVER_PORT}/static/user/auth/local/reset-password-set-new-one`;
|
|
||||||
|
|
||||||
// Tests to validate the validatePasswordResetCodeAndFindUser function
|
// Tests to validate the validatePasswordResetCodeAndFindUser function
|
||||||
|
|
||||||
it('renders an error page if the code is missing', async () => {
|
it('renders an error page if the code is missing', async () => {
|
||||||
try {
|
await expect(api.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||||
await superagent.post(endpoint);
|
code: 401,
|
||||||
throw new Error('Request should fail.');
|
error: 'NotAuthorized',
|
||||||
} catch (err) {
|
message: t('invalidPasswordResetCode'),
|
||||||
expect(err.status).to.equal(401);
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code is invalid json', async () => {
|
it('renders an error page if the code is invalid json', async () => {
|
||||||
try {
|
await expect(api.post(`${endpoint}?code=invalid`)).to.eventually.be.rejected.and.eql({
|
||||||
await superagent.post(`${endpoint}?code=invalid`);
|
code: 401,
|
||||||
throw new Error('Request should fail.');
|
error: 'NotAuthorized',
|
||||||
} catch (err) {
|
message: t('invalidPasswordResetCode'),
|
||||||
expect(err.status).to.equal(401);
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code cannot be decrypted', async () => {
|
it('renders an error page if the code cannot be decrypted', async () => {
|
||||||
let user = await generateUser();
|
let user = await generateUser();
|
||||||
|
|
||||||
try {
|
let code = JSON.stringify({ // not encrypted
|
||||||
let code = JSON.stringify({ // not encrypted
|
userId: user._id,
|
||||||
userId: user._id,
|
expiresAt: new Date(),
|
||||||
expiresAt: new Date(),
|
});
|
||||||
});
|
|
||||||
await superagent.post(`${endpoint}?code=${code}`);
|
|
||||||
|
|
||||||
throw new Error('Request should fail.');
|
await expect(api.post(`${endpoint}`, {
|
||||||
} catch (err) {
|
code,
|
||||||
expect(err.status).to.equal(401);
|
})).to.eventually.be.rejected.and.eql({
|
||||||
}
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('invalidPasswordResetCode'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code is expired', async () => {
|
it('renders an error page if the code is expired', async () => {
|
||||||
|
|
@ -66,12 +63,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent.post(`${endpoint}?code=${code}`);
|
code,
|
||||||
throw new Error('Request should fail.');
|
})).to.eventually.be.rejected.and.eql({
|
||||||
} catch (err) {
|
code: 401,
|
||||||
expect(err.status).to.equal(401);
|
error: 'NotAuthorized',
|
||||||
}
|
message: t('invalidPasswordResetCode'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the user does not exist', async () => {
|
it('renders an error page if the user does not exist', async () => {
|
||||||
|
|
@ -80,12 +78,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
expiresAt: moment().add({days: 1}),
|
expiresAt: moment().add({days: 1}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent.post(`${endpoint}?code=${code}`);
|
code,
|
||||||
throw new Error('Request should fail.');
|
})).to.eventually.be.rejected.and.eql({
|
||||||
} catch (err) {
|
code: 401,
|
||||||
expect(err.status).to.equal(401);
|
error: 'NotAuthorized',
|
||||||
}
|
message: t('invalidPasswordResetCode'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the user has no local auth', async () => {
|
it('renders an error page if the user has no local auth', async () => {
|
||||||
|
|
@ -99,12 +98,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
auth: 'not an object with valid fields',
|
auth: 'not an object with valid fields',
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent.post(`${endpoint}?code=${code}`);
|
code,
|
||||||
throw new Error('Request should fail.');
|
})).to.eventually.be.rejected.and.eql({
|
||||||
} catch (err) {
|
code: 401,
|
||||||
expect(err.status).to.equal(401);
|
error: 'NotAuthorized',
|
||||||
}
|
message: t('invalidPasswordResetCode'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an error page if the code doesn\'t match the one saved at user.auth.passwordResetCode', async () => {
|
it('renders an error page if the code doesn\'t match the one saved at user.auth.passwordResetCode', async () => {
|
||||||
|
|
@ -118,12 +118,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': 'invalid',
|
'auth.local.passwordResetCode': 'invalid',
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent.post(`${endpoint}?code=${code}`);
|
code,
|
||||||
throw new Error('Request should fail.');
|
})).to.eventually.be.rejected.and.eql({
|
||||||
} catch (err) {
|
code: 401,
|
||||||
expect(err.status).to.equal(401);
|
error: 'NotAuthorized',
|
||||||
}
|
message: t('invalidPasswordResetCode'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -139,12 +140,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent.post(`${endpoint}?code=${code}`);
|
code,
|
||||||
throw new Error('Request should fail.');
|
})).to.eventually.be.rejected.and.eql({
|
||||||
} catch (err) {
|
code: 400,
|
||||||
expect(err.status).to.equal(401);
|
error: 'BadRequest',
|
||||||
}
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the error page if the password confirmation is missing', async () => {
|
it('renders the error page if the password confirmation is missing', async () => {
|
||||||
|
|
@ -158,14 +160,14 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent
|
newPassword: 'my new password',
|
||||||
.post(`${endpoint}?code=${code}`)
|
code,
|
||||||
.send({newPassword: 'my new password'});
|
})).to.eventually.be.rejected.and.eql({
|
||||||
throw new Error('Request should fail.');
|
code: 400,
|
||||||
} catch (err) {
|
error: 'BadRequest',
|
||||||
expect(err.status).to.equal(401);
|
message: t('invalidReqParams'),
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the error page if the password confirmation does not match', async () => {
|
it('renders the error page if the password confirmation does not match', async () => {
|
||||||
|
|
@ -179,17 +181,15 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await expect(api.post(`${endpoint}`, {
|
||||||
await superagent
|
newPassword: 'my new password',
|
||||||
.post(`${endpoint}?code=${code}`)
|
confirmPassword: 'not matching',
|
||||||
.send({
|
code,
|
||||||
newPassword: 'my new password',
|
})).to.eventually.be.rejected.and.eql({
|
||||||
confirmPassword: 'not matching',
|
code: 400,
|
||||||
});
|
error: 'BadRequest',
|
||||||
throw new Error('Request should fail.');
|
message: t('passwordConfirmationMatch'),
|
||||||
} catch (err) {
|
});
|
||||||
expect(err.status).to.equal(401);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the success page and save the user', async () => {
|
it('renders the success page and save the user', async () => {
|
||||||
|
|
@ -203,14 +203,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
let res = await superagent
|
let res = await api.post(`${endpoint}`, {
|
||||||
.post(`${endpoint}?code=${code}`)
|
newPassword: 'my new password',
|
||||||
.send({
|
confirmPassword: 'my new password',
|
||||||
newPassword: 'my new password',
|
code,
|
||||||
confirmPassword: 'my new password',
|
});
|
||||||
});
|
|
||||||
|
|
||||||
expect(res.status).to.equal(200);
|
expect(res.message).to.equal(t('passwordChangeSuccess'));
|
||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
expect(user.auth.local.passwordResetCode).to.equal(undefined);
|
expect(user.auth.local.passwordResetCode).to.equal(undefined);
|
||||||
|
|
@ -246,14 +245,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
|
||||||
'auth.local.passwordResetCode': code,
|
'auth.local.passwordResetCode': code,
|
||||||
});
|
});
|
||||||
|
|
||||||
let res = await superagent
|
let res = await api.post(`${endpoint}`, {
|
||||||
.post(`${endpoint}?code=${code}`)
|
newPassword: 'my new password',
|
||||||
.send({
|
confirmPassword: 'my new password',
|
||||||
newPassword: 'my new password',
|
code,
|
||||||
confirmPassword: 'my new password',
|
});
|
||||||
});
|
|
||||||
|
|
||||||
expect(res.status).to.equal(200);
|
expect(res.message).to.equal(t('passwordChangeSuccess'));
|
||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
expect(user.auth.local.passwordResetCode).to.equal(undefined);
|
expect(user.auth.local.passwordResetCode).to.equal(undefined);
|
||||||
|
|
|
||||||
|
|
@ -59,13 +59,8 @@ describe('POST /user/auth/local/register', () => {
|
||||||
let tags = await requests.get('/tags');
|
let tags = await requests.get('/tags');
|
||||||
|
|
||||||
expect(habits).to.have.a.lengthOf(0);
|
expect(habits).to.have.a.lengthOf(0);
|
||||||
|
|
||||||
expect(dailys).to.have.a.lengthOf(0);
|
expect(dailys).to.have.a.lengthOf(0);
|
||||||
|
|
||||||
expect(todos).to.have.a.lengthOf(1);
|
expect(todos).to.have.a.lengthOf(1);
|
||||||
expect(todos[0].text).to.eql(t('defaultTodo1Text'));
|
|
||||||
expect(todos[0].notes).to.eql(t('defaultTodoNotes'));
|
|
||||||
|
|
||||||
expect(rewards).to.have.a.lengthOf(0);
|
expect(rewards).to.have.a.lengthOf(0);
|
||||||
|
|
||||||
expect(tags).to.have.a.lengthOf(7);
|
expect(tags).to.have.a.lengthOf(7);
|
||||||
|
|
@ -78,7 +73,7 @@ describe('POST /user/auth/local/register', () => {
|
||||||
expect(tags[6].name).to.eql(t('defaultTag7'));
|
expect(tags[6].name).to.eql(t('defaultTag7'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('for Web', async () => {
|
xit('for Web', async () => {
|
||||||
api = requester(
|
api = requester(
|
||||||
null,
|
null,
|
||||||
{'x-client': 'habitica-web'},
|
{'x-client': 'habitica-web'},
|
||||||
|
|
@ -623,10 +618,10 @@ describe('POST /user/auth/local/register', () => {
|
||||||
confirmPassword: password,
|
confirmPassword: password,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(user.tasksOrder.todos).to.not.be.empty;
|
expect(user.tasksOrder.todos).to.be.empty;
|
||||||
expect(user.tasksOrder.dailys).to.be.empty;
|
expect(user.tasksOrder.dailys).to.be.empty;
|
||||||
expect(user.tasksOrder.habits).to.not.be.empty;
|
expect(user.tasksOrder.habits).to.be.empty;
|
||||||
expect(user.tasksOrder.rewards).to.not.be.empty;
|
expect(user.tasksOrder.rewards).to.be.empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('populates user with default tags', async () => {
|
it('populates user with default tags', async () => {
|
||||||
|
|
@ -653,23 +648,8 @@ describe('POST /user/auth/local/register', () => {
|
||||||
let habits = await requests.get('/tasks/user?type=habits');
|
let habits = await requests.get('/tasks/user?type=habits');
|
||||||
let todos = await requests.get('/tasks/user?type=todos');
|
let todos = await requests.get('/tasks/user?type=todos');
|
||||||
|
|
||||||
function findTag (tagName) {
|
expect(habits).to.have.a.lengthOf(0);
|
||||||
let tag = user.tags.find((userTag) => {
|
expect(todos).to.have.a.lengthOf(0);
|
||||||
return userTag.name === t(tagName);
|
|
||||||
});
|
|
||||||
return tag.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(habits[0].tags).to.have.a.lengthOf(3);
|
|
||||||
expect(habits[0].tags).to.include.members(['defaultTag1', 'defaultTag4', 'defaultTag6'].map(findTag));
|
|
||||||
|
|
||||||
expect(habits[1].tags).to.have.a.lengthOf(1);
|
|
||||||
expect(habits[1].tags).to.include.members(['defaultTag3'].map(findTag));
|
|
||||||
|
|
||||||
expect(habits[2].tags).to.have.a.lengthOf(2);
|
|
||||||
expect(habits[2].tags).to.include.members(['defaultTag2', 'defaultTag3'].map(findTag));
|
|
||||||
|
|
||||||
expect(todos[0].tags).to.have.a.lengthOf(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -142,12 +142,12 @@ describe('emails', () => {
|
||||||
describe('getGroupUrl', () => {
|
describe('getGroupUrl', () => {
|
||||||
it('returns correct url if group is the tavern', () => {
|
it('returns correct url if group is the tavern', () => {
|
||||||
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
||||||
expect(getGroupUrl({_id: TAVERN_ID, type: 'guild'})).to.eql('/#/options/groups/tavern');
|
expect(getGroupUrl({_id: TAVERN_ID, type: 'guild'})).to.eql('/groups/tavern');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns correct url if group is a guild', () => {
|
it('returns correct url if group is a guild', () => {
|
||||||
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
||||||
expect(getGroupUrl({_id: 'random _id', type: 'guild'})).to.eql('/#/options/groups/guilds/random _id');
|
expect(getGroupUrl({_id: 'random _id', type: 'guild'})).to.eql('/groups/guild/random _id');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns correct url if group is a party', () => {
|
it('returns correct url if group is a party', () => {
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ describe('slack', () => {
|
||||||
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
|
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
|
||||||
attachments: [sandbox.match({
|
attachments: [sandbox.match({
|
||||||
title: 'Flag in Some group',
|
title: 'Flag in Some group',
|
||||||
title_link: sandbox.match(/.*\/#\/options\/groups\/guilds\/group-id/),
|
title_link: sandbox.match(/.*\/groups\/guild\/group-id/),
|
||||||
})],
|
})],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -86,7 +86,7 @@ describe('slack', () => {
|
||||||
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
|
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
|
||||||
attachments: [sandbox.match({
|
attachments: [sandbox.match({
|
||||||
title: 'Flag in Tavern',
|
title: 'Flag in Tavern',
|
||||||
title_link: sandbox.match(/.*\/#\/options\/groups\/tavern/),
|
title_link: sandbox.match(/.*\/groups\/tavern/),
|
||||||
})],
|
})],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ describe('response middleware', () => {
|
||||||
success: true,
|
success: true,
|
||||||
data: {field: 1},
|
data: {field: 1},
|
||||||
notifications: [],
|
notifications: [],
|
||||||
|
userV: res.locals.user._v,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -49,6 +50,7 @@ describe('response middleware', () => {
|
||||||
data: {field: 1},
|
data: {field: 1},
|
||||||
message: 'hello',
|
message: 'hello',
|
||||||
notifications: [],
|
notifications: [],
|
||||||
|
userV: res.locals.user._v,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -64,12 +66,12 @@ describe('response middleware', () => {
|
||||||
success: false,
|
success: false,
|
||||||
data: {field: 1},
|
data: {field: 1},
|
||||||
notifications: [],
|
notifications: [],
|
||||||
|
userV: res.locals.user._v,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns userV if a user is authenticated req.query.userV is passed', () => {
|
it('returns userV if a user is authenticated', () => {
|
||||||
responseMiddleware(req, res, next);
|
responseMiddleware(req, res, next);
|
||||||
req.query.userV = 3;
|
|
||||||
res.respond(200, {field: 1});
|
res.respond(200, {field: 1});
|
||||||
|
|
||||||
expect(res.json).to.be.calledOnce;
|
expect(res.json).to.be.calledOnce;
|
||||||
|
|
@ -101,6 +103,7 @@ describe('response middleware', () => {
|
||||||
data: {},
|
data: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
userV: res.locals.user._v,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ describe('Notification Controller', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User challenge won notification watch', function() {
|
describe('User challenge won notification watch', function() {
|
||||||
it('opens challenge won modal when a challenge-won notification is recieved', function() {
|
it('opens challenge won modal when a challenge-won notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.userNotifications.push({type: 'WON_CHALLENGE'});
|
rootScope.userNotifications.push({type: 'WON_CHALLENGE'});
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
@ -109,7 +109,7 @@ describe('Notification Controller', function() {
|
||||||
expect(achievement.displayAchievement).to.be.calledWith('wonChallenge');
|
expect(achievement.displayAchievement).to.be.calledWith('wonChallenge');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not open challenge won modal if no new challenge-won notification is recieved', function() {
|
it('does not open challenge won modal if no new challenge-won notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ describe('Notification Controller', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User streak achievement notification watch', function() {
|
describe('User streak achievement notification watch', function() {
|
||||||
it('opens streak achievement modal when a streak-achievement notification is recieved', function() {
|
it('opens streak achievement modal when a streak-achievement notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.userNotifications.push({type: 'STREAK_ACHIEVEMENT'});
|
rootScope.userNotifications.push({type: 'STREAK_ACHIEVEMENT'});
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
@ -127,7 +127,7 @@ describe('Notification Controller', function() {
|
||||||
expect(achievement.displayAchievement).to.be.calledWith('streak', {size: 'md'});
|
expect(achievement.displayAchievement).to.be.calledWith('streak', {size: 'md'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not open streak achievement modal if no new streak-achievement notification is recieved', function() {
|
it('does not open streak achievement modal if no new streak-achievement notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
||||||
|
|
@ -136,7 +136,7 @@ describe('Notification Controller', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User ultimate gear set achievement notification watch', function() {
|
describe('User ultimate gear set achievement notification watch', function() {
|
||||||
it('opens ultimate gear set achievement modal when an ultimate-gear-achievement notification is recieved', function() {
|
it('opens ultimate gear set achievement modal when an ultimate-gear-achievement notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.userNotifications.push({type: 'ULTIMATE_GEAR_ACHIEVEMENT'});
|
rootScope.userNotifications.push({type: 'ULTIMATE_GEAR_ACHIEVEMENT'});
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
@ -145,7 +145,7 @@ describe('Notification Controller', function() {
|
||||||
expect(achievement.displayAchievement).to.be.calledWith('ultimateGear', {size: 'md'});
|
expect(achievement.displayAchievement).to.be.calledWith('ultimateGear', {size: 'md'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not open ultimate gear set achievement modal if no new ultimate-gear-achievement notification is recieved', function() {
|
it('does not open ultimate gear set achievement modal if no new ultimate-gear-achievement notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ describe('Notification Controller', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User rebirth achievement notification watch', function() {
|
describe('User rebirth achievement notification watch', function() {
|
||||||
it('opens rebirth achievement modal when a rebirth-achievement notification is recieved', function() {
|
it('opens rebirth achievement modal when a rebirth-achievement notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.userNotifications.push({type: 'REBIRTH_ACHIEVEMENT'});
|
rootScope.userNotifications.push({type: 'REBIRTH_ACHIEVEMENT'});
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
@ -163,7 +163,7 @@ describe('Notification Controller', function() {
|
||||||
expect(achievement.displayAchievement).to.be.calledWith('rebirth');
|
expect(achievement.displayAchievement).to.be.calledWith('rebirth');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not open rebirth achievement modal if no new rebirth-achievement notification is recieved', function() {
|
it('does not open rebirth achievement modal if no new rebirth-achievement notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ describe('Notification Controller', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User contributor achievement notification watch', function() {
|
describe('User contributor achievement notification watch', function() {
|
||||||
it('opens contributor achievement modal when a new-contributor-level notification is recieved', function() {
|
it('opens contributor achievement modal when a new-contributor-level notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.userNotifications.push({type: 'NEW_CONTRIBUTOR_LEVEL'});
|
rootScope.userNotifications.push({type: 'NEW_CONTRIBUTOR_LEVEL'});
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
@ -181,7 +181,7 @@ describe('Notification Controller', function() {
|
||||||
expect(achievement.displayAchievement).to.be.calledWith('contributor', {size: 'md'});
|
expect(achievement.displayAchievement).to.be.calledWith('contributor', {size: 'md'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not open contributor achievement modal if no new new-contributor-level notification is recieved', function() {
|
it('does not open contributor achievement modal if no new new-contributor-level notification is received', function() {
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
rootScope.$digest();
|
rootScope.$digest();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,13 @@ import Vue from 'vue';
|
||||||
|
|
||||||
describe('i18n plugin', () => {
|
describe('i18n plugin', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
Vue.use(i18n);
|
Vue.use(i18n, {
|
||||||
|
i18nData: {
|
||||||
|
strings: {
|
||||||
|
reportBug: 'Report a Bug',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds $t to Vue.prototype', () => {
|
it('adds $t to Vue.prototype', () => {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ describe('user actions', () => {
|
||||||
const user = {_id: 2};
|
const user = {_id: 2};
|
||||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: user}}));
|
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: user}}));
|
||||||
|
|
||||||
await store.dispatch('user:fetch', true);
|
await store.dispatch('user:fetch', {forceLoad: true});
|
||||||
|
|
||||||
expect(store.state.user.data).to.equal(user);
|
expect(store.state.user.data).to.equal(user);
|
||||||
expect(store.state.user.loadingStatus).to.equal('LOADED');
|
expect(store.state.user.loadingStatus).to.equal('LOADED');
|
||||||
|
|
|
||||||
|
|
@ -68,23 +68,6 @@ describe('shared.ops.buyArmoire', () => {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not open without Ultimate Gear achievement', (done) => {
|
|
||||||
user.achievements.ultimateGearSets = {healer: false, wizard: false, rogue: false, warrior: false};
|
|
||||||
|
|
||||||
try {
|
|
||||||
buyArmoire(user);
|
|
||||||
} catch (err) {
|
|
||||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
|
||||||
expect(err.message).to.equal(i18n.t('cannotBuyItem'));
|
|
||||||
expect(user.items.gear.owned).to.eql({
|
|
||||||
weapon_warrior_0: true,
|
|
||||||
});
|
|
||||||
expect(user.items.food).to.be.empty;
|
|
||||||
expect(user.stats.exp).to.eql(0);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context('non-gear awards', () => {
|
context('non-gear awards', () => {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
// https://github.com/shelljs/shelljs
|
// https://github.com/shelljs/shelljs
|
||||||
require('shelljs/global');
|
require('shelljs/global');
|
||||||
env.NODE_ENV = 'production';
|
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
|
|
@ -10,28 +9,39 @@ const ora = require('ora');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const webpackConfig = require('./webpack.prod.conf');
|
const webpackConfig = require('./webpack.prod.conf');
|
||||||
|
|
||||||
console.log( // eslint-disable-line no-console
|
module.exports = function webpackProductionBuild (callback) {
|
||||||
' Tip:\n' +
|
env.NODE_ENV = 'production';
|
||||||
' Built files are meant to be served over an HTTP server.\n' +
|
|
||||||
' Opening index.html over file:// won\'t work.\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
const spinner = ora('building for production...');
|
console.log( // eslint-disable-line no-console
|
||||||
spinner.start();
|
' Tip:\n' +
|
||||||
|
' Built files are meant to be served over an HTTP server.\n' +
|
||||||
|
' Opening index.html over file:// won\'t work.\n'
|
||||||
|
);
|
||||||
|
|
||||||
const assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory);
|
const spinner = ora('building for production...');
|
||||||
rm('-rf', assetsPath);
|
spinner.start();
|
||||||
mkdir('-p', assetsPath);
|
|
||||||
cp('-R', config.build.staticAssetsDirectory, assetsPath);
|
|
||||||
|
|
||||||
webpack(webpackConfig, (err, stats) => {
|
const assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory);
|
||||||
spinner.stop();
|
rm('-rf', assetsPath);
|
||||||
if (err) throw err;
|
mkdir('-p', assetsPath);
|
||||||
process.stdout.write(`${stats.toString({
|
cp('-R', config.build.staticAssetsDirectory, assetsPath);
|
||||||
colors: true,
|
|
||||||
modules: false,
|
webpack(webpackConfig, (err, stats) => {
|
||||||
children: false,
|
spinner.stop();
|
||||||
chunks: false,
|
|
||||||
chunkModules: false,
|
const output = `${stats.toString({
|
||||||
})}\n`);
|
colors: true,
|
||||||
});
|
modules: false,
|
||||||
|
children: false,
|
||||||
|
chunks: false,
|
||||||
|
chunkModules: false,
|
||||||
|
})}\n`;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
return err ? callback(err) : callback(null, output);
|
||||||
|
} else {
|
||||||
|
if (err) throw err;
|
||||||
|
process.stdout.write(output);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ module.exports = {
|
||||||
index: path.resolve(__dirname, '../../dist-client/index.html'),
|
index: path.resolve(__dirname, '../../dist-client/index.html'),
|
||||||
assetsRoot: path.resolve(__dirname, '../../dist-client'),
|
assetsRoot: path.resolve(__dirname, '../../dist-client'),
|
||||||
assetsSubDirectory: 'static',
|
assetsSubDirectory: 'static',
|
||||||
assetsPublicPath: '/new-app/',
|
assetsPublicPath: '/',
|
||||||
staticAssetsDirectory,
|
staticAssetsDirectory,
|
||||||
productionSourceMap: true,
|
productionSourceMap: true,
|
||||||
// Gzip off by default as many popular static hosts such as
|
// Gzip off by default as many popular static hosts such as
|
||||||
|
|
@ -21,7 +21,7 @@ module.exports = {
|
||||||
productionGzipExtensions: ['js', 'css'],
|
productionGzipExtensions: ['js', 'css'],
|
||||||
// Run the build command with an extra argument to
|
// Run the build command with an extra argument to
|
||||||
// View the bundle analyzer report after build finishes:
|
// View the bundle analyzer report after build finishes:
|
||||||
// `npm run build --report`
|
// `npm run client:build --report`
|
||||||
// Set to `true` or `false` to always turn it on or off
|
// Set to `true` or `false` to always turn it on or off
|
||||||
bundleAnalyzerReport: process.env.npm_config_report, // eslint-disable-line no-process-env
|
bundleAnalyzerReport: process.env.npm_config_report, // eslint-disable-line no-process-env
|
||||||
},
|
},
|
||||||
|
|
@ -50,6 +50,10 @@ module.exports = {
|
||||||
target: 'http://localhost:3000',
|
target: 'http://localhost:3000',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
|
'/logout': {
|
||||||
|
target: 'http://localhost:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||||
// with this option, according to the CSS-Loader README
|
// with this option, according to the CSS-Loader README
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,49 @@
|
||||||
module.exports = {
|
const nconf = require('nconf');
|
||||||
|
const { join, resolve } = require('path');
|
||||||
|
|
||||||
|
const PATH_TO_CONFIG = join(resolve(__dirname, '../../config.json'));
|
||||||
|
let configFile = PATH_TO_CONFIG;
|
||||||
|
|
||||||
|
nconf
|
||||||
|
.argv()
|
||||||
|
.env()
|
||||||
|
.file('user', configFile);
|
||||||
|
|
||||||
|
nconf.set('IS_PROD', nconf.get('NODE_ENV') === 'production');
|
||||||
|
nconf.set('IS_DEV', nconf.get('NODE_ENV') === 'development');
|
||||||
|
nconf.set('IS_TEST', nconf.get('NODE_ENV') === 'test');
|
||||||
|
|
||||||
|
// @TODO: Check if we can import from client. Items like admin emails can be imported
|
||||||
|
// and that should be prefered
|
||||||
|
|
||||||
|
// To avoid stringifying more data then we need,
|
||||||
|
// items from `env` used on the client will have to be specified in this array
|
||||||
|
// @TODO: Do we need? const CLIENT_VARS = ['language', 'isStaticPage', 'availableLanguages', 'translations',
|
||||||
|
// 'FACEBOOK_KEY', 'GOOGLE_CLIENT_ID', 'NODE_ENV', 'BASE_URL', 'GA_ID',
|
||||||
|
// 'AMAZON_PAYMENTS', 'STRIPE_PUB_KEY', 'AMPLITUDE_KEY',
|
||||||
|
// 'worldDmg', 'mods', 'IS_MOBILE', 'PUSHER:KEY', 'PUSHER:ENABLED'];
|
||||||
|
|
||||||
|
const AMAZON_SELLER_ID = nconf.get('AMAZON_PAYMENTS:SELLER_ID') || nconf.get('AMAZON_PAYMENTS_SELLER_ID');
|
||||||
|
const AMAZON_CLIENT_ID = nconf.get('AMAZON_PAYMENTS:CLIENT_ID') || nconf.get('AMAZON_PAYMENTS_CLIENT_ID');
|
||||||
|
|
||||||
|
let env = {
|
||||||
NODE_ENV: '"production"',
|
NODE_ENV: '"production"',
|
||||||
|
// clientVars: CLIENT_VARS,
|
||||||
|
AMAZON_PAYMENTS: {
|
||||||
|
SELLER_ID: `"${AMAZON_SELLER_ID}"`,
|
||||||
|
CLIENT_ID: `"${AMAZON_CLIENT_ID}"`,
|
||||||
|
},
|
||||||
|
EMAILS: {
|
||||||
|
COMMUNITY_MANAGER_EMAIL: `"${nconf.get('EMAILS:COMMUNITY_MANAGER_EMAIL')}"`,
|
||||||
|
TECH_ASSISTANCE_EMAIL: `"${nconf.get('EMAILS:TECH_ASSISTANCE_EMAIL')}"`,
|
||||||
|
PRESS_ENQUIRY_EMAIL: `"${nconf.get('EMAILS:PRESS_ENQUIRY_EMAIL')}"`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
'NODE_ENV BASE_URL GA_ID STRIPE_PUB_KEY FACEBOOK_KEY GOOGLE_CLIENT_ID AMPLITUDE_KEY PUSHER:KEY PUSHER:ENABLED'
|
||||||
|
.split(' ')
|
||||||
|
.forEach(key => {
|
||||||
|
env[key] = `"${nconf.get(key)}"`;
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = env;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const projectRoot = path.resolve(__dirname, '../');
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
const projectRoot = path.resolve(__dirname, '../');
|
||||||
const autoprefixer = require('autoprefixer');
|
const autoprefixer = require('autoprefixer');
|
||||||
const postcssEasyImport = require('postcss-easy-import');
|
const postcssEasyImport = require('postcss-easy-import');
|
||||||
const IS_PROD = process.env.NODE_ENV === 'production';
|
const IS_PROD = process.env.NODE_ENV === 'production';
|
||||||
|
|
@ -36,7 +36,6 @@ const baseConfig = {
|
||||||
path.join(projectRoot, 'node_modules'),
|
path.join(projectRoot, 'node_modules'),
|
||||||
],
|
],
|
||||||
alias: {
|
alias: {
|
||||||
jquery: 'jquery/src/jquery',
|
|
||||||
website: path.resolve(projectRoot, 'website'),
|
website: path.resolve(projectRoot, 'website'),
|
||||||
common: path.resolve(projectRoot, 'website/common'),
|
common: path.resolve(projectRoot, 'website/common'),
|
||||||
client: path.resolve(projectRoot, 'website/client'),
|
client: path.resolve(projectRoot, 'website/client'),
|
||||||
|
|
@ -45,10 +44,7 @@ const baseConfig = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(NOT_EXISTING)$/),
|
||||||
$: 'jquery',
|
|
||||||
jQuery: 'jquery',
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
|
|
||||||
|
|
@ -1102,55 +1102,55 @@
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_bamboo_forest {
|
.icon_background_back_of_giant_beast {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -846px -1480px;
|
background-position: -846px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_beach {
|
.icon_background_bamboo_forest {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -846px -1549px;
|
background-position: -846px -1549px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_beehive {
|
.icon_background_beach {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1605px -1480px;
|
background-position: -1605px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_bell_tower {
|
.icon_background_beehive {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1536px -1480px;
|
background-position: -1536px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_blacksmithy {
|
.icon_background_bell_tower {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1467px -1480px;
|
background-position: -1467px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_blizzard {
|
.icon_background_beside_well {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1398px -1480px;
|
background-position: -1398px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_blue {
|
.icon_background_blacksmithy {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1329px -1480px;
|
background-position: -1329px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_bug_covered_log {
|
.icon_background_blizzard {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1260px -1480px;
|
background-position: -1260px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
.icon_background_buried_treasure {
|
.icon_background_blue {
|
||||||
background-image: url(/static/sprites/spritesmith-main-0.png);
|
background-image: url(/static/sprites/spritesmith-main-0.png);
|
||||||
background-position: -1191px -1480px;
|
background-position: -1191px -1480px;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
|
|
|
||||||
BIN
website/assets/sprites/dist/spritesmith-main-0.png
vendored
|
Before Width: | Height: | Size: 557 KiB After Width: | Height: | Size: 556 KiB |
6450
website/assets/sprites/dist/spritesmith-main-1.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-1.png
vendored
|
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 285 KiB |
3110
website/assets/sprites/dist/spritesmith-main-10.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-10.png
vendored
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 279 KiB |
2626
website/assets/sprites/dist/spritesmith-main-11.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-11.png
vendored
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 156 KiB |
1950
website/assets/sprites/dist/spritesmith-main-12.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-12.png
vendored
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 152 KiB |
2546
website/assets/sprites/dist/spritesmith-main-13.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-13.png
vendored
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 143 KiB |
2606
website/assets/sprites/dist/spritesmith-main-14.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-14.png
vendored
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 150 KiB |
2976
website/assets/sprites/dist/spritesmith-main-15.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-15.png
vendored
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 145 KiB |
3544
website/assets/sprites/dist/spritesmith-main-16.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-16.png
vendored
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 155 KiB |
2836
website/assets/sprites/dist/spritesmith-main-17.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-17.png
vendored
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 173 KiB |
2560
website/assets/sprites/dist/spritesmith-main-18.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-18.png
vendored
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 160 KiB |
1860
website/assets/sprites/dist/spritesmith-main-19.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-19.png
vendored
|
Before Width: | Height: | Size: 466 B After Width: | Height: | Size: 151 KiB |
5364
website/assets/sprites/dist/spritesmith-main-2.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-2.png
vendored
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 56 KiB |
6470
website/assets/sprites/dist/spritesmith-main-3.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-3.png
vendored
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 75 KiB |
4662
website/assets/sprites/dist/spritesmith-main-4.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-4.png
vendored
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 73 KiB |
3996
website/assets/sprites/dist/spritesmith-main-5.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-5.png
vendored
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 143 KiB |
2922
website/assets/sprites/dist/spritesmith-main-6.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-6.png
vendored
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 136 KiB |
3278
website/assets/sprites/dist/spritesmith-main-7.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-7.png
vendored
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 129 KiB |
2968
website/assets/sprites/dist/spritesmith-main-8.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-8.png
vendored
|
Before Width: | Height: | Size: 316 KiB After Width: | Height: | Size: 115 KiB |
2550
website/assets/sprites/dist/spritesmith-main-9.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-9.png
vendored
|
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 361 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 447 B |
|
Before Width: | Height: | Size: 833 B After Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 479 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 447 B |
|
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 472 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 513 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 455 B |
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 416 B |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 618 B |
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 435 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 618 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 447 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 464 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 460 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 556 B |