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; }