kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1import { Hono } from "hono";
2import { describeRoute, resolver, validator } from "hono-openapi";
3import * as v from "valibot";
4import { commentSchema } from "../schemas";
5import { workspaceAccess } from "../utils/workspace-access-middleware";
6import createComment from "./controllers/create-comment";
7import deleteComment from "./controllers/delete-comment";
8import getComments from "./controllers/get-comments";
9import updateComment from "./controllers/update-comment";
10
11const comment = new Hono<{
12 Variables: {
13 userId: string;
14 };
15}>()
16 .get(
17 "/:taskId",
18 describeRoute({
19 operationId: "getTaskComments",
20 tags: ["Comments"],
21 description: "Get all comments for a specific task",
22 responses: {
23 200: {
24 description: "List of comments for the task",
25 content: {
26 "application/json": {
27 schema: resolver(v.array(commentSchema)),
28 },
29 },
30 },
31 },
32 }),
33 validator("param", v.object({ taskId: v.string() })),
34 workspaceAccess.fromTaskId(),
35 async (c) => {
36 const { taskId } = c.req.valid("param");
37 const comments = await getComments(taskId);
38 return c.json(comments);
39 },
40 )
41 .post(
42 "/:taskId",
43 describeRoute({
44 operationId: "createTaskComment",
45 tags: ["Comments"],
46 description: "Create a new comment on a task",
47 responses: {
48 200: {
49 description: "Comment created successfully",
50 content: {
51 "application/json": { schema: resolver(commentSchema) },
52 },
53 },
54 },
55 }),
56 validator("param", v.object({ taskId: v.string() })),
57 validator(
58 "json",
59 v.object({ content: v.pipe(v.string(), v.minLength(1)) }),
60 ),
61 workspaceAccess.fromTaskId(),
62 async (c) => {
63 const { taskId } = c.req.valid("param");
64 const { content } = c.req.valid("json");
65 const userId = c.get("userId");
66 const newComment = await createComment(taskId, userId, content);
67 return c.json(newComment);
68 },
69 )
70 .put(
71 "/:id",
72 describeRoute({
73 operationId: "updateTaskComment",
74 tags: ["Comments"],
75 description: "Update an existing comment (author only)",
76 responses: {
77 200: {
78 description: "Comment updated successfully",
79 content: {
80 "application/json": { schema: resolver(commentSchema) },
81 },
82 },
83 },
84 }),
85 validator("param", v.object({ id: v.string() })),
86 validator(
87 "json",
88 v.object({ content: v.pipe(v.string(), v.minLength(1)) }),
89 ),
90 workspaceAccess.fromComment(),
91 async (c) => {
92 const { id } = c.req.valid("param");
93 const { content } = c.req.valid("json");
94 const userId = c.get("userId");
95 const updated = await updateComment(userId, id, content);
96 return c.json(updated);
97 },
98 )
99 .delete(
100 "/:id",
101 describeRoute({
102 operationId: "deleteTaskComment",
103 tags: ["Comments"],
104 description: "Delete a comment (author only)",
105 responses: {
106 200: {
107 description: "Comment deleted successfully",
108 content: {
109 "application/json": { schema: resolver(commentSchema) },
110 },
111 },
112 },
113 }),
114 validator("param", v.object({ id: v.string() })),
115 workspaceAccess.fromComment(),
116 async (c) => {
117 const { id } = c.req.valid("param");
118 const userId = c.get("userId");
119 const deleted = await deleteComment(userId, id);
120 return c.json(deleted);
121 },
122 );
123
124export default comment;