a fun bot for the hc slack

feat: add time endpoint and improve api docs

dunkirk.sh e510e9d0 521d2e41

verified
Changed files
+88
src
features
api
routes
+24
README.md
···
- if user not found, returns `404` with an empty takes array
- returns up to 40 takes ordered by creation date (newest first)
- includes project info and total time stats
+
- includes userName for each take
```
GET /api/projects?user=<userId>
···
- with user param: returns a single project for that user
- without user param: returns all projects
- returns empty array if no projects found
+
- includes userName for each project
+
+
```
+
GET /api/time?userId=<userId>
+
```
+
returns the total time spent on takes for a user
+
- requires userId parameter
+
- returns 400 if userId is missing
+
- returns 404 if user not found
typical take object looks like:
```ts
···
elapsedTime: number; // seconds
project: string;
totalTakesTime: number; // seconds
+
userName: string;
+
}
+
```
+
+
typical project object looks like:
+
```ts
+
{
+
projectName: string;
+
projectDescription: string;
+
projectBannerUrl: string;
+
totalTakesTime: number; // seconds
+
userId: string;
+
userName: string;
+
takesCount: number;
}
```
+3
src/features/api/index.ts
···
import video from "./routes/video";
import { handleApiError } from "../../libs/apiError";
import { projects } from "./routes/projects";
+
import { time } from "./routes/time";
export { default as video } from "./routes/video";
···
return await recentTakes(url);
case "projects":
return await projects(url);
+
case "time":
+
return await time(url);
default:
return new Response(
JSON.stringify({ error: "Route not found" }),
+61
src/features/api/routes/time.ts
···
+
import { db } from "../../../libs/db";
+
import { users as usersTable } from "../../../libs/schema";
+
import { handleApiError } from "../../../libs/apiError";
+
import { eq } from "drizzle-orm";
+
+
export async function time(url: URL): Promise<Response> {
+
try {
+
const userId = url.searchParams.get("userId");
+
+
if (!userId) {
+
return new Response(
+
JSON.stringify({
+
error: "User ID is required",
+
}),
+
{
+
headers: {
+
"Content-Type": "application/json",
+
},
+
status: 400,
+
},
+
);
+
}
+
+
// Get user's total takes time from the database
+
const userData = await db
+
.select({
+
totalTakesTime: usersTable.totalTakesTime,
+
})
+
.from(usersTable)
+
.where(eq(usersTable.id, userId))
+
.limit(1);
+
+
if (!userData[0]) {
+
return new Response(
+
JSON.stringify({
+
error: "User not found",
+
}),
+
{
+
headers: {
+
"Content-Type": "application/json",
+
},
+
status: 404,
+
},
+
);
+
}
+
+
return new Response(
+
JSON.stringify({
+
userId,
+
totalTakesTime: userData[0].totalTakesTime || 0,
+
}),
+
{
+
headers: {
+
"Content-Type": "application/json",
+
},
+
},
+
);
+
} catch (error) {
+
return handleApiError(error, "userTime");
+
}
+
}