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 { timeEntrySchema } from "../schemas";
5import { workspaceAccess } from "../utils/workspace-access-middleware";
6import createTimeEntry from "./controllers/create-time-entry";
7import getTimeEntriesByTaskId from "./controllers/get-time-entries";
8import getTimeEntry from "./controllers/get-time-entry";
9import updateTimeEntry from "./controllers/update-time-entry";
10
11const timeEntry = new Hono<{
12 Variables: {
13 userId: string;
14 };
15}>()
16 .get(
17 "/task/:taskId",
18 describeRoute({
19 operationId: "getTaskTimeEntries",
20 tags: ["Time Entries"],
21 description: "Get all time entries for a specific task",
22 responses: {
23 200: {
24 description: "List of time entries for the task",
25 content: {
26 "application/json": { schema: resolver(v.array(timeEntrySchema)) },
27 },
28 },
29 },
30 }),
31 validator("param", v.object({ taskId: v.string() })),
32 workspaceAccess.fromTaskId(),
33 async (c) => {
34 const { taskId } = c.req.valid("param");
35 const timeEntries = await getTimeEntriesByTaskId(taskId);
36 return c.json(timeEntries);
37 },
38 )
39 .get(
40 "/:id",
41 describeRoute({
42 operationId: "getTimeEntry",
43 tags: ["Time Entries"],
44 description: "Get a specific time entry by ID",
45 responses: {
46 200: {
47 description: "Time entry details",
48 content: {
49 "application/json": { schema: resolver(timeEntrySchema) },
50 },
51 },
52 },
53 }),
54 validator("param", v.object({ id: v.string() })),
55 workspaceAccess.fromTimeEntry(),
56 async (c) => {
57 const { id } = c.req.valid("param");
58 const timeEntry = await getTimeEntry(id);
59 return c.json(timeEntry);
60 },
61 )
62 .post(
63 "/",
64 describeRoute({
65 operationId: "createTimeEntry",
66 tags: ["Time Entries"],
67 description: "Create a new time entry for a task",
68 responses: {
69 200: {
70 description: "Time entry created successfully",
71 content: {
72 "application/json": { schema: resolver(timeEntrySchema) },
73 },
74 },
75 },
76 }),
77 validator(
78 "json",
79 v.object({
80 taskId: v.string(),
81 startTime: v.string(),
82 endTime: v.optional(v.string()),
83 description: v.optional(v.string()),
84 }),
85 ),
86 workspaceAccess.fromTaskId(),
87 async (c) => {
88 const { taskId, startTime, endTime, description } = c.req.valid("json");
89 const userId = c.get("userId");
90 const timeEntry = await createTimeEntry({
91 taskId,
92 userId,
93 startTime: new Date(startTime),
94 endTime: endTime ? new Date(endTime) : undefined,
95 description,
96 });
97 return c.json(timeEntry);
98 },
99 )
100 .put(
101 "/:id",
102 describeRoute({
103 operationId: "updateTimeEntry",
104 tags: ["Time Entries"],
105 description: "Update an existing time entry",
106 responses: {
107 200: {
108 description: "Time entry updated successfully",
109 content: {
110 "application/json": { schema: resolver(timeEntrySchema) },
111 },
112 },
113 },
114 }),
115 validator("param", v.object({ id: v.string() })),
116 validator(
117 "json",
118 v.object({
119 startTime: v.string(),
120 endTime: v.optional(v.string()),
121 description: v.optional(v.string()),
122 }),
123 ),
124 workspaceAccess.fromTimeEntry(),
125 async (c) => {
126 const { id } = c.req.valid("param");
127 const { startTime, endTime, description } = c.req.valid("json");
128 const timeEntry = await updateTimeEntry({
129 timeEntryId: id,
130 startTime: new Date(startTime),
131 endTime: endTime ? new Date(endTime) : undefined,
132 description,
133 });
134 return c.json(timeEntry);
135 },
136 );
137
138export default timeEntry;