kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1import { and, eq, max } from "drizzle-orm";
2import { HTTPException } from "hono/http-exception";
3import db from "../../database";
4import { columnTable, taskTable, userTable } from "../../database/schema";
5import { publishEvent } from "../../events";
6import { assertValidTaskStatus } from "../validate-task-fields";
7import getNextTaskNumber from "./get-next-task-number";
8
9async function createTask({
10 projectId,
11 userId,
12 title,
13 status,
14 startDate,
15 dueDate,
16 description,
17 priority,
18}: {
19 projectId: string;
20 userId?: string;
21 title: string;
22 status: string;
23 startDate?: Date;
24 dueDate?: Date;
25 description?: string;
26 priority?: string;
27}) {
28 const resolvedStatus = status || "to-do";
29 const resolvedPriority = priority || "no-priority";
30
31 await assertValidTaskStatus(resolvedStatus, projectId);
32
33 const [assignee] = await db
34 .select({ name: userTable.name })
35 .from(userTable)
36 .where(eq(userTable.id, userId ?? ""));
37
38 const nextTaskNumber = await getNextTaskNumber(projectId);
39
40 const column = await db.query.columnTable.findFirst({
41 where: and(
42 eq(columnTable.projectId, projectId),
43 eq(columnTable.slug, resolvedStatus),
44 ),
45 });
46
47 const [maxPositionResult] = await db
48 .select({ maxPosition: max(taskTable.position) })
49 .from(taskTable)
50 .where(
51 and(
52 eq(taskTable.projectId, projectId),
53 column?.id
54 ? eq(taskTable.columnId, column.id)
55 : eq(taskTable.status, resolvedStatus),
56 ),
57 );
58
59 const nextPosition = (maxPositionResult?.maxPosition ?? 0) + 1;
60
61 const [createdTask] = await db
62 .insert(taskTable)
63 .values({
64 projectId,
65 userId: userId || null,
66 title: title || "",
67 status: resolvedStatus,
68 columnId: column?.id ?? null,
69 startDate: startDate || null,
70 dueDate: dueDate || null,
71 description: description || "",
72 priority: resolvedPriority,
73 number: nextTaskNumber + 1,
74 position: nextPosition,
75 })
76 .returning();
77
78 if (!createdTask) {
79 throw new HTTPException(500, {
80 message: "Failed to create task",
81 });
82 }
83
84 await publishEvent("task.created", {
85 ...createdTask,
86 taskId: createdTask.id,
87 userId: createdTask.userId ?? "",
88 type: "task",
89 content: null,
90 });
91
92 return {
93 ...createdTask,
94 assigneeName: assignee?.name,
95 };
96}
97
98export default createTask;