mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 17:46:28 +08:00
bug fixes & improvements for on site contest
This commit is contained in:
19 files changed
+383
-68
No files matched your search
@@ -0,0 +1,92 @@
|
||||
import {
|
||||
ContestModel, Context, DomainModel, fs, nanoid, ProblemDoc, ProblemModel,
|
||||
RecordModel, SettingModel, StorageModel, SystemModel,
|
||||
} from 'hydrooj';
|
||||
import { ContestDetailBaseHandler } from 'hydrooj/src/handler/contest';
|
||||
|
||||
class AutoSubmitHandler extends ContestDetailBaseHandler {
|
||||
pdoc: ProblemDoc;
|
||||
|
||||
async submit({ domainId, dryrun }: { domainId: string, dryrun: boolean }) {
|
||||
if (!this.tdoc || !ContestModel.isOngoing(this.tdoc, this.tsdoc)) return { error: 'Contest not live' };
|
||||
if (!this.tdoc.allowPrint) return { error: 'Not a on-site contest' };
|
||||
const file = this.request.files?.file;
|
||||
if (!file) return { error: 'No file uploaded' };
|
||||
const filename = file.originalFilename.split('/').pop();
|
||||
if (!/^[A-Z]\./i.test(filename.toUpperCase())) return { error: 'Unsupported file name' };
|
||||
const pids = this.tdoc.pids;
|
||||
const pidIndex = filename.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
|
||||
if (pidIndex < 0 || pidIndex >= pids.length) return { error: 'Unsupported file name' };
|
||||
const pid = pids[pidIndex];
|
||||
this.pdoc = await ProblemModel.get(domainId, pid);
|
||||
|
||||
const ext = filename.split('.').pop();
|
||||
let lang = ext.toLowerCase();
|
||||
|
||||
const config = this.pdoc.config;
|
||||
const lengthLimit = SystemModel.get('limit.codelength') || 128 * 1024;
|
||||
if (typeof config === 'string' || config === null) return { error: 'system error' };
|
||||
const sizeLimit = config.type === 'submit_answer' ? 128 * 1024 * 1024 : lengthLimit;
|
||||
if (file.size > sizeLimit) return { error: 'File too large' };
|
||||
|
||||
if (['submit_answer', 'objective'].includes(config.type)) {
|
||||
lang = '_';
|
||||
} else if ((config.langs && !config.langs.includes(lang)) || !SettingModel.langs[lang] || SettingModel.langs[lang].disabled) {
|
||||
return { error: 'Unsupported language' };
|
||||
}
|
||||
const shouldReadFile = () => {
|
||||
if (config.type === 'objective') return true;
|
||||
if (lang === '_') return false;
|
||||
return file.size < lengthLimit && !file.filepath.endsWith('.zip') && !SettingModel.langs[lang].isBinary;
|
||||
};
|
||||
let code = '';
|
||||
const files: Record<string, string> = {};
|
||||
if (shouldReadFile()) code = await fs.readFile(file.filepath, 'utf-8');
|
||||
else {
|
||||
const id = nanoid();
|
||||
await StorageModel.put(`submission/${this.user._id}/${id}`, file.filepath, this.user._id);
|
||||
files.code = `${this.user._id}/${id}#${file.originalFilename}`;
|
||||
}
|
||||
|
||||
if (!code) return { error: 'Cannot submit empty code' };
|
||||
|
||||
if (dryrun) {
|
||||
return {
|
||||
info: `Info
|
||||
|
||||
Contest ${this.tdoc.title}
|
||||
Problem ${this.pdoc.title}
|
||||
User ${this.user.uname}
|
||||
School ${this.user.school}
|
||||
Language ${SettingModel.langs[lang].display} (${lang})
|
||||
`,
|
||||
};
|
||||
}
|
||||
|
||||
await this.limitRate('add_record', 60, SystemModel.get('limit.submission_user'), '{{user}}');
|
||||
await this.limitRate('add_record', 60, SystemModel.get('limit.submission'));
|
||||
|
||||
const rid = await RecordModel.add(
|
||||
domainId, this.pdoc.docId, this.user._id, lang, code, true,
|
||||
{ contest: this.tdoc.docId, files, type: 'judge' },
|
||||
);
|
||||
await Promise.all([
|
||||
ProblemModel.inc(domainId, this.pdoc.docId, 'nSubmit', 1),
|
||||
DomainModel.incUserInDomain(domainId, this.user._id, 'nSubmit'),
|
||||
ContestModel.updateStatus(domainId, this.tdoc.docId, this.user._id, rid, this.pdoc.docId),
|
||||
]);
|
||||
return { rid };
|
||||
}
|
||||
|
||||
async post({ domainId, dryrun }) {
|
||||
try {
|
||||
this.response.body = await this.submit({ domainId, dryrun });
|
||||
} catch (e) {
|
||||
this.response.body = { error: e.message };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function apply(ctx: Context) {
|
||||
ctx.Route('contest_autosubmit', '/contest/:tid/autosubmit', AutoSubmitHandler);
|
||||
}
|
||||
Reference in new issue
Block a user