core: import from hydro

This commit is contained in:
undefined committed 2021-05-22 19:17:43 +08:00
1 parent d5204eac9e
commit 664938c075
4 files changed
+72 -11

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.26.26", "version": "2.26.27",
"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",
+1 -1
View File
@@ -25,7 +25,7 @@ export const builtinModel = [
export const builtinHandler = [ export const builtinHandler = [
'home', 'problem', 'record', 'judge', 'user', 'home', 'problem', 'record', 'judge', 'user',
'contest', 'training', 'discussion', 'manage', 'import.syzoj', 'contest', 'training', 'discussion', 'manage', 'import',
'misc', 'homework', 'domain', 'remote', 'status', 'misc', 'homework', 'domain', 'remote', 'status',
]; ];
@@ -1,4 +1,5 @@
import fs from 'fs'; /* eslint-disable no-await-in-loop */
import fs from 'fs-extra';
import path from 'path'; import path from 'path';
import os from 'os'; import os from 'os';
import assert from 'assert'; import assert from 'assert';
@@ -10,7 +11,7 @@ import yaml from 'js-yaml';
import { ValidationError, RemoteOnlineJudgeError } from '../error'; import { ValidationError, RemoteOnlineJudgeError } from '../error';
import { Logger } from '../logger'; import { Logger } from '../logger';
import type { ContentNode } from '../interface'; import type { ContentNode } from '../interface';
import problem from '../model/problem'; import problem, { ProblemDoc } from '../model/problem';
import TaskModel from '../model/task'; import TaskModel from '../model/task';
import { PERM } from '../model/builtin'; import { PERM } from '../model/builtin';
import { import {
@@ -19,11 +20,12 @@ import {
import { isPid, parsePid } from '../lib/validator'; import { isPid, parsePid } from '../lib/validator';
import download from '../lib/download'; import download from '../lib/download';
import { buildContent } from '../lib/content'; import { buildContent } from '../lib/content';
import { ProblemAdd } from '../lib/ui';
const RE_SYZOJ = /(https?):\/\/([^/]+)\/(problem|p)\/([0-9]+)\/?/i; const RE_SYZOJ = /(https?):\/\/([^/]+)\/(problem|p)\/([0-9]+)\/?/i;
const logger = new Logger('import.syzoj'); const logger = new Logger('import.syzoj');
async function syncFiles(info) { async function syzojSync(info) {
const { const {
protocol, host, body, pid, domainId, docId, protocol, host, body, pid, domainId, docId,
} = info; } = info;
@@ -67,7 +69,7 @@ async function syncFiles(info) {
await problem.addAdditionalFile(domainId, docId, f.filename, p); await problem.addAdditionalFile(domainId, docId, f.filename, p);
} }
} }
TaskModel.Worker.addHandler('import.syzoj', syncFiles); TaskModel.Worker.addHandler('import.syzoj', syzojSync);
class ProblemImportSYZOJHandler extends Handler { class ProblemImportSYZOJHandler extends Handler {
async get() { async get() {
@@ -226,7 +228,7 @@ class ProblemImportSYZOJHandler extends Handler {
const payload = { const payload = {
protocol, host, pid, domainId, docId, body: result.body, protocol, host, pid, domainId, docId, body: result.body,
}; };
if (wait) await syncFiles(payload); if (wait) await syzojSync(payload);
else await TaskModel.add({ ...payload, type: 'schedule', subType: 'import.syzoj' }); else await TaskModel.add({ ...payload, type: 'schedule', subType: 'import.syzoj' });
return docId; return docId;
} }
@@ -272,8 +274,67 @@ class ProblemImportSYZOJHandler extends Handler {
} }
} }
export async function apply() { class ProblemImportHydroHandler extends Handler {
Route('problem_import_syzoj', '/problem/import/syzoj', ProblemImportSYZOJHandler, PERM.PERM_CREATE_PROBLEM); async get() {
this.response.template = 'problem_import.html';
}
async post({ domainId }) {
if (!this.request.files.file) throw new ValidationError('file');
const tmpdir = path.join(os.tmpdir(), 'hydro', `${Math.random()}.import`);
const zip = new AdmZip(this.request.files.file.path);
await new Promise((resolve, reject) => {
zip.extractAllToAsync(tmpdir, true, (err) => {
if (err) reject(err);
resolve(null);
});
});
try {
const problems = await fs.readdir(tmpdir);
for (const i of problems) {
const files = await fs.readdir(path.join(tmpdir, i));
if (!files.includes('problem.yaml')) continue;
const content = fs.readFileSync(path.join(tmpdir, i, 'problem.yaml'), 'utf-8');
const pdoc: ProblemDoc = yaml.load(content) as any;
const current = await problem.get(domainId, pdoc.pid);
const pid = current ? undefined : pdoc.pid;
const docId = await problem.add(domainId, pid, pdoc.title, pdoc.content, pdoc.owner, pdoc.tag, pdoc.hidden);
if (files.includes('testdata')) {
const datas = await fs.readdir(path.join(tmpdir, i, 'testdata'), { withFileTypes: true });
for (const f of datas) {
if (f.isDirectory()) {
const sub = await fs.readdir(path.join(tmpdir, i, 'testdata', f.name));
for (const s of sub) {
const stream = fs.createReadStream(path.join(tmpdir, i, 'testdata', f.name, s));
await problem.addTestdata(domainId, docId, `${f.name}/${s}`, stream);
}
} else if (f.isFile()) {
const stream = fs.createReadStream(path.join(tmpdir, i, 'testdata', f.name));
await problem.addTestdata(domainId, docId, f.name, stream);
}
}
}
if (files.includes('additional_file')) {
const datas = await fs.readdir(path.join(tmpdir, i, 'additional_file'), { withFileTypes: true });
for (const f of datas) {
if (f.isFile()) {
const stream = fs.createReadStream(path.join(tmpdir, i, 'additional_file', f.name));
await problem.addAdditionalFile(domainId, docId, f.name, stream);
}
}
}
}
} finally {
await fs.remove(tmpdir);
}
this.response.redirect = this.url('problem_main');
}
} }
global.Hydro.handler['import.syzoj'] = apply; export async function apply() {
ProblemAdd('problem_import_hydro', {}, 'copy', 'Import From Hydro');
Route('problem_import_syzoj', '/problem/import/syzoj', ProblemImportSYZOJHandler, PERM.PERM_CREATE_PROBLEM);
Route('problem_import_hydro', '/problem/import/hydro', ProblemImportHydroHandler, PERM.PERM_CREATE_PROBLEM);
}
global.Hydro.handler.import = apply;
+1 -1
View File
@@ -182,7 +182,7 @@ export class ProblemReceiveHandler extends Handler {
} }
export async function apply() { export async function apply() {
ProblemAdd('problem_receive', {}, 'copy', 'Import From Hydro'); ProblemAdd('problem_receive', {}, 'copy', 'Receive From Hydro');
Route('problem_receive', '/problem/receive', ProblemReceiveHandler); Route('problem_receive', '/problem/receive', ProblemReceiveHandler);
Route('problem_send', '/problem/send', ProblemSendHandler); Route('problem_send', '/problem/send', ProblemSendHandler);
} }