Commit b46898e3 authored by Yechang's avatar Yechang
Browse files

feat(submission): rejudge

parent 23a768da
Loading
Loading
Loading
Loading
Loading
+43 −13
Original line number Diff line number Diff line
@@ -60,10 +60,11 @@ export const fixAndCalculatePenalty = async (currentSubmissionId: number): Promi
        if (_.isNil(feedback)) {
            break
        }
        if (feedback.score === -1) {
        const originalScore = await getFeedbackScore(feedback)
        const finalScore = _.max([originalScore - penaltyScore, 0]) || 0;
        if (feedback.score !== finalScore) {
            await db.$transaction(async (tx) => {
                if (feedback.score === -1) {
                    await tx.gradeRecord.create({
                        data: {
                            grade: finalScore,
@@ -75,6 +76,35 @@ export const fixAndCalculatePenalty = async (currentSubmissionId: number): Promi
                            groupId: submission.problem.gradeGroupId,
                        }
                    })
                } else {
                    await tx.gradeRecord.updateMany({
                        where: {
                            AND: [
                                {
                                    source: {
                                        path: "$.type",
                                        equals: "submission"
                                    },
                                },
                                {
                                    source: {
                                        path: "$.id",
                                        equals: s.id
                                    },
                                }
                            ]
                        },
                        data: {
                            grade: finalScore,
                            source: {
                                type: "submission",
                                id: s.id
                            },
                            studentId: submission.submitterId,
                            groupId: submission.problem.gradeGroupId,
                        }
                    })
                }
                await tx.submissionFeedback.update({
                    where: {
                        id: feedback.id
+28 −23
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ import { judgementArgsSchema } from '../oj/args';
import moment from 'moment';
import axios from 'axios';
import { createJudgementByHTTP, SlotType } from '../oj';
import type { File, Problem, Submission } from '@prisma/client';

type CreateSubmissionSchema = {
	problemId: number;
@@ -65,66 +66,70 @@ export const createSubmission = async ({
		}
	});

	const judgementArgs = judgementArgsSchema.parse(submission.problem.judgementArgs)
	await judge(submission.problem, submission, file);

	return submission;
};

export async function judge(problem: Problem, submission: Submission, file: File) {
	const judgementArgs = judgementArgsSchema.parse(problem.judgementArgs);
	if ("program" in judgementArgs) {
		const { program } = judgementArgs
		const { program } = judgementArgs;
		const id = await createJudgementByHTTP(program, [{
			type: SlotType.S3_FILE,
			key: submission.volumeId
		}])
		}]);

		const task = await db.task.create({
			data: {
				fileKey: volumeId,
				fileKey: file.id,
				language: "",
				testdataKey: "",
				ioj: id,
				args: {},
				submissionId: submission.id,
			}
		})
		});
	} else {
		const language = file.filename.endsWith("cpp") ? "cpp" : "java"
		let { memoryLimit, timeLimit } = judgementArgs
		const spec = judgementArgs[language]
		const language = file.filename.endsWith("cpp") ? "cpp" : "java";
		let { memoryLimit, timeLimit } = judgementArgs;
		const spec = judgementArgs[language];
		if (!_.isNil(spec)) {
			memoryLimit = spec.memoryLimit || memoryLimit
			timeLimit = spec.timeLimit || timeLimit
			memoryLimit = spec.memoryLimit || memoryLimit;
			timeLimit = spec.timeLimit || timeLimit;
		}
		let args: { memoryLimit: number, timeLimit: number, compileAndRunOptions?: {} } = {
		let args: { memoryLimit: number; timeLimit: number; compileAndRunOptions?: {}; } = {
			memoryLimit, timeLimit
		}
		};

		if (language === 'cpp') {
			if (spec && "compileAndRunOptions" in spec) {
				args.compileAndRunOptions = spec.compileAndRunOptions
				args.compileAndRunOptions = spec.compileAndRunOptions;
			} else {
				args.compileAndRunOptions = {
					std: "c++11",
					O: "2",
					m: "64",
				}
				};
			}
		}
		const task = await db.task.create({
			data: {
				submissionId: submission.id,
				fileKey: volumeId,
				fileKey: file.id,
				language,
				testdataKey: submission.problem.testdata || "",
				testdataKey: problem.testdata || "",
				args: {
					subtasks: judgementArgs.subtasks,
					...args
				}
			}
		})
		const hash = nanoid()
		await redis.hset(`lms:task:hash`, hash, `${task.id}`)
		await redis.rpush(`lms:task:queue`, hash)
		});
		const hash = nanoid();
		await redis.hset(`lms:task:hash`, hash, `${task.id}`);
		await redis.rpush(`lms:task:queue`, hash);
	}
}

	return submission;
};

export const getSubmission = async (id: number) => {
	const submission = await db.submission.findUnique({
+2 −62
Original line number Diff line number Diff line
import { db } from '$lib/server/db'
import { log } from '$lib/server/log'
import { SlotType, type SlotValue } from '$lib/server/oj'
import { redis } from '$lib/server/redis'
import { messageSchema, type contentSchema } from '$lib/shared/feedback'
import { type contentSchema } from '$lib/shared/feedback'
import { TaskStatus } from '@prisma/client'
import { error, json } from '@sveltejs/kit'
import { error } from '@sveltejs/kit'
import assert from 'assert'
import _ from 'lodash'
import { z } from 'zod'


const schema = z.discriminatedUnion('status', [
    z.object({
        compile: z.object({ success: z.literal(false), message: messageSchema }),
        status: z.literal("CompilationError"),
        score: z.number(),
        totalOccupiedTime: z.number()
    }),
    z.object({
        status: z.literal('SystemError'),
        systemMessage: messageSchema
    }),
    z.object({
        status: z.literal('ConfigurationError'),
        systemMessage: messageSchema
    }),
    z.object({
        status: z.enum(["Accepted",
            "FileError",
            "RuntimeError",
            "TimeLimitExceeded",
            "MemoryLimitExceeded",
            "OutputLimitExceeded",
            "PartiallyCorrect",
            "WrongAnswer",
            "JudgementFailed"
        ]),
        compile: z.object({ success: z.literal(true), message: messageSchema }),
        testcaseResult: z.record(z.string(), z.object({
            testcaseInfo: z.object({
                timeLimit: z.number(),
                memoryLimit: z.number(),
                inputFile: z.string(),
                outputFile: z.string()
            }),
            status: z.string(),
            score: z.number(),
            input: messageSchema,
            output: messageSchema,
            userOutput: messageSchema,
            userError: messageSchema,
            time: z.number(),
            memory: z.number(),
            checkerMessage: messageSchema.optional(),
        })),
        subtasks: z.array(
            z.object({
                score: z.number(),
                fullScore: z.number(),
                testcases: z.array(z.object({ testcaseHash: z.string() }))
            })
        ),
        score: z.number(),
        totalOccupiedTime: z.number()
    })
])



export const POST = async ({ request }) => {
    const req = await request.json()
    const { name, outputs }: { name: string; outputs: Array<SlotValue> } = req
+49 −4
Original line number Diff line number Diff line
@@ -110,8 +110,27 @@ export const PUT = async ({ request, params }) => {
        const res = parsed.data

        if (res.status === 'CompilationError') {
            const feedback = await db.submissionFeedback.create({
                data: {
            const feedback = await db.submissionFeedback.upsert({
                where: {
                    submissionId: task.submissionId,
                },
                update: {
                    score: 0,
                    description: "Compile Error",
                    descriptionHTML: "",
                    content: [
                        {
                            type: "status",
                            value: res.status
                        },
                        {
                            type: "ansi",
                            value: res.compile.message
                        }
                    ] as z.infer<typeof contentSchema>,
                    isValid: false
                },
                create: {
                    score: 0,
                    description: "Compile Error",
                    descriptionHTML: "",
@@ -158,8 +177,34 @@ export const PUT = async ({ request, params }) => {
            return new Response(null, { status: 201 })
        }

        await db.submissionFeedback.create({
            data: {
        await db.submissionFeedback.upsert({
            where: {
                submissionId: task.submissionId,
            },
            update: {
                description: res.status,
                descriptionHTML: "",
                content: [
                    {
                        type: "status",
                        value: res.status
                    },
                    {
                        type: "score",
                        value: res.score
                    },
                    {
                        type: "testcases",
                        value: _.entries(res.testcaseResult).map(([key, v]) => {
                            const { input, output, userOutput, userError, ...data } = v
                            return data
                        })
                    }
                ] as z.infer<typeof contentSchema>,
                submissionId: task.submissionId,
                isValid: true
            },
            create: {
                score: -1,
                description: res.status,
                descriptionHTML: "",
+10 −42
Original line number Diff line number Diff line
import { db } from '$lib/server/db';
import { getSubmission } from '$lib/server/db/submission';
import { getSubmission, judge } from '$lib/server/db/submission';
import { createJudgement, SlotType } from '$lib/server/oj';
import { signDownloadRequest } from '$lib/server/storage';
import { error, redirect, type Actions, type ServerLoad } from '@sveltejs/kit';
@@ -62,56 +62,24 @@ export const load: PageServerLoad = async ({ params, locals, parent }) => {
};

export const actions: Actions = {
	rejudge: async (event) => {
		const user = event.locals.user;
	rejudge: async ({ locals, params }) => {
		const user = locals.user;
		if (_.isNil(user)) {
			return redirect(302, '/login');
		}
		const submissionId = _.toNumber(event.params.submissionId);
		const submissionId = _.toNumber(params.submissionId);
		const submission = await getSubmission(submissionId);
		if (_.isNil(submission)) {
			error(404, { message: 'Not found' });
		}

		const { testdata, judgementArgs } = submission.problem;
		if (!_.isNil(judgementArgs) && !_.isNil(testdata)) {
			const result = z
				.object({
					program: z.enum(['syzoj-judger2']),
					testdata: z.string(),
					memoryLimit: z.number(),
					timeLimit: z.number()
		const file = await db.file.findFirst({
			where: { id: submission.volumeId }
		})
				.safeParse(judgementArgs);
			if (result.success) {
				const userFile = submission.volumeId;
				const { memoryLimit, timeLimit } = result.data;
				await createJudgement('syzoj-judger2', [
					{
						type: SlotType.STRING,
						value: 'cpp'
					},
					{
						type: SlotType.S3_FILE,
						key: userFile
					},
					{
						type: SlotType.S3_FILE,
						key: testdata
					},
					{
						type: SlotType.NUMBER,
						value: timeLimit
					},
					{
						type: SlotType.NUMBER,
						value: memoryLimit
					}
				]);
			} else {
				console.log(result.error);
			}
		if (_.isNil(file)) {
			return error(400)
		}
		await judge(submission.problem, submission, file)
		return redirect(302, `/submission/${submission.id}`);
	}
};
Loading