Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
feat(api:user:submissions): add endpoint `/api/users/[username]/submi…
Browse files Browse the repository at this point in the history
…ssions`

  ## what
  - add endpoint `/api/users/[username]/submissions`

  ## how
  - check if username is valid (using zod schema)
  - if username doesn't exist, return 404
  - fetch all problems from `/api/problems`
    - used as a cache for `pnum`, `pTitle`
  - fetch user submissions
  - sort the submissions by submission time in descending order
  - take only the first 500 elements in the array
  - convert submission array into `UserSub` object
    - add properties
      - pnum
      - pTitle
      - verdict

  ## why
  - this will be used for fetching user submissions

  ## where
  - ./src/app/api/users/[username]/submissions/route.ts

  ## usage
  • Loading branch information
Clumsy-Coder committed Jan 16, 2024
1 parent 6e61b13 commit 4d7cfa1
Showing 1 changed file with 118 additions and 0 deletions.
118 changes: 118 additions & 0 deletions src/app/api/users/[username]/submissions/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { NextResponse } from "next/server";
import { z } from "zod";

import { userSchema as schema } from "@/schema";
import {
uhuntUserSubmissionsUrl,
uhuntUsername2UidUrl,
} from "@/utils/constants";
import {
Language,
Problem,
ProblemVerdictMap,
UserSub,
UserSubmission,
} from "@/types";

type getParamsType = {
params: z.infer<typeof schema>;
};

export const GET = async (_request: Request, { params }: getParamsType) => {
// validate params
const schemaResponse = await schema.safeParseAsync(params);
if (!schemaResponse.success) {
const message = {
message: schemaResponse.error.issues[0].message,
};

return NextResponse.json(message, {
status: 400,
});
}

//----------------------------------------------------------------------------------------------//

// fetch username ID
const { username } = params;

const usernameUrl = uhuntUsername2UidUrl(username);
const usernameResponse = await fetch(usernameUrl);
const usernameData: number = await usernameResponse.json();

// return 404 if problem doesn't exist
if (usernameData === 0) {
const message = {
message: `Username ${username} not found`,
};
return NextResponse.json(message, {
status: 404,
});
}

//----------------------------------------------------------------------------------------------//

// fetch all problems
// this is needed because later each submission will need problem number and problem title.
// if repeatedly fetching from upstream api server, it will slow down.
const allProblemsUrl = `http://localhost:${process.env.PORT}/api/problems`;
const allProblemsResponse = await fetch(allProblemsUrl);
const allProblemsData: Problem[] = await allProblemsResponse.json();

// fetch submissions of the user
const userSubmissionsUrl = uhuntUserSubmissionsUrl(usernameData);
const userSubmissionResponse = await fetch(userSubmissionsUrl, {
cache: "no-cache",
});
const userSubmissionData =
(await userSubmissionResponse.json()) as UserSubmission;

// change userSubmissionData.sub[] into UserSub[]
// originally the upstream api would return `userSubmissionData.sub` as an array of array
// // ex:
// [
// [
// 0: 5251911 // submission ID
// 1: 62 // problem ID
// 2: 10 // verdict ID
// 3: 0 // runtime
// 4: 1168359789 // submission time
// 5: 4 // language ID
// 6: -1 // rank
// ]
// ]
const converted = (userSubmissionData.subs as unknown as number[][])
.sort((a, b) => b[4] - a[4]) // sort by submission time in descending order
.slice(0, 500) // take only the most recent 500 submissions
.map((submission: number[]) => {
const converted: Partial<UserSub> = {};
converted.sid = submission[0];
converted.pid = submission[1];
converted.ver = submission[2];
converted.run = submission[3];
converted.sbt = submission[4];
converted.lan = submission[5] as unknown as string;
converted.rank = submission[6];

const problemData = allProblemsData.find(
(problem) => problem.pid === converted.pid,
);

converted.pnum = (problemData as Problem).num;
converted.pTitle = (problemData as Problem).title;
converted.verdict = ProblemVerdictMap[converted.ver as number] || {
fgColor: "text-primary-foreground dark:text-secondary-foreground",
bgColor: "bg-gray-500",
title: "- In Queue -",
fgHex: "",
bgHex: "6b7280",
};
converted.lan = Language[converted.lan];

return converted;
});

userSubmissionData.subs = converted as unknown as UserSub[];

return Response.json(userSubmissionData);
};

0 comments on commit 4d7cfa1

Please sign in to comment.