core&ui: remove deprecated apis

This commit is contained in:
undefined committed 2025-03-28 23:49:37 +08:00
1 parent 574d45f914
commit baa9436c30
26 files changed
+90 -249

No files matched your search

+3 -1
View File
@@ -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
+5 -1
View File
@@ -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 = [
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -336,7 +336,7 @@ export interface WebServiceConfig {
enableSSE?: boolean;
}
export class WebService<C extends CordisContext = CordisContext> extends Service<C> {
export class WebService<C extends CordisContext = CordisContext> extends Service<never, C> {
private registry: Record<string, any> = Object.create(null);
private registrationCount = Counter();
private serverLayers = [];
+2 -2
View File
@@ -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,
@@ -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;
+21
View File
@@ -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;
}
+1 -1
View File
@@ -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",
+2 -2
View File
@@ -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);
});
+4 -4
View File
@@ -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",
+2 -2
View File
@@ -39,7 +39,7 @@ export interface Context extends cordis.Context {
geoip?: GeoIP;
}
export abstract class Service extends cordis.Service<Context> {
export abstract class Service<T = never> extends cordis.Service<T, Context> {
}
const T = <F extends (...args: any[]) => any>(origFunc: F, disposeFunc?) =>
@@ -50,7 +50,7 @@ const T = <F extends (...args: any[]) => any>(origFunc: F, disposeFunc?) =>
});
};
export class ApiMixin extends cordis.Service<Context> {
export class ApiMixin extends cordis.Service<never, Context> {
addScript = T(addScript);
setImmediate = T(setImmediate, clearImmediate);
provideModule = T(provideModule);
+36 -47
View File
@@ -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<JudgeResultBody>) {
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<string, {
resolve: (_: any) => 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;
-9
View File
@@ -42,14 +42,6 @@ export function inject(node: UIInjectableFields, name: string, args: Record<stri
export function getNodes(name: UIInjectableFields) {
return nodes[name];
}
/** @deprecated */
export const Nav = (name, args, prefix, ...permPrivChecker) => {
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 });
-1
View File
@@ -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');
-3
View File
@@ -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,
+2 -6
View File
@@ -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';
+1 -19
View File
@@ -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);
+3 -137
View File
@@ -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;
+1 -1
View File
@@ -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 {
+1 -1
View File
@@ -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 {
@@ -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 {
@@ -1,5 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import AutoComplete from '.';
import DomainSelectAutoCompleteFC from './components/DomainSelectAutoComplete';
@@ -1,5 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import AutoComplete, { AutoCompleteOptions } from '.';
import FileSelectAutoCompleteFC from './components/FileSelectAutoComplete';
@@ -1,5 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import AutoComplete from '.';
import ProblemSelectAutoCompleteFC from './components/ProblemSelectAutoComplete';
@@ -1,5 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import AutoComplete, { AutoCompleteOptions } from '.';
import UserSelectAutoCompleteFC from './components/UserSelectAutoComplete';
+4 -4
View File
@@ -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",