mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 07:37:25 +01:00
v3: limit fields of challenge tasks that can be updated
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
|
generateGroup,
|
||||||
|
sleep,
|
||||||
|
generateChallenge,
|
||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../helpers/api-integration/v3';
|
||||||
import { v4 as generateUUID } from 'uuid';
|
import { v4 as generateUUID } from 'uuid';
|
||||||
|
|
||||||
@@ -43,8 +46,8 @@ describe('PUT /tasks/:id', () => {
|
|||||||
expect(savedTask.createdAt).to.equal(task.createdAt);
|
expect(savedTask.createdAt).to.equal(task.createdAt);
|
||||||
expect(savedTask.updatedAt).to.be.greaterThan(task.updatedAt);
|
expect(savedTask.updatedAt).to.be.greaterThan(task.updatedAt);
|
||||||
expect(savedTask.challenge).to.equal(task.challenge);
|
expect(savedTask.challenge).to.equal(task.challenge);
|
||||||
expect(savedTask.completed).to.equal(task.completed);
|
expect(savedTask.completed).to.eql(task.completed);
|
||||||
expect(savedTask.streak).to.equal(task.streak);
|
expect(savedTask.streak).to.equal(savedTask.streak); // it's an habit, dailies can change it
|
||||||
expect(savedTask.dateCompleted).to.equal(task.dateCompleted);
|
expect(savedTask.dateCompleted).to.equal(task.dateCompleted);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -55,6 +58,90 @@ describe('PUT /tasks/:id', () => {
|
|||||||
|
|
||||||
expect(savedTask.notValid).to.be.undefined;
|
expect(savedTask.notValid).to.be.undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`only allows setting streak, reminders, checklist, notes, attribute, tags
|
||||||
|
fields for challenge tasks owned by a user`, async () => {
|
||||||
|
let guild = await generateGroup(user);
|
||||||
|
let challenge = await generateChallenge(user, guild);
|
||||||
|
|
||||||
|
let challengeTask = await user.post(`/tasks/challenge/${challenge._id}`, {
|
||||||
|
type: 'daily',
|
||||||
|
text: 'Daily in challenge',
|
||||||
|
reminders: [
|
||||||
|
{time: new Date(), startDate: new Date()},
|
||||||
|
],
|
||||||
|
checklist: [
|
||||||
|
{text: 123, completed: false},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await sleep(2);
|
||||||
|
|
||||||
|
await user.sync();
|
||||||
|
|
||||||
|
// Pick challenge task
|
||||||
|
let challengeUserTaskId = user.tasksOrder.dailys[user.tasksOrder.dailys.length - 1];
|
||||||
|
|
||||||
|
let challengeUserTask = await user.get(`/tasks/${challengeUserTaskId}`);
|
||||||
|
|
||||||
|
let savedChallengeUserTask = await user.put(`/tasks/${challengeUserTaskId}`, {
|
||||||
|
_id: 123,
|
||||||
|
type: 'daily',
|
||||||
|
userId: 123,
|
||||||
|
history: [123],
|
||||||
|
createdAt: 'yesterday',
|
||||||
|
updatedAt: 'tomorrow',
|
||||||
|
challenge: 'no',
|
||||||
|
completed: true,
|
||||||
|
streak: 25,
|
||||||
|
priority: 1.5,
|
||||||
|
repeat: {
|
||||||
|
m: false,
|
||||||
|
},
|
||||||
|
everyX: 15,
|
||||||
|
frequency: 'weekly',
|
||||||
|
text: 'new text',
|
||||||
|
dateCompleted: 'never',
|
||||||
|
reminders: [
|
||||||
|
{time: new Date(), startDate: new Date()},
|
||||||
|
{time: new Date(), startDate: new Date()},
|
||||||
|
],
|
||||||
|
checklist: [
|
||||||
|
{text: 123, completed: false},
|
||||||
|
{text: 456, completed: true},
|
||||||
|
],
|
||||||
|
notes: 'new notes',
|
||||||
|
attribute: 'per',
|
||||||
|
tags: [challengeUserTaskId],
|
||||||
|
});
|
||||||
|
|
||||||
|
// original task is not touched
|
||||||
|
let updatedChallengeTask = await user.get(`/tasks/${challengeTask._id}`);
|
||||||
|
expect(updatedChallengeTask).to.eql(challengeTask);
|
||||||
|
|
||||||
|
// ignored
|
||||||
|
expect(savedChallengeUserTask._id).to.equal(challengeUserTask._id);
|
||||||
|
expect(savedChallengeUserTask.type).to.equal(challengeUserTask.type);
|
||||||
|
expect(savedChallengeUserTask.repeat.m).to.equal(true);
|
||||||
|
expect(savedChallengeUserTask.priority).to.equal(challengeUserTask.priority);
|
||||||
|
expect(savedChallengeUserTask.frequency).to.equal(challengeUserTask.frequency);
|
||||||
|
expect(savedChallengeUserTask.userId).to.equal(challengeUserTask.userId);
|
||||||
|
expect(savedChallengeUserTask.text).to.equal(challengeUserTask.text);
|
||||||
|
expect(savedChallengeUserTask.history).to.eql(challengeUserTask.history);
|
||||||
|
expect(savedChallengeUserTask.createdAt).to.equal(challengeUserTask.createdAt);
|
||||||
|
expect(savedChallengeUserTask.updatedAt).to.be.greaterThan(challengeUserTask.updatedAt);
|
||||||
|
expect(savedChallengeUserTask.challenge).to.eql(challengeUserTask.challenge);
|
||||||
|
expect(savedChallengeUserTask.completed).to.equal(challengeUserTask.completed);
|
||||||
|
expect(savedChallengeUserTask.dateCompleted).to.equal(challengeUserTask.dateCompleted);
|
||||||
|
expect(savedChallengeUserTask.priority).to.equal(challengeUserTask.priority);
|
||||||
|
|
||||||
|
// changed
|
||||||
|
expect(savedChallengeUserTask.notes).to.equal('new notes');
|
||||||
|
expect(savedChallengeUserTask.attribute).to.equal('per');
|
||||||
|
expect(savedChallengeUserTask.tags).to.eql([challengeUserTaskId]);
|
||||||
|
expect(savedChallengeUserTask.streak).to.equal(25);
|
||||||
|
expect(savedChallengeUserTask.reminders.length).to.equal(2);
|
||||||
|
expect(savedChallengeUserTask.checklist.length).to.equal(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('all types', () => {
|
context('all types', () => {
|
||||||
|
|||||||
@@ -307,7 +307,18 @@ api.updateTask = {
|
|||||||
|
|
||||||
// we have to convert task to an object because otherwise things don't get merged correctly. Bad for performances?
|
// we have to convert task to an object because otherwise things don't get merged correctly. Bad for performances?
|
||||||
let [updatedTaskObj] = common.ops.updateTask(task.toObject(), req);
|
let [updatedTaskObj] = common.ops.updateTask(task.toObject(), req);
|
||||||
_.assign(task, Tasks.Task.sanitize(updatedTaskObj));
|
|
||||||
|
|
||||||
|
// Sanitize differently user tasks linked to a challenge
|
||||||
|
let sanitizedObj;
|
||||||
|
|
||||||
|
if (!challenge && task.userId && task.challenge && task.challenge.id) {
|
||||||
|
sanitizedObj = Tasks.Task.sanitizeUserChallengeTask(updatedTaskObj);
|
||||||
|
} else {
|
||||||
|
sanitizedObj = Tasks.Task.sanitize(updatedTaskObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.assign(task, sanitizedObj);
|
||||||
// console.log(task.modifiedPaths(), task.toObject().repeat === tep)
|
// console.log(task.modifiedPaths(), task.toObject().repeat === tep)
|
||||||
// repeat is always among modifiedPaths because mongoose changes the other of the keys when using .toObject()
|
// repeat is always among modifiedPaths because mongoose changes the other of the keys when using .toObject()
|
||||||
// see https://github.com/Automattic/mongoose/issues/2749
|
// see https://github.com/Automattic/mongoose/issues/2749
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export let TaskSchema = new Schema({
|
|||||||
}, discriminatorOptions));
|
}, discriminatorOptions));
|
||||||
|
|
||||||
TaskSchema.plugin(baseModel, {
|
TaskSchema.plugin(baseModel, {
|
||||||
noSet: ['challenge', 'userId', 'completed', 'history', 'dateCompleted', 'completed'],
|
noSet: ['challenge', 'userId', 'completed', 'history', 'dateCompleted', '_legacyId'],
|
||||||
sanitizeTransform (taskObj) {
|
sanitizeTransform (taskObj) {
|
||||||
if (taskObj.type && taskObj.type !== 'reward') { // value should be settable directly only for rewards
|
if (taskObj.type && taskObj.type !== 'reward') { // value should be settable directly only for rewards
|
||||||
delete taskObj.value;
|
delete taskObj.value;
|
||||||
@@ -69,6 +69,14 @@ TaskSchema.plugin(baseModel, {
|
|||||||
timestamps: true,
|
timestamps: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sanitize user tasks linked to a challenge
|
||||||
|
// See http://habitica.wikia.com/wiki/Challenges#Challenge_Participant.27s_Permissions for more info
|
||||||
|
TaskSchema.statics.sanitizeUserChallengeTask = function sanitizeUserChallengeTask (taskObj) {
|
||||||
|
let initialSanitization = this.sanitize(taskObj);
|
||||||
|
|
||||||
|
return _.pick(initialSanitization, ['streak', 'checklist', 'attribute', 'reminders', 'tags', 'notes']);
|
||||||
|
};
|
||||||
|
|
||||||
// Sanitize checklist objects (disallowing id)
|
// Sanitize checklist objects (disallowing id)
|
||||||
TaskSchema.statics.sanitizeChecklist = function sanitizeChecklist (checklistObj) {
|
TaskSchema.statics.sanitizeChecklist = function sanitizeChecklist (checklistObj) {
|
||||||
delete checklistObj.id;
|
delete checklistObj.id;
|
||||||
|
|||||||
Reference in New Issue
Block a user