a fun bot for the hc slack

feat: improve time endpoint with daily time

dunkirk.sh b9e86da2 e510e9d0

verified
Changed files
+59 -13
src
features
api
routes
+2 -1
README.md
···
```
GET /api/time?userId=<userId>
```
-
returns the total time spent on takes for a user
+
returns the total time spent on takes for a user and daily time statistics
- requires userId parameter
- returns 400 if userId is missing
- returns 404 if user not found
+
- includes totalTakesTime (in seconds) and dailyStats showing time logged per day
typical take object looks like:
```ts
+57 -12
src/features/api/routes/time.ts
···
import { db } from "../../../libs/db";
-
import { users as usersTable } from "../../../libs/schema";
+
import { users as usersTable, takes as takesTable } from "../../../libs/schema";
import { handleApiError } from "../../../libs/apiError";
-
import { eq } from "drizzle-orm";
+
import { eq, sql } from "drizzle-orm";
+
+
// Time data cache to reduce database queries
+
const timeCache = new Map<
+
string,
+
{
+
data: {
+
userId: string;
+
totalTakesTime: number;
+
dailyStats: { date: string; seconds: number }[];
+
};
+
timestamp: number;
+
}
+
>();
+
const TIME_CACHE_TTL = 5 * 60 * 1000; // 5 minutes cache TTL
export async function time(url: URL): Promise<Response> {
try {
···
);
}
+
// Check cache before database query
+
const cacheKey = `time_${userId}`;
+
const cached = timeCache.get(cacheKey);
+
if (cached && Date.now() - cached.timestamp < TIME_CACHE_TTL) {
+
return new Response(JSON.stringify(cached.data), {
+
headers: {
+
"Content-Type": "application/json",
+
},
+
});
+
}
+
// Get user's total takes time from the database
const userData = await db
.select({
···
);
}
-
return new Response(
-
JSON.stringify({
-
userId,
-
totalTakesTime: userData[0].totalTakesTime || 0,
-
}),
-
{
-
headers: {
-
"Content-Type": "application/json",
-
},
+
// Get time logged per day
+
const dailyStats = await db
+
.select({
+
date: sql<string>`DATE(${takesTable.createdAt})`,
+
dailyTotal: sql<number>`SUM(${takesTable.elapsedTime})`,
+
})
+
.from(takesTable)
+
.where(eq(takesTable.userId, userId))
+
.groupBy(sql`DATE(${takesTable.createdAt})`)
+
.orderBy(sql`DATE(${takesTable.createdAt}) DESC`);
+
+
const responseData = {
+
userId,
+
totalTakesTime: userData[0].totalTakesTime || 0,
+
dailyStats: dailyStats.map((day) => ({
+
date: day.date,
+
seconds: day.dailyTotal,
+
})),
+
};
+
+
// Store in cache
+
timeCache.set(cacheKey, {
+
data: responseData,
+
timestamp: Date.now(),
+
});
+
+
return new Response(JSON.stringify(responseData), {
+
headers: {
+
"Content-Type": "application/json",
},
-
);
+
});
} catch (error) {
return handleApiError(error, "userTime");
}