Skip to content

Commit

Permalink
Merge branch 'hydro-dev:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
liaojiqing2012 authored Dec 17, 2024
2 parents 7be3af4 + fdb4f18 commit ab6f258
Show file tree
Hide file tree
Showing 15 changed files with 57 additions and 88 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ Hydro 用户群:1085853538
<details>
<summary><h2>更新日志(点击展开)</h2></summary>

## 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
Expand Down
6 changes: 3 additions & 3 deletions framework/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/elastic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@elastic/elasticsearch": "^8.16.2"
"@elastic/elasticsearch": "^8.17.0"
}
}
12 changes: 6 additions & 6 deletions packages/hydrooj/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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",
Expand Down
27 changes: 12 additions & 15 deletions packages/hydrooj/src/handler/home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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'),
Expand Down Expand Up @@ -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)) {
Expand All @@ -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 });
Expand All @@ -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(),
Expand All @@ -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,
Expand All @@ -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 });
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 });
Expand Down Expand Up @@ -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);
Expand All @@ -575,15 +572,15 @@ 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();
this.back();
}

@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);
Expand Down
10 changes: 4 additions & 6 deletions packages/hydrooj/src/handler/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`;
Expand Down
5 changes: 3 additions & 2 deletions packages/hydrooj/src/model/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
Expand Down
2 changes: 1 addition & 1 deletion packages/hydrooj/src/service/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
2 changes: 1 addition & 1 deletion packages/onsite-toolkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -102,8 +101,8 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
const [rerender, setRerender] = useState(false);
const [draggableId] = useState(uniqueId());

const inputRef = useRef<HTMLInputElement>();
const listRef = useRef<HTMLUListElement>();
const inputRef = useRef<HTMLInputElement>(null);
const listRef = useRef<HTMLUListElement>(null);

let [queryCache, valueCache] = [useRef({}).current, useRef({}).current];
if (props.cacheKey) {
Expand Down Expand Up @@ -347,40 +346,6 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
);
}) as (<T>(props: AutoCompleteProps<T> & { ref: React.Ref<AutoCompleteHandle<T>> }) => 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;
22 changes: 11 additions & 11 deletions packages/ui-default/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
"version": "4.56.1",
"version": "4.56.2",
"author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0",
"main": "index.ts",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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"
},
Expand All @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-default/templates/ranking.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
{% endif %}
{%- for udoc in udocs -%}
<tr>
<td class="col--rank">{{ (page - 1) * 100 + loop.index }}</td>
<td class="col--rank">{{ (page - 1) * model.system.get('pagination.ranking') + loop.index }}</td>
<td class="col--user">{{ user.render_inline(udoc) }}</td>
<td class="col--rp">{{ udoc.rp|default(0)|round(0) }}</td>
{% for key, def in model.rp %}
Expand Down
Loading

0 comments on commit ab6f258

Please sign in to comment.