feat(api): add DELETE endpoint for task removal

This commit is contained in:
Chneemann 2026-08-11 09:11:46 +02:00
parent 9bf86c7e9e
commit 0fd1fa377b
No known key found for this signature in database
2 changed files with 79 additions and 1 deletions

View file

@ -1,6 +1,6 @@
/** /**
* @file app/api/tasks/[id]/route.ts * @file app/api/tasks/[id]/route.ts
* @description API route handler for updating a task's status patch endpoint, ensuring user authorization and valid status transitions. * @description API route handlers for updating a task's status or deleting a task, enforcing user authentication, schema validations, and authorization checks.
*/ */
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
@ -71,3 +71,46 @@ export async function PATCH(request: Request, context: RouteContext) {
); );
} }
} }
/**
* Handles DELETE requests to remove a specific task by its ID.
* Verifies user authentication and checks authorization permissions before deletion.
*
* @async
* @param {Request} request - The incoming HTTP request.
* @param {RouteContext} context - The route context containing dynamic route parameters.
* @returns {Promise<NextResponse>} A JSON response confirming deletion or an error message.
*/
export async function DELETE(request: Request, context: RouteContext) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const { id: taskId } = await context.params;
const deletedTask = await TaskService.deleteIfAuthorized(
taskId,
session.user.id,
);
if (!deletedTask) {
return NextResponse.json(
{ error: "Task not found or access denied" },
{ status: 403 },
);
}
return NextResponse.json(
{ success: true, task: deletedTask },
{ status: 200 },
);
} catch (error) {
console.error("Error deleting task:", error);
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 },
);
}
}

View file

@ -97,4 +97,39 @@ export class TaskService {
return (updatedTask as DbTask | undefined) || null; return (updatedTask as DbTask | undefined) || null;
} }
/**
* Deletes a task if the user is authorized as either the owner or an assignee.
*
* @async
* @param {string} taskId - The unique identifier of the task to delete.
* @param {string} userId - The unique identifier of the user performing the deletion.
* @returns {Promise<DbTask | null>} The deleted task object, or null if the deletion failed or user is unauthorized.
*/
static async deleteIfAuthorized(taskId: string, userId: string) {
const [deletedTask] = await db
.delete(tasksTable)
.where(
and(
eq(tasksTable.id, taskId),
or(
eq(tasksTable.userId, userId),
exists(
db
.select({ taskId: taskAssigneesTable.taskId })
.from(taskAssigneesTable)
.where(
and(
eq(taskAssigneesTable.taskId, taskId),
eq(taskAssigneesTable.userId, userId),
),
),
),
),
),
)
.returning();
return (deletedTask as DbTask | undefined) || null;
}
} }