core&ui: optimize injectable

This commit is contained in:
undefined committed 2022-09-07 20:30:44 +08:00
1 parent 25444f69f0
commit 7343c596e9
9 files changed
+64 -64

No files matched your search

+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "3.17.2", "version": "3.17.3",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "src/loader", "main": "src/loader",
"module": "src/loader", "module": "src/loader",
@@ -8,7 +8,7 @@
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"engines": { "engines": {
"node": ">=10.4" "node": ">=12"
}, },
"preferUnplugged": true, "preferUnplugged": true,
"dependencies": { "dependencies": {
+1 -1
View File
@@ -131,7 +131,7 @@ export async function end(body: Partial<JudgeResultBody>) {
$push.compilerTexts = body.compilerText; $push.compilerTexts = body.compilerText;
} }
if (body.status) $set.status = body.status; if (body.status) $set.status = body.status;
if (Number.isSafeInteger(body.score)) $set.score = body.score; if (Number.isFinite(body.score)) $set.score = Math.floor(body.score * 100) / 100;
if (Number.isFinite(body.time)) $set.time = body.time; if (Number.isFinite(body.time)) $set.time = body.time;
if (Number.isFinite(body.memory)) $set.memory = body.memory; if (Number.isFinite(body.memory)) $set.memory = body.memory;
$set.judgeAt = new Date(); $set.judgeAt = new Date();
+6 -1
View File
@@ -396,11 +396,16 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
.replace(/="file:\/\/(.+?)"/g, (str) => { .replace(/="file:\/\/(.+?)"/g, (str) => {
const info = str.match(/="file:\/\/(.+?)"/); const info = str.match(/="file:\/\/(.+?)"/);
return `="./${this.pdoc.docId}/file/${info[1]}${info[1].includes('?') ? '&' : '?'}tid=${args[1]}"`; return `="./${this.pdoc.docId}/file/${info[1]}${info[1].includes('?') ? '&' : '?'}tid=${args[1]}"`;
})
.replace(/=\\"file:\/\/(.+?)"/g, (str) => {
const info = str.match(/=\\"file:\/\/(.+?)"/);
return `=\\"./${this.pdoc.docId}/file/${info[1]}${info[1].includes('?') ? '&' : '?'}tid=${args[1]}"`;
}); });
} else { } else {
this.response.body.pdoc.content = this.response.body.pdoc.content this.response.body.pdoc.content = this.response.body.pdoc.content
.replace(/\(file:\/\//g, `(./${this.pdoc.docId}/file/`) .replace(/\(file:\/\//g, `(./${this.pdoc.docId}/file/`)
.replace(/="file:\/\//g, `="./${this.pdoc.docId}/file/`); .replace(/="file:\/\//g, `="./${this.pdoc.docId}/file/`)
.replace(/=\\"file:\/\//g, `=\\"${this.pdoc.docId}/file/`);
} }
} }
this.response.body.page_name = this.tdoc this.response.body.page_name = this.tdoc
+1 -1
View File
@@ -1,5 +1,5 @@
const versionNum = +process.version.replace(/v/gim, '').split('.')[0]; const versionNum = +process.version.replace(/v/gim, '').split('.')[0];
if (versionNum < 10) throw new Error('NodeJS >=10.4 required'); if (versionNum < 12) throw new Error('NodeJS >=12 required');
else if (versionNum < 14 && process.env.NODE_APP_INSTANCE === '0') { else if (versionNum < 14 && process.env.NODE_APP_INSTANCE === '0') {
console.warn('NodeJS version <14, startup performance will be impacted.'); console.warn('NodeJS version <14, startup performance will be impacted.');
} }
+4 -6
View File
@@ -694,17 +694,15 @@ export interface Lib extends Record<string, any> {
problemSearch: ProblemSearch; problemSearch: ProblemSearch;
} }
export type UIInjectableFields = 'ProblemAdd' | 'Nav' | 'UserDropdown';
export interface UI { export interface UI {
manifest: Dictionary<string>, manifest: Dictionary<string>,
template: Dictionary<string>, template: Dictionary<string>,
nodes: { nodes: Record<UIInjectableFields, any[]>,
nav: any[], getNodes: typeof import('./lib/ui').getNodes,
problem_add: any[],
user_dropdown: any[],
},
Nav: typeof import('./lib/ui').Nav, Nav: typeof import('./lib/ui').Nav,
ProblemAdd: typeof import('./lib/ui').ProblemAdd, ProblemAdd: typeof import('./lib/ui').ProblemAdd,
UserDropdown: typeof import('./lib/ui').UserDropdown, inject: typeof import('./lib/ui').inject,
} }
export interface HydroGlobal { export interface HydroGlobal {
+41 -44
View File
@@ -1,3 +1,4 @@
import { UIInjectableFields } from '../interface';
import { PERM, PRIV } from '../model/builtin'; import { PERM, PRIV } from '../model/builtin';
const trueChecker = () => true; const trueChecker = () => true;
@@ -6,7 +7,8 @@ const Checker = (perm: bigint | bigint[], priv: number | number[], checker: Func
&& (perm ? handler.user.hasPerm(perm) : true) && (perm ? handler.user.hasPerm(perm) : true)
&& (priv ? handler.user.hasPriv(priv) : true) && (priv ? handler.user.hasPriv(priv) : true)
); );
const buildChecker = (...permPrivChecker: Array<number | bigint | Function | number[] | bigint[]>) => { type PermPrivChecker = Array<number | bigint | Function | number[] | bigint[]>;
const buildChecker = (...permPrivChecker: PermPrivChecker) => {
let _priv: number | number[]; let _priv: number | number[];
let _perm: bigint | bigint[]; let _perm: bigint | bigint[];
let checker: Function = trueChecker; let checker: Function = trueChecker;
@@ -22,51 +24,46 @@ const buildChecker = (...permPrivChecker: Array<number | bigint | Function | num
return Checker(_perm, _priv, checker); return Checker(_perm, _priv, checker);
}; };
export const Nav = ( export const nodes = new Proxy({}, {
name: string, args: ((handler: any) => Record<string, any>) | Record<string, any> = {}, prefix: string, get(self, key) {
...permPrivChecker: Array<number | bigint | Function> if (!self[key]) self[key] = [];
) => { return self[key];
if (typeof args !== 'function') args = () => (args || {}); },
const checker = buildChecker(...permPrivChecker); });
if (name.startsWith('@@')) { export function inject(node: UIInjectableFields, name: string, args: Record<string, any> = {}, ...permPrivChecker: PermPrivChecker) {
global.Hydro.ui.nodes.nav.splice(+name.split('@@')[1], 0, { nodes[node].push({ name, args: args || {}, checker: buildChecker(...permPrivChecker) });
name: name.split('@@')[2], args, prefix, checker, }
}); export function getNodes(name: UIInjectableFields) {
} else { return nodes[name];
global.Hydro.ui.nodes.nav.push({ }
name, args, prefix, checker, /** @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 });
}; };
export const ProblemAdd = ( inject('Nav', 'homepage', { prefix: 'homepage' });
name: string, args: Record<string, any> = {}, icon = 'add', text = 'Create Problem', inject('Nav', 'problem_main', { prefix: 'problem' }, PERM.PERM_VIEW_PROBLEM);
) => { inject('Nav', 'training_main', { prefix: 'training' }, PERM.PERM_VIEW_TRAINING);
global.Hydro.ui.nodes.problem_add.push({ inject('Nav', 'contest_main', { prefix: 'contest' }, PERM.PERM_VIEW_CONTEST);
name, args, icon, text, inject('Nav', 'homework_main', { prefix: 'homework' }, PERM.PERM_VIEW_HOMEWORK);
}); inject('Nav', 'discussion_main', { prefix: 'discussion' }, PERM.PERM_VIEW_DISCUSSION);
}; inject('Nav', 'record_main', {
prefix: 'record',
export const UserDropdown = ( query: (handler) => (handler.user.hasPriv(PRIV.PRIV_USER_PROFILE)
name: string, args: Record<string, any> = {}, ...permPrivChecker: Array<number | bigint | Function> ? ({ uidOrName: handler.user._id })
) => { : ({})),
global.Hydro.ui.nodes.user_dropdown.push({ });
name, args: args || {}, checker: buildChecker(...permPrivChecker), inject('Nav', 'ranking', { prefix: 'ranking' }, PERM.PERM_VIEW_RANKING);
}); inject('Nav', 'domain_dashboard', { prefix: 'domain' }, PERM.PERM_EDIT_DOMAIN);
}; inject('Nav', 'manage_dashboard', { prefix: 'manage' }, PRIV.PRIV_EDIT_SYSTEM);
inject('ProblemAdd', 'problem_create', { icon: 'add', text: 'Create Problem' });
Nav('homepage', {}, 'homepage');
Nav('problem_main', {}, 'problem', PERM.PERM_VIEW_PROBLEM);
Nav('training_main', {}, 'training', PERM.PERM_VIEW_TRAINING);
Nav('homework_main', {}, 'homework', PERM.PERM_VIEW_HOMEWORK);
Nav('discussion_main', {}, 'discussion', PERM.PERM_VIEW_DISCUSSION);
Nav('contest_main', {}, 'contest', PERM.PERM_VIEW_CONTEST);
Nav('record_main', (handler) => (handler.user.hasPriv(PRIV.PRIV_USER_PROFILE) ? { query: { uidOrName: handler.user._id } } : {}), 'record');
Nav('ranking', {}, 'ranking', PERM.PERM_VIEW_RANKING);
Nav('domain_dashboard', {}, 'domain', PERM.PERM_EDIT_DOMAIN);
Nav('manage_dashboard', {}, 'manage', PRIV.PRIV_EDIT_SYSTEM);
ProblemAdd('problem_create');
global.Hydro.ui.inject = inject;
global.Hydro.ui.nodes = nodes as any;
global.Hydro.ui.getNodes = getNodes;
global.Hydro.ui.Nav = Nav; global.Hydro.ui.Nav = Nav;
global.Hydro.ui.ProblemAdd = ProblemAdd; global.Hydro.ui.ProblemAdd = ProblemAdd;
global.Hydro.ui.UserDropdown = UserDropdown;
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@hydrooj/ui-default", "name": "@hydrooj/ui-default",
"version": "4.40.2", "version": "4.40.3",
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "hydro.js", "main": "hydro.js",
@@ -1,7 +1,7 @@
{%- macro nav_item(target_page_name, target_page_args, target_page_prefix) -%} {%- macro nav_item(target_name, target_args, target_prefix) -%}
<li class="nav__list-item"> <li class="nav__list-item">
<a href="{{ url(target_page_name, target_page_args) }}" class="nav__item{% if page_name.startsWith(target_page_prefix) %} nav--active{% endif %}"> <a href="{{ url(target_name, query=target_args.query(handler) if typeof(target_args.query) == 'function' else target_args.query or {}) }}" class="nav__item{% if page_name.startsWith(target_prefix) %} nav--active{% endif %}">
{{ _(target_page_name) }} {{ _(target_name) }}
</a> </a>
</li> </li>
{%- endmacro -%} {%- endmacro -%}
@@ -10,8 +10,8 @@
<div class="row"><div class="columns clearfix"> <div class="row"><div class="columns clearfix">
<ol class="nav__list nav__list--main clearfix"> <ol class="nav__list nav__list--main clearfix">
<li class="nav__list-item"><a href="/" class="nav__logo" style="background-size: 100% 100%;">&nbsp;</a></li> <li class="nav__list-item"><a href="/" class="nav__logo" style="background-size: 100% 100%;">&nbsp;</a></li>
{%- for item in ui.nodes.nav -%}{% if item.checker(handler) %} {%- for item in ui.getNodes('Nav') -%}{% if item.checker(handler) %}
{{ nav_item(item.name, item.args(handler), item.prefix) }} {{ nav_item(item.name, item.args, item.args.prefix) }}
{% endif %}{%- endfor -%} {% endif %}{%- endfor -%}
</ol> </ol>
<ol class="nav__list nav__list--secondary clearfix"> <ol class="nav__list nav__list--secondary clearfix">
@@ -65,10 +65,10 @@
<h1 class="section__title">{{ _('Create Problem') }}</h1> <h1 class="section__title">{{ _('Create Problem') }}</h1>
</div> </div>
<ol class="menu"> <ol class="menu">
{%- for item in ui.nodes.problem_add -%} {%- for item in ui.getNodes('ProblemAdd') -%}
<a href="{{ url(item.name, item.args) }}" class="menu__link"> <a href="{{ url(item.name, item.args) }}" class="menu__link">
<span class="icon icon-{{ item.icon|default('add') }}"></span> <span class="icon icon-{{ item.args.icon|default('add') }}"></span>
{{ _(item.text) }} {{ _(item.args.text) }}
</a> </a>
{%- endfor -%} {%- endfor -%}
</ol> </ol>