bug fixes

This commit is contained in:
undefined committed 2024-06-27 03:58:29 +08:00
1 parent 16b6f53653
commit 84f7d5dc80
20 files changed
+42 -34

No files matched your search

+1
View File
@@ -137,6 +137,7 @@ Hydro 用户群:1085853538
- serializer: 移除 showDisplayName 参数 - serializer: 移除 showDisplayName 参数
- 移除了 loader.addScript, loader.addon 函数 - 移除了 loader.addScript, loader.addon 函数
- 移除了 Hydro.module.render (请使用 ctx.server.registerRenderer) - 移除了 Hydro.module.render (请使用 ctx.server.registerRenderer)
- 移除了 lib/paginate 和 lib/rank (请使用 db.paginate 和 db.ranked)
### Hydro 4.12.3 / UI 4.50.2 ### Hydro 4.12.3 / UI 4.50.2
- core: 将 API 模块移入 service - core: 将 API 模块移入 service
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@hydrooj/hydrojudge", "name": "@hydrooj/hydrojudge",
"bin": "bin/hydrojudge.js", "bin": "bin/hydrojudge.js",
"version": "3.3.14", "version": "3.3.15",
"main": "./src/index.ts", "main": "./src/index.ts",
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"repository": "https://github.com/hydro-dev/Hydro.git", "repository": "https://github.com/hydro-dev/Hydro.git",
+1 -1
View File
@@ -99,7 +99,7 @@ export async function postInit(ctx) {
function collectCompilerInfo() { function collectCompilerInfo() {
const coll = db.collection('status'); const coll = db.collection('status');
compilerVersions(langs).then((compilers) => coll.updateOne( compilerVersions(langs).then((compilers) => coll.updateOne(
{ mid: info.mid, type: 'judge' }, { mid: info.mid, type: 'server' },
{ $set: { compilers } }, { $set: { compilers } },
{ upsert: true }, { upsert: true },
)).catch((e) => logger.error(e)); )).catch((e) => logger.error(e));
+6 -1
View File
@@ -175,6 +175,7 @@ export default class Hydro implements Session {
? JSON.stringify({ key: 'config', ...config }) ? JSON.stringify({ key: 'config', ...config })
: '{"key":"ping"}'; : '{"key":"ping"}';
let compilers = {}; let compilers = {};
let compilerVersionCallback = () => { };
this.ws.on('message', (data) => { this.ws.on('message', (data) => {
if (data.toString() === 'ping') { if (data.toString() === 'ping') {
this.ws.send('pong'); this.ws.send('pong');
@@ -185,6 +186,7 @@ export default class Hydro implements Session {
this.language = request.language; this.language = request.language;
compilerVersions(this.language).then((res) => { compilerVersions(this.language).then((res) => {
compilers = res; compilers = res;
compilerVersionCallback();
}); });
} }
if (request.task) queue.add(() => new JudgeTask(this, request.task).handle().catch((e) => log.error(e))); if (request.task) queue.add(() => new JudgeTask(this, request.task).handle().catch((e) => log.error(e)));
@@ -203,7 +205,10 @@ export default class Hydro implements Session {
this.ws.send('{"key":"start"}'); this.ws.send('{"key":"start"}');
if (!this.config.noStatus) { if (!this.config.noStatus) {
const info = await sysinfo.get(); const info = await sysinfo.get();
this.ws.send(JSON.stringify({ key: 'status', info: { ...info, compilers } })); this.ws.send(JSON.stringify({ key: 'status', info: { ...info } }));
compilerVersionCallback = () => {
this.ws.send(JSON.stringify({ key: 'status', info: { ...info, compilers } }));
};
setInterval(async () => { setInterval(async () => {
const [mid, inf] = await sysinfo.update(); const [mid, inf] = await sysinfo.update();
this.ws.send(JSON.stringify({ key: 'status', info: { mid, ...inf, compilers } })); this.ws.send(JSON.stringify({ key: 'status', info: { mid, ...inf, compilers } }));
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "4.13.0", "version": "4.13.1",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "src/plugin-api", "main": "src/plugin-api",
"module": "src/plugin-api", "module": "src/plugin-api",
+1
View File
@@ -274,6 +274,7 @@ SystemSetting(
Setting('setting_basic', 'pagination.contest', 20, 'number', 'pagination.contest', 'Contests per page'), Setting('setting_basic', 'pagination.contest', 20, 'number', 'pagination.contest', 'Contests per page'),
Setting('setting_basic', 'pagination.discussion', 50, 'number', 'pagination.discussion', 'Discussions per page'), Setting('setting_basic', 'pagination.discussion', 50, 'number', 'pagination.discussion', 'Discussions per page'),
Setting('setting_basic', 'pagination.record', 100, 'number', 'pagination.record', 'Records per page'), Setting('setting_basic', 'pagination.record', 100, 'number', 'pagination.record', 'Records per page'),
Setting('setting_basic', 'pagination.ranking', 100, 'number', 'pagination.ranking', 'Users per page'),
Setting('setting_basic', 'pagination.solution', 20, 'number', 'pagination.solution', 'Solutions per page'), Setting('setting_basic', 'pagination.solution', 20, 'number', 'pagination.solution', 'Solutions per page'),
Setting('setting_basic', 'pagination.training', 10, 'number', 'pagination.training', 'Trainings per page'), Setting('setting_basic', 'pagination.training', 10, 'number', 'pagination.training', 'Trainings per page'),
Setting('setting_basic', 'pagination.reply', 50, 'number', 'pagination.reply', 'Replies per page'), Setting('setting_basic', 'pagination.reply', 50, 'number', 'pagination.reply', 'Replies per page'),
@@ -1,4 +1,4 @@
import { KoaContext } from '@hydrooj/framework'; import { KoaContext, NotFoundError } from '@hydrooj/framework';
import BlackListModel from '../../model/blacklist'; import BlackListModel from '../../model/blacklist';
import DomainModel from '../../model/domain'; import DomainModel from '../../model/domain';
import * as system from '../../model/system'; import * as system from '../../model/system';
@@ -24,5 +24,12 @@ export default async (ctx: KoaContext, next) => {
ctx.domainId = inferDomain?._id || domainId; ctx.domainId = inferDomain?._id || domainId;
ctx.domainInfo = inferDomain || absoluteDomain; ctx.domainInfo = inferDomain || absoluteDomain;
if (ctx.domainInfo && ctx.domainId !== ctx.domainInfo._id) ctx.redirect(ctx.originalPath.replace(/^\/d\/[^/]+\//, `/d/${ctx.domainInfo._id}/`)); if (ctx.domainInfo && ctx.domainId !== ctx.domainInfo._id) ctx.redirect(ctx.originalPath.replace(/^\/d\/[^/]+\//, `/d/${ctx.domainInfo._id}/`));
else await next(); else {
if (!ctx.domainInfo) {
ctx.pendingError = new NotFoundError(ctx.domainId);
ctx.domainId = 'system';
ctx.domainInfo = await DomainModel.get('system');
}
await next();
}
}; };
@@ -1,5 +1,4 @@
import type { KoaContext } from '@hydrooj/framework'; import type { KoaContext } from '@hydrooj/framework';
import { NotFoundError } from '../../error';
import { PERM } from '../../model/builtin'; import { PERM } from '../../model/builtin';
import UserModel from '../../model/user'; import UserModel from '../../model/user';
@@ -15,9 +14,5 @@ export default async (ctx: KoaContext, next) => {
} }
if (user._id === 0) delete user.viewLang; if (user._id === 0) delete user.viewLang;
ctx.HydroContext.user = await user.private(); ctx.HydroContext.user = await user.private();
if (!domain) {
ctx.pendingError = new NotFoundError(args.domainId);
args.domainId = 'system';
}
await next(); await next();
}; };
+1
View File
@@ -276,6 +276,7 @@ export async function apply(ctx: Context) {
text: global.Hydro.module.oauth[key].text, text: global.Hydro.module.oauth[key].text,
})); }));
if (!h.noCheckPermView && !h.user.hasPriv(PRIV.PRIV_VIEW_ALL_DOMAIN)) h.checkPerm(PERM.PERM_VIEW); if (!h.noCheckPermView && !h.user.hasPriv(PRIV.PRIV_VIEW_ALL_DOMAIN)) h.checkPerm(PERM.PERM_VIEW);
if (h.context.pendingError) throw h.context.pendingError;
}); });
on('app/listen', () => { on('app/listen', () => {
@@ -89,6 +89,7 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
output: { output: {
path: root('public'), path: root('public'),
publicPath: '/', // overwrite in entry.js publicPath: '/', // overwrite in entry.js
workerPublicPath: '/',
hashFunction: 'sha1', hashFunction: 'sha1',
hashDigest: 'hex', hashDigest: 'hex',
hashDigestLength: 10, hashDigestLength: 10,
+4 -1
View File
@@ -49,7 +49,10 @@ async function runWebpack({
return; return;
} }
if (argv.options.detail) console.log(stats.toString()); if (argv.options.detail) console.log(stats.toString());
if (!watch && (!stats || stats.hasErrors())) process.exitCode = 1; if (!watch && (!stats || stats.hasErrors())) {
if (!argv.options.detail) console.log(stats.toString());
process.exitCode = 1;
}
resolve(stats); resolve(stats);
} }
if (watch) compiler.watch({}, compilerCallback); if (watch) compiler.watch({}, compilerCallback);
@@ -24,9 +24,8 @@ const Component = React.forwardRef<any, any>((props, ref) => {
); );
}); });
export default class CustomSelectAutoComplete<Multi extends boolean> extends AutoComplete { export default class CustomSelectAutoComplete<Multi extends boolean> extends AutoComplete<CustomSelectOptions> {
static DOMAttachKey = 'ucwCustomSelectAutoCompleteInstance'; static DOMAttachKey = 'ucwCustomSelectAutoCompleteInstance';
options: CustomSelectOptions & AutoCompleteOptions;
constructor($dom, options: CustomSelectOptions & AutoCompleteOptions<Multi>) { constructor($dom, options: CustomSelectOptions & AutoCompleteOptions<Multi>) {
super($dom, { super($dom, {
@@ -27,9 +27,8 @@ const Component = React.forwardRef<any, any>((props, ref) => {
); );
}); });
export default class FileSelectAutoComplete<Multi extends boolean> extends AutoComplete { export default class FileSelectAutoComplete<Multi extends boolean> extends AutoComplete<FileSelectOptions> {
static DOMAttachKey = 'ucwFileSelectAutoCompleteInstance'; static DOMAttachKey = 'ucwFileSelectAutoCompleteInstance';
options: FileSelectOptions & AutoCompleteOptions;
constructor($dom, options: FileSelectOptions & AutoCompleteOptions<Multi>) { constructor($dom, options: FileSelectOptions & AutoCompleteOptions<Multi>) {
super($dom, { super($dom, {
@@ -8,6 +8,7 @@ export interface AutoCompleteOptions<Multi extends boolean = boolean> {
defaultItems?: string; defaultItems?: string;
width?: string; width?: string;
height?: string; height?: string;
classes?: string;
listStyle?: any; listStyle?: any;
allowEmptyQuery?: boolean; allowEmptyQuery?: boolean;
freeSolo?: boolean; freeSolo?: boolean;
@@ -18,17 +19,17 @@ export interface AutoCompleteOptions<Multi extends boolean = boolean> {
text?: () => string; text?: () => string;
} }
export default class AutoComplete extends DOMAttachedObject { export default class AutoComplete<Options extends Record<string, any> = {}> extends DOMAttachedObject {
static DOMAttachKey = 'ucwAutoCompleteInstance'; static DOMAttachKey = 'ucwAutoCompleteInstance';
ref = null; ref = null;
container = document.createElement('div'); container = document.createElement('div');
options: AutoCompleteOptions; options: AutoCompleteOptions & Options;
component = ReactDOM.createRoot(this.container); component = ReactDOM.createRoot(this.container);
changeListener = [ changeListener = [
(val) => this.$dom.val(val), (val) => this.$dom.val(val),
]; ];
constructor($dom, options = {}) { constructor($dom, options = {} as Options) {
super($dom); super($dom);
this.options = { this.options = {
items: async () => [], items: async () => [],
@@ -1,5 +1,4 @@
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import ReconnectingWebsocket from 'reconnecting-websocket';
import { InfoDialog } from 'vj/components/dialog'; import { InfoDialog } from 'vj/components/dialog';
import VjNotification from 'vj/components/notification/index'; import VjNotification from 'vj/components/notification/index';
import { import {
@@ -7,6 +6,7 @@ import {
} from 'vj/constant/message'; } from 'vj/constant/message';
import { AutoloadPage } from 'vj/misc/Page'; import { AutoloadPage } from 'vj/misc/Page';
import { i18n, tpl } from 'vj/utils'; import { i18n, tpl } from 'vj/utils';
import Sock from '../socket';
let previous: VjNotification; let previous: VjNotification;
const onmessage = (msg) => { const onmessage = (msg) => {
@@ -128,12 +128,8 @@ const messagePage = new AutoloadPage('messagePage', (pagename) => {
isMaster = true; isMaster = true;
localStorage.setItem('page.master', selfId); localStorage.setItem('page.master', selfId);
const masterChannel = new BroadcastChannel('hydro-messages'); const masterChannel = new BroadcastChannel('hydro-messages');
const sock = new ReconnectingWebsocket(endpoint); const sock = new Sock(endpoint);
sock.onopen = () => console.log('Connected');
sock.onerror = console.error;
sock.onclose = (...args) => console.log('Closed', ...args);
sock.onmessage = async (message) => { sock.onmessage = async (message) => {
if (process.env.NODE_ENV !== 'production') console.log('onmessage: ', message);
const payload = JSON.parse(message.data); const payload = JSON.parse(message.data);
masterChannel.postMessage({ type: 'message', payload }); masterChannel.postMessage({ type: 'message', payload });
}; };
+1 -1
View File
@@ -31,7 +31,7 @@ window.UserContext = JSON.parse(window.UserContext);
if (process.env.NODE_ENV === 'production' && !UiContext.sentry_disable) { if (process.env.NODE_ENV === 'production' && !UiContext.sentry_disable) {
window.captureException = (e) => Sentry.captureException(e); window.captureException = (e) => Sentry.captureException(e);
Sentry.init({ Sentry.init({
dsn: UiContext.sentry_dsn || 'https://04d1d77b095231d55e1202bdc912ff16@sentry.hydro.ac/3', dsn: UiContext.sentry_dsn || 'https://2f95d53751e08c74c1af1c4b93ccaff7@sentry.hydro.ac/2',
release: process.env.VERSION, release: process.env.VERSION,
integrations: [ integrations: [
Sentry.browserTracingIntegration(), Sentry.browserTracingIntegration(),
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@hydrooj/ui-default", "name": "@hydrooj/ui-default",
"version": "4.51.0", "version": "4.51.1",
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "index.ts", "main": "index.ts",
@@ -51,6 +51,7 @@
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"copy-webpack-plugin": "^12.0.2", "copy-webpack-plugin": "^12.0.2",
"core-js": "^3.37.1",
"css-loader": "^6.11.0", "css-loader": "^6.11.0",
"diff": "^5.2.0", "diff": "^5.2.0",
"diff-dom": "^5.1.3", "diff-dom": "^5.1.3",
@@ -90,7 +91,6 @@
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"qface": "^1.4.1", "qface": "^1.4.1",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"queue-microtask": "^1.2.3",
"react": "^18.3.1", "react": "^18.3.1",
"react-colorful": "^5.6.1", "react-colorful": "^5.6.1",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
+1 -2
View File
@@ -1,9 +1,8 @@
import 'matchmedia-polyfill'; import 'matchmedia-polyfill';
import 'core-js/stable';
import browserUpdate from 'browser-update'; import browserUpdate from 'browser-update';
import queueMicrotask from 'queue-microtask';
window.queueMicrotask = queueMicrotask;
browserUpdate({ browserUpdate({
required: { required: {
e: -10, f: -10, o: -3, s: -1, c: -10, e: -10, f: -10, o: -3, s: -1, c: -10,
@@ -47,7 +47,7 @@
var _htmlNode = document.documentElement; var _htmlNode = document.documentElement;
_htmlNode.className = _htmlNode.className.replace(' nojs', ' hasjs'); _htmlNode.className = _htmlNode.className.replace(' nojs', ' hasjs');
try { try {
import('data:text/javascript,');Object.fromEntries([]);window.matchMedia('all').addEventListener('change',()=>{}); import('data:text/javascript,');Object.fromEntries([]);window.matchMedia('all').addEventListener('change',()=>{});Array.prototype.at(0);
} catch(e) { } catch(e) {
const s = document.createElement('script'); const s = document.createElement('script');
s.async = false; s.async = false;
+3 -3
View File
@@ -34,8 +34,8 @@ export function secureRandomString(digit = 32, dict = defaultDict) {
type Substitution = string | number | { templateRaw: true, html: string }; type Substitution = string | number | { templateRaw: true, html: string };
export function tpl(node: React.ReactNode, reactive?: boolean); export function tpl<T extends boolean>(node: React.ReactNode, reactive?: T): T extends true ? React.ReactElement : string;
export function tpl(pieces: TemplateStringsArray, ...substitutions: Substitution[]); export function tpl(pieces: TemplateStringsArray, ...substitutions: Substitution[]): string;
export function tpl(pieces: TemplateStringsArray | React.ReactNode, ...substitutions: Substitution[] | boolean[]) { export function tpl(pieces: TemplateStringsArray | React.ReactNode, ...substitutions: Substitution[] | boolean[]) {
if (React.isValidElement(pieces)) { if (React.isValidElement(pieces)) {
if (substitutions[0]) { if (substitutions[0]) {
@@ -49,7 +49,7 @@ export function tpl(pieces: TemplateStringsArray | React.ReactNode, ...substitut
for (let i = 0; i < substitutions.length; ++i) { for (let i = 0; i < substitutions.length; ++i) {
const subst = substitutions[i]; const subst = substitutions[i];
let substHtml: string; let substHtml: string;
if (typeof subst === 'object' && subst.templateRaw) { if (subst && typeof subst === 'object' && subst.templateRaw) {
substHtml = subst.html; substHtml = subst.html;
} else substHtml = _.escape(String(subst)); } else substHtml = _.escape(String(subst));
result += substHtml + pieces[i + 1]; result += substHtml + pieces[i + 1];