mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
template into ui
This commit is contained in:
1 parent
43ee86d34b
commit
8bb389eedd
13 files changed
+65
-201
No files matched your search
@@ -5,7 +5,6 @@ import { PRIV } from '../model/builtin';
|
|||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import * as file from '../model/file';
|
import * as file from '../model/file';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as markdown from '../lib/markdown';
|
|
||||||
import * as db from '../service/db';
|
import * as db from '../service/db';
|
||||||
import {
|
import {
|
||||||
Route, Handler, Types, param, multipart,
|
Route, Handler, Types, param, multipart,
|
||||||
@@ -103,15 +102,6 @@ class SwitchLanguageHandler extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MarkdownHandler extends Handler {
|
|
||||||
async post({ text, html = false, inline = false }) {
|
|
||||||
this.response.body = inline
|
|
||||||
? markdown.renderInline(text, html)
|
|
||||||
: markdown.render(text, html);
|
|
||||||
this.response.type = 'text/html';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SockToken extends Handler {
|
class SockToken extends Handler {
|
||||||
async get() {
|
async get() {
|
||||||
this.response.body = { token: this.UIContext.token };
|
this.response.body = { token: this.UIContext.token };
|
||||||
@@ -153,7 +143,6 @@ export async function apply() {
|
|||||||
Route('status', '/status', StatusHandler);
|
Route('status', '/status', StatusHandler);
|
||||||
Route('status_update', '/status/update', StatusUpdateHandler);
|
Route('status_update', '/status/update', StatusUpdateHandler);
|
||||||
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
||||||
Route('markdown', '/markdown', MarkdownHandler);
|
|
||||||
Route('token', '/token', SockToken);
|
Route('token', '/token', SockToken);
|
||||||
Route('ui', '/extra.css', UiSettingsHandler);
|
Route('ui', '/extra.css', UiSettingsHandler);
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-6
@@ -238,7 +238,9 @@ class OauthHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OauthCallbackHandler extends Handler {
|
class OauthCallbackHandler extends Handler {
|
||||||
async github({ state, code }) {
|
@param('state', Types.String)
|
||||||
|
@param('code', Types.String)
|
||||||
|
async github(domainId: string, state: string, code: string) {
|
||||||
const [appid, secret, url, proxy, s] = await Promise.all([
|
const [appid, secret, url, proxy, s] = await Promise.all([
|
||||||
system.get('oauth.githubappid'),
|
system.get('oauth.githubappid'),
|
||||||
system.get('oauth.githubsecret'),
|
system.get('oauth.githubsecret'),
|
||||||
@@ -272,13 +274,14 @@ class OauthCallbackHandler extends Handler {
|
|||||||
uname: [userInfo.body.name, userInfo.body.login],
|
uname: [userInfo.body.name, userInfo.body.login],
|
||||||
};
|
};
|
||||||
this.response.redirect = s.redirect;
|
this.response.redirect = s.redirect;
|
||||||
await token.del(s, token.TYPE_OAUTH);
|
await token.del(s._id, token.TYPE_OAUTH);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async google({
|
@param('state', Types.String)
|
||||||
code, error, state,
|
@param('code', Types.String)
|
||||||
}) {
|
@param('error', Types.String)
|
||||||
|
async google(domainId: string, state: string, code: string, error: string) {
|
||||||
if (error) throw new UserFacingError(error);
|
if (error) throw new UserFacingError(error);
|
||||||
const [
|
const [
|
||||||
[appid, secret, url, proxy],
|
[appid, secret, url, proxy],
|
||||||
@@ -308,9 +311,11 @@ class OauthCallbackHandler extends Handler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(args) {
|
async get(args: any) {
|
||||||
let r;
|
let r;
|
||||||
|
// @ts-ignore
|
||||||
if (args.type === 'github') r = await this.github(args);
|
if (args.type === 'github') r = await this.github(args);
|
||||||
|
// @ts-ignore
|
||||||
else if (args.type === 'google') r = await this.google(args);
|
else if (args.type === 'google') r = await this.google(args);
|
||||||
else throw new UserFacingError('Oauth type');
|
else throw new UserFacingError('Oauth type');
|
||||||
const udoc = await user.getByEmail('system', r.email);
|
const udoc = await user.getByEmail('system', r.email);
|
||||||
|
|||||||
+9
-2
@@ -277,6 +277,15 @@ export interface Drrdoc {
|
|||||||
ip: string,
|
ip: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TokenDoc {
|
||||||
|
_id: string,
|
||||||
|
tokenType: number,
|
||||||
|
createAt: Date,
|
||||||
|
updateAt: Date,
|
||||||
|
expireAt: Date,
|
||||||
|
[key: string]: any,
|
||||||
|
}
|
||||||
|
|
||||||
export interface ContestStat extends Dictionary<any> {
|
export interface ContestStat extends Dictionary<any> {
|
||||||
detail: any,
|
detail: any,
|
||||||
}
|
}
|
||||||
@@ -372,7 +381,6 @@ declare global {
|
|||||||
jwt: typeof import('./lib/jwt'),
|
jwt: typeof import('./lib/jwt'),
|
||||||
logger: typeof import('./lib/logger').default,
|
logger: typeof import('./lib/logger').default,
|
||||||
mail: typeof import('./lib/mail'),
|
mail: typeof import('./lib/mail'),
|
||||||
markdown: typeof import('./lib/markdown'),
|
|
||||||
md5: typeof import('./lib/md5').default,
|
md5: typeof import('./lib/md5').default,
|
||||||
misc: typeof import('./lib/misc'),
|
misc: typeof import('./lib/misc'),
|
||||||
nav: typeof import('./lib/nav').default,
|
nav: typeof import('./lib/nav').default,
|
||||||
@@ -382,7 +390,6 @@ declare global {
|
|||||||
testdataConfig: typeof import('./lib/testdataConfig'),
|
testdataConfig: typeof import('./lib/testdataConfig'),
|
||||||
sha1: typeof import('./lib/sha1').default,
|
sha1: typeof import('./lib/sha1').default,
|
||||||
sysinfo: typeof import('./lib/sysinfo'),
|
sysinfo: typeof import('./lib/sysinfo'),
|
||||||
template: typeof import('./lib/template'),
|
|
||||||
'testdata.convert.ini': typeof import('./lib/testdata.convert.ini').default,
|
'testdata.convert.ini': typeof import('./lib/testdata.convert.ini').default,
|
||||||
useragent: typeof import('./lib/useragent'),
|
useragent: typeof import('./lib/useragent'),
|
||||||
validator: typeof import('./lib/validator'),
|
validator: typeof import('./lib/validator'),
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
import MarkdownIt from 'markdown-it';
|
|
||||||
import Prism from 'prismjs';
|
|
||||||
|
|
||||||
// For math: $a\times b\eq 10$
|
|
||||||
// Specific image size: 
|
|
||||||
import Imsize from 'markdown-it-imsize';
|
|
||||||
/* Footnote support.
|
|
||||||
Here is a footnote reference,[^1] and another.[^longnote]
|
|
||||||
|
|
||||||
[^1]: Here is the footnote.
|
|
||||||
|
|
||||||
[^longnote]: Here's one with multiple blocks.
|
|
||||||
|
|
||||||
Subsequent paragraphs are indented to show that they
|
|
||||||
belong to the previous footnote.
|
|
||||||
*/
|
|
||||||
import Footnote from 'markdown-it-footnote';
|
|
||||||
// ==Highlight==
|
|
||||||
import Mark from 'markdown-it-mark';
|
|
||||||
import TOC from 'markdown-it-table-of-contents';
|
|
||||||
import Anchor from 'markdown-it-anchor';
|
|
||||||
|
|
||||||
require('prismjs/components/index');
|
|
||||||
|
|
||||||
type Plugin = MarkdownIt.PluginSimple | MarkdownIt.PluginWithOptions | MarkdownIt.PluginWithParams;
|
|
||||||
|
|
||||||
class Markdown extends MarkdownIt {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
linkify: true,
|
|
||||||
highlight(str, lang) {
|
|
||||||
if (lang && Prism.languages[lang]) {
|
|
||||||
try {
|
|
||||||
return Prism.highlight(str, Prism.languages[lang], lang);
|
|
||||||
} catch (__) { } // eslint-disable-line no-empty
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.linkify.tlds('.py', false);
|
|
||||||
this.use(Imsize);
|
|
||||||
this.use(Footnote);
|
|
||||||
this.use(Mark);
|
|
||||||
this.use(Anchor);
|
|
||||||
this.use(TOC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const md = new Markdown();
|
|
||||||
|
|
||||||
export function plugin(func: Plugin, ...args: any[]) {
|
|
||||||
md.use(func, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function render(text: string, html = false) {
|
|
||||||
md.set({ html: !!html });
|
|
||||||
return md.render(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderInline(text: string, html = false) {
|
|
||||||
md.set({ html: !!html });
|
|
||||||
return md.renderInline(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.lib.markdown = {
|
|
||||||
md, plugin, render, renderInline,
|
|
||||||
};
|
|
||||||
@@ -3,7 +3,7 @@ import { ValidationError } from '../error';
|
|||||||
|
|
||||||
export default async function paginate(
|
export default async function paginate(
|
||||||
cursor: Cursor, page: number, pageSize: number,
|
cursor: Cursor, page: number, pageSize: number,
|
||||||
): Promise<[any[], number, number]> {
|
): Promise<[any[]/* docs */, number/* numPages */, number/* count */]> {
|
||||||
if (page <= 0) throw new ValidationError('page');
|
if (page <= 0) throw new ValidationError('page');
|
||||||
const [count, pageDocs] = await Promise.all([
|
const [count, pageDocs] = await Promise.all([
|
||||||
cursor.count(),
|
cursor.count(),
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import serialize from 'serialize-javascript';
|
|
||||||
import nunjucks from 'nunjucks';
|
|
||||||
import html2text from 'html-to-text';
|
|
||||||
import { argv } from 'yargs';
|
|
||||||
import * as markdown from './markdown';
|
|
||||||
import * as misc from './misc';
|
|
||||||
|
|
||||||
class Loader extends nunjucks.Loader {
|
|
||||||
// eslint-disable-next-line class-methods-use-this
|
|
||||||
getSource(name: string) {
|
|
||||||
if (!argv.template) {
|
|
||||||
if (!global.Hydro.ui.template[name]) throw new Error(`Cannot get template ${name}`);
|
|
||||||
return {
|
|
||||||
src: global.Hydro.ui.template[name],
|
|
||||||
path: name,
|
|
||||||
noCache: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let fullpath = null;
|
|
||||||
const p = path.resolve(process.cwd(), argv.template as string, name);
|
|
||||||
if (fs.existsSync(p)) fullpath = p;
|
|
||||||
if (!fullpath) throw new Error(`Cannot get template ${name}`);
|
|
||||||
return {
|
|
||||||
src: fs.readFileSync(fullpath, 'utf-8').toString(),
|
|
||||||
path: fullpath,
|
|
||||||
noCache: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Nunjucks extends nunjucks.Environment {
|
|
||||||
constructor() {
|
|
||||||
super(new Loader(), { autoescape: true, trimBlocks: true });
|
|
||||||
this.addFilter('json', (self) => JSON.stringify(self), false);
|
|
||||||
this.addFilter('serialize', (self, ignoreFunction = true) => serialize(self, { ignoreFunction }));
|
|
||||||
this.addFilter('assign', (self, data) => Object.assign(self, data));
|
|
||||||
this.addFilter('markdown', (self, html = false) => markdown.render(self, html));
|
|
||||||
this.addFilter('ansi', (self) => misc.ansiToHtml(self));
|
|
||||||
this.addFilter('inline', (self) => html2text.fromString(self).replace(/\n/gmi, ' '));
|
|
||||||
this.addFilter('base64_encode', (s) => Buffer.from(s).toString('base64'));
|
|
||||||
this.addFilter('bitand', (self, val) => self & val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const env = new Nunjucks();
|
|
||||||
|
|
||||||
export async function render(name: string, state: any): Promise<string> {
|
|
||||||
const cdnPrefix = await global.Hydro.model.system.get('server.cdn');
|
|
||||||
return await new Promise((resolve, reject) => {
|
|
||||||
env.render(name, {
|
|
||||||
page_name: name.split('.')[0],
|
|
||||||
...state,
|
|
||||||
typeof: (o) => typeof o,
|
|
||||||
static_url: (assetName: string) => {
|
|
||||||
if (global.Hydro.ui.manifest[assetName]) {
|
|
||||||
return `${cdnPrefix}${global.Hydro.ui.manifest[assetName]}`;
|
|
||||||
}
|
|
||||||
return `${cdnPrefix}${assetName}`;
|
|
||||||
},
|
|
||||||
datetimeSpan: misc.datetimeSpan,
|
|
||||||
paginate: misc.paginate,
|
|
||||||
perm: global.Hydro.model.builtin.PERM,
|
|
||||||
PRIV: global.Hydro.model.builtin.PRIV,
|
|
||||||
STATUS: global.Hydro.model.builtin.STATUS,
|
|
||||||
size: misc.size,
|
|
||||||
gravatar: misc.gravatar,
|
|
||||||
model: global.Hydro.model,
|
|
||||||
Context: global.Hydro.ui,
|
|
||||||
isIE: (str: string) => str.includes('MSIE') || str.includes('rv:11.0'),
|
|
||||||
}, (err, res) => {
|
|
||||||
if (err) reject(err);
|
|
||||||
else resolve(res);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.lib.template = { render };
|
|
||||||
@@ -6,7 +6,6 @@ import * as problem from './problem';
|
|||||||
import {
|
import {
|
||||||
Rdoc, TestCase, PretestConfig, ContestInfo, ProblemConfig,
|
Rdoc, TestCase, PretestConfig, ContestInfo, ProblemConfig,
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
import { RecordNotFoundError } from '../error';
|
|
||||||
import * as db from '../service/db';
|
import * as db from '../service/db';
|
||||||
|
|
||||||
const coll = db.collection('record');
|
const coll = db.collection('record');
|
||||||
@@ -48,7 +47,9 @@ export interface JudgeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function get(domainId: string, _id: ObjectID): Promise<Rdoc | null> {
|
export async function get(domainId: string, _id: ObjectID): Promise<Rdoc | null> {
|
||||||
return await coll.findOne({ domainId, _id });
|
const res = await coll.findOne({ _id });
|
||||||
|
if (res && res.domainId === domainId) return res;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function judge(domainId: string, rid: ObjectID) {
|
export async function judge(domainId: string, rid: ObjectID) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { TokenDoc } from '../interface';
|
||||||
import * as db from '../service/db';
|
import * as db from '../service/db';
|
||||||
|
|
||||||
const coll = db.collection('token');
|
const coll = db.collection('token');
|
||||||
@@ -16,7 +17,9 @@ function ensureIndexes() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function add(tokenType: number, expireSeconds: number, data: any) {
|
export async function add(
|
||||||
|
tokenType: number, expireSeconds: number, data: any,
|
||||||
|
): Promise<[string, TokenDoc]> {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const str = String.random(32);
|
const str = String.random(32);
|
||||||
const res = await coll.insertOne({
|
const res = await coll.insertOne({
|
||||||
@@ -30,9 +33,8 @@ export async function add(tokenType: number, expireSeconds: number, data: any) {
|
|||||||
return [str, res.ops[0]];
|
return [str, res.ops[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(tokenId: string, tokenType: number) {
|
export async function get(tokenId: string, tokenType: number): Promise<TokenDoc | null> {
|
||||||
const res = await coll.findOne({ _id: tokenId, tokenType });
|
return await coll.findOne({ _id: tokenId, tokenType });
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(
|
export async function update(
|
||||||
@@ -73,11 +75,11 @@ export async function createOrUpdate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getSessionListByUid(uid: number) {
|
export function getSessionListByUid(uid: number) {
|
||||||
return coll.find({ uid, tokenType: this.TYPE_SESSION }).sort('updateAt', -1).toArray();
|
return coll.find({ uid, tokenType: TYPE_SESSION }).sort('updateAt', -1).toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMostRecentSessionByUid(uid: number) {
|
export function getMostRecentSessionByUid(uid: number) {
|
||||||
return coll.findOne({ uid, tokenType: this.TYPE_SESSION }, { sort: { updateAt: -1 } });
|
return coll.findOne({ uid, tokenType: TYPE_SESSION }, { sort: { updateAt: -1 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function delByUid(uid: number) {
|
export function delByUid(uid: number) {
|
||||||
|
|||||||
+2
-2
@@ -199,7 +199,7 @@ export async function create(
|
|||||||
return uid;
|
return uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMulti(params) {
|
export function getMulti(params: any) {
|
||||||
return coll.find(params);
|
return coll.find(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ export async function getPrefixList(prefix: string, limit = 50) {
|
|||||||
return udocs;
|
return udocs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setPriv(uid: number, priv: number) {
|
export async function setPriv(uid: number, priv: number): Promise<Udoc | null> {
|
||||||
const udoc = await coll.findOneAndUpdate(
|
const udoc = await coll.findOneAndUpdate(
|
||||||
{ _id: uid },
|
{ _id: uid },
|
||||||
{ $set: { priv } },
|
{ $set: { priv } },
|
||||||
|
|||||||
+27
-22
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { NumericDictionary, filter } from 'lodash';
|
import { NumericDictionary } from 'lodash';
|
||||||
import { ObjectID } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { Tdoc, Pdoc } from '../interface';
|
import { Tdoc, Pdoc } from '../interface';
|
||||||
import * as domain from '../model/domain';
|
import * as domain from '../model/domain';
|
||||||
@@ -8,23 +8,12 @@ import * as problem from '../model/problem';
|
|||||||
import * as record from '../model/record';
|
import * as record from '../model/record';
|
||||||
import { STATUS } from '../model/builtin';
|
import { STATUS } from '../model/builtin';
|
||||||
import rating from '../lib/rating';
|
import rating from '../lib/rating';
|
||||||
|
import paginate from '../lib/paginate';
|
||||||
|
|
||||||
export const description = 'Calculate rp of a domain, or all domains';
|
export const description = 'Calculate rp of a domain, or all domains';
|
||||||
|
|
||||||
type ND = NumericDictionary<number>
|
type ND = NumericDictionary<number>
|
||||||
|
|
||||||
function calc(udict: ND, rankedDocs: [number, number][]) {
|
|
||||||
const users = [];
|
|
||||||
for (const [rk, uid] of rankedDocs) {
|
|
||||||
users.push({ uid, rank: rk, old: udict[uid] || 1500 });
|
|
||||||
}
|
|
||||||
// FIXME sum(rating.new) always less than sum(rating.old)
|
|
||||||
const rated = rating(users);
|
|
||||||
for (const udoc of rated) {
|
|
||||||
udict[udoc.uid] = udoc.new;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runProblem(pdoc: Pdoc, udict: ND): Promise<void>
|
async function runProblem(pdoc: Pdoc, udict: ND): Promise<void>
|
||||||
async function runProblem(domainId: string, pid: number, udict: ND): Promise<void>
|
async function runProblem(domainId: string, pid: number, udict: ND): Promise<void>
|
||||||
async function runProblem(...arg: any[]) {
|
async function runProblem(...arg: any[]) {
|
||||||
@@ -32,13 +21,26 @@ async function runProblem(...arg: any[]) {
|
|||||||
? await problem.get(arg[0], arg[1], -1)
|
? await problem.get(arg[0], arg[1], -1)
|
||||||
: arg[0];
|
: arg[0];
|
||||||
const udict: ND = (typeof arg[0] === 'string') ? arg[2] : arg[1];
|
const udict: ND = (typeof arg[0] === 'string') ? arg[2] : arg[1];
|
||||||
const psdocs = await problem.getMultiStatus(
|
const [, nPages] = await paginate(
|
||||||
|
problem.getMultiStatus(
|
||||||
pdoc.domainId, { docId: pdoc.docId, rid: { $ne: null } },
|
pdoc.domainId, { docId: pdoc.docId, rid: { $ne: null } },
|
||||||
).toArray();
|
),
|
||||||
if (!psdocs.length) return;
|
1,
|
||||||
const rdict = await record.getList(pdoc.domainId, psdocs.map((psdoc) => psdoc.rid), true);
|
100,
|
||||||
const nAccept = filter(psdocs, (psdoc) => psdoc.status === STATUS.STATUS_ACCEPTED).length;
|
);
|
||||||
|
const nAccept = await problem.getMultiStatus(
|
||||||
|
pdoc.domainId, { docId: pdoc.docId, status: STATUS.STATUS_ACCEPTED },
|
||||||
|
).count();
|
||||||
const p = (pdoc.difficulty || 5) / (Math.sqrt(Math.sqrt(nAccept)) + 1);
|
const p = (pdoc.difficulty || 5) / (Math.sqrt(Math.sqrt(nAccept)) + 1);
|
||||||
|
for (let page = 1; page <= nPages; page++) {
|
||||||
|
const [psdocs] = await paginate(
|
||||||
|
problem.getMultiStatus(
|
||||||
|
pdoc.domainId, { docId: pdoc.docId, rid: { $ne: null } },
|
||||||
|
),
|
||||||
|
page,
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
const rdict = await record.getList(pdoc.domainId, psdocs.map((psdoc) => psdoc.rid), true);
|
||||||
for (const psdoc of psdocs) {
|
for (const psdoc of psdocs) {
|
||||||
if (rdict[psdoc.rid]) {
|
if (rdict[psdoc.rid]) {
|
||||||
const rp = rdict[psdoc.rid].score * p;
|
const rp = rdict[psdoc.rid].score * p;
|
||||||
@@ -46,6 +48,7 @@ async function runProblem(...arg: any[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function runContest(tdoc: Tdoc, udict: ND, report: Function): Promise<void>
|
async function runContest(tdoc: Tdoc, udict: ND, report: Function): Promise<void>
|
||||||
async function runContest(
|
async function runContest(
|
||||||
@@ -62,11 +65,13 @@ async function runContest(...arg: any[]) {
|
|||||||
.sort(contest.RULES[tdoc.rule].statusSort).toArray();
|
.sort(contest.RULES[tdoc.rule].statusSort).toArray();
|
||||||
if (!tsdocs.length) return;
|
if (!tsdocs.length) return;
|
||||||
const rankedTsdocs = contest.RULES[tdoc.rule].rank(tsdocs);
|
const rankedTsdocs = contest.RULES[tdoc.rule].rank(tsdocs);
|
||||||
const ranked = [];
|
const users = [];
|
||||||
for (const result of rankedTsdocs) {
|
for (const result of rankedTsdocs) {
|
||||||
ranked.push([result[0], result[1].uid]);
|
users.push({ uid: result[1].uid, rank: result[0], old: udict[result[1].uid] || 1500 });
|
||||||
}
|
}
|
||||||
calc(udict, ranked);
|
// FIXME sum(rating.new) always less than sum(rating.old)
|
||||||
|
const rated = rating(users);
|
||||||
|
for (const udoc of rated) udict[udoc.uid] = udoc.new;
|
||||||
await report({
|
await report({
|
||||||
case: {
|
case: {
|
||||||
status: STATUS.STATUS_ACCEPTED,
|
status: STATUS.STATUS_ACCEPTED,
|
||||||
@@ -79,7 +84,6 @@ async function runContest(...arg: any[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function runInDomain(domainId: string, isSub: boolean, report: Function) {
|
async function runInDomain(domainId: string, isSub: boolean, report: Function) {
|
||||||
await domain.setMultiUserInDomain(domainId, {}, { rp: 1500 });
|
|
||||||
const udict: ND = {};
|
const udict: ND = {};
|
||||||
const contests = await contest.getMulti(domainId, { rated: true }, -1).sort('endAt', -1).toArray();
|
const contests = await contest.getMulti(domainId, { rated: true }, -1).sort('endAt', -1).toArray();
|
||||||
await report({ message: `Found ${contests.length} contests in ${domainId}` });
|
await report({ message: `Found ${contests.length} contests in ${domainId}` });
|
||||||
@@ -104,6 +108,7 @@ async function runInDomain(domainId: string, isSub: boolean, report: Function) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await domain.setMultiUserInDomain(domainId, {}, { rp: 1500 });
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
for (const uid in udict) {
|
for (const uid in udict) {
|
||||||
tasks.push(domain.setUserInDomain(domainId, parseInt(uid, 10), { rp: udict[uid] }));
|
tasks.push(domain.setUserInDomain(domainId, parseInt(uid, 10), { rp: udict[uid] }));
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// TODO add a set_priv interface
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import { PRIV } from '../model/builtin';
|
import { PRIV } from '../model/builtin';
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import {
|
|||||||
CsrfTokenError, InvalidOperationError, MethodNotAllowedError,
|
CsrfTokenError, InvalidOperationError, MethodNotAllowedError,
|
||||||
NotFoundError, HydroError,
|
NotFoundError, HydroError,
|
||||||
} from '../error';
|
} from '../error';
|
||||||
import { render } from '../lib/template';
|
|
||||||
import hash from '../lib/hash.hydro';
|
import hash from '../lib/hash.hydro';
|
||||||
import * as misc from '../lib/misc';
|
import * as misc from '../lib/misc';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
@@ -276,7 +275,7 @@ export class Handler {
|
|||||||
gravatar: misc.gravatar(this.user.gravatar || '', 128),
|
gravatar: misc.gravatar(this.user.gravatar || '', 128),
|
||||||
perm: this.user.perm.toString(),
|
perm: this.user.perm.toString(),
|
||||||
};
|
};
|
||||||
const res = await render(name, {
|
const res = await global.Hydro.lib.template.render(name, {
|
||||||
handler: this,
|
handler: this,
|
||||||
UserContext,
|
UserContext,
|
||||||
url: this.url.bind(this),
|
url: this.url.bind(this),
|
||||||
@@ -615,7 +614,7 @@ export class ConnectionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async renderHTML(name: string, context: any): Promise<string> {
|
async renderHTML(name: string, context: any): Promise<string> {
|
||||||
const res = await render(name, Object.assign(context, {
|
const res = await global.Hydro.lib.template.render(name, Object.assign(context, {
|
||||||
handler: this,
|
handler: this,
|
||||||
url: this.url.bind(this),
|
url: this.url.bind(this),
|
||||||
_: this.translate.bind(this),
|
_: this.translate.bind(this),
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.11.1",
|
"version": "2.11.2",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
Reference in new issue
Block a user