feat(api): add DELETE endpoint for task removal
This commit is contained in:
parent
9bf86c7e9e
commit
0fd1fa377b
2 changed files with 79 additions and 1 deletions
|
|
@ -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 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue