mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 07:37:25 +01:00
Merge branch 'sabrecat/teams-hotfixes' into release
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
|||||||
describe('POST /group/:groupId/remove-manager', () => {
|
describe('POST /group/:groupId/remove-manager', () => {
|
||||||
let leader; let nonLeader; let
|
let leader; let nonLeader; let
|
||||||
groupToUpdate;
|
groupToUpdate;
|
||||||
const groupName = 'Test Public Guild';
|
const groupName = 'Test Private Guild';
|
||||||
const groupType = 'guild';
|
const groupType = 'guild';
|
||||||
let nonManager;
|
let nonManager;
|
||||||
|
|
||||||
@@ -20,9 +20,10 @@ describe('POST /group/:groupId/remove-manager', () => {
|
|||||||
groupDetails: {
|
groupDetails: {
|
||||||
name: groupName,
|
name: groupName,
|
||||||
type: groupType,
|
type: groupType,
|
||||||
privacy: 'public',
|
privacy: 'private',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
groupToUpdate = group;
|
groupToUpdate = group;
|
||||||
@@ -83,7 +84,7 @@ describe('POST /group/:groupId/remove-manager', () => {
|
|||||||
|
|
||||||
await nonLeader.sync();
|
await nonLeader.sync();
|
||||||
|
|
||||||
expect(nonLeader.notifications.length).to.equal(0);
|
expect(nonLeader.notifications.length).to.equal(1); // user gets mystery items
|
||||||
expect(updatedGroup.managers[nonLeader._id]).to.not.exist;
|
expect(updatedGroup.managers[nonLeader._id]).to.not.exist;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ describe('GET /tasks/:id', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 1,
|
members: 1,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
group = groupData.group;
|
group = groupData.group;
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import {
|
|||||||
describe('POST /tasks/clearCompletedTodos', () => {
|
describe('POST /tasks/clearCompletedTodos', () => {
|
||||||
it('deletes all completed todos except the ones from a challenge and group', async () => {
|
it('deletes all completed todos except the ones from a challenge and group', async () => {
|
||||||
const user = await generateUser({ balance: 1 });
|
const user = await generateUser({ balance: 1 });
|
||||||
const guild = await generateGroup(user);
|
const guild = await generateGroup(
|
||||||
|
user,
|
||||||
|
{},
|
||||||
|
{ 'purchased.plan.customerId': 'group-unlimited' },
|
||||||
|
);
|
||||||
const challenge = await generateChallenge(user, guild);
|
const challenge = await generateChallenge(user, guild);
|
||||||
await user.post(`/challenges/${challenge._id}/join`);
|
await user.post(`/challenges/${challenge._id}/join`);
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe('Groups DELETE /tasks/:id', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
@@ -77,18 +78,18 @@ describe('Groups DELETE /tasks/:id', () => {
|
|||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
await member2.sync();
|
await member2.sync();
|
||||||
expect(user.notifications.length).to.equal(2);
|
expect(user.notifications.length).to.equal(3); // mystery items
|
||||||
expect(user.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
expect(member2.notifications.length).to.equal(2);
|
expect(member2.notifications.length).to.equal(3);
|
||||||
expect(member2.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(member2.notifications[2].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
|
|
||||||
await member2.del(`/tasks/${task._id}`);
|
await member2.del(`/tasks/${task._id}`);
|
||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
await member2.sync();
|
await member2.sync();
|
||||||
|
|
||||||
expect(user.notifications.length).to.equal(1);
|
expect(user.notifications.length).to.equal(2);
|
||||||
expect(member2.notifications.length).to.equal(1);
|
expect(member2.notifications.length).to.equal(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deletes task from assigned user', async () => {
|
it('deletes task from assigned user', async () => {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ describe('GET /approvals/group/:groupId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ describe('GET /tasks/group/:groupId', () => {
|
|||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
user = await generateUser();
|
user = await generateUser();
|
||||||
group = await generateGroup(user);
|
group = await generateGroup(user, {}, { 'purchased.plan.customerId': 'group-unlimited' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error when group is not found', async () => {
|
it('returns error when group is not found', async () => {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe('POST /tasks/:id/approve/:userId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
@@ -63,9 +64,9 @@ describe('POST /tasks/:id/approve/:userId', () => {
|
|||||||
|
|
||||||
await member.sync();
|
await member.sync();
|
||||||
|
|
||||||
expect(member.notifications.length).to.equal(2);
|
expect(member.notifications.length).to.equal(3);
|
||||||
expect(member.notifications[1].type).to.equal('GROUP_TASK_APPROVED');
|
expect(member.notifications[2].type).to.equal('GROUP_TASK_APPROVED');
|
||||||
expect(member.notifications[1].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text }));
|
expect(member.notifications[2].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text }));
|
||||||
|
|
||||||
memberTasks = await member.get('/tasks/user');
|
memberTasks = await member.get('/tasks/user');
|
||||||
syncedTask = find(memberTasks, findAssignedTask);
|
syncedTask = find(memberTasks, findAssignedTask);
|
||||||
@@ -89,9 +90,9 @@ describe('POST /tasks/:id/approve/:userId', () => {
|
|||||||
await member2.post(`/tasks/${task._id}/approve/${member._id}`);
|
await member2.post(`/tasks/${task._id}/approve/${member._id}`);
|
||||||
await member.sync();
|
await member.sync();
|
||||||
|
|
||||||
expect(member.notifications.length).to.equal(2);
|
expect(member.notifications.length).to.equal(3);
|
||||||
expect(member.notifications[1].type).to.equal('GROUP_TASK_APPROVED');
|
expect(member.notifications[2].type).to.equal('GROUP_TASK_APPROVED');
|
||||||
expect(member.notifications[1].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text }));
|
expect(member.notifications[2].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text }));
|
||||||
|
|
||||||
memberTasks = await member.get('/tasks/user');
|
memberTasks = await member.get('/tasks/user');
|
||||||
syncedTask = find(memberTasks, findAssignedTask);
|
syncedTask = find(memberTasks, findAssignedTask);
|
||||||
@@ -113,18 +114,18 @@ describe('POST /tasks/:id/approve/:userId', () => {
|
|||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
await member2.sync();
|
await member2.sync();
|
||||||
expect(user.notifications.length).to.equal(2);
|
expect(user.notifications.length).to.equal(3);
|
||||||
expect(user.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
expect(member2.notifications.length).to.equal(1);
|
expect(member2.notifications.length).to.equal(2);
|
||||||
expect(member2.notifications[0].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(member2.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
|
|
||||||
await member2.post(`/tasks/${task._id}/approve/${member._id}`);
|
await member2.post(`/tasks/${task._id}/approve/${member._id}`);
|
||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
await member2.sync();
|
await member2.sync();
|
||||||
|
|
||||||
expect(user.notifications.length).to.equal(1);
|
expect(user.notifications.length).to.equal(2);
|
||||||
expect(member2.notifications.length).to.equal(0);
|
expect(member2.notifications.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('prevents double approval on a task', async () => {
|
it('prevents double approval on a task', async () => {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe('POST /tasks/:id/needs-work/:userId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
@@ -72,7 +73,7 @@ describe('POST /tasks/:id/needs-work/:userId', () => {
|
|||||||
expect(syncedTask.group.approval.requestedDate).to.equal(undefined);
|
expect(syncedTask.group.approval.requestedDate).to.equal(undefined);
|
||||||
|
|
||||||
// Check that the notification is correct
|
// Check that the notification is correct
|
||||||
expect(member.notifications.length).to.equal(initialNotifications + 2);
|
expect(member.notifications.length).to.equal(initialNotifications + 3);
|
||||||
const notification = member.notifications[member.notifications.length - 1];
|
const notification = member.notifications[member.notifications.length - 1];
|
||||||
expect(notification.type).to.equal('GROUP_TASK_NEEDS_WORK');
|
expect(notification.type).to.equal('GROUP_TASK_NEEDS_WORK');
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ describe('POST /tasks/:id/needs-work/:userId', () => {
|
|||||||
expect(syncedTask.group.approval.requested).to.equal(false);
|
expect(syncedTask.group.approval.requested).to.equal(false);
|
||||||
expect(syncedTask.group.approval.requestedDate).to.equal(undefined);
|
expect(syncedTask.group.approval.requestedDate).to.equal(undefined);
|
||||||
|
|
||||||
expect(member.notifications.length).to.equal(initialNotifications + 2);
|
expect(member.notifications.length).to.equal(initialNotifications + 3);
|
||||||
const notification = member.notifications[member.notifications.length - 1];
|
const notification = member.notifications[member.notifications.length - 1];
|
||||||
expect(notification.type).to.equal('GROUP_TASK_NEEDS_WORK');
|
expect(notification.type).to.equal('GROUP_TASK_NEEDS_WORK');
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe('POST /tasks/:id/score/:direction', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
@@ -53,15 +54,15 @@ describe('POST /tasks/:id/score/:direction', () => {
|
|||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
expect(user.notifications.length).to.equal(2);
|
expect(user.notifications.length).to.equal(3);
|
||||||
expect(user.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
expect(user.notifications[1].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
expect(user.notifications[2].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
||||||
user: member.auth.local.username,
|
user: member.auth.local.username,
|
||||||
taskName: updatedTask.text,
|
taskName: updatedTask.text,
|
||||||
taskId: updatedTask._id,
|
taskId: updatedTask._id,
|
||||||
direction,
|
direction,
|
||||||
}, 'cs')); // This test only works if we have the notification translated
|
}, 'cs')); // This test only works if we have the notification translated
|
||||||
expect(user.notifications[1].data.groupId).to.equal(guild._id);
|
expect(user.notifications[2].data.groupId).to.equal(guild._id);
|
||||||
|
|
||||||
expect(updatedTask.group.approval.requested).to.equal(true);
|
expect(updatedTask.group.approval.requested).to.equal(true);
|
||||||
expect(updatedTask.group.approval.requestedDate).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type
|
expect(updatedTask.group.approval.requestedDate).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type
|
||||||
@@ -80,25 +81,25 @@ describe('POST /tasks/:id/score/:direction', () => {
|
|||||||
await user.sync();
|
await user.sync();
|
||||||
await member2.sync();
|
await member2.sync();
|
||||||
|
|
||||||
expect(user.notifications.length).to.equal(2);
|
expect(user.notifications.length).to.equal(3);
|
||||||
expect(user.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
expect(user.notifications[1].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
expect(user.notifications[2].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
||||||
user: member.auth.local.username,
|
user: member.auth.local.username,
|
||||||
taskName: updatedTask.text,
|
taskName: updatedTask.text,
|
||||||
taskId: updatedTask._id,
|
taskId: updatedTask._id,
|
||||||
direction,
|
direction,
|
||||||
}));
|
}));
|
||||||
expect(user.notifications[1].data.groupId).to.equal(guild._id);
|
expect(user.notifications[2].data.groupId).to.equal(guild._id);
|
||||||
|
|
||||||
expect(member2.notifications.length).to.equal(1);
|
expect(member2.notifications.length).to.equal(2);
|
||||||
expect(member2.notifications[0].type).to.equal('GROUP_TASK_APPROVAL');
|
expect(member2.notifications[1].type).to.equal('GROUP_TASK_APPROVAL');
|
||||||
expect(member2.notifications[0].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
expect(member2.notifications[1].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
||||||
user: member.auth.local.username,
|
user: member.auth.local.username,
|
||||||
taskName: updatedTask.text,
|
taskName: updatedTask.text,
|
||||||
taskId: updatedTask._id,
|
taskId: updatedTask._id,
|
||||||
direction,
|
direction,
|
||||||
}));
|
}));
|
||||||
expect(member2.notifications[0].data.groupId).to.equal(guild._id);
|
expect(member2.notifications[1].data.groupId).to.equal(guild._id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('errors when approval has already been requested', async () => {
|
it('errors when approval has already been requested', async () => {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ describe('POST /tasks/group/:groupid', () => {
|
|||||||
privacy: 'private',
|
privacy: 'private',
|
||||||
},
|
},
|
||||||
members: 1,
|
members: 1,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ describe('POST /tasks/:taskId/assign/:memberId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
@@ -103,14 +104,14 @@ describe('POST /tasks/:taskId/assign/:memberId', () => {
|
|||||||
await member2.sync();
|
await member2.sync();
|
||||||
const groupTask = await user.get(`/tasks/group/${guild._id}`);
|
const groupTask = await user.get(`/tasks/group/${guild._id}`);
|
||||||
|
|
||||||
expect(user.notifications.length).to.equal(2); // includes Guild Joined achievement
|
expect(user.notifications.length).to.equal(3); // includes Guild Joined achievement
|
||||||
expect(user.notifications[1].type).to.equal('GROUP_TASK_CLAIMED');
|
expect(user.notifications[2].type).to.equal('GROUP_TASK_CLAIMED');
|
||||||
expect(user.notifications[1].data.taskId).to.equal(groupTask[0]._id);
|
expect(user.notifications[2].data.taskId).to.equal(groupTask[0]._id);
|
||||||
expect(user.notifications[1].data.groupId).to.equal(guild._id);
|
expect(user.notifications[2].data.groupId).to.equal(guild._id);
|
||||||
expect(member2.notifications.length).to.equal(1);
|
expect(member2.notifications.length).to.equal(2);
|
||||||
expect(member2.notifications[0].type).to.equal('GROUP_TASK_CLAIMED');
|
expect(member2.notifications[1].type).to.equal('GROUP_TASK_CLAIMED');
|
||||||
expect(member2.notifications[0].data.taskId).to.equal(groupTask[0]._id);
|
expect(member2.notifications[1].data.taskId).to.equal(groupTask[0]._id);
|
||||||
expect(member2.notifications[0].data.groupId).to.equal(guild._id);
|
expect(member2.notifications[1].data.groupId).to.equal(guild._id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('assigns a task to a user', async () => {
|
it('assigns a task to a user', async () => {
|
||||||
@@ -130,9 +131,9 @@ describe('POST /tasks/:taskId/assign/:memberId', () => {
|
|||||||
|
|
||||||
const groupTask = await user.get(`/tasks/group/${guild._id}`);
|
const groupTask = await user.get(`/tasks/group/${guild._id}`);
|
||||||
|
|
||||||
expect(member.notifications.length).to.equal(1);
|
expect(member.notifications.length).to.equal(2);
|
||||||
expect(member.notifications[0].type).to.equal('GROUP_TASK_ASSIGNED');
|
expect(member.notifications[1].type).to.equal('GROUP_TASK_ASSIGNED');
|
||||||
expect(member.notifications[0].taskId).to.equal(groupTask._id);
|
expect(member.notifications[1].taskId).to.equal(groupTask._id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('assigns a task to multiple users', async () => {
|
it('assigns a task to multiple users', async () => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe('POST group-tasks/:taskId/move/to/:position', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
user = await generateUser({ balance: 1 });
|
user = await generateUser({ balance: 1 });
|
||||||
guild = await generateGroup(user, { type: 'guild' });
|
guild = await generateGroup(user, { type: 'guild' }, { 'purchased.plan.customerId': 'group-unlimited' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can move task to new position', async () => {
|
it('can move task to new position', async () => {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
@@ -91,7 +92,7 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => {
|
|||||||
await user.post(`/tasks/${task._id}/unassign/${member._id}`);
|
await user.post(`/tasks/${task._id}/unassign/${member._id}`);
|
||||||
|
|
||||||
await member.sync();
|
await member.sync();
|
||||||
expect(member.notifications.length).to.equal(0);
|
expect(member.notifications.length).to.equal(1); // mystery items
|
||||||
});
|
});
|
||||||
|
|
||||||
it('unassigns a user and only that user from a task', async () => {
|
it('unassigns a user and only that user from a task', async () => {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ describe('PUT /tasks/:id', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ describe('DELETE group /tasks/:taskId/checklist/:itemId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ describe('POST group /tasks/:taskId/checklist/', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ describe('PUT group /tasks/:taskId/checklist/:itemId', () => {
|
|||||||
type: 'guild',
|
type: 'guild',
|
||||||
},
|
},
|
||||||
members: 2,
|
members: 2,
|
||||||
|
upgradeToGroupPlan: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
guild = group;
|
guild = group;
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ describe('POST /user/class/cast/:spellId', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns an error if a group task was targeted', async () => {
|
it('returns an error if a group task was targeted', async () => {
|
||||||
const { group, groupLeader } = await createAndPopulateGroup();
|
const { group, groupLeader } = await createAndPopulateGroup({ upgradeToGroupPlan: true });
|
||||||
|
|
||||||
const groupTask = await groupLeader.post(`/tasks/group/${group._id}`, {
|
const groupTask = await groupLeader.post(`/tasks/group/${group._id}`, {
|
||||||
text: 'todo group',
|
text: 'todo group',
|
||||||
@@ -266,7 +266,7 @@ describe('POST /user/class/cast/:spellId', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('searing brightness does not affect challenge or group tasks', async () => {
|
it('searing brightness does not affect challenge or group tasks', async () => {
|
||||||
const guild = await generateGroup(user);
|
const guild = await generateGroup(user, {}, { 'purchased.plan.customerId': 'group-unlimited' });
|
||||||
const challenge = await generateChallenge(user, guild);
|
const challenge = await generateChallenge(user, guild);
|
||||||
await user.post(`/challenges/${challenge._id}/join`);
|
await user.post(`/challenges/${challenge._id}/join`);
|
||||||
await user.post(`/tasks/challenge/${challenge._id}`, {
|
await user.post(`/tasks/challenge/${challenge._id}`, {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ describe('POST /user/reset', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not delete challenge or group tasks', async () => {
|
it('does not delete challenge or group tasks', async () => {
|
||||||
const guild = await generateGroup(user);
|
const guild = await generateGroup(user, {}, { 'purchased.plan.customerId': 'group-unlimited' });
|
||||||
const challenge = await generateChallenge(user, guild);
|
const challenge = await generateChallenge(user, guild);
|
||||||
await user.post(`/challenges/${challenge._id}/join`);
|
await user.post(`/challenges/${challenge._id}/join`);
|
||||||
await user.post(`/tasks/challenge/${challenge._id}`, {
|
await user.post(`/tasks/challenge/${challenge._id}`, {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ describe('POST /user/class/cast/:spellId', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns an error if a group task was targeted', async () => {
|
it('returns an error if a group task was targeted', async () => {
|
||||||
const { group, groupLeader } = await createAndPopulateGroup();
|
const { group, groupLeader } = await createAndPopulateGroup({ upgradeToGroupPlan: true });
|
||||||
|
|
||||||
const groupTask = await groupLeader.post(`/tasks/group/${group._id}`, {
|
const groupTask = await groupLeader.post(`/tasks/group/${group._id}`, {
|
||||||
text: 'todo group',
|
text: 'todo group',
|
||||||
@@ -234,7 +234,7 @@ describe('POST /user/class/cast/:spellId', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('searing brightness does not affect challenge or group tasks', async () => {
|
it('searing brightness does not affect challenge or group tasks', async () => {
|
||||||
const guild = await generateGroup(user);
|
const guild = await generateGroup(user, {}, { 'purchased.plan.customerId': 'group-unlimited' });
|
||||||
const challenge = await generateChallenge(user, guild);
|
const challenge = await generateChallenge(user, guild);
|
||||||
await user.post(`/challenges/${challenge._id}/join`);
|
await user.post(`/challenges/${challenge._id}/join`);
|
||||||
await user.post(`/tasks/challenge/${challenge._id}`, {
|
await user.post(`/tasks/challenge/${challenge._id}`, {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ describe('POST /user/reset', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not delete challenge or group tasks', async () => {
|
it('does not delete challenge or group tasks', async () => {
|
||||||
const guild = await generateGroup(user);
|
const guild = await generateGroup(user, {}, { 'purchased.plan.customerId': 'group-unlimited' });
|
||||||
const challenge = await generateChallenge(user, guild);
|
const challenge = await generateChallenge(user, guild);
|
||||||
await user.post(`/challenges/${challenge._id}/join`);
|
await user.post(`/challenges/${challenge._id}/join`);
|
||||||
await user.post(`/tasks/challenge/${challenge._id}`, {
|
await user.post(`/tasks/challenge/${challenge._id}`, {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { v4 as generateUUID } from 'uuid';
|
|||||||
import { ApiUser, ApiGroup, ApiChallenge } from '../api-classes';
|
import { ApiUser, ApiGroup, ApiChallenge } from '../api-classes';
|
||||||
import { requester } from '../requester';
|
import { requester } from '../requester';
|
||||||
import * as Tasks from '../../../../website/server/models/task';
|
import * as Tasks from '../../../../website/server/models/task';
|
||||||
|
import payments from '../../../../website/server/libs/payments/payments';
|
||||||
|
import { model as User } from '../../../../website/server/models/user';
|
||||||
|
|
||||||
// Creates a new user and returns it
|
// Creates a new user and returns it
|
||||||
// If you need the user to have specific requirements,
|
// If you need the user to have specific requirements,
|
||||||
@@ -77,6 +79,26 @@ export async function generateGroup (leader, details = {}, update = {}) {
|
|||||||
return apiGroup;
|
return apiGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function _upgradeToGroupPlan (groupLeader, group) {
|
||||||
|
const groupLeaderModel = await User.findById(groupLeader._id).exec();
|
||||||
|
|
||||||
|
// Create subscription
|
||||||
|
const paymentData = {
|
||||||
|
user: groupLeaderModel,
|
||||||
|
groupId: group._id,
|
||||||
|
sub: {
|
||||||
|
key: 'basic_3mo',
|
||||||
|
},
|
||||||
|
customerId: 'customer-id',
|
||||||
|
paymentMethod: 'Payment Method',
|
||||||
|
headers: {
|
||||||
|
'x-client': 'habitica-web',
|
||||||
|
'user-agent': '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await payments.createSubscription(paymentData);
|
||||||
|
}
|
||||||
|
|
||||||
// This is generate group + the ability to create
|
// This is generate group + the ability to create
|
||||||
// real users to populate it. The settings object
|
// real users to populate it. The settings object
|
||||||
// takes in:
|
// takes in:
|
||||||
@@ -95,6 +117,7 @@ export async function generateGroup (leader, details = {}, update = {}) {
|
|||||||
export async function createAndPopulateGroup (settings = {}) {
|
export async function createAndPopulateGroup (settings = {}) {
|
||||||
const numberOfMembers = settings.members || 0;
|
const numberOfMembers = settings.members || 0;
|
||||||
const numberOfInvites = settings.invites || 0;
|
const numberOfInvites = settings.invites || 0;
|
||||||
|
const upgradeToGroupPlan = settings.upgradeToGroupPlan || false;
|
||||||
const { groupDetails } = settings;
|
const { groupDetails } = settings;
|
||||||
const leaderDetails = settings.leaderDetails || { balance: 10 };
|
const leaderDetails = settings.leaderDetails || { balance: 10 };
|
||||||
|
|
||||||
@@ -124,6 +147,10 @@ export async function createAndPopulateGroup (settings = {}) {
|
|||||||
|
|
||||||
await Promise.all(invitees.map(invitee => invitee.sync()));
|
await Promise.all(invitees.map(invitee => invitee.sync()));
|
||||||
|
|
||||||
|
if (upgradeToGroupPlan) {
|
||||||
|
await _upgradeToGroupPlan(groupLeader, group);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
groupLeader,
|
groupLeader,
|
||||||
group,
|
group,
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ export default {
|
|||||||
this.group = await this.$store.dispatch('guilds:getGroup', {
|
this.group = await this.$store.dispatch('guilds:getGroup', {
|
||||||
groupId: this.searchId,
|
groupId: this.searchId,
|
||||||
});
|
});
|
||||||
|
if (!this.group?.purchased?.active) {
|
||||||
|
if (this.group.type === 'guild') this.$router.push(`/groups/guild/${this.group._id}`);
|
||||||
|
if (this.group.type === 'party') this.$router.push('/party');
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.$store.dispatch('common:setTitle', {
|
this.$store.dispatch('common:setTitle', {
|
||||||
subSection: this.group.name,
|
subSection: this.group.name,
|
||||||
section: this.$route.path.startsWith('/group-plans') ? this.$t('groupPlans') : this.$t('group'),
|
section: this.$route.path.startsWith('/group-plans') ? this.$t('groupPlans') : this.$t('group'),
|
||||||
|
|||||||
@@ -1280,12 +1280,17 @@ export default {
|
|||||||
createTag: 'tags:createTag',
|
createTag: 'tags:createTag',
|
||||||
}),
|
}),
|
||||||
async syncTask () {
|
async syncTask () {
|
||||||
if (this.task && this.task.group && this.task.group.managerNotes) {
|
if (this.task?.group?.managerNotes) {
|
||||||
this.managerNotes = this.task.group.managerNotes;
|
this.managerNotes = this.task.group.managerNotes;
|
||||||
}
|
}
|
||||||
if (this.groupId && this.task.group && this.task.group.approval) {
|
if (this.groupId && this.task.group?.approval) {
|
||||||
this.requiresApproval = this.task.group.approval.required;
|
this.requiresApproval = this.task.group.approval.required;
|
||||||
}
|
}
|
||||||
|
if (this.task?.group?.sharedCompletion) {
|
||||||
|
this.sharedCompletion = this.task.group.sharedCompletion;
|
||||||
|
} else if (this.task.group) {
|
||||||
|
this.sharedCompletion = 'singleCompletion';
|
||||||
|
}
|
||||||
|
|
||||||
if (this.groupId) {
|
if (this.groupId) {
|
||||||
const members = await this.$store.dispatch('members:getGroupMembers', {
|
const members = await this.$store.dispatch('members:getGroupMembers', {
|
||||||
@@ -1306,9 +1311,6 @@ export default {
|
|||||||
if (this.task.group && this.task.group.assignedUsers) {
|
if (this.task.group && this.task.group.assignedUsers) {
|
||||||
this.assignedMembers = this.task.group.assignedUsers;
|
this.assignedMembers = this.task.group.assignedUsers;
|
||||||
}
|
}
|
||||||
if (this.task.group) {
|
|
||||||
this.sharedCompletion = this.task.group.sharedCompletion || 'singleCompletion';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: This whole component is mutating a prop
|
// @TODO: This whole component is mutating a prop
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
canNotEditTasks,
|
canNotEditTasks,
|
||||||
createTasks,
|
createTasks,
|
||||||
getTasks,
|
getTasks,
|
||||||
|
groupSubscriptionNotFound,
|
||||||
} from '../../../libs/tasks';
|
} from '../../../libs/tasks';
|
||||||
import {
|
import {
|
||||||
moveTask,
|
moveTask,
|
||||||
@@ -50,9 +51,9 @@ api.createGroupTasks = {
|
|||||||
|
|
||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
|
|
||||||
const fields = requiredGroupFields.concat(' managers');
|
const fields = requiredGroupFields.concat(' purchased managers');
|
||||||
const group = await Group.getGroup({ user, groupId: req.params.groupId, fields });
|
const group = await Group.getGroup({ user, groupId: req.params.groupId, fields });
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||||
|
|
||||||
@@ -99,9 +100,9 @@ api.getGroupTasks = {
|
|||||||
const group = await Group.getGroup({
|
const group = await Group.getGroup({
|
||||||
user,
|
user,
|
||||||
groupId: req.params.groupId,
|
groupId: req.params.groupId,
|
||||||
fields: requiredGroupFields,
|
fields: requiredGroupFields.concat(' purchased'),
|
||||||
});
|
});
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
const tasks = await getTasks(req, res, { user, group });
|
const tasks = await getTasks(req, res, { user, group });
|
||||||
res.respond(200, tasks);
|
res.respond(200, tasks);
|
||||||
@@ -152,9 +153,9 @@ api.groupMoveTask = {
|
|||||||
const group = await Group.getGroup({
|
const group = await Group.getGroup({
|
||||||
user,
|
user,
|
||||||
groupId: task.group.id,
|
groupId: task.group.id,
|
||||||
fields: requiredGroupFields,
|
fields: requiredGroupFields.concat(' purchased'),
|
||||||
});
|
});
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||||
|
|
||||||
@@ -219,9 +220,9 @@ api.assignTask = {
|
|||||||
throw new NotAuthorized(res.t('onlyGroupTasksCanBeAssigned'));
|
throw new NotAuthorized(res.t('onlyGroupTasksCanBeAssigned'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupFields = `${requiredGroupFields} chat managers`;
|
const groupFields = `${requiredGroupFields} purchased chat managers`;
|
||||||
const group = await Group.getGroup({ user, groupId: task.group.id, fields: groupFields });
|
const group = await Group.getGroup({ user, groupId: task.group.id, fields: groupFields });
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||||
|
|
||||||
@@ -294,9 +295,9 @@ api.unassignTask = {
|
|||||||
throw new NotAuthorized(res.t('onlyGroupTasksCanBeAssigned'));
|
throw new NotAuthorized(res.t('onlyGroupTasksCanBeAssigned'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = requiredGroupFields.concat(' managers');
|
const fields = requiredGroupFields.concat(' purchased managers');
|
||||||
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||||
|
|
||||||
@@ -350,9 +351,9 @@ api.approveTask = {
|
|||||||
throw new NotFound(res.t('messageTaskNotFound'));
|
throw new NotFound(res.t('messageTaskNotFound'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = requiredGroupFields.concat(' managers');
|
const fields = requiredGroupFields.concat(' purchased managers');
|
||||||
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||||
if (task.group.approval.approved === true) throw new NotAuthorized(res.t('canOnlyApproveTaskOnce'));
|
if (task.group.approval.approved === true) throw new NotAuthorized(res.t('canOnlyApproveTaskOnce'));
|
||||||
@@ -458,9 +459,9 @@ api.taskNeedsWork = {
|
|||||||
throw new NotFound(res.t('messageTaskNotFound'));
|
throw new NotFound(res.t('messageTaskNotFound'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = requiredGroupFields.concat(' managers');
|
const fields = requiredGroupFields.concat(' purchased managers');
|
||||||
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||||
if (task.group.approval.approved === true) throw new NotAuthorized(res.t('canOnlyApproveTaskOnce'));
|
if (task.group.approval.approved === true) throw new NotAuthorized(res.t('canOnlyApproveTaskOnce'));
|
||||||
@@ -538,9 +539,9 @@ api.getGroupApprovals = {
|
|||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
const { groupId } = req.params;
|
const { groupId } = req.params;
|
||||||
|
|
||||||
const fields = requiredGroupFields.concat(' managers');
|
const fields = requiredGroupFields.concat(' purchased managers');
|
||||||
const group = await Group.getGroup({ user, groupId, fields });
|
const group = await Group.getGroup({ user, groupId, fields });
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (groupSubscriptionNotFound(group)) throw new NotFound(res.t('groupNotFound'));
|
||||||
|
|
||||||
let approvals;
|
let approvals;
|
||||||
if (canNotEditTasks(group, user)) {
|
if (canNotEditTasks(group, user)) {
|
||||||
|
|||||||
@@ -245,6 +245,11 @@ function canNotEditTasks (group, user, assignedUserId) {
|
|||||||
return isNotGroupLeader && !isManager && !userIsAssigningToSelf;
|
return isNotGroupLeader && !isManager && !userIsAssigningToSelf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function groupSubscriptionNotFound (group) {
|
||||||
|
return !group || !group.purchased || !group.purchased.plan || !group.purchased.plan.customerId
|
||||||
|
|| (group.purchased.plan.dateTerminated && group.purchased.plan.dateTerminated < new Date());
|
||||||
|
}
|
||||||
|
|
||||||
async function getGroupFromTaskAndUser (task, user) {
|
async function getGroupFromTaskAndUser (task, user) {
|
||||||
if (task.group.id && !task.userId) {
|
if (task.group.id && !task.userId) {
|
||||||
const fields = requiredGroupFields.concat(' managers');
|
const fields = requiredGroupFields.concat(' managers');
|
||||||
@@ -550,5 +555,6 @@ export {
|
|||||||
canNotEditTasks,
|
canNotEditTasks,
|
||||||
getGroupFromTaskAndUser,
|
getGroupFromTaskAndUser,
|
||||||
getChallengeFromTask,
|
getChallengeFromTask,
|
||||||
|
groupSubscriptionNotFound,
|
||||||
verifyTaskModification,
|
verifyTaskModification,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user