mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
WIP(teams): can do To Do's
This commit is contained in:
@@ -17,7 +17,6 @@ async function updateTeamTasks (team) {
|
|||||||
) {
|
) {
|
||||||
const tasks = await Tasks.Task.find({
|
const tasks = await Tasks.Task.find({
|
||||||
'group.id': team._id,
|
'group.id': team._id,
|
||||||
'group.assignedUsers': [],
|
|
||||||
userId: { $exists: false },
|
userId: { $exists: false },
|
||||||
$or: [
|
$or: [
|
||||||
{ type: 'todo', completed: false },
|
{ type: 'todo', completed: false },
|
||||||
@@ -51,9 +50,18 @@ async function updateTeamTasks (team) {
|
|||||||
processChecklist = true;
|
processChecklist = true;
|
||||||
daily.completed = false;
|
daily.completed = false;
|
||||||
} else if (shouldDo(team.cron.lastProcessed, daily, teamLeader.preferences)) {
|
} else if (shouldDo(team.cron.lastProcessed, daily, teamLeader.preferences)) {
|
||||||
|
let assignments = 0;
|
||||||
|
let completions = 0;
|
||||||
|
for (const assignedUser in daily.group.assignedUsers) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(daily.group.assignedUsers, assignedUser)) {
|
||||||
|
assignments += 1;
|
||||||
|
if (assignedUser.completed) completions += 1;
|
||||||
|
assignedUser.completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
processChecklist = true;
|
processChecklist = true;
|
||||||
const delta = TASK_VALUE_CHANGE_FACTOR ** daily.value;
|
const delta = TASK_VALUE_CHANGE_FACTOR ** daily.value;
|
||||||
daily.value -= delta;
|
daily.value -= ((completions / assignments) * delta);
|
||||||
if (daily.value < MIN_TASK_VALUE) daily.value = MIN_TASK_VALUE;
|
if (daily.value < MIN_TASK_VALUE) daily.value = MIN_TASK_VALUE;
|
||||||
}
|
}
|
||||||
daily.isDue = shouldDo(new Date(), daily, teamLeader.preferences);
|
daily.isDue = shouldDo(new Date(), daily, teamLeader.preferences);
|
||||||
|
|||||||
@@ -58,8 +58,8 @@
|
|||||||
class="task-control daily-todo-control"
|
class="task-control daily-todo-control"
|
||||||
:class="controlClass.inner"
|
:class="controlClass.inner"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="score(task.completed ? 'down' : 'up' )"
|
@click="score(showCheckIcon ? 'down' : 'up' )"
|
||||||
@keypress.enter="score(task.completed ? 'down' : 'up' )"
|
@keypress.enter="score(showCheckIcon ? 'down' : 'up' )"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="showTaskLockIcon"
|
v-if="showTaskLockIcon"
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
v-else
|
v-else
|
||||||
class="svg-icon check"
|
class="svg-icon check"
|
||||||
:class="{
|
:class="{
|
||||||
'display-check-icon': task.completed,
|
'display-check-icon': showCheckIcon,
|
||||||
[controlClass.checkbox]: true,
|
[controlClass.checkbox]: true,
|
||||||
}"
|
}"
|
||||||
v-html="icons.check"
|
v-html="icons.check"
|
||||||
@@ -1043,12 +1043,22 @@ export default {
|
|||||||
if (this.task.group.assignedUsers) return false;
|
if (this.task.group.assignedUsers) return false;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
showCheckIcon () {
|
||||||
|
if (this.isGroupTask && this.task.group.assignedUsers
|
||||||
|
&& this.task.group.assignedUsers[this.user._id]) {
|
||||||
|
return this.task.group.assignedUsers[this.user._id].completed;
|
||||||
|
}
|
||||||
|
return this.task.completed;
|
||||||
|
},
|
||||||
showTaskLockIcon () {
|
showTaskLockIcon () {
|
||||||
if (this.isUser) return false;
|
if (this.isUser) return false;
|
||||||
if (this.isGroupTask) {
|
if (this.isGroupTask) {
|
||||||
if (this.task.completed) {
|
if (this.task.completed) {
|
||||||
if (this.task.group.completedBy === this.user._id) return false;
|
if (this.task.group.assignedUsers && this.task.group.assignedUsers[this.user._id]) {
|
||||||
if (this.teamManagerAccess) return false;
|
return false;
|
||||||
|
}
|
||||||
|
if (this.task.group.completedBy.userId === this.user._id) return false;
|
||||||
|
if (this.teamManagerAccess && !this.task.group.assignedUsers) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.isOpenTask) return false;
|
if (this.isOpenTask) return false;
|
||||||
|
|||||||
@@ -176,8 +176,8 @@
|
|||||||
"onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned",
|
"onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned",
|
||||||
"assignedTo": "Assign To",
|
"assignedTo": "Assign To",
|
||||||
"assignedToUser": "Assigned to <strong><%- userName %></strong>",
|
"assignedToUser": "Assigned to <strong><%- userName %></strong>",
|
||||||
"assignedToMembers": "Assigned to <strong><%= userCount %> members</strong>",
|
"assignedToMembers": "Assigned to <strong><%= userCount %> users</strong>",
|
||||||
"assignedToYouAndMembers": "Assigned to you and <strong><%= userCount %> members</strong>",
|
"assignedToYouAndMembers": "Assigned to you and <strong><%= userCount %> users</strong>",
|
||||||
"youAreAssigned": "Assigned to you",
|
"youAreAssigned": "Assigned to you",
|
||||||
"taskIsUnassigned": "This task is unassigned",
|
"taskIsUnassigned": "This task is unassigned",
|
||||||
"unassigned": "Unassigned",
|
"unassigned": "Unassigned",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import find from 'lodash/find';
|
||||||
import timesLodash from 'lodash/times';
|
import timesLodash from 'lodash/times';
|
||||||
import reduce from 'lodash/reduce';
|
import reduce from 'lodash/reduce';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -330,13 +331,37 @@ export default function scoreTask (options = {}, req = {}, analytics) {
|
|||||||
delta += _changeTaskValue(user, task, direction, times, cron);
|
delta += _changeTaskValue(user, task, direction, times, cron);
|
||||||
} else {
|
} else {
|
||||||
if (direction === 'up') {
|
if (direction === 'up') {
|
||||||
task.dateCompleted = new Date();
|
if (task.group.id) {
|
||||||
task.completed = true;
|
if (!task.group.assignedUsers) {
|
||||||
if (task.group) task.group.completedBy = user._id;
|
task.group.completedBy = {
|
||||||
|
userId: user._id,
|
||||||
|
date: new Date(),
|
||||||
|
};
|
||||||
|
task.completed = true;
|
||||||
|
} else {
|
||||||
|
task.group.assignedUsers[user._id].completed = true;
|
||||||
|
task.group.assignedUsers[user._id].completedDate = new Date();
|
||||||
|
if (!find(task.group.assignedUsers, assignedUser => !assignedUser.completed)) {
|
||||||
|
task.dateCompleted = new Date();
|
||||||
|
task.completed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (task.markModified) task.markModified('group');
|
||||||
|
} else {
|
||||||
|
task.dateCompleted = new Date();
|
||||||
|
task.completed = true;
|
||||||
|
}
|
||||||
} else if (direction === 'down') {
|
} else if (direction === 'down') {
|
||||||
task.completed = false;
|
task.completed = false;
|
||||||
task.dateCompleted = undefined;
|
task.dateCompleted = undefined;
|
||||||
if (task.group && task.group.completedBy) task.group.completedBy = undefined;
|
if (task.group.id) {
|
||||||
|
if (task.group.completedBy) task.group.completedBy = {};
|
||||||
|
if (task.group.assignedUsers && task.group.assignedUsers[user._id]) {
|
||||||
|
task.group.assignedUsers[user._id].completed = false;
|
||||||
|
task.group.assignedUsers[user._id].completedDate = undefined;
|
||||||
|
}
|
||||||
|
if (task.markModified) task.markModified('group');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delta += _changeTaskValue(user, task, direction, times, cron);
|
delta += _changeTaskValue(user, task, direction, times, cron);
|
||||||
|
|||||||
@@ -688,7 +688,7 @@ api.updateTask = {
|
|||||||
setNextDue(task, user);
|
setNextDue(task, user);
|
||||||
const savedTask = await task.save();
|
const savedTask = await task.save();
|
||||||
|
|
||||||
if (group && task.group.id && task.group.assignedUsers.length > 0) {
|
if (group && task.group.id && task.group.assignedUsers) {
|
||||||
const updateCheckListItems = _.remove(sanitizedObj.checklist, checklist => {
|
const updateCheckListItems = _.remove(sanitizedObj.checklist, checklist => {
|
||||||
const indexOld = _.findIndex(oldCheckList, check => check.id === checklist.id);
|
const indexOld = _.findIndex(oldCheckList, check => check.id === checklist.id);
|
||||||
if (indexOld !== -1) return checklist.text !== oldCheckList[indexOld].text;
|
if (indexOld !== -1) return checklist.text !== oldCheckList[indexOld].text;
|
||||||
@@ -702,7 +702,7 @@ api.updateTask = {
|
|||||||
|
|
||||||
if (challenge) {
|
if (challenge) {
|
||||||
challenge.updateTask(savedTask);
|
challenge.updateTask(savedTask);
|
||||||
} else if (group && task.group.id && task.group.assignedUsers.length > 0) {
|
} else if (group && task.group.id && task.group.assignedUsers) {
|
||||||
await group.updateTask(savedTask);
|
await group.updateTask(savedTask);
|
||||||
} else {
|
} else {
|
||||||
taskActivityWebhook.send(user, {
|
taskActivityWebhook.send(user, {
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ async function handleTeamTask (task, delta, direction) {
|
|||||||
|
|
||||||
if (teamTask) {
|
if (teamTask) {
|
||||||
const groupDelta = teamTask.group.assignedUsers
|
const groupDelta = teamTask.group.assignedUsers
|
||||||
? delta / teamTask.group.assignedUsers.length
|
? delta / _.keys(teamTask.group.assignedUsers).length
|
||||||
: delta;
|
: delta;
|
||||||
await teamTask.scoreChallengeTask(groupDelta, direction);
|
await teamTask.scoreChallengeTask(groupDelta, direction);
|
||||||
if (task.type === 'daily' || task.type === 'todo') {
|
if (task.type === 'daily' || task.type === 'todo') {
|
||||||
@@ -328,14 +328,19 @@ async function handleTeamTask (task, delta, direction) {
|
|||||||
*/
|
*/
|
||||||
async function scoreTask (user, task, direction, req, res) {
|
async function scoreTask (user, task, direction, req, res) {
|
||||||
if (task.type === 'daily' || task.type === 'todo') {
|
if (task.type === 'daily' || task.type === 'todo') {
|
||||||
if (task.completed && direction === 'up') {
|
if (task.group.id && task.group.assignedUsers) {
|
||||||
|
if (task.group.assignedUsers[user._id].completed && direction === 'up') {
|
||||||
|
throw new NotAuthorized(res.t('sessionOutdated'));
|
||||||
|
} else if (!task.group.assignedUsers[user._id].completed && direction === 'down') {
|
||||||
|
throw new NotAuthorized(res.t('sessionOutdated'));
|
||||||
|
}
|
||||||
|
} else if (task.completed && direction === 'up') {
|
||||||
throw new NotAuthorized(res.t('sessionOutdated'));
|
throw new NotAuthorized(res.t('sessionOutdated'));
|
||||||
} else if (!task.completed && direction === 'down') {
|
} else if (!task.completed && direction === 'down') {
|
||||||
throw new NotAuthorized(res.t('sessionOutdated'));
|
throw new NotAuthorized(res.t('sessionOutdated'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let localTask;
|
|
||||||
let rollbackUser;
|
let rollbackUser;
|
||||||
let group;
|
let group;
|
||||||
|
|
||||||
@@ -347,46 +352,36 @@ async function scoreTask (user, task, direction, req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
group && task.group.id && !task.userId
|
group && task.group.id && !task.userId // Task is on team board
|
||||||
&& direction === 'down'
|
&& ['todo', 'daily'].includes(task.type) // Task is a To Do or Daily
|
||||||
&& ['todo', 'daily'].includes(task.type)
|
&& direction === 'down' // Task is being "unchecked"
|
||||||
&& task.completed
|
|
||||||
&& task.group.completedBy !== user._id
|
|
||||||
) {
|
) {
|
||||||
if (group.leader !== user._id && !group.managers[user._id]) {
|
const userIsManagement = group.leader === user._id || Boolean(group.managers[user._id]);
|
||||||
|
if (!userIsManagement
|
||||||
|
&& !(task.group.completedBy && task.group.completedBy.userId === user._id)
|
||||||
|
&& !(task.group.assignedUsers && task.group.assignedUsers[user._id])
|
||||||
|
) {
|
||||||
throw new BadRequest('Cannot uncheck task you did not complete if not a manager.');
|
throw new BadRequest('Cannot uncheck task you did not complete if not a manager.');
|
||||||
}
|
}
|
||||||
rollbackUser = await User.findOne({ _id: task.group.completedBy });
|
rollbackUser = await User.findOne({ _id: task.group.completedBy.userId });
|
||||||
task.group.completedBy = undefined;
|
task.group.completedBy = {};
|
||||||
} else if (task.group.id && !task.userId && task.group.assignedUsers.length > 0) {
|
|
||||||
// Task is being scored from team board, and a user copy should exist
|
|
||||||
if (!task.group.assignedUsers.includes(user._id)) {
|
|
||||||
throw new BadRequest('Task has not been assigned to this user.');
|
|
||||||
}
|
|
||||||
|
|
||||||
localTask = await Tasks.Task.findOne(
|
|
||||||
{ userId: user._id, 'group.taskId': task._id },
|
|
||||||
).exec();
|
|
||||||
if (!localTask) throw new NotFound('Task not found.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetTask = localTask || task;
|
const wasCompleted = task.completed;
|
||||||
|
|
||||||
const wasCompleted = targetTask.completed;
|
|
||||||
const firstTask = !user.achievements.completedTask;
|
const firstTask = !user.achievements.completedTask;
|
||||||
let delta;
|
let delta;
|
||||||
|
|
||||||
if (rollbackUser) {
|
if (rollbackUser) {
|
||||||
delta = shared.ops.scoreTask({
|
delta = shared.ops.scoreTask({
|
||||||
task: targetTask,
|
task,
|
||||||
user: rollbackUser,
|
user: rollbackUser,
|
||||||
direction,
|
direction,
|
||||||
}, req, res.analytics);
|
}, req, res.analytics);
|
||||||
rollbackUser.addNotification('GROUP_TASK_NEEDS_WORK', {
|
rollbackUser.addNotification('GROUP_TASK_NEEDS_WORK', {
|
||||||
message: res.t('taskNeedsWork', { taskText: targetTask.text, managerName: user.profile.name }, rollbackUser.preferences.language),
|
message: res.t('taskNeedsWork', { taskText: task.text, managerName: user.profile.name }, rollbackUser.preferences.language),
|
||||||
task: {
|
task: {
|
||||||
id: targetTask._id,
|
id: task._id,
|
||||||
text: targetTask.text,
|
text: task.text,
|
||||||
},
|
},
|
||||||
group: {
|
group: {
|
||||||
id: group._id,
|
id: group._id,
|
||||||
@@ -399,51 +394,70 @@ async function scoreTask (user, task, direction, req, res) {
|
|||||||
});
|
});
|
||||||
await rollbackUser.save();
|
await rollbackUser.save();
|
||||||
} else {
|
} else {
|
||||||
delta = shared.ops.scoreTask({ task: targetTask, user, direction }, req, res.analytics);
|
delta = shared.ops.scoreTask({ task, user, direction }, req, res.analytics);
|
||||||
}
|
}
|
||||||
// Drop system (don't run on the client,
|
// Drop system (don't run on the client,
|
||||||
// as it would only be discarded since ops are sent to the API, not the results)
|
// as it would only be discarded since ops are sent to the API, not the results)
|
||||||
if (direction === 'up' && !firstTask) shared.fns.randomDrop(user, { task: targetTask, delta }, req, res.analytics);
|
if (direction === 'up' && !firstTask) shared.fns.randomDrop(user, { task, delta }, req, res.analytics);
|
||||||
|
|
||||||
// If a todo was completed or uncompleted move it in or out of the user.tasksOrder.todos list
|
// If a todo was completed or uncompleted move it in or out of the user.tasksOrder.todos list
|
||||||
// TODO move to common code?
|
// TODO move to common code?
|
||||||
let pullTask;
|
let pullTask;
|
||||||
let pushTask;
|
let pushTask;
|
||||||
if (targetTask.type === 'todo') {
|
if (task.type === 'todo') {
|
||||||
if (!wasCompleted && task.completed) {
|
if (!wasCompleted && task.completed) {
|
||||||
// @TODO: mongoose's push and pull should be atomic and help with
|
// @TODO: mongoose's push and pull should be atomic and help with
|
||||||
// our concurrency issues. If not, we need to use this update $pull and $push
|
// our concurrency issues. If not, we need to use this update $pull and $push
|
||||||
pullTask = targetTask._id;
|
pullTask = task._id;
|
||||||
} else if (
|
} else if (
|
||||||
wasCompleted
|
wasCompleted
|
||||||
&& !targetTask.completed
|
&& !task.completed
|
||||||
&& user.tasksOrder.todos.indexOf(task._id) === -1
|
&& user.tasksOrder.todos.indexOf(task._id) === -1
|
||||||
) {
|
) {
|
||||||
pushTask = targetTask._id;
|
pushTask = task._id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetTask.completed && targetTask.group.id && !targetTask.userId) {
|
if (task.completed && task.group.id
|
||||||
targetTask.group.completedBy = user._id;
|
&& !task.userId && !task.group.assignedUsers) {
|
||||||
|
task.group.completedBy = {
|
||||||
|
userId: user._id,
|
||||||
|
date: new Date(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setNextDue(task, user);
|
setNextDue(task, user);
|
||||||
|
|
||||||
if (localTask) {
|
|
||||||
localTask.completed = targetTask.completed;
|
|
||||||
localTask.value = Number(targetTask.value) + Number(delta);
|
|
||||||
await localTask.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
taskScoredWebhook.send(user, {
|
taskScoredWebhook.send(user, {
|
||||||
task: targetTask,
|
task,
|
||||||
direction,
|
direction,
|
||||||
delta,
|
delta,
|
||||||
user,
|
user,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (group) {
|
||||||
|
let role;
|
||||||
|
if (group.leader === user._id) {
|
||||||
|
role = 'leader';
|
||||||
|
} else if (group.managers[user._id]) {
|
||||||
|
role = 'manager';
|
||||||
|
} else {
|
||||||
|
role = 'member';
|
||||||
|
}
|
||||||
|
res.analytics.track('team task scored', {
|
||||||
|
uuid: user._id,
|
||||||
|
hitType: 'event',
|
||||||
|
category: 'behavior',
|
||||||
|
taskType: task.type,
|
||||||
|
direction,
|
||||||
|
headers: req.headers,
|
||||||
|
groupID: group._id,
|
||||||
|
role,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
task: targetTask,
|
task,
|
||||||
delta,
|
delta,
|
||||||
direction,
|
direction,
|
||||||
pullTask,
|
pullTask,
|
||||||
|
|||||||
@@ -1466,9 +1466,7 @@ schema.methods.updateTask = async function updateTask (taskToSync, options = {})
|
|||||||
updateCmd.$set[key] = syncableAttributes[key];
|
updateCmd.$set[key] = syncableAttributes[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCmd.$set['group.approval.required'] = taskToSync.group.approval.required;
|
|
||||||
updateCmd.$set['group.assignedUsers'] = taskToSync.group.assignedUsers;
|
updateCmd.$set['group.assignedUsers'] = taskToSync.group.assignedUsers;
|
||||||
updateCmd.$set['group.sharedCompletion'] = taskToSync.group.sharedCompletion;
|
|
||||||
updateCmd.$set['group.managerNotes'] = taskToSync.group.managerNotes;
|
updateCmd.$set['group.managerNotes'] = taskToSync.group.managerNotes;
|
||||||
|
|
||||||
const taskSchema = Tasks[taskToSync.type];
|
const taskSchema = Tasks[taskToSync.type];
|
||||||
@@ -1516,6 +1514,7 @@ schema.methods.syncTask = async function groupSyncTask (taskToSync, users, assig
|
|||||||
if (!taskToSync.group.assignedUsers[user._id]) {
|
if (!taskToSync.group.assignedUsers[user._id]) {
|
||||||
taskToSync.group.assignedUsers[user._id] = assignmentData;
|
taskToSync.group.assignedUsers[user._id] = assignmentData;
|
||||||
}
|
}
|
||||||
|
taskToSync.markModified('group.assignedUsers');
|
||||||
|
|
||||||
// Sync tags
|
// Sync tags
|
||||||
const userTags = user.tags;
|
const userTags = user.tags;
|
||||||
@@ -1556,7 +1555,6 @@ schema.methods.syncTask = async function groupSyncTask (taskToSync, users, assig
|
|||||||
if (orderList.indexOf(matchingTask._id) === -1 && (matchingTask.type !== 'todo' || !matchingTask.completed)) orderList.push(matchingTask._id);
|
if (orderList.indexOf(matchingTask._id) === -1 && (matchingTask.type !== 'todo' || !matchingTask.completed)) orderList.push(matchingTask._id);
|
||||||
}
|
}
|
||||||
matchingTask.group.assignedUsers = taskToSync.group.assignedUsers;
|
matchingTask.group.assignedUsers = taskToSync.group.assignedUsers;
|
||||||
matchingTask.group.sharedCompletion = taskToSync.group.sharedCompletion;
|
|
||||||
matchingTask.group.managerNotes = taskToSync.group.managerNotes;
|
matchingTask.group.managerNotes = taskToSync.group.managerNotes;
|
||||||
|
|
||||||
// sync checklist
|
// sync checklist
|
||||||
@@ -1589,8 +1587,9 @@ schema.methods.unlinkTask = async function groupUnlinkTask (
|
|||||||
userId: user._id,
|
userId: user._id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const assignedUserIndex = unlinkingTask.group.assignedUsers.indexOf(user._id);
|
delete unlinkingTask.group.assignedUsers[user._id];
|
||||||
unlinkingTask.group.assignedUsers.splice(assignedUserIndex, 1);
|
unlinkingTask.markModified('group.assignedUsers');
|
||||||
|
const promises = [unlinkingTask.save()];
|
||||||
|
|
||||||
if (keep === 'keep-all') {
|
if (keep === 'keep-all') {
|
||||||
await Tasks.Task.update(findQuery, {
|
await Tasks.Task.update(findQuery, {
|
||||||
@@ -1608,16 +1607,14 @@ schema.methods.unlinkTask = async function groupUnlinkTask (
|
|||||||
user.markModified('tasksOrder');
|
user.markModified('tasksOrder');
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises = [unlinkingTask.save()];
|
|
||||||
if (task) {
|
if (task) {
|
||||||
promises.push(task.remove());
|
promises.push(task.remove());
|
||||||
}
|
}
|
||||||
// When multiple tasks are being unlinked at the same time,
|
// When multiple tasks are being unlinked at the same time,
|
||||||
// save the user once outside of this function
|
// save the user once outside of this function
|
||||||
if (saveUser) promises.push(user.save());
|
if (saveUser) promises.push(user.save());
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
};
|
};
|
||||||
|
|
||||||
schema.methods.removeTask = async function groupRemoveTask (task) {
|
schema.methods.removeTask = async function groupRemoveTask (task) {
|
||||||
|
|||||||
@@ -133,16 +133,14 @@ export const TaskSchema = new Schema({
|
|||||||
// key is assigned UUID, with
|
// key is assigned UUID, with
|
||||||
// { assignedDate: Date,
|
// { assignedDate: Date,
|
||||||
// assigningUsername: '@username',
|
// assigningUsername: '@username',
|
||||||
// completed: Boolean }
|
// completed: Boolean,
|
||||||
|
// completedDate: Date }
|
||||||
},
|
},
|
||||||
taskId: { $type: String, ref: 'Task', validate: [v => validator.isUUID(v), 'Invalid uuid for group task.'] },
|
taskId: { $type: String, ref: 'Task', validate: [v => validator.isUUID(v), 'Invalid uuid for group task.'] },
|
||||||
sharedCompletion: {
|
|
||||||
$type: String, default: 'singleCompletion', // legacy data
|
|
||||||
},
|
|
||||||
managerNotes: { $type: String },
|
managerNotes: { $type: String },
|
||||||
completedBy: {
|
completedBy: {
|
||||||
$type: Schema.Types.Mixed,
|
userId: { $type: String, ref: 'User', validate: [v => validator.isUUID(v), 'Invalid uuid for task completing user.'] },
|
||||||
default: () => ({}), // { 'UUID': Date }
|
date: { $type: Date },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user