mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
* Allow challenge tasks to be draggable by leaders and admins * Drag challenge tasks, ensure they're ordered * Ensure group tasks are ordered properly, make draggable * Add tests, fix broken tests * Resolve merge conflict * Remove console.log() * Address code review comments * Code review fixes * Fix lint * Fix importing * taskManager * Lint * Fix collapseChecklist test Co-authored-by: Sabe Jones <sabrecat@gmail.com>
95 lines
3.0 KiB
JavaScript
95 lines
3.0 KiB
JavaScript
import moment from 'moment';
|
|
import _ from 'lodash';
|
|
import {
|
|
BadRequest,
|
|
} from '../errors';
|
|
import shared from '../../../common';
|
|
|
|
export const requiredGroupFields = '_id leader tasksOrder name';
|
|
|
|
export async function validateTaskAlias (tasks, res) {
|
|
const tasksWithAliases = tasks.filter(task => task.alias);
|
|
const aliases = tasksWithAliases.map(task => task.alias);
|
|
|
|
// Compares the short names in tasks against
|
|
// a Set, where values cannot repeat. If the
|
|
// lengths are different, some name was duplicated
|
|
if (aliases.length !== [...new Set(aliases)].length) {
|
|
throw new BadRequest(res.t('taskAliasAlreadyUsed'));
|
|
}
|
|
|
|
await Promise.all(tasksWithAliases.map(task => task.validate()));
|
|
}
|
|
|
|
// Takes a Task document and return a plain object of attributes that can be synced to the user
|
|
export function syncableAttrs (task) {
|
|
const t = task.toObject(); // lodash doesn't seem to like _.omit on Document
|
|
// only sync/compare important attrs
|
|
const omitAttrs = ['_id', 'userId', 'challenge', 'history', 'tags', 'completed', 'streak', 'notes', 'updatedAt', 'createdAt', 'group', 'checklist', 'attribute'];
|
|
if (t.type !== 'reward') omitAttrs.push('value');
|
|
return _.omit(t, omitAttrs);
|
|
}
|
|
|
|
/**
|
|
* Moves a task to a specified position.
|
|
*
|
|
* @param order The list of ordered tasks
|
|
* @param taskId The Task._id of the task to move
|
|
* @param to A integer specifying the index to move the task to
|
|
*
|
|
* @return Empty
|
|
*/
|
|
export function moveTask (order, taskId, to) {
|
|
const currentIndex = order.indexOf(taskId);
|
|
|
|
// If for some reason the task isn't ordered (should never happen), push it in the new position
|
|
// if the task is moved to a non existing position
|
|
// or if the task is moved to position -1 (push to bottom)
|
|
// -> push task at end of list
|
|
if (!order[to] && to !== -1) {
|
|
order.push(taskId);
|
|
return;
|
|
}
|
|
|
|
if (currentIndex !== -1) order.splice(currentIndex, 1);
|
|
if (to === -1) {
|
|
order.push(taskId);
|
|
} else {
|
|
order.splice(to, 0, taskId);
|
|
}
|
|
}
|
|
|
|
export function setNextDue (task, user, dueDateOption) {
|
|
if (task.type !== 'daily') return;
|
|
|
|
let now = moment().toDate();
|
|
let dateTaskIsDue = Date.now();
|
|
if (dueDateOption) {
|
|
// @TODO Add required ISO format
|
|
dateTaskIsDue = moment(dueDateOption);
|
|
|
|
// If not time is supplied. Let's assume we want start of Custom Day Start day.
|
|
if (
|
|
dateTaskIsDue.hour() === 0
|
|
&& dateTaskIsDue.minute() === 0
|
|
&& dateTaskIsDue.second() === 0
|
|
&& dateTaskIsDue.millisecond() === 0
|
|
) {
|
|
dateTaskIsDue.add(user.preferences.timezoneOffset, 'minutes');
|
|
dateTaskIsDue.add(user.preferences.dayStart, 'hours');
|
|
}
|
|
|
|
now = dateTaskIsDue;
|
|
}
|
|
|
|
const optionsForShouldDo = user.preferences.toObject();
|
|
optionsForShouldDo.now = now;
|
|
task.isDue = shared.shouldDo(dateTaskIsDue, task, optionsForShouldDo);
|
|
|
|
optionsForShouldDo.nextDue = true;
|
|
const nextDue = shared.shouldDo(dateTaskIsDue, task, optionsForShouldDo);
|
|
if (nextDue && nextDue.length > 0) {
|
|
task.nextDue = nextDue.map(dueDate => dueDate.toISOString());
|
|
}
|
|
}
|