mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-23 22:27:06 +00:00
fix(get tasks): improve tests and add ability to fetch group tasks (#12339)
This commit is contained in:
parent
c7eae6f26b
commit
359ef47ce7
3 changed files with 156 additions and 47 deletions
|
|
@ -2,6 +2,8 @@ import { v4 as generateUUID } from 'uuid';
|
|||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
createAndPopulateGroup,
|
||||
generateChallenge,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
|
||||
describe('GET /tasks/:id', () => {
|
||||
|
|
@ -11,55 +13,158 @@ describe('GET /tasks/:id', () => {
|
|||
user = await generateUser();
|
||||
});
|
||||
|
||||
context('task can be accessed', async () => {
|
||||
let task;
|
||||
context('general', () => {
|
||||
context('task cannot be accessed', () => {
|
||||
it('cannot get a non-existent task', async () => {
|
||||
const dummyId = generateUUID();
|
||||
|
||||
beforeEach(async () => {
|
||||
task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
alias: 'alias',
|
||||
await expect(user.get(`/tasks/${dummyId}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('taskNotFound'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('gets specified task', async () => {
|
||||
const getTask = await user.get(`/tasks/${task._id}`);
|
||||
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
|
||||
it('can use alias to retrieve task', async () => {
|
||||
const getTask = await user.get(`/tasks/${task.alias}`);
|
||||
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
|
||||
// TODO after challenges are implemented
|
||||
it('can get active challenge task that user does not own'); // Yes?
|
||||
});
|
||||
|
||||
context('task cannot be accessed', () => {
|
||||
it('cannot get a non-existent task', async () => {
|
||||
const dummyId = generateUUID();
|
||||
context('user', () => {
|
||||
context('task can be accessed', async () => {
|
||||
let task;
|
||||
|
||||
await expect(user.get(`/tasks/${dummyId}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('taskNotFound'),
|
||||
beforeEach(async () => {
|
||||
task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
alias: 'alias',
|
||||
});
|
||||
});
|
||||
|
||||
it('gets specified task', async () => {
|
||||
const getTask = await user.get(`/tasks/${task._id}`);
|
||||
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
|
||||
it('can use alias to retrieve task', async () => {
|
||||
const getTask = await user.get(`/tasks/${task.alias}`);
|
||||
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot get a task owned by someone else', async () => {
|
||||
const anotherUser = await generateUser();
|
||||
const task = await user.post('/tasks/user', {
|
||||
context('task cannot be accessed', () => {
|
||||
it('cannot get a task owned by someone else', async () => {
|
||||
const anotherUser = await generateUser();
|
||||
const task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
|
||||
await expect(anotherUser.get(`/tasks/${task._id}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('taskNotFound'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('challenge', () => {
|
||||
let challenge; let task; let leader; let member;
|
||||
|
||||
before(async () => {
|
||||
const populatedGroup = await createAndPopulateGroup({
|
||||
members: 1,
|
||||
});
|
||||
|
||||
const guild = populatedGroup.group;
|
||||
leader = populatedGroup.groupLeader;
|
||||
member = populatedGroup.members[0]; // eslint-disable-line prefer-destructuring
|
||||
|
||||
challenge = await generateChallenge(leader, guild);
|
||||
await leader.post(`/challenges/${challenge._id}/join`);
|
||||
|
||||
task = await leader.post(`/tasks/challenge/${challenge._id}`, {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
});
|
||||
|
||||
await expect(anotherUser.get(`/tasks/${task._id}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('taskNotFound'),
|
||||
context('task can be accessed', async () => {
|
||||
it('can get challenge task if member of that challenge', async () => {
|
||||
await member.post(`/challenges/${challenge._id}/join`);
|
||||
|
||||
const getTask = await member.get(`/tasks/${task._id}`);
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
|
||||
it('can get challenge task if leader of that challenge', async () => {
|
||||
const getTask = await leader.get(`/tasks/${task._id}`);
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
|
||||
it('can get challenge task if admin', async () => {
|
||||
const admin = await generateUser({
|
||||
'contributor.admin': true,
|
||||
});
|
||||
|
||||
const getTask = await admin.get(`/tasks/${task._id}`);
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
});
|
||||
|
||||
context('task cannot be accessed', () => {
|
||||
it('cannot get a task in a challenge i am not part of', async () => {
|
||||
await expect(user.get(`/tasks/${task._id}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('taskNotFound'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('group', () => {
|
||||
let group; let task; let members; let leader;
|
||||
|
||||
before(async () => {
|
||||
const groupData = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Test Guild',
|
||||
type: 'guild',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
group = groupData.group;
|
||||
members = groupData.members;
|
||||
leader = groupData.groupLeader;
|
||||
|
||||
task = await leader.post(`/tasks/group/${group._id}`, {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
});
|
||||
|
||||
context('task can be accessed', async () => {
|
||||
it('can get group task if leader of that group', async () => {
|
||||
const getTask = await leader.get(`/tasks/${task._id}`);
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
|
||||
it('can get group task if member of that group', async () => {
|
||||
const getTask = await members[0].get(`/tasks/${task._id}`);
|
||||
expect(getTask).to.eql(task);
|
||||
});
|
||||
});
|
||||
|
||||
context('task cannot be accessed', () => {
|
||||
it('cannot get a task in a group i am not part of', async () => {
|
||||
await expect(user.get(`/tasks/${task._id}`)).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('taskNotFound'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import common from '../../../common';
|
|||
import logger from '../../libs/logger';
|
||||
import apiError from '../../libs/apiError';
|
||||
|
||||
// @TODO abstract, see api-v3/tasks/groups.js
|
||||
function canNotEditTasks (group, user, assignedUserId, taskPayload = null) {
|
||||
const isNotGroupLeader = group.leader !== user._id;
|
||||
const isManager = Boolean(group.managers[user._id]);
|
||||
|
|
@ -530,18 +531,20 @@ api.getTask = {
|
|||
|
||||
if (!task) {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
// @TODO: Abstract this access snippet
|
||||
const fields = requiredGroupFields.concat(' managers');
|
||||
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
||||
if (!group) throw new NotFound(res.t('taskNotFound'));
|
||||
|
||||
// If the task belongs to a challenge make sure the user has rights
|
||||
const isNotGroupLeader = group.leader !== user._id;
|
||||
if (!group.isMember(user) && isNotGroupLeader) throw new NotFound(res.t('taskNotFound'));
|
||||
// If the task belongs to a challenge make sure the user has rights (leader, admin or members)
|
||||
} else if (task.challenge.id && !task.userId) {
|
||||
const challenge = await Challenge.find({ _id: task.challenge.id }).select('leader').exec();
|
||||
if (
|
||||
!challenge
|
||||
|| (
|
||||
user.challenges.indexOf(task.challenge.id) === -1
|
||||
&& challenge.leader !== user._id
|
||||
&& !user.contributor.admin
|
||||
)
|
||||
) { // eslint-disable-line no-extra-parens
|
||||
const challenge = await Challenge.findOne({ _id: task.challenge.id }).select('leader').exec();
|
||||
// @TODO: Abstract this access snippet
|
||||
if (!challenge) throw new NotFound(res.t('taskNotFound'));
|
||||
if (!challenge.canModify(user) && !challenge.isMember(user)) {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
}
|
||||
|
||||
|
|
@ -628,7 +631,7 @@ api.updateTask = {
|
|||
if (!task) {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
// @TODO: Abstract this access snippet
|
||||
// @TODO: Abstract this access snippet
|
||||
const fields = requiredGroupFields.concat(' managers');
|
||||
group = await Group.getGroup({ user, groupId: task.group.id, fields });
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const types = Tasks.tasksTypes.map(type => `${type}s`);
|
|||
// _allCompletedTodos is currently in BETA and is likely to be removed in future
|
||||
types.push('completedTodos', '_allCompletedTodos');
|
||||
|
||||
// @TODO abstract this snipped (also see api-v3/tasks.js)
|
||||
function canNotEditTasks (group, user, assignedUserId) {
|
||||
const isNotGroupLeader = group.leader !== user._id;
|
||||
const isManager = Boolean(group.managers[user._id]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue