Merge branch 'develop' into release

This commit is contained in:
SabreCat 2017-09-28 16:02:47 +00:00
commit 1eb31a4fec
2213 changed files with 121882 additions and 101395 deletions

View file

@ -14,7 +14,7 @@ files:
owner: root
group: users
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:
01_makeBabel:
command: "touch /tmp/.babel.json"

View file

@ -13,7 +13,7 @@ addons:
- g++-4.8
before_install:
- $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
install:
- npm install &> npm.install.log || (cat npm.install.log; false)
@ -34,6 +34,5 @@ env:
- TEST="test:sanity"
- TEST="test:content" COVERAGE=true
- TEST="test:common" COVERAGE=true
- TEST="test:karma" COVERAGE=true
- TEST="client:unit" COVERAGE=true
- TEST="apidoc"

View file

@ -1,5 +1,8 @@
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
RUN npm install -g gulp grunt-cli bower mocha

View file

@ -1,5 +1,8 @@
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
RUN npm install -g gulp grunt-cli bower mocha

View file

@ -1,6 +1,7 @@
import gulp from 'gulp';
import runSequence from 'run-sequence';
import babel from 'gulp-babel';
import webpackProductionBuild from '../webpack/build';
require('gulp-grunt')(gulp);
gulp.task('build', () => {
@ -25,6 +26,14 @@ gulp.task('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.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.task('build:prod', ['browserify', 'build:server', 'prepare:staticNewStuff'], (done) => {
gulp.task('build:prod', [
'browserify',
'build:server',
'prepare:staticNewStuff',
'build:client',
], (done) => {
runSequence(
'grunt-build:prod',
'apidoc',

View 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 = '![Guild Logo](' + group.logo + ')\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;

View 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
View 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

File diff suppressed because it is too large Load diff

21115
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -30,14 +30,15 @@
"bcrypt": "^1.0.2",
"bluebird": "^3.3.5",
"body-parser": "^1.15.0",
"bootstrap": "^4.0.0-alpha.6",
"bootstrap-vue": "^0.18.0",
"bootstrap": "4.0.0-alpha.6",
"bootstrap-vue": "^1.0.0-beta.6",
"bower": "~1.3.12",
"browserify": "~12.0.1",
"compression": "^1.6.1",
"connect-ratelimit": "0.0.7",
"cookie-session": "^1.2.0",
"coupon-code": "^0.4.5",
"cross-env": "^4.0.0",
"css-loader": "^0.28.0",
"csv-stringify": "^1.0.2",
"cwait": "~1.0.1",
@ -59,7 +60,7 @@
"grunt-contrib-stylus": "~0.20.0",
"grunt-contrib-uglify": "~0.6.0",
"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-babel": "^6.1.2",
"gulp-grunt": "^0.5.2",
@ -75,13 +76,13 @@
"in-app-purchase": "^1.1.6",
"intro.js": "^2.6.0",
"jade": "~1.11.0",
"jquery": "^3.1.1",
"jquery": ">=3.0.0",
"js2xmlparser": "~1.0.0",
"lodash": "^4.17.4",
"merge-stream": "^1.0.0",
"method-override": "^2.3.5",
"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-id-autoinc": "~2013.7.14-4",
"morgan": "^1.7.0",
@ -98,11 +99,12 @@
"passport-google-oauth20": "1.0.0",
"paypal-ipn": "3.0.0",
"paypal-rest-sdk": "^1.2.1",
"popper.js": "^1.11.0",
"postcss-easy-import": "^2.0.0",
"pretty-data": "^0.40.0",
"ps-tree": "^1.0.0",
"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",
"request": "~2.74.0",
"rimraf": "^2.4.3",
@ -111,6 +113,7 @@
"sass-loader": "^6.0.2",
"serve-favicon": "^2.3.0",
"shelljs": "^0.7.6",
"sortablejs": "^1.6.1",
"stripe": "^4.2.0",
"superagent": "^3.4.3",
"svg-inline-loader": "^0.7.1",
@ -126,11 +129,10 @@
"vue": "^2.1.0",
"vue-loader": "^11.0.0",
"vue-mugen-scroll": "^0.2.1",
"vue-notification": "^1.3.2",
"vue-router": "^2.0.0-rc.5",
"vue-style-loader": "^3.0.0",
"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-merge": "^4.0.0",
"winston": "^2.1.0",
@ -140,7 +142,7 @@
"private": true,
"engines": {
"node": "^6.9.1",
"npm": "^4.0.2"
"npm": "^5.0.0"
},
"scripts": {
"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",
"sprites": "gulp sprites:compile",
"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:watch": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js",
"client:e2e": "node test/client/e2e/runner.js",
"client:test": "npm run client:unit && npm run client:e2e",
"start": "gulp run:dev",
"postinstall": "bower --config.interactive=false install -f && gulp build && npm run client:build",
"postinstall": "gulp build",
"apidoc": "gulp apidoc"
},
"devDependencies": {
@ -179,7 +181,6 @@
"chromedriver": "^2.27.2",
"connect-history-api-fallback": "^1.1.0",
"coveralls": "^2.11.2",
"cross-env": "^4.0.0",
"cross-spawn": "^5.0.1",
"csv": "~0.3.6",
"deep-diff": "~0.1.4",

View file

@ -48,8 +48,10 @@ describe('GET /challenges/:challengeId', () => {
});
expect(chal.group).to.eql({
_id: group._id,
categories: [],
id: group.id,
name: group.name,
summary: group.name,
type: group.type,
privacy: group.privacy,
leader: groupLeader.id,
@ -100,8 +102,10 @@ describe('GET /challenges/:challengeId', () => {
});
expect(chal.group).to.eql({
_id: group._id,
categories: [],
id: group.id,
name: group.name,
summary: group.name,
type: group.type,
privacy: group.privacy,
leader: groupLeader.id,
@ -153,7 +157,9 @@ describe('GET /challenges/:challengeId', () => {
expect(chal.group).to.eql({
_id: group._id,
id: group.id,
categories: [],
name: group.name,
summary: group.name,
type: group.type,
privacy: group.privacy,
leader: groupLeader.id,

View file

@ -41,10 +41,12 @@ describe('GET challenges/user', () => {
});
expect(foundChallenge.group).to.eql({
_id: publicGuild._id,
categories: [],
id: publicGuild._id,
type: publicGuild.type,
privacy: publicGuild.privacy,
name: publicGuild.name,
summary: publicGuild.name,
leader: publicGuild.leader._id,
});
});
@ -61,10 +63,12 @@ describe('GET challenges/user', () => {
});
expect(foundChallenge1.group).to.eql({
_id: publicGuild._id,
categories: [],
id: publicGuild._id,
type: publicGuild.type,
privacy: publicGuild.privacy,
name: publicGuild.name,
summary: publicGuild.name,
leader: publicGuild.leader._id,
});
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
@ -76,10 +80,12 @@ describe('GET challenges/user', () => {
});
expect(foundChallenge2.group).to.eql({
_id: publicGuild._id,
categories: [],
id: publicGuild._id,
type: publicGuild.type,
privacy: publicGuild.privacy,
name: publicGuild.name,
summary: publicGuild.name,
leader: publicGuild.leader._id,
});
});
@ -96,10 +102,12 @@ describe('GET challenges/user', () => {
});
expect(foundChallenge1.group).to.eql({
_id: publicGuild._id,
categories: [],
id: publicGuild._id,
type: publicGuild.type,
privacy: publicGuild.privacy,
name: publicGuild.name,
summary: publicGuild.name,
leader: publicGuild.leader._id,
});
let foundChallenge2 = _.find(challenges, { _id: challenge2._id });
@ -111,14 +119,26 @@ describe('GET challenges/user', () => {
});
expect(foundChallenge2.group).to.eql({
_id: publicGuild._id,
categories: [],
id: publicGuild._id,
type: publicGuild.type,
privacy: publicGuild.privacy,
name: publicGuild.name,
summary: publicGuild.name,
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 () => {
let challenges = await user.get('/challenges/user');
@ -137,6 +157,7 @@ describe('GET challenges/user', () => {
let { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestPrivateGuild',
summary: 'summary for TestPrivateGuild',
type: 'guild',
privacy: 'private',
},
@ -158,6 +179,7 @@ describe('GET challenges/user', () => {
let { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestGuild',
summary: 'summary for TestGuild',
type: 'guild',
privacy: 'public',
},

View file

@ -224,7 +224,7 @@ describe('POST /chat', () => {
color: 'danger',
author_name: `${user.profile.name} - ${user.auth.local.email} - ${user._id}`,
title: 'Slur in Test Guild',
title_link: `${BASE_URL}/#/options/groups/guilds/${groupWithChat.id}`,
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
text: testSlurMessage,
// footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
mrkdwn_in: [

View 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);
});
});

View file

@ -6,7 +6,7 @@ import superagent from 'superagent';
import nconf from 'nconf';
const API_TEST_SERVER_PORT = nconf.get('PORT');
describe('GET /qr-code/user/:memberId', () => {
xdescribe('GET /qr-code/user/:memberId', () => {
let user;
before(async () => {

View file

@ -13,7 +13,7 @@ describe('GET /tasks/user', () => {
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 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 () => {

View file

@ -95,7 +95,7 @@ describe('POST /tasks/unlink-all/:challengeId', () => {
// Have the leader delete the challenge and unlink the tasks
await user.del(`/challenges/${challenge._id}`);
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');
// Expect the second user to still have the task, but unlinked
expect(anotherUserTask.challenge).to.eql({
@ -106,4 +106,4 @@ describe('POST /tasks/unlink-all/:challengeId', () => {
winner: null,
});
});
});
});

View file

@ -131,7 +131,7 @@ describe('POST /tasks/user', () => {
expect(task.updatedAt).not.to.equal('tomorrow');
expect(task.challenge).not.to.equal('no');
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.yesterDaily).to.equal(true);
});

View file

@ -86,6 +86,12 @@ describe('DELETE /user', () => {
});
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
let ids = [];
each(user.tasksOrder, (idsForOrder) => {

View file

@ -82,7 +82,7 @@ describe('GET /user/anonymized', () => {
});
// tasks
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;
_.forEach(tasks2, (task) => {
expect(task.text).to.eql('task text');

View file

@ -10,43 +10,31 @@ import nconf from 'nconf';
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`;
// Tests to validate the validatePasswordResetCodeAndFindUser function
it('renders an error page if the code is missing', async () => {
try {
await superagent.get(endpoint);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
const res = await superagent.get(endpoint);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
it('renders an error page if the code is invalid json', async () => {
try {
await superagent.get(`${endpoint}?code=invalid`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
const res = await superagent.get(`${endpoint}?code=invalid`);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
it('renders an error page if the code cannot be decrypted', async () => {
let user = await generateUser();
try {
let code = JSON.stringify({ // not encrypted
userId: user._id,
expiresAt: new Date(),
});
await superagent.get(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
let code = JSON.stringify({ // not encrypted
userId: user._id,
expiresAt: new Date(),
});
const res = await superagent.get(`${endpoint}?code=${code}`);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
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,
});
try {
await superagent.get(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
const res = await superagent.get(`${endpoint}?code=${code}`);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
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}),
}));
try {
await superagent.get(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
const res = await superagent.get(`${endpoint}?code=${code}`);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
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',
});
try {
await superagent.get(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
const res = await superagent.get(`${endpoint}?code=${code}`);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
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',
});
try {
await superagent.get(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
const res = await superagent.get(`${endpoint}?code=${code}`);
expect(res.req.path.indexOf('hasError=true') !== -1).to.equal(true);
});
//
@ -134,7 +106,8 @@ describe('GET /user/auth/local/reset-password-set-new-one', () => {
});
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);
});
});

View file

@ -10,49 +10,46 @@ import {
import moment from 'moment';
import {
generateUser,
requester,
translate as t,
} 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/local/reset-password-set-new-one', () => {
let endpoint = `http://localhost:${API_TEST_SERVER_PORT}/static/user/auth/local/reset-password-set-new-one`;
describe('POST /user/auth/reset-password-set-new-one', () => {
const endpoint = '/user/auth/reset-password-set-new-one';
const api = requester();
// Tests to validate the validatePasswordResetCodeAndFindUser function
it('renders an error page if the code is missing', async () => {
try {
await superagent.post(endpoint);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidPasswordResetCode'),
});
});
it('renders an error page if the code is invalid json', async () => {
try {
await superagent.post(`${endpoint}?code=invalid`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}?code=invalid`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidPasswordResetCode'),
});
});
it('renders an error page if the code cannot be decrypted', async () => {
let user = await generateUser();
try {
let code = JSON.stringify({ // not encrypted
userId: user._id,
expiresAt: new Date(),
});
await superagent.post(`${endpoint}?code=${code}`);
let code = JSON.stringify({ // not encrypted
userId: user._id,
expiresAt: new Date(),
});
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
code,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidPasswordResetCode'),
});
});
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,
});
try {
await superagent.post(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
code,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidPasswordResetCode'),
});
});
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}),
}));
try {
await superagent.post(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
code,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidPasswordResetCode'),
});
});
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',
});
try {
await superagent.post(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
code,
})).to.eventually.be.rejected.and.eql({
code: 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 () => {
@ -118,12 +118,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
'auth.local.passwordResetCode': 'invalid',
});
try {
await superagent.post(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
code,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidPasswordResetCode'),
});
});
//
@ -139,12 +140,13 @@ describe('POST /user/auth/local/reset-password-set-new-one', () => {
'auth.local.passwordResetCode': code,
});
try {
await superagent.post(`${endpoint}?code=${code}`);
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
code,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
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,
});
try {
await superagent
.post(`${endpoint}?code=${code}`)
.send({newPassword: 'my new password'});
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
newPassword: 'my new password',
code,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
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,
});
try {
await superagent
.post(`${endpoint}?code=${code}`)
.send({
newPassword: 'my new password',
confirmPassword: 'not matching',
});
throw new Error('Request should fail.');
} catch (err) {
expect(err.status).to.equal(401);
}
await expect(api.post(`${endpoint}`, {
newPassword: 'my new password',
confirmPassword: 'not matching',
code,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('passwordConfirmationMatch'),
});
});
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,
});
let res = await superagent
.post(`${endpoint}?code=${code}`)
.send({
newPassword: 'my new password',
confirmPassword: 'my new password',
});
let res = await api.post(`${endpoint}`, {
newPassword: 'my new password',
confirmPassword: 'my new password',
code,
});
expect(res.status).to.equal(200);
expect(res.message).to.equal(t('passwordChangeSuccess'));
await user.sync();
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,
});
let res = await superagent
.post(`${endpoint}?code=${code}`)
.send({
newPassword: 'my new password',
confirmPassword: 'my new password',
});
let res = await api.post(`${endpoint}`, {
newPassword: 'my new password',
confirmPassword: 'my new password',
code,
});
expect(res.status).to.equal(200);
expect(res.message).to.equal(t('passwordChangeSuccess'));
await user.sync();
expect(user.auth.local.passwordResetCode).to.equal(undefined);

View file

@ -59,13 +59,8 @@ describe('POST /user/auth/local/register', () => {
let tags = await requests.get('/tags');
expect(habits).to.have.a.lengthOf(0);
expect(dailys).to.have.a.lengthOf(0);
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(tags).to.have.a.lengthOf(7);
@ -78,7 +73,7 @@ describe('POST /user/auth/local/register', () => {
expect(tags[6].name).to.eql(t('defaultTag7'));
});
it('for Web', async () => {
xit('for Web', async () => {
api = requester(
null,
{'x-client': 'habitica-web'},
@ -623,10 +618,10 @@ describe('POST /user/auth/local/register', () => {
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.habits).to.not.be.empty;
expect(user.tasksOrder.rewards).to.not.be.empty;
expect(user.tasksOrder.habits).to.be.empty;
expect(user.tasksOrder.rewards).to.be.empty;
});
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 todos = await requests.get('/tasks/user?type=todos');
function findTag (tagName) {
let tag = user.tags.find((userTag) => {
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);
expect(habits).to.have.a.lengthOf(0);
expect(todos).to.have.a.lengthOf(0);
});
});
});

View file

@ -142,12 +142,12 @@ describe('emails', () => {
describe('getGroupUrl', () => {
it('returns correct url if group is the tavern', () => {
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', () => {
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', () => {

View file

@ -71,7 +71,7 @@ describe('slack', () => {
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
attachments: [sandbox.match({
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({
attachments: [sandbox.match({
title: 'Flag in Tavern',
title_link: sandbox.match(/.*\/#\/options\/groups\/tavern/),
title_link: sandbox.match(/.*\/groups\/tavern/),
})],
});
});

View file

@ -33,6 +33,7 @@ describe('response middleware', () => {
success: true,
data: {field: 1},
notifications: [],
userV: res.locals.user._v,
});
});
@ -49,6 +50,7 @@ describe('response middleware', () => {
data: {field: 1},
message: 'hello',
notifications: [],
userV: res.locals.user._v,
});
});
@ -64,12 +66,12 @@ describe('response middleware', () => {
success: false,
data: {field: 1},
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);
req.query.userV = 3;
res.respond(200, {field: 1});
expect(res.json).to.be.calledOnce;
@ -101,6 +103,7 @@ describe('response middleware', () => {
data: {},
},
],
userV: res.locals.user._v,
});
});
});

View file

@ -100,7 +100,7 @@ describe('Notification Controller', 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.userNotifications.push({type: 'WON_CHALLENGE'});
rootScope.$digest();
@ -109,7 +109,7 @@ describe('Notification Controller', function() {
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();
@ -118,7 +118,7 @@ describe('Notification Controller', 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.userNotifications.push({type: 'STREAK_ACHIEVEMENT'});
rootScope.$digest();
@ -127,7 +127,7 @@ describe('Notification Controller', function() {
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();
@ -136,7 +136,7 @@ describe('Notification Controller', 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.userNotifications.push({type: 'ULTIMATE_GEAR_ACHIEVEMENT'});
rootScope.$digest();
@ -145,7 +145,7 @@ describe('Notification Controller', function() {
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();
@ -154,7 +154,7 @@ describe('Notification Controller', 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.userNotifications.push({type: 'REBIRTH_ACHIEVEMENT'});
rootScope.$digest();
@ -163,7 +163,7 @@ describe('Notification Controller', function() {
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();
@ -172,7 +172,7 @@ describe('Notification Controller', 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.userNotifications.push({type: 'NEW_CONTRIBUTOR_LEVEL'});
rootScope.$digest();
@ -181,7 +181,7 @@ describe('Notification Controller', function() {
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();

View file

@ -4,7 +4,13 @@ import Vue from 'vue';
describe('i18n plugin', () => {
before(() => {
Vue.use(i18n);
Vue.use(i18n, {
i18nData: {
strings: {
reportBug: 'Report a Bug',
},
},
});
});
it('adds $t to Vue.prototype', () => {

View file

@ -45,7 +45,7 @@ describe('user actions', () => {
const user = {_id: 2};
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.loadingStatus).to.equal('LOADED');

View file

@ -68,23 +68,6 @@ describe('shared.ops.buyArmoire', () => {
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', () => {

View file

@ -2,7 +2,6 @@
// https://github.com/shelljs/shelljs
require('shelljs/global');
env.NODE_ENV = 'production';
const path = require('path');
const config = require('./config');
@ -10,28 +9,39 @@ const ora = require('ora');
const webpack = require('webpack');
const webpackConfig = require('./webpack.prod.conf');
console.log( // eslint-disable-line no-console
' Tip:\n' +
' Built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
);
module.exports = function webpackProductionBuild (callback) {
env.NODE_ENV = 'production';
const spinner = ora('building for production...');
spinner.start();
console.log( // eslint-disable-line no-console
' 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);
rm('-rf', assetsPath);
mkdir('-p', assetsPath);
cp('-R', config.build.staticAssetsDirectory, assetsPath);
const spinner = ora('building for production...');
spinner.start();
webpack(webpackConfig, (err, stats) => {
spinner.stop();
if (err) throw err;
process.stdout.write(`${stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
})}\n`);
});
const assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory);
rm('-rf', assetsPath);
mkdir('-p', assetsPath);
cp('-R', config.build.staticAssetsDirectory, assetsPath);
webpack(webpackConfig, (err, stats) => {
spinner.stop();
const output = `${stats.toString({
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);
}
});
};

View file

@ -10,7 +10,7 @@ module.exports = {
index: path.resolve(__dirname, '../../dist-client/index.html'),
assetsRoot: path.resolve(__dirname, '../../dist-client'),
assetsSubDirectory: 'static',
assetsPublicPath: '/new-app/',
assetsPublicPath: '/',
staticAssetsDirectory,
productionSourceMap: true,
// Gzip off by default as many popular static hosts such as
@ -21,7 +21,7 @@ module.exports = {
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// 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
bundleAnalyzerReport: process.env.npm_config_report, // eslint-disable-line no-process-env
},
@ -50,6 +50,10 @@ module.exports = {
target: 'http://localhost:3000',
changeOrigin: true,
},
'/logout': {
target: 'http://localhost:3000',
changeOrigin: true,
},
},
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README

View file

@ -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"',
// 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;

View file

@ -3,8 +3,8 @@
const path = require('path');
const config = require('./config');
const utils = require('./utils');
const projectRoot = path.resolve(__dirname, '../');
const webpack = require('webpack');
const projectRoot = path.resolve(__dirname, '../');
const autoprefixer = require('autoprefixer');
const postcssEasyImport = require('postcss-easy-import');
const IS_PROD = process.env.NODE_ENV === 'production';
@ -36,7 +36,6 @@ const baseConfig = {
path.join(projectRoot, 'node_modules'),
],
alias: {
jquery: 'jquery/src/jquery',
website: path.resolve(projectRoot, 'website'),
common: path.resolve(projectRoot, 'website/common'),
client: path.resolve(projectRoot, 'website/client'),
@ -45,10 +44,7 @@ const baseConfig = {
},
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
}),
new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(NOT_EXISTING)$/),
],
module: {
rules: [

View file

@ -1102,55 +1102,55 @@
width: 68px;
height: 68px;
}
.icon_background_bamboo_forest {
.icon_background_back_of_giant_beast {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -846px -1480px;
width: 68px;
height: 68px;
}
.icon_background_beach {
.icon_background_bamboo_forest {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -846px -1549px;
width: 68px;
height: 68px;
}
.icon_background_beehive {
.icon_background_beach {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1605px -1480px;
width: 68px;
height: 68px;
}
.icon_background_bell_tower {
.icon_background_beehive {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1536px -1480px;
width: 68px;
height: 68px;
}
.icon_background_blacksmithy {
.icon_background_bell_tower {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1467px -1480px;
width: 68px;
height: 68px;
}
.icon_background_blizzard {
.icon_background_beside_well {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1398px -1480px;
width: 68px;
height: 68px;
}
.icon_background_blue {
.icon_background_blacksmithy {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1329px -1480px;
width: 68px;
height: 68px;
}
.icon_background_bug_covered_log {
.icon_background_blizzard {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1260px -1480px;
width: 68px;
height: 68px;
}
.icon_background_buried_treasure {
.icon_background_blue {
background-image: url(/static/sprites/spritesmith-main-0.png);
background-position: -1191px -1480px;
width: 68px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 KiB

After

Width:  |  Height:  |  Size: 556 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 285 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 279 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 156 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 152 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 143 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 150 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 145 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 155 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 173 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 160 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 151 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 75 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 73 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 143 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 136 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 129 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

After

Width:  |  Height:  |  Size: 115 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 B

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 556 B

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