diff --git a/packages/fps-importer/handler.ts b/packages/fps-importer/handler.ts index 848d578f6..e948560e2 100644 --- a/packages/fps-importer/handler.ts +++ b/packages/fps-importer/handler.ts @@ -5,7 +5,6 @@ import fs from 'fs-extra'; import AdmZip from 'adm-zip'; import xml2js from 'xml2js'; import { LocalProblemConfig } from 'hydrooj'; -import { convertHTML } from '@hydrooj/html2md'; import { Route, Handler, param, Types, } from 'hydrooj/dist/service/server'; @@ -26,19 +25,19 @@ class FpsProblemImportHandler extends Handler { if (p.description) { content.push( this.translate('problem.import.problem_description'), - p.description.map(convertHTML).join('\n'), + p.description.join('\n'), ); } if (p.input) { content.push( this.translate('problem.import.input_format'), - p.input.map(convertHTML).join('\n'), + p.input.join('\n'), ); } if (p.output) { content.push( this.translate('problem.import.output_format'), - p.output.map(convertHTML).join('\n'), + p.output.join('\n'), ); } if (p.sample_input) { @@ -58,7 +57,7 @@ class FpsProblemImportHandler extends Handler { if (p.hint) { content.push( this.translate('problem.import.hint'), - p.hint.map(convertHTML).join('\n'), + p.hint.join('\n'), ); } const config: LocalProblemConfig = { @@ -79,6 +78,7 @@ class FpsProblemImportHandler extends Handler { }); }); await problem.setTestdata(domainId, pid, file); + await problem.edit(domainId, pid, { html: true }); await fs.unlink(file); } this.response.body = { count: result.fps.item.length }; diff --git a/packages/fps-importer/package.json b/packages/fps-importer/package.json index 469253930..9aa0753e7 100644 --- a/packages/fps-importer/package.json +++ b/packages/fps-importer/package.json @@ -1,13 +1,12 @@ { "name": "@hydrooj/fps-importer", - "version": "1.0.2", + "version": "1.0.3", "description": "Import FPS problems", "main": "package.json", "repository": "https://github.com/hydro-dev/Hydro.git", "author": "undefined ", "license": "AGPL-3.0-only", "dependencies": { - "@hydrooj/html2md": "^1.0.0", "adm-zip": "^0.4.16", "fs-extra": "^9.0.1", "hydrooj": "^2.12.22", diff --git a/packages/html2md/lib.ts b/packages/html2md/lib.ts index ed0c82e00..5d8e6807c 100644 --- a/packages/html2md/lib.ts +++ b/packages/html2md/lib.ts @@ -2,14 +2,20 @@ import 'hydrooj'; import TurndownService from 'turndown'; import { JSDOM } from 'jsdom'; -const turndownService = new TurndownService(); +const turndownService = new TurndownService({ + headingStyle: 'atx', + codeBlockStyle: 'fenced', + bulletListMarker: '-', +}); export function convertHTML(html: string) { const DOM = new JSDOM(html); const eles = DOM.window.document.querySelectorAll('span.katex-mathml'); eles.forEach((ele) => { - const MathML = ele.innerHTML; - ele.parentElement.replaceWith(MathML); + const MathML = ele.innerHTML + .replace(/\\{/gmi, '{') + .replace(/\\}/gmi, '}'); + ele.parentElement.replaceWith(`$${MathML}$`); }); return turndownService.turndown(DOM.serialize()); } diff --git a/packages/html2md/package.json b/packages/html2md/package.json index be8e0f3f8..a78fecdc9 100644 --- a/packages/html2md/package.json +++ b/packages/html2md/package.json @@ -2,7 +2,8 @@ "name": "@hydrooj/html2md", "version": "1.0.0", "description": "turn html into markdown", - "main": "package.json", + "main": "lib.js", + "typings": "lib.d.ts", "repository": "https://github.com/hydro-dev/Hydro.git", "author": "undefined ", "license": "AGPL-3.0-only", @@ -19,4 +20,4 @@ "build": "tsc", "lint": "eslint . --ext ts --fix" } -} +} \ No newline at end of file diff --git a/packages/html2md/test/lib.spec.ts b/packages/html2md/test/lib.spec.ts new file mode 100644 index 000000000..59c9aa8fb --- /dev/null +++ b/packages/html2md/test/lib.spec.ts @@ -0,0 +1,44 @@ +import 'hydrooj'; +import { convertHTML } from '@hydrooj/html2md/lib'; + +describe('html2md', () => { + const Katex1 = `\ + + nn + + + + + n + + +`; + const Katex2 = `\ + + E={1,2,..,n}E=\\{1,2,..,n\\} + + + + + E + = + { + 1 + , + 2 + , + . + . + , + n + } + + +`; + + test('convertHTML', () => { + expect(convertHTML('

Test

test

')).toStrictEqual('# Test\n\ntest'); + expect(convertHTML(Katex1)).toStrictEqual('$n$'); + expect(convertHTML(Katex2)).toStrictEqual('$E={1,2,..,n}$'); + }); +}); diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 1e32f53d0..684aca2c6 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.12.23", + "version": "2.12.24", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index a00dd5f60..7763b7291 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -1,5 +1,5 @@ import { isSafeInteger, flatten } from 'lodash'; -import yaml from 'js-yaml'; +import yaml, { safeLoad } from 'js-yaml'; import { ObjectID } from 'mongodb'; import { NoProblemError, ProblemDataNotFoundError, BadRequestError, @@ -360,7 +360,7 @@ class ProblemSettingsHandler extends ProblemManageHandler { async postConfig(domainId: string, pid: string | number, cfg: string) { const pdoc = await problem.get(domainId, pid); // TODO validate - const config = yaml.safeLoad(cfg); + const config = yaml.safeLoad(cfg) as any; await problem.edit(domainId, pdoc.docId, { config }); this.back(); } diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index 3d48274ff..35661ce55 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -141,11 +141,12 @@ export interface Pdoc { hidden: boolean, config: ProblemConfig, acMsg?: string, + html?: boolean, difficulty?: number, difficultyAlgo?: number, difficultyAdmin?: number, - difficultySetting?: number, + difficultySetting?: any, } export type Pdict = NumericDictionary; diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts index 77fcbb04a..f8e2c9fa0 100644 --- a/packages/hydrooj/src/model/problem.ts +++ b/packages/hydrooj/src/model/problem.ts @@ -1,5 +1,6 @@ -import { ObjectID } from 'mongodb'; +import { ObjectID, FilterQuery } from 'mongodb'; import { Dictionary } from 'lodash'; +import { safeLoad } from 'js-yaml'; import { STATUS } from './builtin'; import * as file from './file'; import * as document from './document'; @@ -29,6 +30,7 @@ export const pdocHidden: Pdoc = { owner: 1, title: '*', content: '', + html: false, nSubmit: 0, nAccept: 0, difficulty: 0, @@ -75,11 +77,11 @@ export function getMulti(domainId: string, query: object) { return document.getMulti(domainId, document.TYPE_PROBLEM, query); } -export function getMultiStatus(domainId: string, query: object) { +export function getMultiStatus(domainId: string, query: FilterQuery) { return document.getMultiStatus(domainId, document.TYPE_PROBLEM, query); } -export function edit(domainId: string, _id: number, $set: any): Promise { +export function edit(domainId: string, _id: number, $set: Partial): Promise { return document.set(domainId, document.TYPE_PROBLEM, _id, $set); } @@ -158,7 +160,7 @@ export async function setTestdata(domainId: string, _id: number, filePath: strin const config = await testdataConfig.readConfig(filePath); const id = await file.add(filePath, 'data.zip', 1); if (pdoc.data instanceof ObjectID) file.del(pdoc.data); - return await edit(domainId, _id, { data: id, config }); + return await edit(domainId, _id, { data: id, config: safeLoad(config) as any }); } global.Hydro.model.problem = {