Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,4 @@ base url: `http://localhost:3000`
### Task

- Create a new task: `POST /api/organization/:organizationId/team/:teamId/project/:projectId/task/create`
- Update a task: `PUT /api/organization/:organizationId/team/:teamId/project/:projectId/task/:taskId`
190 changes: 189 additions & 1 deletion src/controllers/task.controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import prisma from '../config/prismaClient.js';
import { createTaskValidation } from '../validations/task.validation.js';
import {
createTaskValidation,
updateTaskValidation,
} from '../validations/task.validation.js';

/**
* Helper function to validate required params
Expand Down Expand Up @@ -357,3 +360,188 @@ export const createTask = async (req, res, next) => {
next(error);
}
};

/**
* @desc Update a task
* @route /api/organization/:organizationId/team/:teamId/project/:projectId/task/:taskId
* @method PUT
* @access private
*/
export const updateTask = async (req, res, next) => {
try {
const { organizationId, teamId, projectId, taskId } = req.params;
const {
title,
description,
priority,
sprintId,
assignedTo,
dueDate,
estimatedTime,
parentId,
labels,
} = req.body;

const user = req.user;

const { error } = updateTaskValidation(req.body);
if (error) {
return res.status(400).json({ message: error.details[0].message });
}

// Check if organization exists
const orgCheck = await checkOrganization(organizationId);
if (!orgCheck.success) {
return res.status(404).json({
success: false,
message: orgCheck.message,
});
}

// Check if team exists
const teamCheck = await checkTeam(teamId, organizationId);
if (!teamCheck.success) {
return res.status(404).json({
success: false,
message: teamCheck.message,
});
}

// Check if project exists
const projectCheck = await checkProject(projectId, teamId, organizationId);
if (!projectCheck.success) {
return res.status(404).json({
success: false,
message: projectCheck.message,
});
}

// Check if task exists and belongs to the project
const task = await prisma.task.findFirst({
where: {
id: taskId,
projectId,
deletedAt: null,
},
});

if (!task) {
return res.status(404).json({
success: false,
message: 'Task not found or does not belong to the specified project',
});
}

// Check task permissions
const permissionsCheck = checkTaskPermissions(
user,
orgCheck.organization,
teamCheck.team,
projectCheck.project,
'update',
);

if (!permissionsCheck.success) {
return res.status(403).json({
success: false,
message: permissionsCheck.message,
});
}

// If sprintId is provided, verify the sprint exists and belongs to the project
if (sprintId && sprintId !== task.sprintId) {
const sprint = await prisma.sprint.findFirst({
where: {
id: sprintId,
projectId,
},
});

if (!sprint) {
return res.status(404).json({
success: false,
message:
'Sprint not found or does not belong to the specified project',
});
}
}

// If parentId is provided, verify the parent task exists, belongs to the project, and is not the task itself
if (parentId && parentId !== task.parentId) {
if (parentId === taskId) {
return res.status(400).json({
success: false,
message: 'A task cannot be its own parent',
});
}

const parentTask = await prisma.task.findFirst({
where: {
id: parentId,
projectId,
deletedAt: null,
},
});

if (!parentTask) {
return res.status(404).json({
success: false,
message:
'Parent task not found or does not belong to the specified project',
});
}

// Check for circular dependencies
let currentParent = parentId;
while (currentParent) {
const parent = await prisma.task.findUnique({
where: { id: currentParent },
select: { parentId: true },
});

Comment thread
mdawoud27 marked this conversation as resolved.
if (!parent) {
return res.status(404).json({
success: false,
message: 'Parent task not found during circular dependency check',
});
}

if (parent.parentId === taskId) {
return res.status(400).json({
success: false,
message: 'Circular dependency detected in task hierarchy',
});
}

currentParent = parent.parentId;
}
}

// Update the task
const updatedTask = await prisma.task.update({
where: { id: taskId },
data: {
title: title !== undefined ? title : task.title,
description: description !== undefined ? description : task.description,
priority: priority !== undefined ? priority : task.priority,
sprintId: sprintId !== undefined ? sprintId : task.sprintId,
assignedTo: assignedTo !== undefined ? assignedTo : task.assignedTo,
dueDate: dueDate !== undefined ? new Date(dueDate) : task.dueDate,
estimatedTime:
estimatedTime !== undefined ? estimatedTime : task.estimatedTime,
parentId: parentId !== undefined ? parentId : task.parentId,
labels: labels !== undefined ? labels : task.labels,
updatedAt: new Date(),
lastModifiedBy: user.id,
},
});

return res.status(200).json({
success: true,
message: 'Task updated successfully',
task: updatedTask,
});
} catch (error) {
next(error);
}
};
Loading