forked from codechefPesuecc/CodeChef-PESUECC-Chapter
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprofile.ts
More file actions
81 lines (75 loc) · 2.35 KB
/
Copy pathprofile.ts
File metadata and controls
81 lines (75 loc) · 2.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { desc, eq } from "drizzle-orm";
import { getDb } from "@/server/db";
import { submissions } from "@/server/db/schema";
import { getChallengeTitles } from "@/lib/challenges";
import { aggregateLeaderboard } from "@/server/leaderboard";
/**
* Profile data for a signed-in user: their recorded submission history plus their
* standing on the aggregate boards. Ranked (live Problem-of-the-Day) submissions
* are recorded in full; accepted practice solves on past problems are also kept
* (they earn the flat base score).
*/
export interface ProfileSubmission {
id: string;
slug: string;
title: string;
language: string;
status: string;
elapsedSeconds: number | null;
flags: number;
createdAt: number;
}
export interface ProfileStats {
allPoints: number;
allRank: number | null;
monthPoints: number;
monthRank: number | null;
solved: number;
submissions: number;
}
/** Every recorded submission for a user, newest first. */
export async function getUserSubmissions(
userId: string,
): Promise<ProfileSubmission[]> {
const db = getDb();
const rows = await db
.select({
id: submissions.id,
slug: submissions.challengeSlug,
language: submissions.language,
status: submissions.status,
elapsedSeconds: submissions.elapsedSeconds,
flags: submissions.flags,
createdAt: submissions.createdAt,
})
.from(submissions)
.where(eq(submissions.userId, userId))
.orderBy(desc(submissions.createdAt));
// One batched title lookup instead of a per-row query.
const titles = await getChallengeTitles([...new Set(rows.map((r) => r.slug))]);
return rows.map((r) => ({
...r,
title: titles.get(r.slug) ?? r.slug,
}));
}
/** A user's points/rank/solved on the month and all-time boards. */
export async function getProfileStats(
identity: string,
submissionCount: number,
): Promise<ProfileStats> {
const [all, month] = await Promise.all([
aggregateLeaderboard("all"),
aggregateLeaderboard("month"),
]);
// The boards are keyed by SRN-else-PRN; match on that identity.
const a = all.find((r) => r.display === identity);
const m = month.find((r) => r.display === identity);
return {
allPoints: a?.points ?? 0,
allRank: a?.rank ?? null,
monthPoints: m?.points ?? 0,
monthRank: m?.rank ?? null,
solved: a?.solved ?? 0,
submissions: submissionCount,
};
}