diff --git a/README.md b/README.md index 543454e3d..2a58ec9bf 100644 --- a/README.md +++ b/README.md @@ -145,8 +145,10 @@ Hydro 用户群:1085853538 - core: 移除 global.Hydro.service - core: 移除 global.Hydro.ui.template - core: 移除 global.Hydro.lib -- core: 移除 String.prototype.translate (使用 app.i18n.translate) +- core: 移除 String.prototype.translate (使用 ctx.i18n.translate) - core: 升级至 Mongo Driver 6 +- core: 移除 registerResolver, registerValue, registerUnion (使用 ctx.api.resolver/...) +- core: 移除 paginate, rank (使用 ctx.db.paginate, ctx.db.ranked) ## Hydro 4.19.0 / UI 4.57.0 diff --git a/build/prepare.js b/build/prepare.js index 51e3757ba..415292497 100644 --- a/build/prepare.js +++ b/build/prepare.js @@ -20,7 +20,7 @@ const compilerOptionsBase = { module: 'preserve', esModuleInterop: true, moduleResolution: 'bundler', - jsx: 'react', + jsx: 'react-jsx', sourceMap: false, composite: true, strictBindCallApply: true, @@ -70,6 +70,10 @@ for (const name of ['plugins', 'modules']) { } // Write an empty file to make eslint happy fs.writeFileSync(path.resolve(process.cwd(), name, 'nop.ts'), 'export default {};\n'); + fs.writeFileSync( + path.resolve(process.cwd(), name, 'vue.d.ts'), + 'declare module "*.vue" {\n const content: any;\n export default content;\n}\n', + ); } const modules = [ diff --git a/framework/eslint-config/package.json b/framework/eslint-config/package.json index f5b0ac147..e416ce386 100644 --- a/framework/eslint-config/package.json +++ b/framework/eslint-config/package.json @@ -4,7 +4,7 @@ "license": "MIT", "main": "base.mjs", "dependencies": { - "@eslint-react/eslint-plugin": "^1.38.2", + "@eslint-react/eslint-plugin": "^1.38.3", "@eslint/compat": "^1.2.7", "@eslint/eslintrc": "^3.3.1", "@stylistic/eslint-plugin": "^4.2.0", diff --git a/framework/framework/server.ts b/framework/framework/server.ts index b9df6d4b7..607381a16 100644 --- a/framework/framework/server.ts +++ b/framework/framework/server.ts @@ -336,7 +336,7 @@ export interface WebServiceConfig { enableSSE?: boolean; } -export class WebService extends Service { +export class WebService extends Service { private registry: Record = Object.create(null); private registrationCount = Counter(); private serverLayers = []; diff --git a/packages/blog/index.ts b/packages/blog/index.ts index f58e3db75..d03afca76 100644 --- a/packages/blog/index.ts +++ b/packages/blog/index.ts @@ -1,6 +1,6 @@ import { _, Context, DiscussionNotFoundError, DocumentModel, Filter, - Handler, NumberKeys, ObjectId, OplogModel, paginate, + Handler, NumberKeys, ObjectId, OplogModel, param, PRIV, Types, UserModel, } from 'hydrooj'; @@ -116,7 +116,7 @@ class BlogUserHandler extends BlogHandler { @param('uid', Types.Int) @param('page', Types.PositiveInt, true) async get(domainId: string, uid: number, page = 1) { - const [ddocs, dpcount] = await paginate( + const [ddocs, dpcount] = await this.ctx.db.paginate( BlogModel.getMulti({ owner: uid }), page, 10, diff --git a/packages/components/frontend/autocomplete/autocomplete.scss b/packages/components/frontend/autocomplete/autocomplete.scss index bae74b0cf..db8e6ba90 100644 --- a/packages/components/frontend/autocomplete/autocomplete.scss +++ b/packages/components/frontend/autocomplete/autocomplete.scss @@ -11,7 +11,6 @@ flex-wrap: wrap; overflow-y: auto; - @include form-styles(); background-color: $input-background-color; outline: $input-outline; transition: outline-color .2s, border-color .2s; diff --git a/packages/components/frontend/types.d.ts b/packages/components/frontend/types.d.ts new file mode 100644 index 000000000..325b3b0b9 --- /dev/null +++ b/packages/components/frontend/types.d.ts @@ -0,0 +1,21 @@ +declare module '*.svg?react' { + import { ComponentType } from 'react'; + const content: ComponentType; + export default content; +} +declare module '*.vue' { + const content: any; + export default content; +} +declare module '*.css' { + const content: string; + export default content; +} +declare module '*.styl' { + const content: string; + export default content; +} +declare module '*.scss' { + const content: string; + export default content; +} diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index 959abb0c5..cbfbc44f0 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -8,7 +8,7 @@ "dependencies": { "@hydrooj/common": "workspace:^", "@hydrooj/utils": "workspace:^", - "adm-zip": "0.5.14", + "adm-zip": "0.5.16", "cac": "^6.7.14", "p-queue": "^8.1.0", "schemastery": "^3.16.1", diff --git a/packages/hydrojudge/src/hosts/vj4.ts b/packages/hydrojudge/src/hosts/vj4.ts index 0a8b06133..6cd4120d3 100644 --- a/packages/hydrojudge/src/hosts/vj4.ts +++ b/packages/hydrojudge/src/hosts/vj4.ts @@ -158,7 +158,7 @@ export default class VJ4 implements Session { if (entries.length > 512) throw new FormatError('Too many files'); if (Math.sum(entries.map((i) => i.header.size)) > 256 * 1024 * 1024) throw new FormatError('File too large'); await new Promise((resolve, reject) => { - zip.extractAllToAsync(savePath, true, (e) => { + zip.extractAllToAsync(savePath, true, false, (e) => { if (e) reject(e); else resolve(null); }); @@ -183,7 +183,7 @@ export default class VJ4 implements Session { const entries = zip.getEntries(); if (entries.length > 512) throw new FormatError('Too many files'); await new Promise((resolve, reject) => { - zip.extractAllToAsync(savePath, true, (e) => { + zip.extractAllToAsync(savePath, true, false, (e) => { if (e) reject(e); else resolve(null); }); diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index b64ca8f58..fdf6a4b73 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -16,8 +16,8 @@ "@aws-sdk/lib-storage": "3.726.1", "@aws-sdk/s3-presigned-post": "3.726.1", "@aws-sdk/s3-request-presigner": "3.726.1", - "@cordisjs/core": "4.0.0-alpha.7", - "@cordisjs/logger": "1.0.0-alpha.4", + "@cordisjs/core": "4.0.0-alpha.8", + "@cordisjs/logger": "1.0.0-alpha.5", "@cordisjs/plugin-timer": "1.0.0-alpha.0", "@graphql-tools/schema": "^10.0.23", "@hydrooj/common": "workspace:^", @@ -26,7 +26,7 @@ "@simplewebauthn/server": "13.1.1", "@undefined-moe/require-resolve-hook": "^1.1.0", "@yarnpkg/libzip": "^3.1.1", - "adm-zip": "0.5.14", + "adm-zip": "0.5.16", "cac": "^6.7.14", "csv-stringify": "^6.5.2", "emoji-regex": "^10.4.0", @@ -39,7 +39,7 @@ "koa-static-cache": "^5.1.4", "lodash": "^4.17.21", "lru-cache": "^10.4.3", - "mime-types": "^2.1.35", + "mime-types": "^3.0.1", "moment-timezone": "^0.5.48", "mongodb": "^6.15.0", "mongodb-uri": "^0.9.7", diff --git a/packages/hydrooj/src/context.ts b/packages/hydrooj/src/context.ts index 0bc23c27b..f722ca580 100644 --- a/packages/hydrooj/src/context.ts +++ b/packages/hydrooj/src/context.ts @@ -39,7 +39,7 @@ export interface Context extends cordis.Context { geoip?: GeoIP; } -export abstract class Service extends cordis.Service { +export abstract class Service extends cordis.Service { } const T = any>(origFunc: F, disposeFunc?) => @@ -50,7 +50,7 @@ const T = any>(origFunc: F, disposeFunc?) => }); }; -export class ApiMixin extends cordis.Service { +export class ApiMixin extends cordis.Service { addScript = T(addScript); setImmediate = T(setImmediate, clearImmediate); provideModule = T(provideModule); diff --git a/packages/hydrooj/src/handler/judge.ts b/packages/hydrooj/src/handler/judge.ts index f5141df6b..f8d76c2b4 100644 --- a/packages/hydrooj/src/handler/judge.ts +++ b/packages/hydrooj/src/handler/judge.ts @@ -8,7 +8,7 @@ import sanitize from 'sanitize-filename'; import { JudgeResultBody, ProblemConfigFile, TestCase } from '@hydrooj/common'; import { Context } from '../context'; import { - FileLimitExceededError, ForbiddenError, ProblemIsReferencedError, ValidationError, + BadRequestError, FileLimitExceededError, ForbiddenError, ProblemIsReferencedError, ValidationError, } from '../error'; import { RecordDoc, Task } from '../interface'; import { Logger } from '../logger'; @@ -102,40 +102,6 @@ export async function postJudge(rdoc: RecordDoc) { await bus.parallel('record/judge', rdoc, updated, pdoc); } -bus.on('record/judge', async (rdoc, updated, pdoc) => { - if (!pdoc || rdoc.status !== STATUS.STATUS_HACK_SUCCESSFUL) return; - if (rdoc.contest) return; - try { - const config = yaml.load(pdoc.config as string) as ProblemConfigFile; - assert(config.subtasks instanceof Array); - const file = await storage.get(`submission/${rdoc.files.hack.split('#')[0]}`); - assert(file); - const hackSubtask = config.subtasks[config.subtasks.length - 1]; - hackSubtask.cases ||= []; - const input = `hack-${rdoc._id}-${hackSubtask.cases.length + 1}.in`; - hackSubtask.cases.push({ input, output: '/dev/null' }); - await Promise.all([ - problem.addTestdata(rdoc.domainId, rdoc.pid, input, file), - problem.addTestdata(rdoc.domainId, rdoc.pid, 'config.yaml', Buffer.from(yaml.dump(config))), - ]); - // trigger rejudge - const rdocs = await record.getMulti(rdoc.domainId, { - pid: rdoc.pid, - status: STATUS.STATUS_ACCEPTED, - contest: { $nin: [record.RECORD_GENERATE, record.RECORD_PRETEST] }, - }).project({ _id: 1, contest: 1 }).toArray(); - const priority = await record.submissionPriority(rdoc.uid, -5000 - rdocs.length * 5 - 50); - await record.judge(rdoc.domainId, rdocs.map((r) => r._id), priority, {}, { hackRejudge: input }); - } catch (e) { - next({ - rid: rdoc._id.toString(), - domainId: rdoc.domainId, - key: 'next', - message: { message: 'Unable to apply hack: {0}', params: [e.message] }, - }); - } -}); - export async function end(body: Partial) { const { $set, $push } = processPayload(body); const $unset: any = { progress: '' }; @@ -219,7 +185,6 @@ export class JudgeConnectionHandler extends ConnectionHandler { query: any = { type: { $in: ['judge', 'generate'] } }; concurrency = 1; consumer: Consumer = null; - startTimeout: NodeJS.Timeout = null; tasks: Record void, queue: PQueue, @@ -230,10 +195,6 @@ export class JudgeConnectionHandler extends ConnectionHandler { async prepare() { logger.info('Judge daemon connected from ', this.request.ip); this.sendLanguageConfig(); - // TODO deprecated, just for compatibility - this.startTimeout = setTimeout(() => { - this.consumer ||= task.consume(this.query, this.newTask.bind(this), true, this.concurrency); - }, 15000); } @subscribe('system/setting') @@ -274,10 +235,6 @@ export class JudgeConnectionHandler extends ConnectionHandler { } } else if (msg.key === 'status') { await updateJudge(msg.info); - } else if (msg.key === 'prio' && typeof msg.prio === 'number') { - // TODO deprecated, use config instead - this.query.priority = { $gt: msg.prio }; - this.consumer?.setQuery(this.query); } else if (msg.key === 'config') { if (Number.isSafeInteger(msg.prio)) { this.query.priority = { $gt: msg.prio }; @@ -296,14 +253,13 @@ export class JudgeConnectionHandler extends ConnectionHandler { this.consumer?.setQuery(this.query); } } else if (msg.key === 'start') { - clearTimeout(this.startTimeout); - this.consumer ||= task.consume(this.query, this.newTask.bind(this), true, this.concurrency); + if (this.consumer) throw new BadRequestError('Judge daemon already started'); + this.consumer = task.consume(this.query, this.newTask.bind(this), true, this.concurrency); logger.info('Judge daemon started'); } } async cleanup() { - clearTimeout(this.startTimeout); this.consumer?.destroy(); logger.info('Judge daemon disconnected from ', this.request.ip); await Promise.all(Object.values(this.tasks).map(async ({ t }) => { @@ -318,6 +274,39 @@ export async function apply(ctx: Context) { ctx.Route('judge_files_download', '/judge/files', JudgeFilesDownloadHandler, builtin.PRIV.PRIV_JUDGE); ctx.Route('judge_files_upload', '/judge/upload', JudgeFileUpdateHandler, builtin.PRIV.PRIV_JUDGE); ctx.Connection('judge_conn', '/judge/conn', JudgeConnectionHandler, builtin.PRIV.PRIV_JUDGE); + ctx.on('record/judge', async (rdoc, updated, pdoc) => { + if (!pdoc || rdoc.status !== STATUS.STATUS_HACK_SUCCESSFUL) return; + if (rdoc.contest) return; + try { + const config = yaml.load(pdoc.config as string) as ProblemConfigFile; + assert(Array.isArray(config.subtasks)); + const file = await storage.get(`submission/${rdoc.files.hack.split('#')[0]}`); + assert(file); + const hackSubtask = config.subtasks[config.subtasks.length - 1]; + hackSubtask.cases ||= []; + const input = `hack-${rdoc._id}-${hackSubtask.cases.length + 1}.in`; + hackSubtask.cases.push({ input, output: '/dev/null' }); + await Promise.all([ + problem.addTestdata(rdoc.domainId, rdoc.pid, input, file), + problem.addTestdata(rdoc.domainId, rdoc.pid, 'config.yaml', Buffer.from(yaml.dump(config))), + ]); + // trigger rejudge + const rdocs = await record.getMulti(rdoc.domainId, { + pid: rdoc.pid, + status: STATUS.STATUS_ACCEPTED, + contest: { $nin: [record.RECORD_GENERATE, record.RECORD_PRETEST] }, + }).project({ _id: 1, contest: 1 }).toArray(); + const priority = await record.submissionPriority(rdoc.uid, -5000 - rdocs.length * 5 - 50); + await record.judge(rdoc.domainId, rdocs.map((r) => r._id), priority, {}, { hackRejudge: input }); + } catch (e) { + next({ + rid: rdoc._id.toString(), + domainId: rdoc.domainId, + key: 'next', + message: { message: 'Unable to apply hack: {0}', params: [e.message] }, + }); + } + }); } apply.next = next; diff --git a/packages/hydrooj/src/lib/ui.ts b/packages/hydrooj/src/lib/ui.ts index 145e95692..741822ce3 100644 --- a/packages/hydrooj/src/lib/ui.ts +++ b/packages/hydrooj/src/lib/ui.ts @@ -42,14 +42,6 @@ export function inject(node: UIInjectableFields, name: string, args: Record { - inject('Nav', name, { ...args, prefix }, ...permPrivChecker); -}; -/** @deprecated */ -export const ProblemAdd = (name, args, icon = 'add', text = 'Create Problem') => { - inject('ProblemAdd', name, { ...args, icon, text }); -}; inject('Nav', 'homepage', { prefix: 'homepage' }); inject('Nav', 'problem_main', { prefix: 'problem' }, PERM.PERM_VIEW_PROBLEM); @@ -84,4 +76,3 @@ inject('DomainManage', 'domain_group', { family: 'Access Control', icon: 'user' global.Hydro.ui.inject = inject; global.Hydro.ui.nodes = nodes as any; global.Hydro.ui.getNodes = getNodes; -Object.assign(global.Hydro.ui, { ProblemAdd, Nav }); diff --git a/packages/hydrooj/src/model/discussion.ts b/packages/hydrooj/src/model/discussion.ts index f62e10b06..32156e83e 100644 --- a/packages/hydrooj/src/model/discussion.ts +++ b/packages/hydrooj/src/model/discussion.ts @@ -37,7 +37,6 @@ export const typeDisplay = { [document.TYPE_CONTEST]: 'contest', [document.TYPE_DISCUSSION_NODE]: 'node', [document.TYPE_TRAINING]: 'training', - [document.TYPE_HOMEWORK]: 'homework', }; export const coll = db.collection('discussion.history'); diff --git a/packages/hydrooj/src/model/document.ts b/packages/hydrooj/src/model/document.ts index 850930daa..d076b0a26 100644 --- a/packages/hydrooj/src/model/document.ts +++ b/packages/hydrooj/src/model/document.ts @@ -29,8 +29,6 @@ export const TYPE_DISCUSSION_REPLY = 22 as const; export const TYPE_CONTEST = 30 as const; export const TYPE_CONTEST_CLARIFICATION = 31 as const; export const TYPE_TRAINING = 40 as const; -/** @deprecated use `TYPE_CONTEST` with rule `homework` instead. */ -export const TYPE_HOMEWORK = 60 as const; export interface DocType { [TYPE_PROBLEM]: ProblemDoc; @@ -486,7 +484,6 @@ global.Hydro.model.document = { TYPE_DISCUSSION, TYPE_DISCUSSION_NODE, TYPE_DISCUSSION_REPLY, - TYPE_HOMEWORK, TYPE_PROBLEM, TYPE_PROBLEM_LIST, TYPE_PROBLEM_SOLUTION, diff --git a/packages/hydrooj/src/plugin-api.ts b/packages/hydrooj/src/plugin-api.ts index 775d3ed51..b75c70c3b 100644 --- a/packages/hydrooj/src/plugin-api.ts +++ b/packages/hydrooj/src/plugin-api.ts @@ -34,7 +34,6 @@ export { default as StorageModel } from './model/storage'; export { default as TaskModel } from './model/task'; export * from './model/builtin'; export * as JudgeHandler from './handler/judge'; -export { registerResolver, registerValue, registerUnion } from './service/api'; export { postJudge } from './handler/judge'; export { Collections } from './service/db'; export { Handler, ConnectionHandler, requireSudo } from './service/server'; @@ -46,10 +45,6 @@ export { default as rating } from './lib/rating'; export { default as avatar } from './lib/avatar'; export { parseConfig as testdataConfig } from './lib/testdataConfig'; export { sendMail } from './lib/mail'; -/** @deprecated use Handler.paginate instead */ -export const paginate = db.paginate.bind(db); -/** @deprecated use db.ranked instead */ -export const rank = db.ranked.bind(db); export { UiContextBase } from './service/layers/base'; export * from '@hydrooj/framework/decorators'; export * from '@hydrooj/framework/validator'; @@ -57,5 +52,6 @@ export * as StorageService from './service/storage'; export { EventMap } from './service/bus'; export { db, pwsh }; -// to load ctx.scoreboard +// to load services into to context export { } from './handler/contest'; +export { } from './service/api'; diff --git a/packages/hydrooj/src/service/api.ts b/packages/hydrooj/src/service/api.ts index bf4c655f5..e8c34d512 100644 --- a/packages/hydrooj/src/service/api.ts +++ b/packages/hydrooj/src/service/api.ts @@ -99,24 +99,6 @@ class ApiHandler extends Handler { } } -/** @deprecated use ctx.api.value() instead */ -export function registerValue(...args: any[]) { - // @ts-ignore - return app.api.value(...args); -} - -/** @deprecated use ctx.api.resolver() instead */ -export function registerResolver(...args: any[]) { - // @ts-ignore - return app.api.resolver(...args); -} - -/** @deprecated use ctx.api.union() instead */ -export function registerUnion(...args: any[]) { - // @ts-ignore - return app.api.resolver(...args); -} - // TODO support dispose class ApiService extends Service { constructor(ctx: Context) { @@ -212,7 +194,7 @@ class ApiService extends Service { } export const sideEffect = true; -export const using = ['server']; +export const inject = ['server']; export function apply(ctx: Context) { ctx.plugin(ApiService); diff --git a/packages/hydrooj/src/upgrade.ts b/packages/hydrooj/src/upgrade.ts index 5be8b0fed..5466b5b22 100644 --- a/packages/hydrooj/src/upgrade.ts +++ b/packages/hydrooj/src/upgrade.ts @@ -32,8 +32,8 @@ import welcome from './welcome'; const logger = new Logger('upgrade'); const unsupportedUpgrade = async function _26_27() { - throw new Error('This upgrade was no longer supported in hydrooj@4. \ -Please use hydrooj@3 to perform these upgrades before upgrading to v4'); + throw new Error('This upgrade was no longer supported in hydrooj@5. \ +Please use hydrooj@4 to perform these upgrades before upgrading to v5'); }; const onPrimary = { readPreference: 'primary' } as const; @@ -53,141 +53,7 @@ export const coreScripts: MigrationScript[] = [ return true; }, // Init - ...new Array(28).fill(unsupportedUpgrade), // oxlint-disable-line no-new-array - async function _29_30() { - return await iterateAllDomain((ddoc) => RecordModel.coll.updateMany({ domainId: ddoc._id }, { $set: { pdomain: ddoc._id } })); - }, - // Add send_message priv to user - async function _30_31() { - return await iterateAllUser((udoc) => user.setPriv(udoc._id, udoc.priv | PRIV.PRIV_SEND_MESSAGE)); - }, - null, - // Write builtin users to database - async function _32_33() { - if (!await user.getById('system', 0)) { - await user.create('Guest@hydro.local', 'Guest', String.random(32), 0, '127.0.0.1', PRIV.PRIV_REGISTER_USER); - } - if (!await user.getById('system', 1)) { - await user.create('Hydro@hydro.local', 'Hydro', String.random(32), 1, '127.0.0.1', PRIV.PRIV_USER_PROFILE); - } - return true; - }, - async function _33_34() { - return await iterateAllProblem(['content'], async (pdoc) => { - if (typeof pdoc.content !== 'string') return; - await problem.edit(pdoc.domainId, pdoc.docId, { content: pdoc.content.replace(/%file%:\/\//g, 'file://') }); - }); - }, - async function _34_35() { - return await iterateAllDomain((ddoc) => domain.edit(ddoc._id, { lower: ddoc._id.toLowerCase() })); - }, - async function _35_36() { - await RecordModel.coll.updateMany({}, { $unset: { effective: '' } }); - return true; - }, - async function _36_37() { - for await (const doc of document.collStatus.find()) { - await document.collStatus.deleteMany({ - ...pick(doc, ['docId', 'domainId', 'uid', 'docType']), - _id: { $gt: doc._id }, - }); - } - return true; - }, - async function _37_38() { - return await iterateAllProblem(['docId', 'domainId', 'config'], async (pdoc) => { - logger.info('%s/%s', pdoc.domainId, pdoc.docId); - if (typeof pdoc.config !== 'string') return; - if (!pdoc.config.includes('type: subjective')) return; - await problem.addTestdata( - pdoc.domainId, pdoc.docId, 'config.yaml', - Buffer.from(pdoc.config.replace('type: subjective', 'type: objective')), - ); - }); - }, - async function _38_39() { - return await iterateAllDomain(async (ddoc) => { - ddoc.roles.root = '-1'; - await domain.setRoles(ddoc._id, ddoc.roles); - }); - }, - async function _39_40() { - return await iterateAllDomain(async ({ _id }) => { - const ddocs = await discussion.getMulti(_id, { parentType: document.TYPE_PROBLEM }).toArray(); - for (const ddoc of ddocs) { - const pdoc = await problem.get(_id, ddoc.parentId as any); - await document.set(_id, document.TYPE_DISCUSSION, ddoc.docId, { parentId: pdoc.docId }); - } - }); - }, - async function _40_41() { - // Ignore drop index failure - await db.collection('storage').dropIndex('path_1').catch(() => { }); - await db.collection('storage').updateMany( - { autoDelete: { $gte: moment().add(5, 'days').toDate() } }, - { $unset: { autoDelete: '' } }, - ); - return true; - }, - async function _41_42() { - return await iterateAllDomain(async (ddoc) => { - const cursor = discussion.getMulti(ddoc._id, { parentType: document.TYPE_CONTEST }); - while (await cursor.hasNext()) { - const doc = await cursor.next(); - const tdoc = await document.coll.findOne({ docType: doc.parentType, docId: doc.parentId }); - if (!tdoc) await discussion.del(ddoc._id, doc.docId); - } - }); - }, - null, - async function _43_44() { - const processer = (i) => { - i.status = i.accept ? STATUS.STATUS_ACCEPTED : STATUS.STATUS_WRONG_ANSWER; - return i; - }; - return await iterateAllDomain(async (ddoc) => { - const tdocs = await contest.getMulti(ddoc._id, { rule: { $ne: 'acm' } }).toArray(); - for (const tdoc of tdocs) { - const tsdocs = await contest.getMultiStatus(ddoc._id, { docId: tdoc.docId }).toArray(); - for (const tsdoc of tsdocs) { - const $set: any = {}; - if (tsdoc.journal?.length) $set.journal = tsdoc.journal.map(processer); - if (tsdoc.detail?.length) $set.detail = tsdoc.detail.map(processer); - if (Object.keys($set).length) { - await contest.setStatus(ddoc._id, tdoc.docId, tsdoc.uid, $set); - } - } - } - }); - }, - async function _44_45() { - return await iterateAllUser((udoc) => user.setById(udoc._id, { ip: [udoc.regip] }, { regip: '' })); - }, - async function _45_46() { - return await iterateAllDomain(async (ddoc) => { - const ddocs = await discussion.getMulti(ddoc._id, { - docType: document.TYPE_DISCUSSION, - parentType: { $in: [document.TYPE_CONTEST, 60, document.TYPE_TRAINING] }, - parentId: { $type: 'string' }, - }).toArray(); - for (const doc of ddocs) { - if (ObjectId.isValid(doc.parentId)) { - await document.set(ddoc._id, document.TYPE_DISCUSSION, doc.docId, { parentId: new ObjectId(doc.parentId) }); - } - } - }); - }, - null, - async function _47_48() { - await document.coll.updateMany({ docType: document.TYPE_HOMEWORK }, { $set: { docType: document.TYPE_CONTEST } }); - await document.collStatus.updateMany({ docType: document.TYPE_HOMEWORK }, { $set: { docType: document.TYPE_CONTEST } }); - await RecordModel.coll.deleteMany({ 'contest.tid': { $ne: null }, hidden: true }); - await RecordModel.coll.updateMany({}, { $unset: { hidden: '' } }); - await RecordModel.coll.updateMany({ 'contest.tid': { $exists: true } }, { $rename: { 'contest.tid': 'contest1' } }); - await RecordModel.coll.updateMany({ contest1: { $exists: true } }, { $rename: { contest1: 'contest' } }); - await RecordModel.coll.updateMany({ contest: null }, { $unset: { contest: '' } }); - return true; - }, + ...new Array(47).fill(unsupportedUpgrade), // oxlint-disable-line no-new-array async function _48_49() { await RecordModel.coll.updateMany({ input: { $exists: true } }, { $set: { contest: new ObjectId('000000000000000000000000') } }); return true; diff --git a/packages/import-hoj/index.ts b/packages/import-hoj/index.ts index 405ab9844..f6bd8d010 100644 --- a/packages/import-hoj/index.ts +++ b/packages/import-hoj/index.ts @@ -19,7 +19,7 @@ class ImportHojHandler extends Handler { } const tmp = path.resolve(tmpdir, String.random(32)); await new Promise((resolve, reject) => { - zip.extractAllToAsync(tmp, true, (err) => (err ? reject(err) : resolve(null))); + zip.extractAllToAsync(tmp, true, false, (err) => (err ? reject(err) : resolve(null))); }); let cnt = 0; try { diff --git a/packages/import-qduoj/index.ts b/packages/import-qduoj/index.ts index c4179aef8..ff6036213 100644 --- a/packages/import-qduoj/index.ts +++ b/packages/import-qduoj/index.ts @@ -52,7 +52,7 @@ class ImportQduojHandler extends Handler { } const tmp = path.resolve(tmpdir, String.random(32)); await new Promise((resolve, reject) => { - zip.extractAllToAsync(tmp, true, (err) => (err ? reject(err) : resolve(null))); + zip.extractAllToAsync(tmp, true, false, (err) => (err ? reject(err) : resolve(null))); }); let cnt = 0; try { diff --git a/packages/ui-default/components/autocomplete/CustomSelectAutoComplete.tsx b/packages/ui-default/components/autocomplete/CustomSelectAutoComplete.tsx index 807773e75..a51275796 100644 --- a/packages/ui-default/components/autocomplete/CustomSelectAutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/CustomSelectAutoComplete.tsx @@ -1,6 +1,5 @@ import { CustomSelectAutoComplete as CustomSelectAutoCompleteFC } from '@hydrooj/components'; import React from 'react'; -import ReactDOM from 'react-dom/client'; import AutoComplete, { AutoCompleteOptions } from '.'; interface CustomSelectOptions { diff --git a/packages/ui-default/components/autocomplete/DomainSelectAutoComplete.tsx b/packages/ui-default/components/autocomplete/DomainSelectAutoComplete.tsx index 8a3e20331..14b5bcde8 100644 --- a/packages/ui-default/components/autocomplete/DomainSelectAutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/DomainSelectAutoComplete.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import ReactDOM from 'react-dom/client'; import AutoComplete from '.'; import DomainSelectAutoCompleteFC from './components/DomainSelectAutoComplete'; diff --git a/packages/ui-default/components/autocomplete/FileSelectAutoComplete.tsx b/packages/ui-default/components/autocomplete/FileSelectAutoComplete.tsx index bc017313a..2bec61478 100644 --- a/packages/ui-default/components/autocomplete/FileSelectAutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/FileSelectAutoComplete.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import ReactDOM from 'react-dom/client'; import AutoComplete, { AutoCompleteOptions } from '.'; import FileSelectAutoCompleteFC from './components/FileSelectAutoComplete'; diff --git a/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.tsx b/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.tsx index 279c30f69..bc5e88fe3 100644 --- a/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import ReactDOM from 'react-dom/client'; import AutoComplete from '.'; import ProblemSelectAutoCompleteFC from './components/ProblemSelectAutoComplete'; diff --git a/packages/ui-default/components/autocomplete/UserSelectAutoComplete.tsx b/packages/ui-default/components/autocomplete/UserSelectAutoComplete.tsx index 71d697fcf..f6c444c9a 100644 --- a/packages/ui-default/components/autocomplete/UserSelectAutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/UserSelectAutoComplete.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import ReactDOM from 'react-dom/client'; import AutoComplete, { AutoCompleteOptions } from '.'; import UserSelectAutoCompleteFC from './components/UserSelectAutoComplete'; diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 5a378c2ef..b666bfb5e 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -12,7 +12,7 @@ }, "devDependencies": { "@blueprintjs/core": "^5.17.6", - "@cordisjs/core": "4.0.0-alpha.7", + "@cordisjs/core": "4.0.0-alpha.8", "@fontsource/dm-mono": "^5.2.5", "@fontsource/fira-code": "^5.2.5", "@fontsource/inconsolata": "^5.2.5", @@ -23,7 +23,7 @@ "@fontsource/ubuntu-mono": "^5.2.5", "@hydrooj/utils": "workspace:^", "@sentry/browser": "^9.10.0", - "@sentry/webpack-plugin": "^3.2.3", + "@sentry/webpack-plugin": "^3.2.4", "@simplewebauthn/browser": "13.1.0", "@svgr/webpack": "^8.1.0", "@types/html-to-text": "^9.0.4", @@ -35,7 +35,7 @@ "@types/nunjucks": "^3.2.6", "@types/pickadate": "^3.5.35", "@types/qrcode": "^1.5.5", - "@types/react": "^18.3.19", + "@types/react": "^18.3.20", "@types/react-dom": "^18.3.5", "@types/redux-logger": "^3.0.13", "@types/uuid": "^10.0.0", @@ -52,7 +52,7 @@ "copy-webpack-plugin": "^13.0.0", "core-js": "^3.41.0", "core-js-compat": "^3.41.0", - "css-loader": "^6.11.0", + "css-loader": "^7.1.2", "diff": "^7.0.0", "diff-dom": "^5.1.4", "echarts": "^5.6.0",