core: remote judge api

This commit is contained in:
undefined committed 2021-06-21 13:39:39 +08:00
1 parent 939584ec5e
commit 680e3ccd32
11 files changed
+54 -13

No files matched your search

+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.28.44", "version": "2.28.45",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "dist/loader.js", "main": "dist/loader.js",
"typings": "dist/loader.d.ts", "typings": "dist/loader.d.ts",
@@ -12,7 +12,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"dependencies": { "dependencies": {
"@hydrooj/utils": "workspace:*", "@hydrooj/utils": "workspace:packages/utils",
"adm-zip": "^0.5.5", "adm-zip": "^0.5.5",
"ansi_up": "^5.0.1", "ansi_up": "^5.0.1",
"cac": "^6.7.3", "cac": "^6.7.3",
+5 -1
View File
@@ -295,7 +295,8 @@ export class ContestProblemHandler extends Handler {
// Navigate to current additional file download // Navigate to current additional file download
// e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg) // e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg)
this.response.body.pdoc.content = this.response.body.pdoc.content this.response.body.pdoc.content = this.response.body.pdoc.content
.replace(/\(file:\/\//g, `(./${args[2]}/file/`); .replace(/\(file:\/\//g, `(./${args[2]}/file/`)
.replace(/="file:\/\//g, `="./${args[2]}/file/`);
} }
} }
@@ -344,6 +345,9 @@ export class ContestDetailProblemSubmitHandler extends ContestProblemHandler {
if (this.response.body.pdoc.config?.langs && !this.response.body.pdoc.config.langs.includes(lang)) { if (this.response.body.pdoc.config?.langs && !this.response.body.pdoc.config.langs.includes(lang)) {
throw new BadRequestError('Language not allowed.'); throw new BadRequestError('Language not allowed.');
} }
if (this.domain.langs && !this.domain.langs.includes(lang)) {
throw new BadRequestError('Language not allowed');
}
await this.limitRate('add_record', 60, 10); await this.limitRate('add_record', 60, 10);
const rid = await record.add(domainId, pid, this.user._id, lang, code, true, pretest ? input : { const rid = await record.add(domainId, pid, this.user._id, lang, code, true, pretest ? input : {
type: document.TYPE_CONTEST, type: document.TYPE_CONTEST,
+5 -1
View File
@@ -168,7 +168,8 @@ class HomeworkDetailProblemHandler extends Handler {
// Navigate to current additional file download // Navigate to current additional file download
// e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg) // e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg)
this.response.body.pdoc.content = this.response.body.pdoc.content this.response.body.pdoc.content = this.response.body.pdoc.content
.replace(/\(file:\/\//g, `(./${pid}/file/`); .replace(/\(file:\/\//g, `(./${pid}/file/`)
.reaplce(/="file:\/\//g, `="./${pid}/file/`);
} }
} }
@@ -219,6 +220,9 @@ class HomeworkDetailProblemSubmitHandler extends HomeworkDetailProblemHandler {
if (this.response.body.pdoc.config?.langs && !this.response.body.pdoc.config.langs.includes(lang)) { if (this.response.body.pdoc.config?.langs && !this.response.body.pdoc.config.langs.includes(lang)) {
throw new BadRequestError('Language not allowed.'); throw new BadRequestError('Language not allowed.');
} }
if (this.domain.langs && !this.domain.langs.includes(lang)) {
throw new BadRequestError('Language not allowed');
}
await this.limitRate('add_record', 60, 5); await this.limitRate('add_record', 60, 5);
const rid = await record.add(domainId, pid, this.user._id, lang, code, true, pretest ? input : { const rid = await record.add(domainId, pid, this.user._id, lang, code, true, pretest ? input : {
type: document.TYPE_HOMEWORK, type: document.TYPE_HOMEWORK,
+5 -1
View File
@@ -212,7 +212,8 @@ export class ProblemDetailHandler extends ProblemHandler {
// e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg) // e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg)
if (!this.request.json) { if (!this.request.json) {
this.response.body.pdoc.content = this.response.body.pdoc.content this.response.body.pdoc.content = this.response.body.pdoc.content
.replace(/\(file:\/\//g, `(./${this.pdoc.docId}/file/`); .replace(/\(file:\/\//g, `(./${this.pdoc.docId}/file/`)
.replace(/="file:\/\//g, `="./${this.pdoc.docId}/file/`);
} }
if (this.psdoc) { if (this.psdoc) {
this.response.body.rdoc = await record.get(this.domainId, this.psdoc.rid); this.response.body.rdoc = await record.get(this.domainId, this.psdoc.rid);
@@ -269,6 +270,9 @@ export class ProblemSubmitHandler extends ProblemDetailHandler {
if (this.response.body.pdoc.config?.langs && !this.response.body.pdoc.config.langs.includes(lang)) { if (this.response.body.pdoc.config?.langs && !this.response.body.pdoc.config.langs.includes(lang)) {
throw new BadRequestError('Language not allowed.'); throw new BadRequestError('Language not allowed.');
} }
if (this.domain.langs && !this.domain.langs.includes(lang)) {
throw new BadRequestError('Language not allowed');
}
await this.limitRate('add_record', 60, 5); await this.limitRate('add_record', 60, 5);
const rid = await record.add(domainId, this.pdoc.docId, this.user._id, lang, code, true, pretest ? input : undefined); const rid = await record.add(domainId, this.pdoc.docId, this.user._id, lang, code, true, pretest ? input : undefined);
const rdoc = await record.get(domainId, rid); const rdoc = await record.get(domainId, rid);
+11 -5
View File
@@ -136,15 +136,19 @@ export enum SubtaskType {
} }
export interface SubtaskConfig { export interface SubtaskConfig {
time?: number, time?: number;
memory?: number, memory?: number;
score?: number, score?: number;
type?: SubtaskType, if?: number[];
cases?: TestCaseConfig[], id?: number;
type?: SubtaskType;
cases?: TestCaseConfig[];
} }
export interface ProblemConfigFile { export interface ProblemConfigFile {
type?: ProblemType; type?: ProblemType;
subType?: string;
target?: string;
score?: number; score?: number;
time?: string; time?: string;
memory?: string; memory?: string;
@@ -168,6 +172,8 @@ export interface ProblemConfig {
timeMin: number; timeMin: number;
langs?: string[]; langs?: string[];
type: string; type: string;
subType?: string;
target?: string;
} }
export interface PlainContentNode { export interface PlainContentNode {
+5
View File
@@ -26,15 +26,20 @@ export function buildContent(source: ProblemSource | ContentNode[], type: 'markd
node.type !== 'Plain' ? `## ${node.sectionTitle}` : '', node.type !== 'Plain' ? `## ${node.sectionTitle}` : '',
...node.type === 'Sample' ...node.type === 'Sample'
? [ ? [
'',
`\`\`\`input${++cnt}`, `\`\`\`input${++cnt}`,
node.payload[0], node.payload[0],
'```', '```',
'',
`\`\`\`output${cnt}`, `\`\`\`output${cnt}`,
node.payload[1], node.payload[1],
'```', '```',
'',
] ]
: [], : [],
'',
node.text, node.text,
'',
].join('\n')).join('\n'); ].join('\n')).join('\n');
} }
return type === 'html' return type === 'html'
@@ -16,6 +16,8 @@ export async function parseConfig(config: string | ProblemConfigFile = {}) {
timeMax: 0, timeMax: 0,
type: cfg.type || 'default', type: cfg.type || 'default',
}; };
if (cfg.subType) result.subType = cfg.subType;
if (cfg.target) result.target = cfg.target;
if (cfg.subtasks.length) { if (cfg.subtasks.length) {
for (const subtask of cfg.subtasks) { for (const subtask of cfg.subtasks) {
result.memoryMax = Math.max(result.memoryMax, subtask.memory); result.memoryMax = Math.max(result.memoryMax, subtask.memory);
+1 -1
View File
@@ -39,7 +39,7 @@ export class ProblemModel {
domainId: 'system', domainId: 'system',
docType: document.TYPE_PROBLEM, docType: document.TYPE_PROBLEM,
docId: 0, docId: 0,
pid: null, pid: '',
owner: 1, owner: 1,
title: '*', title: '*',
content: '', content: '',
+16 -2
View File
@@ -9,7 +9,7 @@ import { STATUS } from './builtin';
import task from './task'; import task from './task';
import problem from './problem'; import problem from './problem';
import { import {
RecordDoc, ContestInfo, ProblemConfigFile, ExternalProblemId, RecordDoc, ContestInfo, ProblemConfigFile, ExternalProblemId, ProblemConfig,
} from '../interface'; } from '../interface';
import { ArgMethod, buildProjection, Time } from '../utils'; import { ArgMethod, buildProjection, Time } from '../utils';
import { MaybeArray } from '../typeutils'; import { MaybeArray } from '../typeutils';
@@ -62,11 +62,25 @@ class RecordModel {
static async judge(domainId: string, rid: ObjectID, priority = 0, config: ProblemConfigFile = {}) { static async judge(domainId: string, rid: ObjectID, priority = 0, config: ProblemConfigFile = {}) {
const rdoc = await RecordModel.get(domainId, rid); const rdoc = await RecordModel.get(domainId, rid);
let data = []; let data = [];
delete rdoc._id;
if (rdoc.pid) { if (rdoc.pid) {
const pdoc = await problem.get(rdoc.pdomain, rdoc.pid); const pdoc = await problem.get(rdoc.pdomain, rdoc.pid);
data = pdoc.data; data = pdoc.data;
if (typeof pdoc.config === 'string') throw new Error(); // Just for typings. This won't happen.
if (pdoc.config.type === 'remote_judge') {
return await task.add({
...rdoc,
priority,
type: 'remotejudge',
subType: pdoc.config.subType,
target: pdoc.config.target,
rid,
domainId,
config,
data,
});
}
} }
delete rdoc._id;
await task.add({ await task.add({
...rdoc, ...rdoc,
priority, priority,
+1
View File
@@ -140,6 +140,7 @@ DomainSetting(
Setting('setting_domain', 'avatar', '', 'text', 'avatar', 'Will be used as the domain icon.'), Setting('setting_domain', 'avatar', '', 'text', 'avatar', 'Will be used as the domain icon.'),
Setting('setting_domain', 'share', '', 'text', 'Share problem with domain (* for any)'), Setting('setting_domain', 'share', '', 'text', 'Share problem with domain (* for any)'),
Setting('setting_domain', 'bulletin', '', 'markdown', 'Bulletin'), Setting('setting_domain', 'bulletin', '', 'markdown', 'Bulletin'),
Setting('setting_domain', 'langs', '', 'text', 'Allowed langs', null),
Setting('setting_storage', 'host', '', 'text', 'Custom host', null, FLAG_HIDDEN | FLAG_DISABLED), Setting('setting_storage', 'host', '', 'text', 'Custom host', null, FLAG_HIDDEN | FLAG_DISABLED),
); );
+1
View File
@@ -503,6 +503,7 @@ export class Handler extends HandlerCommon {
throw new NotFoundError(domainId); throw new NotFoundError(domainId);
} }
this.UiContext.domainId = this.domainId; this.UiContext.domainId = this.domainId;
this.UiContext.domain = this.domain;
this.user = await user.getById(domainId, this.session.uid, this.session.scope); this.user = await user.getById(domainId, this.session.uid, this.session.scope);
if (!this.user) { if (!this.user) {
this.session.uid = 0; this.session.uid = 0;