Skip to content

Commit

Permalink
Merge branch 'develop' into inbox-outside-user
Browse files Browse the repository at this point in the history
  • Loading branch information
paglias committed Sep 9, 2018
2 parents 7ba837e + 92e4d5c commit 2bd3108
Show file tree
Hide file tree
Showing 202 changed files with 12,058 additions and 10,996 deletions.
2 changes: 1 addition & 1 deletion migrations/migration-runner.js
Expand Up @@ -17,5 +17,5 @@ function setUpServer () {
setUpServer();

// Replace this with your migration
const processUsers = require('./groups/reconcile-group-plan-members.js');
const processUsers = require('./users/takeThis.js');
processUsers();
4 changes: 2 additions & 2 deletions migrations/users/takeThis.js
@@ -1,4 +1,4 @@
let migrationName = '20180801_takeThis.js'; // Update per month
let migrationName = '20180904_takeThis.js'; // Update per month
let authorName = 'Sabe'; // in case script author needs to know when their ...
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done

Expand All @@ -15,7 +15,7 @@ function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
challenges: {$in: ['081f8912-3526-47d5-984f-f71bbeec77fc']}, // Update per month
challenges: {$in: ['1044ec0c-4a85-48c5-9f36-d51c0c62c7d3']}, // Update per month
};

if (lastId) {
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.59.1",
"version": "4.60.2",
"main": "./website/server/index.js",
"dependencies": {
"@slack/client": "^3.8.1",
Expand Down
21 changes: 0 additions & 21 deletions test/api/unit/libs/cron.test.js
Expand Up @@ -1589,27 +1589,6 @@ describe('cron', () => {
flagCount: 0,
};
});

xit('does not clear pms under 200', () => {
cron({user, tasksByType, daysMissed, analytics});
expect(user.inbox.messages[lastMessageId]).to.exist;
});

xit('clears pms over 200', () => {
let messageId = common.uuid();
user.inbox.messages[messageId] = {
id: messageId,
text: `test ${messageId}`,
timestamp: Number(new Date()),
likes: {},
flags: {},
flagCount: 0,
};

cron({user, tasksByType, daysMissed, analytics});

expect(user.inbox.messages[messageId]).to.not.exist;
});
});

describe('login incentives', () => {
Expand Down
Expand Up @@ -63,45 +63,48 @@ describe('GET /challenges/:challengeId', () => {

context('private guild', () => {
let groupLeader;
let challengeLeader;
let group;
let challenge;
let members;
let user;
let nonMember;
let otherMember;

beforeEach(async () => {
user = await generateUser();
nonMember = await generateUser();

let populatedGroup = await createAndPopulateGroup({
groupDetails: {type: 'guild', privacy: 'private'},
members: 1,
members: 2,
});

groupLeader = populatedGroup.groupLeader;
group = populatedGroup.group;
members = populatedGroup.members;

challenge = await generateChallenge(groupLeader, group);
await members[0].post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/challenges/${challenge._id}/join`);
challengeLeader = members[0];
otherMember = members[1];

challenge = await generateChallenge(challengeLeader, group);
});

it('fails if user doesn\'t have access to the challenge', async () => {
await expect(user.get(`/challenges/${challenge._id}`)).to.eventually.be.rejected.and.eql({
it('fails if user isn\'t in the guild and isn\'t challenge leader', async () => {
await expect(nonMember.get(`/challenges/${challenge._id}`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});

it('should return challenge data', async () => {
let chal = await members[0].get(`/challenges/${challenge._id}`);
it('returns challenge data for any user in the guild', async () => {
let chal = await otherMember.get(`/challenges/${challenge._id}`);
expect(chal.name).to.equal(challenge.name);
expect(chal._id).to.equal(challenge._id);

expect(chal.leader).to.eql({
_id: groupLeader._id,
id: groupLeader._id,
profile: {name: groupLeader.profile.name},
_id: challengeLeader._id,
id: challengeLeader._id,
profile: {name: challengeLeader.profile.name},
});
expect(chal.group).to.eql({
_id: group._id,
Expand All @@ -114,53 +117,72 @@ describe('GET /challenges/:challengeId', () => {
leader: groupLeader.id,
});
});

it('returns challenge data if challenge leader isn\'t in the guild or challenge', async () => {
await challengeLeader.post(`/groups/${group._id}/leave`);
await challengeLeader.sync();
expect(challengeLeader.guilds).to.be.empty; // check that leaving worked

let chal = await challengeLeader.get(`/challenges/${challenge._id}`);
expect(chal.name).to.equal(challenge.name);
expect(chal._id).to.equal(challenge._id);

expect(chal.leader).to.eql({
_id: challengeLeader._id,
id: challengeLeader._id,
profile: {name: challengeLeader.profile.name},
});
});
});

context('party', () => {
let groupLeader;
let challengeLeader;
let group;
let challenge;
let members;
let user;
let nonMember;
let otherMember;

beforeEach(async () => {
user = await generateUser();
nonMember = await generateUser();

let populatedGroup = await createAndPopulateGroup({
groupDetails: {type: 'party'},
members: 1,
groupDetails: {type: 'party', privacy: 'private'},
members: 2,
});

groupLeader = populatedGroup.groupLeader;
group = populatedGroup.group;
members = populatedGroup.members;

challenge = await generateChallenge(groupLeader, group);
await members[0].post(`/challenges/${challenge._id}/join`);
await groupLeader.post(`/challenges/${challenge._id}/join`);
challengeLeader = members[0];
otherMember = members[1];

challenge = await generateChallenge(challengeLeader, group);
});

it('fails if user doesn\'t have access to the challenge', async () => {
await expect(user.get(`/challenges/${challenge._id}`)).to.eventually.be.rejected.and.eql({
it('fails if user isn\'t in the party and isn\'t challenge leader', async () => {
await expect(nonMember.get(`/challenges/${challenge._id}`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});

it('should return challenge data', async () => {
let chal = await members[0].get(`/challenges/${challenge._id}`);
it('returns challenge data for any user in the party', async () => {
let chal = await otherMember.get(`/challenges/${challenge._id}`);
expect(chal.name).to.equal(challenge.name);
expect(chal._id).to.equal(challenge._id);

expect(chal.leader).to.eql({
_id: groupLeader._id,
id: groupLeader.id,
profile: {name: groupLeader.profile.name},
_id: challengeLeader._id,
id: challengeLeader._id,
profile: {name: challengeLeader.profile.name},
});
expect(chal.group).to.eql({
_id: group._id,
id: group.id,
id: group._id,
categories: [],
name: group.name,
summary: group.name,
Expand All @@ -169,5 +191,21 @@ describe('GET /challenges/:challengeId', () => {
leader: groupLeader.id,
});
});

it('returns challenge data if challenge leader isn\'t in the party or challenge', async () => {
await challengeLeader.post('/groups/party/leave');
await challengeLeader.sync();
expect(challengeLeader.party._id).to.be.undefined; // check that leaving worked

let chal = await challengeLeader.get(`/challenges/${challenge._id}`);
expect(chal.name).to.equal(challenge.name);
expect(chal._id).to.equal(challenge._id);

expect(chal.leader).to.eql({
_id: challengeLeader._id,
id: challengeLeader._id,
profile: {name: challengeLeader.profile.name},
});
});
});
});
@@ -1,6 +1,7 @@
import {
generateUser,
generateGroup,
createAndPopulateGroup,
generateChallenge,
translate as t,
} from '../../../../helpers/api-integration/v3';
Expand All @@ -10,7 +11,7 @@ describe('GET /challenges/:challengeId/members', () => {
let user;

beforeEach(async () => {
user = await generateUser();
user = await generateUser({ balance: 1 });
});

it('validates optional req.query.lastId to be an UUID', async () => {
Expand All @@ -21,16 +22,16 @@ describe('GET /challenges/:challengeId/members', () => {
});
});

it('fails if challenge doesn\'t exists', async () => {
it('fails if challenge doesn\'t exist', async () => {
await expect(user.get(`/challenges/${generateUUID()}/members`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});

it('fails if user doesn\'t have access to the challenge', async () => {
let group = await generateGroup(user);
it('fails if user isn\'t in the private group and isn\'t challenge leader', async () => {
let group = await generateGroup(user, {type: 'party', privacy: 'private'});
let challenge = await generateChallenge(user, group);
let anotherUser = await generateUser();

Expand All @@ -41,6 +42,27 @@ describe('GET /challenges/:challengeId/members', () => {
});
});

it('works if user isn\'t in the private group but is challenge leader', async () => {
let populatedGroup = await createAndPopulateGroup({
groupDetails: {type: 'party', privacy: 'private'},
members: 1,
});
let groupLeader = populatedGroup.groupLeader;
let challengeLeader = populatedGroup.members[0];
let challenge = await generateChallenge(challengeLeader, populatedGroup.group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
await challengeLeader.post('/groups/party/leave');
await challengeLeader.sync();
expect(challengeLeader.party._id).to.be.undefined; // check that leaving worked

let res = await challengeLeader.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({
_id: groupLeader._id,
id: groupLeader._id,
profile: {name: groupLeader.profile.name},
});
});

it('works with challenges belonging to public guild', async () => {
let leader = await generateUser({balance: 4});
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});
Expand Down
10 changes: 0 additions & 10 deletions test/api/v3/integration/challenges/POST-challenges.test.js
Expand Up @@ -94,16 +94,6 @@ describe('POST /challenges', () => {
});
});

it('returns an error when non-leader member creates a challenge in leaderOnly group', async () => {
await expect(groupMember.post('/challenges', {
group: group._id,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('onlyGroupLeaderChal'),
});
});

it('allows non-leader member to create a challenge', async () => {
let populatedGroup = await createAndPopulateGroup({
members: 1,
Expand Down
Expand Up @@ -46,7 +46,7 @@ describe('POST /challenges/:challengeId/join', () => {
await groupLeader.post(`/challenges/${challenge._id}/join`);
});

it('returns an error when user doesn\'t have permissions to access the challenge', async () => {
it('returns an error when user isn\'t in the private group and isn\'t challenge leader', async () => {
let unauthorizedUser = await generateUser();

await expect(unauthorizedUser.post(`/challenges/${challenge._id}/join`)).to.eventually.be.rejected.and.eql({
Expand All @@ -56,6 +56,16 @@ describe('POST /challenges/:challengeId/join', () => {
});
});

it('succeeds when user isn\'t in the private group but is challenge leader', async () => {
await groupLeader.post(`/challenges/${challenge._id}/leave`);
await groupLeader.post(`/groups/${group._id}/leave`);
await groupLeader.sync();
expect(groupLeader.guilds).to.be.empty; // check that leaving worked

let res = await groupLeader.post(`/challenges/${challenge._id}/join`);
expect(res.name).to.equal(challenge.name);
});

it('returns challenge data', async () => {
let res = await authorizedUser.post(`/challenges/${challenge._id}/join`);

Expand Down
50 changes: 50 additions & 0 deletions test/client/unit/specs/components/notifications.js
@@ -0,0 +1,50 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import NotificationsComponent from 'client/components/notifications.vue';
import Store from 'client/libs/store';
import { hasClass } from 'client/store/getters/members';

const localVue = createLocalVue();
localVue.use(Store);

describe('Notifications', () => {
let store;

beforeEach(() => {
store = new Store({
state: {
user: {
data: {
stats: {
lvl: 0,
},
flags: {},
preferences: {},
party: {
quest: {
},
},
},
},
},
actions: {
'user:fetch': () => {},
'tasks:fetchUserTasks': () => {},
},
getters: {
'members:hasClass': hasClass,
},
});
});

it('set user has class computed prop', () => {
const wrapper = shallowMount(NotificationsComponent, { store, localVue });

expect(wrapper.vm.userHasClass).to.be.false;

store.state.user.data.stats.lvl = 10;
store.state.user.data.flags.classSelected = true;
store.state.user.data.preferences.disableClasses = false;

expect(wrapper.vm.userHasClass).to.be.true;
});
});

0 comments on commit 2bd3108

Please sign in to comment.