v3: limit fields of challenge tasks that can be updated

This commit is contained in:
Matteo Pagliazzi
2016-05-18 23:27:49 +02:00
parent 65c739f7de
commit e98930cd4a
3 changed files with 110 additions and 4 deletions

View File

@@ -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', () => {

View File

@@ -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

View File

@@ -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;