163 lines
5.4 KiB
JavaScript
163 lines
5.4 KiB
JavaScript
const { Task, Tag, Project } = require('../../../models');
|
|
const taskRepository = require('../repository');
|
|
const permissionsService = require('../../../services/permissionsService');
|
|
const { logError } = require('../../../services/logService');
|
|
const { serializeTask } = require('../core/serializers');
|
|
const { parsePriority, parseStatus } = require('../core/parsers');
|
|
|
|
async function getSubtasks(parentTaskId, userId, timezone) {
|
|
const parent = await taskRepository.findById(parentTaskId);
|
|
if (!parent) {
|
|
return { error: 'Not found', subtasks: [] };
|
|
}
|
|
|
|
const pAccess = await permissionsService.getAccess(
|
|
userId,
|
|
'task',
|
|
parent.uid
|
|
);
|
|
if (pAccess === 'none') {
|
|
return { error: 'Forbidden', subtasks: null };
|
|
}
|
|
|
|
const subtasks = await taskRepository.findAll(
|
|
{ parent_task_id: parentTaskId },
|
|
{
|
|
include: [
|
|
{
|
|
model: Tag,
|
|
attributes: ['id', 'name', 'uid'],
|
|
through: { attributes: [] },
|
|
},
|
|
{
|
|
model: Project,
|
|
attributes: ['id', 'name', 'uid'],
|
|
required: false,
|
|
},
|
|
],
|
|
order: [
|
|
['order', 'ASC'],
|
|
['created_at', 'ASC'],
|
|
], // Order by order field, fallback to created_at
|
|
}
|
|
);
|
|
|
|
const serializedSubtasks = await Promise.all(
|
|
subtasks.map((subtask) => serializeTask(subtask, timezone))
|
|
);
|
|
|
|
return { error: null, subtasks: serializedSubtasks };
|
|
}
|
|
|
|
async function createSubtasks(parentTaskId, subtasks, userId) {
|
|
if (!subtasks || !Array.isArray(subtasks)) return;
|
|
|
|
// Get the highest order value for existing subtasks
|
|
const existingSubtasks = await taskRepository.findAll(
|
|
{ parent_task_id: parentTaskId },
|
|
{ attributes: ['order'], order: [['order', 'DESC']], limit: 1 }
|
|
);
|
|
const maxOrder = existingSubtasks[0]?.order ?? 0;
|
|
|
|
const subtasksData = subtasks
|
|
.filter((subtask) => subtask.name && subtask.name.trim())
|
|
.map((subtask, index) => ({
|
|
name: subtask.name.trim(),
|
|
parent_task_id: parentTaskId,
|
|
user_id: userId,
|
|
priority: parsePriority(subtask.priority) || Task.PRIORITY.LOW,
|
|
status: parseStatus(subtask.status),
|
|
completed_at:
|
|
subtask.status === 'done' || subtask.status === Task.STATUS.DONE
|
|
? subtask.completed_at
|
|
? new Date(subtask.completed_at)
|
|
: new Date()
|
|
: null,
|
|
recurrence_type: 'none',
|
|
completion_based: false,
|
|
order: maxOrder + index + 1, // Assign sequential order values
|
|
}));
|
|
|
|
await taskRepository.createMany(subtasksData);
|
|
}
|
|
|
|
async function updateSubtasks(taskId, subtasks, userId) {
|
|
if (!subtasks || !Array.isArray(subtasks)) return;
|
|
|
|
const existingSubtasks = await taskRepository.findChildren(taskId, userId);
|
|
|
|
const subtasksToKeep = subtasks.filter((s) => s.id && !s.isNew);
|
|
const subtasksToDelete = existingSubtasks.filter(
|
|
(existing) => !subtasksToKeep.find((keep) => keep.id === existing.id)
|
|
);
|
|
|
|
if (subtasksToDelete.length > 0) {
|
|
await taskRepository.destroyMany({
|
|
where: {
|
|
id: subtasksToDelete.map((s) => s.id),
|
|
user_id: userId,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Update order for all subtasks to reflect their position in the array
|
|
const allSubtasksToUpdate = subtasks.filter((s) => s.id);
|
|
|
|
const subtasksToUpdate = subtasks.filter(
|
|
(s) =>
|
|
s.id &&
|
|
((s.isEdited && s.name && s.name.trim()) || s._statusChanged)
|
|
);
|
|
|
|
if (subtasksToUpdate.length > 0 || allSubtasksToUpdate.length > 0) {
|
|
const updatePromises = allSubtasksToUpdate.map((subtask, index) => {
|
|
const updateData = {
|
|
order: index + 1, // Update order based on position in array
|
|
};
|
|
|
|
if (subtasksToUpdate.includes(subtask)) {
|
|
if (subtask.isEdited && subtask.name && subtask.name.trim()) {
|
|
updateData.name = subtask.name.trim();
|
|
}
|
|
|
|
if (subtask._statusChanged || subtask.status !== undefined) {
|
|
updateData.status = parseStatus(subtask.status);
|
|
|
|
if (
|
|
updateData.status === Task.STATUS.DONE &&
|
|
!subtask.completed_at
|
|
) {
|
|
updateData.completed_at = new Date();
|
|
} else if (updateData.status !== Task.STATUS.DONE) {
|
|
updateData.completed_at = null;
|
|
}
|
|
}
|
|
|
|
if (subtask.priority !== undefined) {
|
|
updateData.priority =
|
|
parsePriority(subtask.priority) || Task.PRIORITY.LOW;
|
|
}
|
|
}
|
|
|
|
return taskRepository.bulkUpdate(updateData, {
|
|
where: { id: subtask.id, user_id: userId },
|
|
});
|
|
});
|
|
|
|
await Promise.all(updatePromises);
|
|
}
|
|
|
|
const newSubtasks = subtasks.filter(
|
|
(s) => s.isNew && s.name && s.name.trim()
|
|
);
|
|
|
|
if (newSubtasks.length > 0) {
|
|
await createSubtasks(taskId, newSubtasks, userId);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getSubtasks,
|
|
createSubtasks,
|
|
updateSubtasks,
|
|
};
|