添加html支持

This commit is contained in:
undefined committed 2020-09-02 13:32:47 +08:00
1 parent 0b0c34b0c6
commit 3f2d98534f
9 files changed
+72 -19

No files matched your search

+5 -5
View File
@@ -5,7 +5,6 @@ import fs from 'fs-extra';
import AdmZip from 'adm-zip'; import AdmZip from 'adm-zip';
import xml2js from 'xml2js'; import xml2js from 'xml2js';
import { LocalProblemConfig } from 'hydrooj'; import { LocalProblemConfig } from 'hydrooj';
import { convertHTML } from '@hydrooj/html2md';
import { import {
Route, Handler, param, Types, Route, Handler, param, Types,
} from 'hydrooj/dist/service/server'; } from 'hydrooj/dist/service/server';
@@ -26,19 +25,19 @@ class FpsProblemImportHandler extends Handler {
if (p.description) { if (p.description) {
content.push( content.push(
this.translate('problem.import.problem_description'), this.translate('problem.import.problem_description'),
p.description.map(convertHTML).join('\n'), p.description.join('\n'),
); );
} }
if (p.input) { if (p.input) {
content.push( content.push(
this.translate('problem.import.input_format'), this.translate('problem.import.input_format'),
p.input.map(convertHTML).join('\n'), p.input.join('\n'),
); );
} }
if (p.output) { if (p.output) {
content.push( content.push(
this.translate('problem.import.output_format'), this.translate('problem.import.output_format'),
p.output.map(convertHTML).join('\n'), p.output.join('\n'),
); );
} }
if (p.sample_input) { if (p.sample_input) {
@@ -58,7 +57,7 @@ class FpsProblemImportHandler extends Handler {
if (p.hint) { if (p.hint) {
content.push( content.push(
this.translate('problem.import.hint'), this.translate('problem.import.hint'),
p.hint.map(convertHTML).join('\n'), p.hint.join('\n'),
); );
} }
const config: LocalProblemConfig = { const config: LocalProblemConfig = {
@@ -79,6 +78,7 @@ class FpsProblemImportHandler extends Handler {
}); });
}); });
await problem.setTestdata(domainId, pid, file); await problem.setTestdata(domainId, pid, file);
await problem.edit(domainId, pid, { html: true });
await fs.unlink(file); await fs.unlink(file);
} }
this.response.body = { count: result.fps.item.length }; this.response.body = { count: result.fps.item.length };
+1 -2
View File
@@ -1,13 +1,12 @@
{ {
"name": "@hydrooj/fps-importer", "name": "@hydrooj/fps-importer",
"version": "1.0.2", "version": "1.0.3",
"description": "Import FPS problems", "description": "Import FPS problems",
"main": "package.json", "main": "package.json",
"repository": "https://github.com/hydro-dev/Hydro.git", "repository": "https://github.com/hydro-dev/Hydro.git",
"author": "undefined <masnn0@outlook.com>", "author": "undefined <masnn0@outlook.com>",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"dependencies": { "dependencies": {
"@hydrooj/html2md": "^1.0.0",
"adm-zip": "^0.4.16", "adm-zip": "^0.4.16",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"hydrooj": "^2.12.22", "hydrooj": "^2.12.22",
+9 -3
View File
@@ -2,14 +2,20 @@ import 'hydrooj';
import TurndownService from 'turndown'; import TurndownService from 'turndown';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
const turndownService = new TurndownService(); const turndownService = new TurndownService({
headingStyle: 'atx',
codeBlockStyle: 'fenced',
bulletListMarker: '-',
});
export function convertHTML(html: string) { export function convertHTML(html: string) {
const DOM = new JSDOM(html); const DOM = new JSDOM(html);
const eles = DOM.window.document.querySelectorAll('span.katex-mathml'); const eles = DOM.window.document.querySelectorAll('span.katex-mathml');
eles.forEach((ele) => { eles.forEach((ele) => {
const MathML = ele.innerHTML; const MathML = ele.innerHTML
ele.parentElement.replaceWith(MathML); .replace(/\\{/gmi, '{')
.replace(/\\}/gmi, '}');
ele.parentElement.replaceWith(`$${MathML}$`);
}); });
return turndownService.turndown(DOM.serialize()); return turndownService.turndown(DOM.serialize());
} }
+2 -1
View File
@@ -2,7 +2,8 @@
"name": "@hydrooj/html2md", "name": "@hydrooj/html2md",
"version": "1.0.0", "version": "1.0.0",
"description": "turn html into markdown", "description": "turn html into markdown",
"main": "package.json", "main": "lib.js",
"typings": "lib.d.ts",
"repository": "https://github.com/hydro-dev/Hydro.git", "repository": "https://github.com/hydro-dev/Hydro.git",
"author": "undefined <masnn0@outlook.com>", "author": "undefined <masnn0@outlook.com>",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
+44
View File
@@ -0,0 +1,44 @@
import 'hydrooj';
import { convertHTML } from '@hydrooj/html2md/lib';
describe('html2md', () => {
const Katex1 = `\
<span class="katex">
<span class="katex-mathml">nn</span>
<span class="katex-html">
<span class="strut"></span>
<span class="strut bottom" style="vertical-align:0em;"></span>
<span class="base textstyle uncramped">
<span class="mord mathit">n</span>
</span>
</span>
</span>`;
const Katex2 = `\
<span class="katex">
<span class="katex-mathml">E={1,2,..,n}E=\\{1,2,..,n\\}</span>
<span class="katex-html">
<span class="strut"></span>
<span class="strut bottom" style="vertical-align:-0.25em;"></span>
<span class="base textstyle uncramped">
<span class="mord mathit">E</span>
<span class="mrel">=</span>
<span class="mopen">{</span>
<span class="mord mathrm">1</span>
<span class="mpunct">,</span>
<span class="mord mathrm">2</span>
<span class="mpunct">,</span>
<span class="mord mathrm">.</span>
<span class="mord mathrm">.</span>
<span class="mpunct">,</span>
<span class="mord mathit">n</span>
<span class="mclose">}</span>
</span>
</span>
</span>`;
test('convertHTML', () => {
expect(convertHTML('<h1>Test</h1><p>test</p>')).toStrictEqual('# Test\n\ntest');
expect(convertHTML(Katex1)).toStrictEqual('$n$');
expect(convertHTML(Katex2)).toStrictEqual('$E={1,2,..,n}$');
});
});
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.12.23", "version": "2.12.24",
"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",
+2 -2
View File
@@ -1,5 +1,5 @@
import { isSafeInteger, flatten } from 'lodash'; import { isSafeInteger, flatten } from 'lodash';
import yaml from 'js-yaml'; import yaml, { safeLoad } from 'js-yaml';
import { ObjectID } from 'mongodb'; import { ObjectID } from 'mongodb';
import { import {
NoProblemError, ProblemDataNotFoundError, BadRequestError, NoProblemError, ProblemDataNotFoundError, BadRequestError,
@@ -360,7 +360,7 @@ class ProblemSettingsHandler extends ProblemManageHandler {
async postConfig(domainId: string, pid: string | number, cfg: string) { async postConfig(domainId: string, pid: string | number, cfg: string) {
const pdoc = await problem.get(domainId, pid); const pdoc = await problem.get(domainId, pid);
// TODO validate // TODO validate
const config = yaml.safeLoad(cfg); const config = yaml.safeLoad(cfg) as any;
await problem.edit(domainId, pdoc.docId, { config }); await problem.edit(domainId, pdoc.docId, { config });
this.back(); this.back();
} }
+2 -1
View File
@@ -141,11 +141,12 @@ export interface Pdoc {
hidden: boolean, hidden: boolean,
config: ProblemConfig, config: ProblemConfig,
acMsg?: string, acMsg?: string,
html?: boolean,
difficulty?: number, difficulty?: number,
difficultyAlgo?: number, difficultyAlgo?: number,
difficultyAdmin?: number, difficultyAdmin?: number,
difficultySetting?: number, difficultySetting?: any,
} }
export type Pdict = NumericDictionary<Pdoc>; export type Pdict = NumericDictionary<Pdoc>;
+6 -4
View File
@@ -1,5 +1,6 @@
import { ObjectID } from 'mongodb'; import { ObjectID, FilterQuery } from 'mongodb';
import { Dictionary } from 'lodash'; import { Dictionary } from 'lodash';
import { safeLoad } from 'js-yaml';
import { STATUS } from './builtin'; import { STATUS } from './builtin';
import * as file from './file'; import * as file from './file';
import * as document from './document'; import * as document from './document';
@@ -29,6 +30,7 @@ export const pdocHidden: Pdoc = {
owner: 1, owner: 1,
title: '*', title: '*',
content: '', content: '',
html: false,
nSubmit: 0, nSubmit: 0,
nAccept: 0, nAccept: 0,
difficulty: 0, difficulty: 0,
@@ -75,11 +77,11 @@ export function getMulti(domainId: string, query: object) {
return document.getMulti(domainId, document.TYPE_PROBLEM, query); return document.getMulti(domainId, document.TYPE_PROBLEM, query);
} }
export function getMultiStatus(domainId: string, query: object) { export function getMultiStatus(domainId: string, query: FilterQuery<Pdoc>) {
return document.getMultiStatus(domainId, document.TYPE_PROBLEM, query); return document.getMultiStatus(domainId, document.TYPE_PROBLEM, query);
} }
export function edit(domainId: string, _id: number, $set: any): Promise<Pdoc> { export function edit(domainId: string, _id: number, $set: Partial<Pdoc>): Promise<Pdoc> {
return document.set(domainId, document.TYPE_PROBLEM, _id, $set); 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 config = await testdataConfig.readConfig(filePath);
const id = await file.add(filePath, 'data.zip', 1); const id = await file.add(filePath, 'data.zip', 1);
if (pdoc.data instanceof ObjectID) file.del(pdoc.data); 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 = { global.Hydro.model.problem = {