core: drop array-style problem content (#882)

This commit is contained in:
undefined authored and GitHub committed 2024-10-06 23:12:16 +08:00
1 parent 23dfcbeeae
commit 6ae902d3ca
9 files changed
+120 -180

No files matched your search

+1 -20
View File
@@ -221,26 +221,7 @@ export interface ProblemConfig {
hackable?: boolean;
}
export interface PlainContentNode {
type: 'Plain',
subType: 'html' | 'markdown',
text: string,
}
export interface TextContentNode {
type: 'Text',
subType: 'html' | 'markdown',
sectionTitle: string,
text: string,
}
export interface SampleContentNode {
type: 'Sample',
text: string,
sectionTitle: string,
payload: [string, string],
}
// TODO drop contentNode support
export type ContentNode = PlainContentNode | TextContentNode | SampleContentNode;
export type Content = string | ContentNode[] | Record<string, ContentNode[]>;
export type Content = string | Record<string, string>;
export interface Document {
_id: ObjectId;
+6 -3
View File
@@ -1,17 +1,18 @@
import { ContentNode } from '../interface';
export interface ProblemSource {
description?: string,
input?: string,
output?: string,
samples?: [string, string][],
samplesRaw?: string,
hint?: string,
source?: string,
}
export function buildContent(source: ProblemSource | ContentNode[], type: 'markdown' | 'html' = 'markdown', translate?: Function) {
export function buildContent(source: ProblemSource, type: 'markdown' | 'html' = 'markdown', translate?: Function) {
const _ = translate || ((s: string) => s);
let cnt = 0;
// Keep it for backward compatibility, but don't add to typings
// required by upgrade 90_91
if (source instanceof Array) {
return type === 'html'
? source.map((node) => [
@@ -54,6 +55,7 @@ export function buildContent(source: ProblemSource | ContentNode[], type: 'markd
sample[1],
'</code></pre>',
].join('')),
...source.samplesRaw ? [source.samplesRaw] : [],
...source.hint ? [`<h2>${_('Hint')}</h2>`, source.hint] : [],
...source.source ? [`<h2>${_('Source')}</h2>`, source.source] : [],
].join('\n')
@@ -69,6 +71,7 @@ export function buildContent(source: ProblemSource | ContentNode[], type: 'markd
sample[1],
'```',
].join('\n')),
...source.samplesRaw ? [source.samplesRaw] : [],
...source.hint ? [`## ${_('Hint')}`, source.hint] : [],
...source.source ? [`## ${_('Source')}`, source.source] : [],
].join('\n');
+3 -8
View File
@@ -45,12 +45,7 @@ function findOverrideContent(dir: string, base: string) {
if (!files.length) return null;
for (const file of files) {
const lang = file.slice(8, -3);
let content: string | any[] = fs.readFileSync(path.join(dir, file), 'utf8');
try {
content = JSON.parse(content);
if (!(content instanceof Array)) content = JSON.stringify(content);
} catch (e) { }
languages[lang] = content;
languages[lang] = fs.readFileSync(path.join(dir, file), 'utf8');
}
return JSON.stringify(languages);
}
@@ -548,12 +543,12 @@ export class ProblemModel {
const docId = overridePid
? (await ProblemModel.edit(domainId, overridePid, {
title: pdoc.title.trim(),
content: overrideContent || pdoc.content || 'No content',
content: overrideContent || pdoc.content.toString() || 'No content',
tag,
difficulty: pdoc.difficulty,
})).docId
: await ProblemModel.add(
domainId, pid, pdoc.title.trim(), overrideContent || pdoc.content || 'No content',
domainId, pid, pdoc.title.trim(), overrideContent || pdoc.content.toString() || 'No content',
operator || pdoc.owner, tag, { hidden: pdoc.hidden, difficulty: pdoc.difficulty },
);
// TODO delete unused file when updating pdoc
+36 -19
View File
@@ -1,3 +1,4 @@
/* eslint-disable consistent-return */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-await-in-loop */
/* eslint-disable @typescript-eslint/naming-convention */
@@ -51,25 +52,7 @@ export const coreScripts: MigrationScript[] = [
return true;
},
// Init
...new Array(26).fill(unsupportedUpgrade),
null,
async function _28_29() {
return await iterateAllProblem(['content', 'html'], async (pdoc) => {
try {
const parsed = JSON.parse(pdoc.content);
if (parsed instanceof Array) {
await problem.edit(pdoc.domainId, pdoc.docId, { content: buildContent(parsed, pdoc.html ? 'html' : 'markdown') });
return;
}
const res = {};
for (const key in parsed) {
if (typeof parsed[key] === 'string') res[key] = parsed[key];
else res[key] = buildContent(parsed[key]);
}
await problem.edit(pdoc.domainId, pdoc.docId, { content: JSON.stringify(res) });
} catch { }
});
},
...new Array(28).fill(unsupportedUpgrade),
async function _29_30() {
return await iterateAllDomain((ddoc) => RecordModel.coll.updateMany({ domainId: ddoc._id }, { $set: { pdomain: ddoc._id } }));
},
@@ -685,4 +668,38 @@ export const coreScripts: MigrationScript[] = [
}
});
},
async function _90_91() {
await document.collStatus.updateMany({ docType: document.TYPE_PROBLEM }, { $unset: { nSubmit: '', nAccept: '' } });
const psdocs = await document.coll.find({ docType: document.TYPE_PROBLEM_SOLUTION, vote: { $ne: 0 } })
.project({ docId: 1, domainId: 1 }).toArray();
for (const psdoc of psdocs) {
const filter = { docType: document.TYPE_PROBLEM_SOLUTION, domainId: psdoc.domainId, docId: psdoc.docId };
const [upvote, downvote] = await Promise.all([
document.collStatus.countDocuments({ ...filter, vote: 1 }),
document.collStatus.countDocuments({ ...filter, vote: -1 }),
]);
if (upvote - downvote !== psdoc.vote) {
await document.set(psdoc.domainId, document.TYPE_PROBLEM_SOLUTION, psdoc.docId, { vote: upvote - downvote });
}
}
await iterateAllProblem(['domainId', 'docId', 'tag'], async (pdoc) => {
if (pdoc.tag?.some((i) => typeof i !== 'string')) {
return { tag: pdoc.tag.filter((i) => i).map((i) => i.toString()) };
}
});
return await iterateAllProblem(['domainId', 'docId', 'content', 'html'], async (pdoc) => {
try {
const parsed = JSON.parse(pdoc.content);
if (parsed instanceof Array) {
return { content: buildContent(parsed as any, pdoc.html ? 'html' : 'markdown') };
}
const res = {};
for (const key in parsed) {
if (typeof parsed[key] === 'string') res[key] = parsed[key];
else res[key] = buildContent(parsed[key]);
}
return { content: JSON.stringify(res) };
} catch { }
});
},
];