mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core: move lib/misc to ui
This commit is contained in:
1 parent
08462cf870
commit
baab7bb68c
10 files changed
+62
-69
No files matched your search
@@ -16,7 +16,6 @@
|
|||||||
"@hydrooj/utils": "workspace:*",
|
"@hydrooj/utils": "workspace:*",
|
||||||
"adm-zip": "0.5.5",
|
"adm-zip": "0.5.5",
|
||||||
"ajv": "^8.11.0",
|
"ajv": "^8.11.0",
|
||||||
"ansi_up": "^5.1.0",
|
|
||||||
"cac": "^6.7.12",
|
"cac": "^6.7.12",
|
||||||
"cookies": "^0.8.0",
|
"cookies": "^0.8.0",
|
||||||
"detect-browser": "^5.3.0",
|
"detect-browser": "^5.3.0",
|
||||||
|
|||||||
@@ -376,6 +376,7 @@ export class ContestFilesHandler extends ContestDetailBaseHandler {
|
|||||||
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_CONTEST);
|
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_CONTEST);
|
||||||
const body = {
|
const body = {
|
||||||
tdoc: this.tdoc,
|
tdoc: this.tdoc,
|
||||||
|
tsdoc: this.tsdoc,
|
||||||
owner_udoc: await user.getById(domainId, this.tdoc.owner),
|
owner_udoc: await user.getById(domainId, this.tdoc.owner),
|
||||||
files: sortFiles(this.tdoc.files || []),
|
files: sortFiles(this.tdoc.files || []),
|
||||||
urlForFile: (filename: string) => this.url('contest_file_download', { tid, filename }),
|
urlForFile: (filename: string) => this.url('contest_file_download', { tid, filename }),
|
||||||
|
|||||||
@@ -666,7 +666,6 @@ export interface Lib extends Record<string, any> {
|
|||||||
mail: typeof import('./lib/mail'),
|
mail: typeof import('./lib/mail'),
|
||||||
md5: typeof import('./lib/crypto').md5,
|
md5: typeof import('./lib/crypto').md5,
|
||||||
sha1: typeof import('./lib/crypto').sha1,
|
sha1: typeof import('./lib/crypto').sha1,
|
||||||
misc: typeof import('./lib/misc'),
|
|
||||||
paginate: typeof import('./lib/paginate'),
|
paginate: typeof import('./lib/paginate'),
|
||||||
rank: typeof import('./lib/rank'),
|
rank: typeof import('./lib/rank'),
|
||||||
rating: typeof import('./lib/rating'),
|
rating: typeof import('./lib/rating'),
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import './i18n';
|
|||||||
import './mail';
|
import './mail';
|
||||||
import './useragent';
|
import './useragent';
|
||||||
import './crypto';
|
import './crypto';
|
||||||
import './misc';
|
|
||||||
import './paginate';
|
import './paginate';
|
||||||
import './hash.hydro';
|
import './hash.hydro';
|
||||||
import './rank';
|
import './rank';
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import AnsiUp from 'ansi_up';
|
|
||||||
import moment from 'moment-timezone';
|
|
||||||
import { ObjectID } from 'mongodb';
|
|
||||||
import { formatSeconds, size } from '@hydrooj/utils/lib/utils';
|
|
||||||
|
|
||||||
export { size, formatSeconds } from '@hydrooj/utils/lib/utils';
|
|
||||||
|
|
||||||
const AU = new AnsiUp();
|
|
||||||
|
|
||||||
export function ansiToHtml(str: string, whiteToBlack = true) {
|
|
||||||
const res = AU.ansi_to_html(str);
|
|
||||||
return whiteToBlack ? res.replace(/style="color:rgb\(255,255,255\)"/g, 'style="color:black"') : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function datetimeSpan(dt: Date | ObjectID, relative = true, format = 'YYYY-M-D H:mm:ss', tz = 'Asia/Shanghai') {
|
|
||||||
if (!dt) return 'DATETIME_SPAN_ERROR';
|
|
||||||
if (dt instanceof ObjectID) dt = new Date(dt.generationTime * 1000);
|
|
||||||
else if (typeof dt === 'string' && ObjectID.isValid(dt)) dt = new Date(new ObjectID(dt).generationTime * 1000);
|
|
||||||
else if (typeof dt === 'number' || typeof dt === 'string') dt = new Date(dt);
|
|
||||||
return '<span class="time{0}" data-timestamp="{1}">{2}</span>'.format(
|
|
||||||
relative ? ' relative' : '',
|
|
||||||
dt.getTime() / 1000,
|
|
||||||
moment(dt).tz(tz).format(format),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function* paginate(page: number, numPages: number) {
|
|
||||||
const radius = 5;
|
|
||||||
let first: number;
|
|
||||||
let last: number;
|
|
||||||
if (page > 1) {
|
|
||||||
if (page > 2) yield ['first', 1];
|
|
||||||
yield ['previous', page - 1];
|
|
||||||
}
|
|
||||||
if (page <= radius) [first, last] = [1, Math.min(1 + radius * 2, numPages)];
|
|
||||||
else if (page >= numPages - radius) {
|
|
||||||
[first, last] = [Math.max(1, numPages - radius * 2), numPages];
|
|
||||||
} else {
|
|
||||||
[first, last] = [page - radius, page + radius];
|
|
||||||
}
|
|
||||||
if (first > 1) yield ['ellipsis', 0];
|
|
||||||
for (let page0 = first; page0 < last + 1; page0++) {
|
|
||||||
if (page0 !== page) yield ['page', page0];
|
|
||||||
else yield ['current', page];
|
|
||||||
}
|
|
||||||
if (last < numPages) yield ['ellipsis', 0];
|
|
||||||
if (page < numPages) {
|
|
||||||
yield ['next', page + 1];
|
|
||||||
if (page < numPages - 1) yield ['last', numPages];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.lib.misc = {
|
|
||||||
datetimeSpan, paginate, size, formatSeconds, ansiToHtml,
|
|
||||||
};
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FilterQuery, ObjectID } from 'mongodb';
|
import { FilterQuery, ObjectID } from 'mongodb';
|
||||||
import { Counter, Time } from '@hydrooj/utils/lib/utils';
|
import { Counter, formatSeconds, Time } from '@hydrooj/utils/lib/utils';
|
||||||
import {
|
import {
|
||||||
ContestAlreadyAttendedError, ContestNotAttendedError, ContestNotFoundError,
|
ContestAlreadyAttendedError, ContestNotAttendedError, ContestNotFoundError,
|
||||||
ContestScoreboardHiddenError, ValidationError,
|
ContestScoreboardHiddenError, ValidationError,
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
ScoreboardNode, ScoreboardRow, Tdoc,
|
ScoreboardNode, ScoreboardRow, Tdoc,
|
||||||
Udict,
|
Udict,
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
import * as misc from '../lib/misc';
|
|
||||||
import ranked from '../lib/rank';
|
import ranked from '../lib/rank';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import type { Handler } from '../service/server';
|
import type { Handler } from '../service/server';
|
||||||
@@ -142,13 +141,13 @@ const acm = buildContestRule({
|
|||||||
if (isExport) row.push({ type: 'email', value: udict[tsdoc.uid].mail });
|
if (isExport) row.push({ type: 'email', value: udict[tsdoc.uid].mail });
|
||||||
row.push({
|
row.push({
|
||||||
type: 'time',
|
type: 'time',
|
||||||
value: `${tsdoc.accept || 0}\n${misc.formatSeconds(tsdoc.time || 0.0, false)}`,
|
value: `${tsdoc.accept || 0}\n${formatSeconds(tsdoc.time || 0.0, false)}`,
|
||||||
hover: misc.formatSeconds(tsdoc.time || 0.0),
|
hover: formatSeconds(tsdoc.time || 0.0),
|
||||||
});
|
});
|
||||||
for (const pid of tdoc.pids) {
|
for (const pid of tdoc.pids) {
|
||||||
const doc = tsddict[pid] || {} as Partial<AcmDetail>;
|
const doc = tsddict[pid] || {} as Partial<AcmDetail>;
|
||||||
const accept = doc.status === STATUS.STATUS_ACCEPTED;
|
const accept = doc.status === STATUS.STATUS_ACCEPTED;
|
||||||
const colTime = accept ? misc.formatSeconds(doc.real, false).toString() : '';
|
const colTime = accept ? formatSeconds(doc.real, false).toString() : '';
|
||||||
const colPenalty = doc.rid ? Math.ceil(doc.penalty / 60).toString() : '';
|
const colPenalty = doc.rid ? Math.ceil(doc.penalty / 60).toString() : '';
|
||||||
if (isExport) {
|
if (isExport) {
|
||||||
row.push(
|
row.push(
|
||||||
@@ -164,7 +163,7 @@ const acm = buildContestRule({
|
|||||||
: doc.rid
|
: doc.rid
|
||||||
? `-${doc.naccept}`
|
? `-${doc.naccept}`
|
||||||
: '',
|
: '',
|
||||||
hover: accept ? misc.formatSeconds(doc.time) : '',
|
hover: accept ? formatSeconds(doc.time) : '',
|
||||||
raw: doc.rid,
|
raw: doc.rid,
|
||||||
style: accept && doc.rid.generationTime === first[pid]
|
style: accept && doc.rid.generationTime === first[pid]
|
||||||
? 'background-color: rgb(217, 240, 199);'
|
? 'background-color: rgb(217, 240, 199);'
|
||||||
@@ -406,13 +405,13 @@ const homework = buildContestRule({
|
|||||||
if (isExport) {
|
if (isExport) {
|
||||||
row.push({ type: 'string', value: tsdoc.score || 0 });
|
row.push({ type: 'string', value: tsdoc.score || 0 });
|
||||||
}
|
}
|
||||||
row.push({ type: 'time', value: misc.formatSeconds(tsdoc.time || 0, false), raw: tsdoc.time });
|
row.push({ type: 'time', value: formatSeconds(tsdoc.time || 0, false), raw: tsdoc.time });
|
||||||
for (const pid of tdoc.pids) {
|
for (const pid of tdoc.pids) {
|
||||||
const rid = tsddict[pid]?.rid;
|
const rid = tsddict[pid]?.rid;
|
||||||
const colScore = tsddict[pid]?.penaltyScore || '';
|
const colScore = tsddict[pid]?.penaltyScore || '';
|
||||||
const colOriginalScore = tsddict[pid]?.score || '';
|
const colOriginalScore = tsddict[pid]?.score || '';
|
||||||
const colTime = tsddict[pid]?.time || '';
|
const colTime = tsddict[pid]?.time || '';
|
||||||
const colTimeStr = colTime ? misc.formatSeconds(colTime, false) : '';
|
const colTimeStr = colTime ? formatSeconds(colTime, false) : '';
|
||||||
if (isExport) {
|
if (isExport) {
|
||||||
row.push(
|
row.push(
|
||||||
{ type: 'string', value: colScore },
|
{ type: 'string', value: colScore },
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import moment from 'moment';
|
|||||||
import { GridFSBucket, ObjectID } from 'mongodb';
|
import { GridFSBucket, ObjectID } from 'mongodb';
|
||||||
import Queue from 'p-queue';
|
import Queue from 'p-queue';
|
||||||
import { convertIniConfig } from '@hydrooj/utils/lib/cases';
|
import { convertIniConfig } from '@hydrooj/utils/lib/cases';
|
||||||
|
import { size } from '@hydrooj/utils/lib/utils';
|
||||||
import { buildContent } from './lib/content';
|
import { buildContent } from './lib/content';
|
||||||
import { size } from './lib/misc';
|
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
import { PRIV, STATUS } from './model/builtin';
|
import { PRIV, STATUS } from './model/builtin';
|
||||||
import * as contest from './model/contest';
|
import * as contest from './model/contest';
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import AnsiUp from 'ansi_up';
|
||||||
|
import moment from 'moment-timezone';
|
||||||
|
import { ObjectID } from 'mongodb';
|
||||||
|
|
||||||
|
export { size, formatSeconds } from '@hydrooj/utils/lib/utils';
|
||||||
|
|
||||||
|
const AU = new AnsiUp();
|
||||||
|
|
||||||
|
export function ansiToHtml(str: string, whiteToBlack = true) {
|
||||||
|
const res = AU.ansi_to_html(str);
|
||||||
|
return whiteToBlack ? res.replace(/style="color:rgb\(255,255,255\)"/g, 'style="color:black"') : res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function datetimeSpan(dt: Date | ObjectID, relative = true, format = 'YYYY-M-D H:mm:ss', tz = 'Asia/Shanghai') {
|
||||||
|
if (!dt) return 'DATETIME_SPAN_ERROR';
|
||||||
|
if (dt instanceof ObjectID) dt = new Date(dt.generationTime * 1000);
|
||||||
|
else if (typeof dt === 'string' && ObjectID.isValid(dt)) dt = new Date(new ObjectID(dt).generationTime * 1000);
|
||||||
|
else if (typeof dt === 'number' || typeof dt === 'string') dt = new Date(dt);
|
||||||
|
return '<span class="time{0}" data-timestamp="{1}">{2}</span>'.format(
|
||||||
|
relative ? ' relative' : '',
|
||||||
|
dt.getTime() / 1000,
|
||||||
|
moment(dt).tz(tz).format(format),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* paginate(page: number, numPages: number) {
|
||||||
|
const radius = 5;
|
||||||
|
let first: number;
|
||||||
|
let last: number;
|
||||||
|
if (page > 1) {
|
||||||
|
if (page > 2) yield ['first', 1];
|
||||||
|
yield ['previous', page - 1];
|
||||||
|
}
|
||||||
|
if (page <= radius) [first, last] = [1, Math.min(1 + radius * 2, numPages)];
|
||||||
|
else if (page >= numPages - radius) {
|
||||||
|
[first, last] = [Math.max(1, numPages - radius * 2), numPages];
|
||||||
|
} else {
|
||||||
|
[first, last] = [page - radius, page + radius];
|
||||||
|
}
|
||||||
|
if (first > 1) yield ['ellipsis', 0];
|
||||||
|
for (let page0 = first; page0 < last + 1; page0++) {
|
||||||
|
if (page0 !== page) yield ['page', page0];
|
||||||
|
else yield ['current', page];
|
||||||
|
}
|
||||||
|
if (last < numPages) yield ['ellipsis', 0];
|
||||||
|
if (page < numPages) {
|
||||||
|
yield ['next', page + 1];
|
||||||
|
if (page < numPages - 1) yield ['last', numPages];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,8 +9,9 @@ const { findFileSync } = require('@hydrooj/utils/lib/utils');
|
|||||||
const status = require('@hydrooj/utils/lib/status');
|
const status = require('@hydrooj/utils/lib/status');
|
||||||
const markdown = require('./markdown');
|
const markdown = require('./markdown');
|
||||||
const { xss, ensureTag } = require('./markdown-it-xss');
|
const { xss, ensureTag } = require('./markdown-it-xss');
|
||||||
|
const misc = require('./misc');
|
||||||
|
|
||||||
const { misc, buildContent, avatar } = global.Hydro.lib;
|
const { buildContent, avatar } = global.Hydro.lib;
|
||||||
|
|
||||||
let { template } = argv.options;
|
let { template } = argv.options;
|
||||||
if (template && typeof template !== 'string') template = findFileSync('@hydrooj/ui-default/templates');
|
if (template && typeof template !== 'string') template = findFileSync('@hydrooj/ui-default/templates');
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"@types/qrcode": "^1.4.2",
|
"@types/qrcode": "^1.4.2",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/redux-logger": "^3.0.9",
|
"@types/redux-logger": "^3.0.9",
|
||||||
"ansi_up": "^5.1.0",
|
|
||||||
"autoprefixer": "^9.8.8",
|
"autoprefixer": "^9.8.8",
|
||||||
"browser-update": "^3.3.38",
|
"browser-update": "^3.3.38",
|
||||||
"chalk": "^5.0.1",
|
"chalk": "^5.0.1",
|
||||||
@@ -112,6 +111,7 @@
|
|||||||
"webpackbar": "^5.0.2"
|
"webpackbar": "^5.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ansi_up": "^5.1.0",
|
||||||
"esbuild": "0.14.3",
|
"esbuild": "0.14.3",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
|||||||
Reference in new issue
Block a user