diff --git a/packages/fps-importer/handler.ts b/packages/fps-importer/handler.ts
index 59621195e..d994991eb 100644
--- a/packages/fps-importer/handler.ts
+++ b/packages/fps-importer/handler.ts
@@ -11,7 +11,7 @@ import { LocalProblemConfig } from 'hydrooj';
import {
Route, Handler, param, Types,
} from 'hydrooj/dist/service/server';
-import { streamToBuffer } from 'hydrooj/dist/utils';
+import { buildContent, streamToBuffer } from 'hydrooj/dist/utils';
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
import * as file from 'hydrooj/dist/model/file';
import * as solution from 'hydrooj/dist/model/solution';
@@ -60,57 +60,22 @@ class FpsProblemImportHandler extends Handler {
const problem = global.Hydro.model.problem;
for (const p of result.fps.item) {
const testdata = new AdmZip();
- const content = [];
- if (p.description) {
- content.push(
- `
${this.translate('Description')}
`,
- ...p.description,
- );
- }
- if (p.input) {
- content.push(
- `${this.translate('Input Format')}
`,
- ...p.input,
- );
- }
- if (p.output) {
- content.push(
- `${this.translate('Output Format')}
`,
- ...p.output,
- );
- }
- if (p.sample_input) {
- if (p.sample_input.length === 1) {
- content.push(
- `${this.translate('Sample Input')}
`,
- `${p.sample_input[0]}
`,
- `${this.translate('Sample Output')}
`,
- `${p.sample_output[0]}
`,
- );
- } else {
- for (let i = 0; i < p.sample_input.length; i++) {
- content.push(
- `${this.translate('Sample Input')}${i + 1}
`,
- `${p.sample_input[i]}
`,
- `${this.translate('Sample Output')}${i + 1}
`,
- `${p.sample_output[i]}
`,
- );
- }
- }
- }
- if (p.hint) {
- content.push(
- `${this.translate('Hint')}
`,
- ...p.hint,
- );
- }
+ const content = buildContent({
+ description: p.description,
+ input: p.input,
+ output: p.output,
+ samples: p.sample_input
+ ? p.sample_input.map((si: string, i: number) => [si, p.sample_output[i]])
+ : [],
+ hint: p.hint,
+ }, 'html', this.translate.bind(this));
const config: LocalProblemConfig = {
time: p.time_limit[0]._ + p.time_limit[0].$.unit,
memory: p.memory_limit[0]._ + p.memory_limit[0].$.unit,
};
const title = decodeHTML(p.title.join(' '));
const tags = filter(p.source, (i: string) => i.trim());
- const pid = await problem.add(domainId, null, title, content.join('\n'), this.user._id, tags, []);
+ const pid = await problem.add(domainId, null, title, content, this.user._id, tags, []);
testdata.addFile('config.yaml', Buffer.from(`time: ${config.time}\nmemory: ${config.memory}`));
if (p.test_output) {
for (let i = 0; i < p.test_input.length; i++) {
diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json
index cd42bfc2d..f59dd468c 100644
--- a/packages/hydrooj/package.json
+++ b/packages/hydrooj/package.json
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
- "version": "2.13.52",
+ "version": "2.13.53",
"bin": "bin/hydrooj.js",
"main": "dist/loader.js",
"typings": "dist/loader.d.ts",
diff --git a/packages/hydrooj/src/utils.ts b/packages/hydrooj/src/utils.ts
index 815d2456d..a47df6f51 100644
--- a/packages/hydrooj/src/utils.ts
+++ b/packages/hydrooj/src/utils.ts
@@ -201,3 +201,71 @@ export function sleep(timeout: number) {
}, timeout);
});
}
+
+function deepen(modifyString: (source: string) => string) {
+ function modifyObject(source: T): T {
+ if (typeof source !== 'object' || !source) return source;
+ if (Array.isArray(source)) return source.map(modifyObject) as any;
+ const result = {} as T;
+ for (const key in source) {
+ result[modifyString(key)] = modifyObject(source[key]);
+ }
+ return result;
+ }
+
+ return function t(source: T): T {
+ if (typeof source === 'string') {
+ return modifyString(source) as any;
+ }
+ return modifyObject(source);
+ };
+}
+
+export const camelCase = deepen((source) => source.replace(/[_-][a-z]/g, (str) => str.slice(1).toUpperCase()));
+export const paramCase = deepen((source) => source.replace(/_/g, '-').replace(/(? `-${str.toLowerCase()}`));
+export const snakeCase = deepen((source) => source.replace(/-/g, '_').replace(/(? `_${str.toLowerCase()}`));
+
+interface ProblemSource {
+ description?: string,
+ input?: string,
+ output?: string,
+ samples?: [string, string][],
+ hint?: string,
+ source?: string,
+}
+
+export function buildContent(source: ProblemSource, type: 'markdown' | 'html' = 'markdown', translate?: Function) {
+ const _ = translate || ((s: string) => s);
+ return type === 'html'
+ ? [
+ ...source.description ? [`${_('Description')}
`, source.description] : [],
+ ...source.input ? [`${_('Input Format')}
`, source.input] : [],
+ ...source.output ? [`'${_('Output Format')}
`, source.output] : [],
+ ...(source.samples).map((sample, i) => [
+ `${_('Sample Input')} ${i + 1}
`,
+ sample[0],
+ `
${_('Sample Output')} ${i + 1}
`,
+ sample[1],
+ '
',
+ ].join('\n')),
+ ...source.hint ? [`${_('Hint')}
`, source.hint] : [],
+ ...source.source ? [`${_('Source')}
`, source.source] : [],
+ ].join('\n')
+ : [
+ ...source.description ? [`## ${_('Description')}`, source.description] : [],
+ ...source.input ? [`## ${_('Input Format')}`, source.input] : [],
+ ...source.output ? [`## '${_('Output Format')}`, source.output] : [],
+ ...(source.samples).map((sample, i) => [
+ `## ${_('Sample Input')} ${i + 1}`,
+ '```',
+ sample[0],
+ '```',
+ `## ${_('Sample Output')} ${i + 1}`,
+ '```',
+ sample[1],
+ '```',
+ ].join('\n')),
+ ...source.hint ? [`## ${_('Hint')}`, source.hint] : [],
+ ...source.source ? [`## ${_('Source')}`, source.source] : [],
+ ].join('\n');
+}
diff --git a/packages/import-qduoj/handler.ts b/packages/import-qduoj/handler.ts
index bd4ded6fb..22256f3cf 100644
--- a/packages/import-qduoj/handler.ts
+++ b/packages/import-qduoj/handler.ts
@@ -10,7 +10,7 @@ import {
Route, Handler, param, Types,
} from 'hydrooj/dist/service/server';
import { BadRequestError } from 'hydrooj/dist/error';
-import { streamToBuffer } from 'hydrooj/dist/utils';
+import { buildContent, streamToBuffer } from 'hydrooj/dist/utils';
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
import * as file from 'hydrooj/dist/model/file';
import * as problem from 'hydrooj/dist/model/problem';
@@ -31,36 +31,14 @@ class ImportQduojHandler extends Handler {
for (const folder of folders) {
const buf = await fs.readFile(path.join(tmp, folder, 'problem.json'));
const pdoc = JSON.parse(buf.toString());
- const content = [
- ...pdoc.description?.value
- ? [
- 'Description
',
- pdoc.description.value,
- ] : [],
- ...pdoc.input_description?.value
- ? [
- 'Input Description
',
- pdoc.input_description.value,
- ] : [],
- ...pdoc.output_description?.value
- ? [
- 'Output Description
',
- pdoc.output_description.value,
- ] : [],
- ...(pdoc.samples as any[]).map((sample, i) => [
- `Sample Input ${i + 1}
`,
- sample.input,
- `
Sample Output ${i + 1}
`,
- sample.output,
- '
',
- ].join('\n')),
- ...pdoc.hint?.value
- ? [
- 'Hint
',
- pdoc.hint.value,
- ] : [],
- ...pdoc.source ? ['Source
', pdoc.source] : [],
- ].join('\n');
+ const content = buildContent({
+ description: pdoc.description?.value,
+ input: pdoc.input_description?.value,
+ output: pdoc.output_description?.value,
+ samples: pdoc.samples.map((i) => [i.input, i.output]),
+ hint: pdoc.hint?.value,
+ source: pdoc.source?.value,
+ }, 'html');
const pid = await problem.add(domainId, pdoc.display_id, pdoc.title, content, this.user._id, pdoc.tags);
const testdata = new AdmZip();
const config: LocalProblemConfig = {
diff --git a/packages/migrate-hustoj/script.ts b/packages/migrate-hustoj/script.ts
index 7cd206569..849593dbe 100644
--- a/packages/migrate-hustoj/script.ts
+++ b/packages/migrate-hustoj/script.ts
@@ -2,6 +2,7 @@
/* eslint-disable no-await-in-loop */
import mysql from 'mysql';
import 'hydrooj';
+import { buildContent } from 'hydrooj/dist/utils';
const {
user, problem, builtin: { PRIV },
@@ -79,20 +80,32 @@ export async function run({
submit int 11 Y 总提交次数
solved int 11 Y 解答(未用)
*/
- const [pdocs] = await query('SELECT * FROM `problem`');
- for (const pdoc of pdocs) {
- const pid = await problem.add(
- 'system', `P${pdoc.problem_id}`,
- pdoc.title, pdoc.description + pdoc.input + pdoc.output + pdoc.sample_input + pdoc.sample_output + pdoc.hint,
- 1, pdoc.source.split(' '), undefined, undefined, pdoc.defunct === 'Y',
- );
- const [cdoc] = await query(`SELECT * FROM 'privilege' WHERE rightstr = 'p${pdoc.problem_id}'`);
- await problem.edit('system', pid, {
- nAccept: pdoc.accepted,
- nSubmit: pdoc.submit,
- config: { time: `${pdoc.time_limit}s`, memory: `${pdoc.memory_limit}m` },
- owner: uidMap[cdoc[0].user_id],
- });
+ const [[pcount]] = await query('SELECT count(*) FROM `problem`');
+ const step = 50;
+ const pageCount = Math.ceil(pcount / step);
+ for (let pageId = 0; pageId < pageCount; pageId++) {
+ const [pdocs] = await query(`SELECT * FROM \`problem\` LIMIT ${pageId * step}, ${step}`);
+ for (const pdoc of pdocs) {
+ const pid = await problem.add(
+ 'system', `P${pdoc.problem_id}`,
+ pdoc.title, buildContent({
+ description: pdoc.description,
+ input: pdoc.input,
+ output: pdoc.output,
+ samples: [[pdoc.sample_input, pdoc.sample_output]],
+ hint: pdoc.hint,
+ source: pdoc.source,
+ }, 'html'),
+ 1, pdoc.source.split(' '), undefined, undefined, pdoc.defunct === 'Y',
+ );
+ const [cdoc] = await query(`SELECT * FROM 'privilege' WHERE rightstr = 'p${pdoc.problem_id}'`);
+ await problem.edit('system', pid, {
+ nAccept: pdoc.accepted,
+ nSubmit: pdoc.submit,
+ config: { time: `${pdoc.time_limit}s`, memory: `${pdoc.memory_limit}m` },
+ owner: uidMap[cdoc[0].user_id],
+ });
+ }
}
return true;
}