Skip to content

Commit 657f5ac

Browse files
authored
Merge pull request #70 from codegasms/fix/api-testing
Fix API failures
2 parents 489cc4b + a5373c6 commit 657f5ac

File tree

18 files changed

+605
-135
lines changed

18 files changed

+605
-135
lines changed

app/api/auth/register/route.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { eq } from "drizzle-orm";
66
import { generateSessionToken, createSession } from "@/lib/server/session";
77
import { setSessionTokenCookie } from "@/lib/server/cookies";
88
import { hashPassword } from "@/lib/password";
9+
import { generateUsername } from "@/lib/username";
910

1011
export async function POST(request: NextRequest) {
1112
try {
@@ -25,15 +26,14 @@ export async function POST(request: NextRequest) {
2526

2627
const hashedPassword = await hashPassword(validatedData.password);
2728

29+
const nameId = await generateUsername(validatedData.email);
2830
const [user] = await db
2931
.insert(users)
3032
.values({
3133
email: validatedData.email,
3234
hashedPassword: hashedPassword,
3335
name: validatedData.name,
34-
35-
// TODO: Use a proper readable slug for nameId
36-
nameId: validatedData.email,
36+
nameId,
3737
})
3838
.returning();
3939

@@ -45,6 +45,7 @@ export async function POST(request: NextRequest) {
4545
_id: user.id,
4646
email: user.email,
4747
name: user.name,
48+
nameId: user.nameId,
4849
// role: user.role,
4950
});
5051
} catch (error) {

app/api/orgs/[orgId]/contests/[contestId]/participants/route.ts

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,130 @@
1+
import { NextRequest, NextResponse } from "next/server";
12
import { z } from "zod";
2-
import { NextRequest } from "next/server";
3-
import { createParticipantSchema } from "@/lib/validations";
3+
import { createParticipantSchema, NameIdSchema } from "@/lib/validations";
44
import * as participantService from "./service";
5-
import { IdSchema } from "@/app/api/types";
5+
import { getOrgIdFromNameId, getContestIdFromNameId } from "@/app/api/service";
66

77
export async function POST(
88
request: NextRequest,
9-
{ params }: { params: { contestId: string } },
9+
{ params }: { params: { orgId: string; contestId: string } },
1010
) {
1111
try {
12-
const contestId = IdSchema.parse(params.contestId);
12+
// Validate nameIds first
13+
const orgNameId = NameIdSchema.parse(params.orgId);
14+
const contestNameId = NameIdSchema.parse(params.contestId);
15+
16+
// Then get numeric IDs
17+
const orgId = await getOrgIdFromNameId(orgNameId);
18+
const contestId = await getContestIdFromNameId(orgId, contestNameId);
1319
const data = createParticipantSchema.parse(await request.json());
1420

1521
const participant = await participantService.registerParticipant(
22+
orgId,
23+
contestId,
24+
data.email,
25+
);
26+
27+
return NextResponse.json(participant, { status: 201 });
28+
} catch (error) {
29+
if (error instanceof z.ZodError) {
30+
return NextResponse.json({ error: error.errors }, { status: 400 });
31+
}
32+
if (error instanceof Error) {
33+
if (
34+
error.message === "Organization not found" ||
35+
error.message === "Contest not found"
36+
) {
37+
return NextResponse.json({ error: error.message }, { status: 404 });
38+
}
39+
if (error.message === "User not found") {
40+
return NextResponse.json({ error: error.message }, { status: 404 });
41+
}
42+
if (
43+
error.message === "User already registered" ||
44+
error.message === "Registration closed" ||
45+
error.message === "User not allowed" ||
46+
error.message === "User disallowed"
47+
) {
48+
return NextResponse.json({ error: error.message }, { status: 403 });
49+
}
50+
}
51+
return NextResponse.json({ error: "Registration failed" }, { status: 500 });
52+
}
53+
}
54+
55+
export async function GET(
56+
_req: NextRequest,
57+
{ params }: { params: { orgId: string; contestId: string } },
58+
) {
59+
try {
60+
// Validate nameIds first
61+
const orgNameId = NameIdSchema.parse(params.orgId);
62+
const contestNameId = NameIdSchema.parse(params.contestId);
63+
64+
// Then get numeric IDs
65+
const orgId = await getOrgIdFromNameId(orgNameId);
66+
const contestId = await getContestIdFromNameId(orgId, contestNameId);
67+
68+
const participants = await participantService.getContestParticipants(
69+
orgId,
1670
contestId,
17-
data.userId,
1871
);
72+
return NextResponse.json(participants);
73+
} catch (error) {
74+
if (error instanceof z.ZodError) {
75+
return NextResponse.json({ error: error.errors }, { status: 400 });
76+
}
77+
if (error instanceof Error) {
78+
if (
79+
error.message === "Organization not found" ||
80+
error.message === "Contest not found"
81+
) {
82+
return NextResponse.json({ error: error.message }, { status: 404 });
83+
}
84+
}
85+
return NextResponse.json(
86+
{ error: "Failed to fetch participants" },
87+
{ status: 500 },
88+
);
89+
}
90+
}
1991

20-
return Response.json(participant, { status: 201 });
92+
export async function DELETE(
93+
request: NextRequest,
94+
{ params }: { params: { orgId: string; contestId: string } },
95+
) {
96+
try {
97+
// Validate nameIds first
98+
const orgNameId = NameIdSchema.parse(params.orgId);
99+
const contestNameId = NameIdSchema.parse(params.contestId);
100+
const data = createParticipantSchema.parse(await request.json());
101+
102+
// Then get numeric IDs
103+
const orgId = await getOrgIdFromNameId(orgNameId);
104+
const contestId = await getContestIdFromNameId(orgId, contestNameId);
105+
106+
await participantService.removeParticipant(orgId, contestId, data.email);
107+
return new Response(null, { status: 204 });
21108
} catch (error) {
22109
if (error instanceof z.ZodError) {
23-
return Response.json({ error: error.errors }, { status: 400 });
110+
return NextResponse.json({ error: error.errors }, { status: 400 });
111+
}
112+
if (error instanceof Error) {
113+
if (
114+
error.message === "Organization not found" ||
115+
error.message === "Contest not found"
116+
) {
117+
return NextResponse.json({ error: error.message }, { status: 404 });
118+
}
119+
if (
120+
error.message === "User not found" ||
121+
error.message === "User not registered"
122+
) {
123+
return NextResponse.json({ error: error.message }, { status: 404 });
124+
}
24125
}
25-
return Response.json(
26-
{ error: error instanceof Error ? error.message : "Registration failed" },
126+
return NextResponse.json(
127+
{ error: "Failed to remove participant" },
27128
{ status: 500 },
28129
);
29130
}

app/api/orgs/[orgId]/contests/[contestId]/problems/route.ts

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,50 @@
1-
import * as problemService from "./service";
2-
import { IdSchema } from "@/app/api/types";
3-
import { addProblemSchema } from "@/lib/validations";
4-
5-
// /app/api/orgs/[orgId]/contests/[contestId]/problems/route.ts
61
import { NextRequest, NextResponse } from "next/server";
7-
import { getOrgIdFromNameId, getContestIdFromNameId } from "@/app/api/service";
8-
import { NameIdSchema } from "@/app/api/types";
92
import { z } from "zod";
3+
import * as problemService from "./service";
4+
import { getOrgIdFromNameId, getContestIdFromNameId } from "@/app/api/service";
5+
import { addProblemSchema, NameIdSchema } from "@/lib/validations";
106

117
export async function POST(
128
request: NextRequest,
13-
{ params }: { params: { contestId: string; orgId: string } },
9+
{ params }: { params: { orgId: string; contestId: string } },
1410
) {
1511
try {
16-
const contestId = IdSchema.parse(params.contestId);
12+
// Validate nameIds first
13+
const orgNameId = NameIdSchema.parse(params.orgId);
14+
const contestNameId = NameIdSchema.parse(params.contestId);
15+
16+
// Then get numeric IDs
17+
const orgId = await getOrgIdFromNameId(orgNameId);
18+
const contestId = await getContestIdFromNameId(orgId, contestNameId);
1719
const data = addProblemSchema.parse(await request.json());
1820

1921
const problem = await problemService.addProblemToContest(
22+
orgId,
2023
contestId,
21-
data.problemId,
24+
data.problemCode,
2225
data.order ?? 0,
2326
);
2427

25-
return Response.json(problem, { status: 201 });
28+
return NextResponse.json(problem, { status: 201 });
2629
} catch (error) {
2730
if (error instanceof z.ZodError) {
28-
return Response.json({ error: error.errors }, { status: 400 });
31+
return NextResponse.json({ error: error.errors }, { status: 400 });
2932
}
30-
return Response.json(
33+
if (error instanceof Error) {
34+
if (
35+
error.message === "Organization not found" ||
36+
error.message === "Contest not found"
37+
) {
38+
return NextResponse.json({ error: error.message }, { status: 404 });
39+
}
40+
if (error.message === "Problem not found") {
41+
return NextResponse.json({ error: error.message }, { status: 404 });
42+
}
43+
if (error.message === "Problem already added to contest") {
44+
return NextResponse.json({ error: error.message }, { status: 409 });
45+
}
46+
}
47+
return NextResponse.json(
3148
{ error: "Failed to add problem to contest" },
3249
{ status: 500 },
3350
);
@@ -47,21 +64,64 @@ export async function GET(
4764
const orgId = await getOrgIdFromNameId(orgNameId);
4865
const contestId = await getContestIdFromNameId(orgId, contestNameId);
4966

50-
const problems = await problemService.getContestProblems(contestId);
67+
const problems = await problemService.getContestProblems(orgId, contestId);
5168
return NextResponse.json(problems);
5269
} catch (error) {
5370
if (error instanceof z.ZodError) {
54-
return NextResponse.json({ errors: error.errors }, { status: 400 });
71+
return NextResponse.json({ error: error.errors }, { status: 400 });
72+
}
73+
if (error instanceof Error) {
74+
if (
75+
error.message === "Organization not found" ||
76+
error.message === "Contest not found"
77+
) {
78+
return NextResponse.json({ error: error.message }, { status: 404 });
79+
}
80+
}
81+
return NextResponse.json(
82+
{ error: "Failed to fetch contest problems" },
83+
{ status: 500 },
84+
);
85+
}
86+
}
87+
88+
export async function DELETE(
89+
request: NextRequest,
90+
{
91+
params,
92+
}: { params: { orgId: string; contestId: string; problemId: string } },
93+
) {
94+
try {
95+
// Validate nameIds first
96+
const orgNameId = NameIdSchema.parse(params.orgId);
97+
const contestNameId = NameIdSchema.parse(params.contestId);
98+
const problemCode = NameIdSchema.parse(params.problemId);
99+
100+
// Then get numeric IDs
101+
const orgId = await getOrgIdFromNameId(orgNameId);
102+
const contestId = await getContestIdFromNameId(orgId, contestNameId);
103+
104+
await problemService.removeProblemFromContest(
105+
orgId,
106+
contestId,
107+
problemCode,
108+
);
109+
return new Response(null, { status: 204 });
110+
} catch (error) {
111+
if (error instanceof z.ZodError) {
112+
return NextResponse.json({ error: error.errors }, { status: 400 });
55113
}
56-
if (
57-
error instanceof Error &&
58-
(error.message === "Organization not found" ||
59-
error.message === "Contest not found")
60-
) {
61-
return NextResponse.json({ message: error.message }, { status: 404 });
114+
if (error instanceof Error) {
115+
if (
116+
error.message === "Organization not found" ||
117+
error.message === "Contest not found" ||
118+
error.message === "Problem not found"
119+
) {
120+
return NextResponse.json({ error: error.message }, { status: 404 });
121+
}
62122
}
63123
return NextResponse.json(
64-
{ message: "Failed to fetch contest problems" },
124+
{ error: "Failed to remove problem from contest" },
65125
{ status: 500 },
66126
);
67127
}

0 commit comments

Comments
 (0)