Skip to content
Permalink
Browse files

Merge branch 'develop' of https://github.com/HabitRPG/habitica into n…

…egue/market-fixes-2

# Conflicts:
#	website/client/components/shops/buyModal.vue
  • Loading branch information
negue committed Nov 28, 2017
2 parents 6f3fd9d + 4ab89fd commit f8837865b61e05824d7ef2941dc5998a2fe32650
Showing with 446 additions and 258 deletions.
  1. +2 −2 migrations/20140831_increase_gems_for_previous_contributions.js
  2. +2 −2 migrations/20151021_usernames_emails_lowercase.js
  3. +1 −0 package.json
  4. +11 −8 test/api/v3/integration/chat/POST-groups_id_chat_id_clear_flags.test.js
  5. +2 −2 test/api/v3/integration/coupons/GET-coupons.test.js
  6. +2 −1 test/api/v3/integration/coupons/POST-coupons_generate_event.test.js
  7. +45 −12 test/api/v3/integration/tasks/POST-tasks_id_score_direction.test.js
  8. +7 −0 ...3/integration/tasks/challenges/POST-tasks_challenges_challengeId_tasks_id_score_direction.test.js
  9. +1 −1 test/api/v3/integration/user/DELETE-user.test.js
  10. +2 −1 test/api/v3/unit/middlewares/ensureAccessRight.test.js
  11. +31 −0 test/client/unit/specs/components/groups/membersModal.js
  12. +14 −6 webpack/config/index.js
  13. +2 −8 webpack/config/prod.env.js
  14. +7 −10 website/client/app.vue
  15. +5 −5 website/client/components/appFooter.vue
  16. +5 −5 website/client/components/challenges/sidebar.vue
  17. +8 −5 website/client/components/chat/chatMessages.vue
  18. +18 −16 website/client/components/creatorIntro.vue
  19. +78 −26 website/client/components/groups/membersModal.vue
  20. +13 −5 website/client/components/groups/questDetailsModal.vue
  21. +1 −1 website/client/components/groups/sidebar.vue
  22. +1 −1 website/client/components/header/menu.vue
  23. +3 −3 website/client/components/header/notificationsDropdown.vue
  24. +1 −1 website/client/components/inventory/equipment/index.vue
  25. +1 −1 website/client/components/inventory/items/index.vue
  26. +2 −2 website/client/components/inventory/stable/index.vue
  27. +8 −1 website/client/components/selectMembersModal.vue
  28. +1 −1 website/client/components/settings/deleteModal.vue
  29. +0 −1 website/client/components/settings/site.vue
  30. +5 −8 website/client/components/settings/subscription.vue
  31. +25 −3 website/client/components/shops/buyModal.vue
  32. +6 −4 website/client/components/shops/market/index.vue
  33. +1 −1 website/client/components/shops/quests/index.vue
  34. +1 −1 website/client/components/shops/seasonal/index.vue
  35. +2 −1 website/client/components/shops/shopItem.vue
  36. +2 −2 website/client/components/shops/timeTravelers/index.vue
  37. +8 −3 website/client/components/static/groupPlans.vue
  38. +1 −1 website/client/components/static/staticWrapper.vue
  39. +19 −11 website/client/components/tasks/column.vue
  40. +11 −1 website/client/components/tasks/task.vue
  41. +8 −5 website/client/components/tasks/taskModal.vue
  42. +2 −2 website/client/components/ui/drawer.vue
  43. +0 −46 website/client/directives/sortable.directive.js
  44. +9 −1 website/client/store/actions/shops.js
  45. +1 −0 website/common/locales/en/character.json
  46. +1 −1 website/common/locales/en/contrib.json
  47. +2 −1 website/common/locales/en/front.json
  48. +2 −2 website/common/locales/en/generic.json
  49. +12 −10 website/common/locales/en/groups.json
  50. +1 −1 website/common/locales/en/messages.json
  51. +1 −1 website/common/locales/en/npc.json
  52. +1 −0 website/common/locales/en/quests.json
  53. +1 −1 website/common/locales/en/settings.json
  54. +0 −1 website/common/locales/en/subscriber.json
  55. +3 −1 website/common/locales/en/tasks.json
  56. +2 −0 website/common/script/libs/shops.js
  57. +1 −2 website/common/script/libs/taskClasses.js
  58. +24 −12 website/common/script/ops/pinnedGearUtils.js
  59. +2 −1 website/server/controllers/api-v3/chat.js
  60. +8 −0 website/server/controllers/api-v3/tasks.js
  61. +1 −1 website/server/controllers/api-v3/user.js
  62. +1 −1 website/server/libs/amazonPayments.js
  63. +1 −0 website/server/libs/apiMessages.js
  64. +1 −1 website/server/libs/cron.js
  65. +3 −2 website/server/libs/setupNconf.js
  66. +2 −1 website/server/middlewares/ensureAccessRight.js
  67. +1 −1 website/server/models/user/schema.js
@@ -16,7 +16,7 @@ var migrationName = '20140831_increase_gems_for_previous_contributions';
* https://github.com/HabitRPG/habitrpg/issues/3933
* Increase Number of Gems for Contributors
* author: Alys (d904bd62-da08-416b-a816-ba797c9ee265)
*
*
* Increase everyone's gems per their contribution level.
* Originally they were given 2 gems per tier.
* Now they are given 3 gems per tier for tiers 1,2,3
@@ -70,7 +70,7 @@ dbUsers.findEach(query, fields, function(err, user) {
var extraGems = tier; // tiers 1,2,3
if (tier > 3) { extraGems = 3 + (tier - 3) * 2; }
if (tier == 8) { extraGems = 11; }
extraBalance = extraGems / 4;
var extraBalance = extraGems / 4;
set['balance'] = user.balance + extraBalance;

// Capture current state of user:
@@ -39,7 +39,7 @@ function findUsers(gt){
console.log('User: ', countUsers, user._id);

var update = {
$set: {};
$set: {}
};

if(user.auth && user.auth.local) {
@@ -60,4 +60,4 @@ function findUsers(gt){
});
};

findUsers();
findUsers();
@@ -122,6 +122,7 @@
"vue-router": "^3.0.0",
"vue-style-loader": "^3.0.0",
"vue-template-compiler": "^2.5.2",
"vuedraggable": "^2.15.0",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker#825a866b6a9c52dd8c588a3e8b900880875ce914",
"webpack": "^2.2.1",
"webpack-merge": "^4.0.0",
@@ -3,6 +3,7 @@ import {
generateUser,
translate as t,
} from '../../../../helpers/api-v3-integration.helper';
import config from '../../../../../config.json';
import { v4 as generateUUID } from 'uuid';

describe('POST /groups/:id/chat/:id/clearflags', () => {
@@ -74,7 +75,7 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
expect(messages[0].flagCount).to.eql(0);
});

it('can unflag a system message', async () => {
it('can\'t flag a system message', async () => {
let { group, members } = await createAndPopulateGroup({
groupDetails: {
type: 'party',
@@ -95,13 +96,15 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
await member.post('/user/class/cast/mpheal');

let [skillMsg] = await member.get(`/groups/${group.id}/chat`);

await member.post(`/groups/${group._id}/chat/${skillMsg.id}/flag`);
await admin.post(`/groups/${group._id}/chat/${skillMsg.id}/clearflags`);

let messages = await members[0].get(`/groups/${group._id}/chat`);
expect(messages[0].id).to.eql(skillMsg.id);
expect(messages[0].flagCount).to.eql(0);
await expect(member.post(`/groups/${group._id}/chat/${skillMsg.id}/flag`))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('messageCannotFlagSystemMessages', {communityManagerEmail: config.EMAILS.COMMUNITY_MANAGER_EMAIL}),
});
// let messages = await members[0].get(`/groups/${group._id}/chat`);
// expect(messages[0].id).to.eql(skillMsg.id);
// expect(messages[0].flagCount).to.eql(0);
});
});

@@ -1,8 +1,8 @@
import {
generateUser,
translate as t,
resetHabiticaDB,
} from '../../../../helpers/api-v3-integration.helper';
import apiMessages from '../../../../../website/server/libs/apiMessages';

describe('GET /coupons/', () => {
let user;
@@ -19,7 +19,7 @@ describe('GET /coupons/', () => {
await expect(user.get('/coupons')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('noSudoAccess'),
message: apiMessages('noSudoAccess'),
});
});

@@ -4,6 +4,7 @@ import {
resetHabiticaDB,
} from '../../../../helpers/api-v3-integration.helper';
import couponCode from 'coupon-code';
import apiMessages from '../../../../../website/server/libs/apiMessages';

describe('POST /coupons/generate/:event', () => {
let user;
@@ -25,7 +26,7 @@ describe('POST /coupons/generate/:event', () => {
await expect(user.post('/coupons/generate/aaa')).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('noSudoAccess'),
message: apiMessages('noSudoAccess'),
});
});

@@ -130,16 +130,31 @@ describe('POST /tasks/:id/score/:direction', () => {
});

it('uncompletes todo when direction is down', async () => {
await user.post(`/tasks/${todo._id}/score/up`);
await user.post(`/tasks/${todo._id}/score/down`);
let updatedTask = await user.get(`/tasks/${todo._id}`);

expect(updatedTask.completed).to.equal(false);
expect(updatedTask.dateCompleted).to.be.a('undefined');
});

it('scores up todo even if it is already completed'); // Yes?
it('doesn\'t let a todo be completed twice', async () => {
await user.post(`/tasks/${todo._id}/score/up`);
await expect(user.post(`/tasks/${todo._id}/score/up`))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('sessionOutdated'),
});
});

it('scores down todo even if it is already uncompleted'); // Yes?
it('doesn\'t let a todo be uncompleted twice', async () => {
await expect(user.post(`/tasks/${todo._id}/score/down`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('sessionOutdated'),
});
});

context('user stats when direction is up', () => {
let updatedUser;
@@ -163,23 +178,25 @@ describe('POST /tasks/:id/score/:direction', () => {
});

context('user stats when direction is down', () => {
let updatedUser;
let updatedUser, initialUser;

beforeEach(async () => {
await user.post(`/tasks/${todo._id}/score/up`);
initialUser = await user.get('/user');
await user.post(`/tasks/${todo._id}/score/down`);
updatedUser = await user.get('/user');
});

it('decreases user\'s mp', () => {
expect(updatedUser.stats.mp).to.be.lessThan(user.stats.mp);
expect(updatedUser.stats.mp).to.be.lessThan(initialUser.stats.mp);
});

it('decreases user\'s exp', () => {
expect(updatedUser.stats.exp).to.be.lessThan(user.stats.exp);
expect(updatedUser.stats.exp).to.be.lessThan(initialUser.stats.exp);
});

it('decreases user\'s gold', () => {
expect(updatedUser.stats.gp).to.be.lessThan(user.stats.gp);
expect(updatedUser.stats.gp).to.be.lessThan(initialUser.stats.gp);
});
});
});
@@ -202,6 +219,7 @@ describe('POST /tasks/:id/score/:direction', () => {
});

it('uncompletes daily when direction is down', async () => {
await user.post(`/tasks/${daily._id}/score/up`);
await user.post(`/tasks/${daily._id}/score/down`);
let task = await user.get(`/tasks/${daily._id}`);

@@ -222,9 +240,22 @@ describe('POST /tasks/:id/score/:direction', () => {
expect(task.nextDue.length).to.eql(6);
});

it('scores up daily even if it is already completed'); // Yes?
it('doesn\'t let a daily be completed twice', async () => {
await user.post(`/tasks/${daily._id}/score/up`);
await expect(user.post(`/tasks/${daily._id}/score/up`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('sessionOutdated'),
});
});

it('scores down daily even if it is already uncompleted'); // Yes?
it('doesn\'t let a daily be uncompleted twice', async () => {
await expect(user.post(`/tasks/${daily._id}/score/down`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('sessionOutdated'),
});
});

context('user stats when direction is up', () => {
let updatedUser;
@@ -248,23 +279,25 @@ describe('POST /tasks/:id/score/:direction', () => {
});

context('user stats when direction is down', () => {
let updatedUser;
let updatedUser, initialUser;

beforeEach(async () => {
await user.post(`/tasks/${daily._id}/score/up`);
initialUser = await user.get('/user');
await user.post(`/tasks/${daily._id}/score/down`);
updatedUser = await user.get('/user');
});

it('decreases user\'s mp', () => {
expect(updatedUser.stats.mp).to.be.lessThan(user.stats.mp);
expect(updatedUser.stats.mp).to.be.lessThan(initialUser.stats.mp);
});

it('decreases user\'s exp', () => {
expect(updatedUser.stats.exp).to.be.lessThan(user.stats.exp);
expect(updatedUser.stats.exp).to.be.lessThan(initialUser.stats.exp);
});

it('decreases user\'s gold', () => {
expect(updatedUser.stats.gp).to.be.lessThan(user.stats.gp);
expect(updatedUser.stats.gp).to.be.lessThan(initialUser.stats.gp);
});
});
});
@@ -82,6 +82,13 @@ describe('POST /tasks/:id/score/:direction', () => {
});

it('should update the history', async () => {
let newCron = new Date(2015, 11, 20);

await user.post('/debug/set-cron', {
lastCron: newCron,
});

await user.post('/cron');
await user.post(`/tasks/${usersChallengeTaskId}/score/up`);

let tasks = await user.get(`/tasks/challenge/${challenge._id}`);
@@ -308,7 +308,7 @@ describe('DELETE /user', () => {
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('incorrectDeletePhrase'),
message: t('incorrectDeletePhrase', {magicWord: 'DELETE'}),
});
});

@@ -7,6 +7,7 @@ import {
import i18n from '../../../../../website/common/script/i18n';
import { ensureAdmin, ensureSudo } from '../../../../../website/server/middlewares/ensureAccessRight';
import { NotAuthorized } from '../../../../../website/server/libs/errors';
import apiMessages from '../../../../../website/server/libs/apiMessages';

describe('ensure access middlewares', () => {
let res, req, next;
@@ -42,7 +43,7 @@ describe('ensure access middlewares', () => {

ensureSudo(req, res, next);

expect(next).to.be.calledWith(new NotAuthorized(i18n.t('noSudoAccess')));
expect(next).to.be.calledWith(new NotAuthorized(apiMessages('noSudoAccess')));
});

it('passes when user is a sudo user', () => {
@@ -0,0 +1,31 @@
import Vue from 'vue';
import MembersModalComponent from 'client/components/groups/membersModal.vue';

describe('Members Modal Component', () => {
describe('Party Sort', () => {
let CTor;
let vm;

beforeEach(() => {
CTor = Vue.extend(MembersModalComponent);
vm = new CTor().$mount();
});

afterEach(() => {
vm.$destroy();
});

it('should have an empty object as sort-option at start', () => {
const defaultData = vm.data();
expect(defaultData.sortOption).to.eq({});
});

it('should accept sort-option object', () => {
const sortOption = vm.data().sortOption[0];
vm.sort(sortOption);
Vue.nextTick(() => {
expect(vm.data().sortOption).to.eq(sortOption);
});
});
});
});
@@ -3,6 +3,14 @@ const path = require('path');
const staticAssetsDirectory = './website/static/.'; // The folder where static files (not processed) live
const prodEnv = require('./prod.env');
const devEnv = require('./dev.env');
const nconf = require('nconf');
const setupNconf = require('../../website/server/libs/setupNconf');

let configFile = path.join(path.resolve(__dirname, '../../config.json'));

setupNconf(configFile);

const DEV_BASE_URL = nconf.get('BASE_URL');

module.exports = {
build: {
@@ -33,25 +41,25 @@ module.exports = {
assetsPublicPath: '/',
staticAssetsDirectory,
proxyTable: {
// proxy all requests starting with /api/v3 to localhost:3000
// proxy all requests starting with /api/v3 to IP:PORT as specified in the top-level config
'/api/v3': {
target: 'http://localhost:3000',
target: DEV_BASE_URL,
changeOrigin: true,
},
'/stripe': {
target: 'http://localhost:3000',
target: DEV_BASE_URL,
changeOrigin: true,
},
'/amazon': {
target: 'http://localhost:3000',
target: DEV_BASE_URL,
changeOrigin: true,
},
'/paypal': {
target: 'http://localhost:3000',
target: DEV_BASE_URL,
changeOrigin: true,
},
'/logout': {
target: 'http://localhost:3000',
target: DEV_BASE_URL,
changeOrigin: true,
},
},
@@ -1,17 +1,11 @@
const nconf = require('nconf');
const { join, resolve } = require('path');
const setupNconf = require('../../website/server/libs/setupNconf');

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');
setupNconf(configFile);

// @TODO: Check if we can import from client. Items like admin emails can be imported
// and that should be prefered

0 comments on commit f883786

Please sign in to comment.
You can’t perform that action at this time.