From 5ae557a95fcaa87e318fda1c54a5c2dc6437f63b Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Dec 2024 22:36:24 +0800 Subject: [PATCH 1/5] core: ProblemSubmit: fix submit_answer problem zip answer upload (#917) Co-authored-by: undefined --- packages/hydrooj/src/handler/problem.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index e29d09b52..9c6898d6e 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -496,15 +496,13 @@ export class ProblemSubmitHandler extends ProblemDetailHandler { if (!file || file.size === 0) throw new ValidationError('code'); const sizeLimit = config.type === 'submit_answer' ? 128 * 1024 * 1024 : lengthLimit; if (file.size > sizeLimit) throw new ValidationError('file'); - const showReadFile = () => { + const shouldReadFile = () => { if (config.type === 'objective') return true; - if (lang === '_') return true; + if (lang === '_') return false; return file.size < lengthLimit && !file.filepath.endsWith('.zip') && !setting.langs[lang].isBinary; }; - if (showReadFile()) { - // TODO submission file shape - code = await readFile(file.filepath, 'utf-8'); - } else { + if (shouldReadFile()) code = await readFile(file.filepath, 'utf-8'); + else { const id = nanoid(); await storage.put(`submission/${this.user._id}/${id}`, file.filepath, this.user._id); files.code = `${this.user._id}/${id}#${file.originalFilename}`; From 4879e9ccae04bb1a1fa6cae9c4274596417a9a01 Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 14 Dec 2024 23:15:52 +0800 Subject: [PATCH 2/5] upgrade deps --- framework/eslint-config/package.json | 6 +-- package.json | 2 +- packages/elastic/package.json | 2 +- packages/hydrooj/package.json | 10 ++--- packages/hydrooj/src/handler/home.ts | 27 ++++++------- packages/onsite-toolkit/package.json | 2 +- .../autocomplete/components/AutoComplete.tsx | 39 +------------------ packages/ui-default/package.json | 20 +++++----- packages/utils/package.json | 2 +- 9 files changed, 36 insertions(+), 74 deletions(-) diff --git a/framework/eslint-config/package.json b/framework/eslint-config/package.json index 2a7a58c1c..400054a42 100644 --- a/framework/eslint-config/package.json +++ b/framework/eslint-config/package.json @@ -4,9 +4,9 @@ "license": "MIT", "main": "react.yaml", "dependencies": { - "@stylistic/eslint-plugin": "^2.12.0", - "@typescript-eslint/eslint-plugin": "^8.17.0", - "@typescript-eslint/parser": "^8.17.0", + "@stylistic/eslint-plugin": "^2.12.1", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-github": "^5.1.4", "eslint-plugin-import": "2.31.0", diff --git a/package.json b/package.json index 8b22cad44..36918651e 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "esbuild": "0.24.0", "eslint": "^8.57.1", "eslint-import-resolver-typescript": "^3.7.0", - "eslint-import-resolver-webpack": "^0.13.9", + "eslint-import-resolver-webpack": "^0.13.10", "fs-extra": "^11.2.0", "globby": "^14.0.2", "inspectpack": "^4.7.1", diff --git a/packages/elastic/package.json b/packages/elastic/package.json index 469a18c23..895448400 100644 --- a/packages/elastic/package.json +++ b/packages/elastic/package.json @@ -6,6 +6,6 @@ "author": "undefined ", "license": "AGPL-3.0-or-later", "dependencies": { - "@elastic/elasticsearch": "^8.16.2" + "@elastic/elasticsearch": "^8.17.0" } } diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index f2d91fa99..64d023a30 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -12,11 +12,11 @@ }, "preferUnplugged": true, "dependencies": { - "@aws-sdk/client-s3": "3.705.0", - "@aws-sdk/lib-storage": "3.705.0", - "@aws-sdk/s3-presigned-post": "3.705.0", - "@aws-sdk/s3-request-presigner": "3.705.0", - "@graphql-tools/schema": "^10.0.11", + "@aws-sdk/client-s3": "3.712.0", + "@aws-sdk/lib-storage": "3.712.0", + "@aws-sdk/s3-presigned-post": "3.712.0", + "@aws-sdk/s3-request-presigner": "3.712.0", + "@graphql-tools/schema": "^10.0.12", "@hydrooj/framework": "workspace:^", "@hydrooj/utils": "workspace:^", "@simplewebauthn/server": "9.0.3", diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 175a647ab..f13d1428c 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -3,7 +3,7 @@ import { generateRegistrationOptions, verifyRegistrationResponse } from '@simple import yaml from 'js-yaml'; import { pick } from 'lodash'; import { Binary, ObjectId } from 'mongodb'; -import Parser from 'ua-parser-js'; +import { UAParser } from 'ua-parser-js'; import { Context } from '../context'; import { AuthOperationError, BlacklistedError, DomainAlreadyExistsError, InvalidTokenError, @@ -186,10 +186,7 @@ class HomeSecurityHandler extends Handler { session.isCurrent = session._id === this.session._id; session._id = md5(session._id); const ua = session.updateUa || session.createUa; - if (ua) { - const parser = new Parser(ua); - session.updateUaInfo = parser.getResult(); - } + if (ua) session.updateUaInfo = UAParser(ua); session.updateGeoip = this.ctx.geoip?.lookup?.( session.updateIp || session.createIp, this.translate('geoip_locale'), @@ -253,7 +250,7 @@ class HomeSecurityHandler extends Handler { } @param('tokenDigest', Types.String) - async postDeleteToken(domainId: string, tokenDigest: string) { + async postDeleteToken({ }, tokenDigest: string) { const sessions = await token.getSessionListByUid(this.user._id); for (const session of sessions) { if (tokenDigest === md5(session._id)) { @@ -273,7 +270,7 @@ class HomeSecurityHandler extends Handler { @requireSudo @param('code', Types.String) @param('secret', Types.String) - async postEnableTfa(domainId: string, code: string, secret: string) { + async postEnableTfa({ }, code: string, secret: string) { if (this.user._tfa) throw new AuthOperationError('2FA', 'enabled'); if (!verifyTFA(secret, code)) throw new InvalidTokenError('2FA'); await user.setById(this.user._id, { tfa: secret }); @@ -287,7 +284,7 @@ class HomeSecurityHandler extends Handler { @requireSudo @param('type', Types.Range(['cross-platform', 'platform'])) - async postRegister(domainId: string, type: 'cross-platform' | 'platform') { + async postRegister({ }, type: 'cross-platform' | 'platform') { const options = await generateRegistrationOptions({ rpName: system.get('server.name'), rpID: this.getAuthnHost(), @@ -309,7 +306,7 @@ class HomeSecurityHandler extends Handler { @requireSudo @param('name', Types.String) - async postEnableAuthn(domainId: string, name: string) { + async postEnableAuthn({ }, name: string) { if (!this.session.webauthnVerify) throw new InvalidTokenError(token.TYPE_TEXTS[token.TYPE_WEBAUTHN]); const verification = await verifyRegistrationResponse({ response: this.args.result, @@ -336,7 +333,7 @@ class HomeSecurityHandler extends Handler { @requireSudo @param('id', Types.String) - async postDisableAuthn(domainId: string, id: string) { + async postDisableAuthn({ }, id: string) { const authenticators = this.user._authenticators?.filter((c) => Buffer.from(c.credentialID.buffer).toString('base64') !== id); if (this.user._authenticators?.length === authenticators?.length) throw new ValidationError('authenticator'); await user.setById(this.user._id, { authenticators }); @@ -395,7 +392,7 @@ function set(s: Setting, key: string, value: any) { class HomeSettingsHandler extends Handler { @param('category', Types.Range(['preference', 'account', 'domain'])) - async get(domainId: string, category: string) { + async get({ }, category: string) { this.response.template = 'home_settings.html'; this.response.body = { category, @@ -432,7 +429,7 @@ class HomeSettingsHandler extends Handler { class HomeAvatarHandler extends Handler { @param('avatar', Types.String, true) - async post(domainId: string, input: string) { + async post({ }, input: string) { if (input) { if (!validate(input)) throw new ValidationError('avatar'); await user.setById(this.user._id, { avatar: input }); @@ -565,7 +562,7 @@ class HomeMessagesHandler extends Handler { @param('uid', Types.Int) @param('content', Types.Content) - async postSend(domainId: string, uid: number, content: string) { + async postSend({ }, uid: number, content: string) { this.checkPriv(PRIV.PRIV_SEND_MESSAGE); const udoc = await user.getById('system', uid); if (!udoc) throw new UserNotFoundError(uid); @@ -575,7 +572,7 @@ class HomeMessagesHandler extends Handler { } @param('messageId', Types.ObjectId) - async postDeleteMessage(domainId: string, messageId: ObjectId) { + async postDeleteMessage({ }, messageId: ObjectId) { const msg = await message.get(messageId); if ([msg.from, msg.to].includes(this.user._id)) await message.del(messageId); else throw new PermissionError(); @@ -583,7 +580,7 @@ class HomeMessagesHandler extends Handler { } @param('messageId', Types.ObjectId) - async postRead(domainId: string, messageId: ObjectId) { + async postRead({ }, messageId: ObjectId) { const msg = await message.get(messageId); if ([msg.from, msg.to].includes(this.user._id)) { await message.setFlag(messageId, message.FLAG_UNREAD); diff --git a/packages/onsite-toolkit/package.json b/packages/onsite-toolkit/package.json index 247d6a6c2..d455405e6 100644 --- a/packages/onsite-toolkit/package.json +++ b/packages/onsite-toolkit/package.json @@ -3,6 +3,6 @@ "version": "0.0.3", "dependencies": { "@react-spring/web": "^9.7.5", - "react-use": "^17.5.1" + "react-use": "^17.6.0" } } diff --git a/packages/ui-default/components/autocomplete/components/AutoComplete.tsx b/packages/ui-default/components/autocomplete/components/AutoComplete.tsx index 836ebd159..e90bef43a 100644 --- a/packages/ui-default/components/autocomplete/components/AutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/components/AutoComplete.tsx @@ -1,7 +1,6 @@ /* eslint-disable jsx-a11y/role-supports-aria-props */ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ import { debounce, uniqueId } from 'lodash'; -import PropTypes from 'prop-types'; import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState, @@ -102,8 +101,8 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re const [rerender, setRerender] = useState(false); const [draggableId] = useState(uniqueId()); - const inputRef = useRef(); - const listRef = useRef(); + const inputRef = useRef(null); + const listRef = useRef(null); let [queryCache, valueCache] = [useRef({}).current, useRef({}).current]; if (props.cacheKey) { @@ -347,40 +346,6 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re ); }) as ((props: AutoCompleteProps & { ref: React.Ref> }) => React.ReactElement) & React.FC; -AutoComplete.propTypes = { - width: PropTypes.string, - height: PropTypes.string, - disabled: PropTypes.bool, - disabledHint: PropTypes.string, - listStyle: PropTypes.object, - queryItems: PropTypes.func.isRequired, - itemKey: PropTypes.func, - renderItem: PropTypes.func, - itemText: PropTypes.func, - onChange: PropTypes.func.isRequired, - multi: PropTypes.bool, - selectedKeys: PropTypes.arrayOf(PropTypes.string), - allowEmptyQuery: PropTypes.bool, - freeSolo: PropTypes.bool, - freeSoloConverter: PropTypes.func, - placeholder: PropTypes.string, -}; - -AutoComplete.defaultProps = { - width: '100%', - height: 'auto', - disabled: false, - disabledHint: '', - listStyle: {}, - renderItem: (item) => item, - itemText: (item) => item.toString(), - multi: false, - selectedKeys: [], - allowEmptyQuery: false, - freeSolo: false, - freeSoloConverter: (input) => input, -}; - AutoComplete.displayName = 'AutoComplete'; export default AutoComplete; diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index e65d54550..fd8a8f144 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -14,7 +14,7 @@ "cli": false }, "devDependencies": { - "@blueprintjs/core": "^5.16.0", + "@blueprintjs/core": "^5.16.2", "@cordisjs/core": "3.18.1", "@fontsource/dm-mono": "^5.1.0", "@fontsource/fira-code": "^5.1.0", @@ -25,7 +25,7 @@ "@fontsource/source-code-pro": "^5.1.0", "@fontsource/ubuntu-mono": "^5.1.0", "@hydrooj/utils": "workspace:^", - "@sentry/browser": "^8.42.0", + "@sentry/browser": "^8.45.0", "@sentry/webpack-plugin": "^2.22.7", "@simplewebauthn/browser": "9.0.1", "@svgr/webpack": "^8.1.0", @@ -37,8 +37,8 @@ "@types/nunjucks": "^3.2.6", "@types/pickadate": "^3.5.35", "@types/qrcode": "^1.5.5", - "@types/react": "^19.0.1", - "@types/react-dom": "^19.0.1", + "@types/react": "^18.3.16", + "@types/react-dom": "^18.3.5", "@types/redux-logger": "^3.0.13", "@types/uuid": "^10.0.0", "@types/webpack-env": "^1.18.5", @@ -62,14 +62,14 @@ "emojis-list": "2.1.0", "esbuild-loader": "^4.2.2", "flatpickr": "^4.6.13", - "graphiql": "^3.7.2", + "graphiql": "^3.8.0", "idb": "^8.0.0", "jquery": "^3.7.1", "jquery-scroll-lock": "^3.1.3", "jquery.easing": "^1.4.1", "jquery.transit": "^0.9.12", "matchmedia-polyfill": "^0.3.2", - "md-editor-rt": "^5.0.2", + "md-editor-rt": "^5.1.0", "mini-css-extract-plugin": "^2.9.2", "moment": "^2.30.1", "monaco-editor": "0.50.0", @@ -94,7 +94,7 @@ "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.3.1", "react-query": "^3.39.3", - "react-redux": "^9.1.2", + "react-redux": "^9.2.0", "reconnecting-websocket": "^4.4.0", "redux": "^5.0.1", "redux-logger": "^3.0.6", @@ -117,7 +117,7 @@ "web-streams-polyfill": "^4.0.0", "webpack": "^5.97.1", "webpack-bundle-analyzer": "^4.10.2", - "webpack-dev-server": "^5.1.0", + "webpack-dev-server": "^5.2.0", "webpack-manifest-plugin": "^5.0.0", "webpackbar": "^7.0.0" }, @@ -127,8 +127,8 @@ "esbuild": "0.24.0", "fs-extra": "^11.2.0", "js-yaml": "^4.1.0", - "jsesc": "^3.0.2", - "katex": "^0.16.14", + "jsesc": "^3.1.0", + "katex": "^0.16.15", "lodash": "^4.17.21", "markdown-it": "^14.1.0", "markdown-it-anchor": "^9.2.0", diff --git a/packages/utils/package.json b/packages/utils/package.json index a0d2926c0..825943c16 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -16,7 +16,7 @@ "mongodb": "^5.9.2", "reggol": "^1.7.1", "search-query-parser": "^1.6.0", - "systeminformation": "^5.23.6" + "systeminformation": "^5.23.13" }, "devDependencies": { "@types/fs-extra": "^11.0.4" From 04335f76b704209469771031f9d46884a81f4919 Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 14 Dec 2024 23:55:59 +0800 Subject: [PATCH 3/5] use Buffer.isBuffer --- packages/hydrooj/src/service/storage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hydrooj/src/service/storage.ts b/packages/hydrooj/src/service/storage.ts index f825d868b..0d9ed5ae6 100644 --- a/packages/hydrooj/src/service/storage.ts +++ b/packages/hydrooj/src/service/storage.ts @@ -275,7 +275,7 @@ class LocalStorageService { target = resolve(this.dir, convertPath(target)); await ensureDir(dirname(target)); if (typeof file === 'string') await copyFile(file, target); - else if (file instanceof Buffer) await writeFile(target, file); + else if (Buffer.isBuffer(file)) await writeFile(target, file); else await writeFile(target, await streamToBuffer(file)); } From a27e6a98f0ee73ffaf124f9a53f54a236dd35a72 Mon Sep 17 00:00:00 2001 From: undefined Date: Sun, 15 Dec 2024 01:04:24 +0800 Subject: [PATCH 4/5] bump version --- README.md | 8 ++++++++ packages/hydrooj/package.json | 2 +- packages/hydrooj/src/model/problem.ts | 5 +++-- packages/ui-default/package.json | 2 +- packages/utils/package.json | 2 +- packages/vjudge/package.json | 2 +- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4ab87d360..760b61ea9 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,14 @@ Hydro 用户群:1085853538

更新日志(点击展开)

+## Hydro 4.18.2 / UI 4.56.2 + +- core: 修复提交答案题压缩包提交 (#917) +- ui: 优化 domain_user 页面性能 +- core: 优化评测任务调度 +- ui: 下载文件失败时自动重试 +- core: Consumer: 从错误中自动恢复 + ## Hydro 4.18.0 / UI 4.56.0 - core&ui: ScoreboardView API diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 64d023a30..262653afa 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "4.18.1", + "version": "4.18.2", "bin": "bin/hydrooj.js", "main": "src/plugin-api", "module": "src/plugin-api", diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts index 818e318c3..f2c3904ee 100644 --- a/packages/hydrooj/src/model/problem.ts +++ b/packages/hydrooj/src/model/problem.ts @@ -603,11 +603,12 @@ export class ProblemModel { if (options.delSource) await fs.remove(tmpdir); } - static async export(domainId: string) { + static async export(domainId: string, pidFilter?:string) { console.log('Exporting problems...'); const tmpdir = path.join(os.tmpdir(), 'hydro', `${Math.random()}.export`); await fs.mkdir(tmpdir); - const pdocs = await ProblemModel.getMulti(domainId, {}, ProblemModel.PROJECTION_PUBLIC).toArray(); + const pdocs = await ProblemModel.getMulti(domainId, pidFilter ? { pid: pidFilter } : {}, ProblemModel.PROJECTION_PUBLIC).toArray(); + if (process.env.HYDRO_CLI) logger.info(`Exporting ${pdocs.length} problems`); for (const pdoc of pdocs) { if (process.env.HYDRO_CLI) logger.info(`Exporting problem ${pdoc.pid || (`P${pdoc.docId}`)} (${pdoc.title})`); const problemPath = path.join(tmpdir, `${pdoc.docId}`); diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index fd8a8f144..f83ea131f 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.56.1", + "version": "4.56.2", "author": "undefined ", "license": "AGPL-3.0", "main": "index.ts", diff --git a/packages/utils/package.json b/packages/utils/package.json index 825943c16..e08344bb0 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/utils", - "version": "1.4.30", + "version": "1.4.31", "description": "hydrooj utils", "main": "lib/utils.ts", "repository": "https://github.com/hydro-dev/Hydro.git", diff --git a/packages/vjudge/package.json b/packages/vjudge/package.json index ed15f3659..ee63a2571 100644 --- a/packages/vjudge/package.json +++ b/packages/vjudge/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/vjudge", - "version": "1.9.14", + "version": "1.9.15", "description": "Submit problems to remote oj", "main": "./src/index.ts", "repository": "https://github.com/hydro-dev/Hydro.git", From fdb4f1886e5e21ee1bb77516e6eb640f5d20faab Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 16 Dec 2024 11:01:12 +0800 Subject: [PATCH 5/5] ui: fix ranking pagination --- packages/ui-default/templates/ranking.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-default/templates/ranking.html b/packages/ui-default/templates/ranking.html index 36171120c..81ebf20a6 100644 --- a/packages/ui-default/templates/ranking.html +++ b/packages/ui-default/templates/ranking.html @@ -55,7 +55,7 @@ {% endif %} {%- for udoc in udocs -%} - {{ (page - 1) * 100 + loop.index }} + {{ (page - 1) * model.system.get('pagination.ranking') + loop.index }} {{ user.render_inline(udoc) }} {{ udoc.rp|default(0)|round(0) }} {% for key, def in model.rp %}