diff --git a/packages/hydrooj/TODO b/packages/hydrooj/TODO index f4bd774bd..dc5ac8aab 100644 --- a/packages/hydrooj/TODO +++ b/packages/hydrooj/TODO @@ -1,7 +1,11 @@ @requireCsrfToken -discussion前端权限节点显示异常? 举报功能 SETTINGS_PRIVACY.allowRegisteredUsers model.setting.ui.name pdoc.secretConfig? message.markAsRead +批量导入用户 +domain_join_application +user.displayName +problem.difficulty_setting +用户等级计算 \ No newline at end of file diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 98590808a..03342fd89 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.12.3", + "version": "2.12.4", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/src/entry/common.ts b/packages/hydrooj/src/entry/common.ts index 16bf59eac..87867954a 100644 --- a/packages/hydrooj/src/entry/common.ts +++ b/packages/hydrooj/src/entry/common.ts @@ -26,8 +26,7 @@ export const builtinHandler = [ ]; export const builtinScript = [ - 'rating', 'register', 'problemStat', 'blacklist', 'setSuperadmin', - 'deleteUser', + 'rating', 'register', 'problemStat', 'blacklist', 'deleteUser', 'upgrade0_1', ]; diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 2a4aa0eb4..2b02ed2e2 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -34,9 +34,11 @@ export const DOMAIN_USER_SETTINGS_BY_KEY: SettingDict = {}; export const DOMAIN_SETTINGS_BY_KEY: SettingDict = {}; export const SYSTEM_SETTINGS_BY_KEY: SettingDict = {}; +export type SettingType = 'text' | 'number' | 'markdown' | 'password' | 'select' | 'boolean' | 'textarea'; + export const Setting = ( family: string, key: string, range: Array<[string, string]> | Dictionary = null, - value: any = null, type = 'text', name = '', + value: any = null, type: SettingType = 'text', name = '', desc = '', flag = 0, ): _Setting => ({ family, key, range, value, type, name, desc, flag, @@ -103,11 +105,12 @@ DomainSetting( ); DomainUserSetting( - Setting('setting_info', 'displayName', null, null, 'string', 'display name'), + Setting('setting_info', 'displayName', null, null, 'text', 'display name'), Setting('setting_storage', 'nAccept', null, 0, 'number', 'nAccept', null, FLAG_HIDDEN | FLAG_DISABLED), Setting('setting_storage', 'nSubmit', null, 0, 'number', 'nSubmit', null, FLAG_HIDDEN | FLAG_DISABLED), Setting('setting_storage', 'nLike', null, 0, 'number', 'nLike', null, FLAG_HIDDEN | FLAG_DISABLED), Setting('setting_storage', 'rp', null, 1500, 'number', 'RP', null, FLAG_HIDDEN | FLAG_DISABLED), + Setting('setting_storage', 'level', null, 0, 'number', 'level', null, FLAG_HIDDEN | FLAG_DISABLED), ); SystemSetting( diff --git a/packages/hydrooj/src/model/user.ts b/packages/hydrooj/src/model/user.ts index 4340c1572..0c12ff6aa 100644 --- a/packages/hydrooj/src/model/user.ts +++ b/packages/hydrooj/src/model/user.ts @@ -54,7 +54,7 @@ export class User implements _User { [key: string]: any; - constructor(udoc, dudoc) { + constructor(udoc: Udoc, dudoc) { this.udoc = () => udoc; this.dudoc = () => dudoc; this._id = udoc._id; @@ -223,6 +223,16 @@ export async function setPriv(uid: number, priv: number): Promise { return udoc.value; } +export async function setSuperAdmin(uid: number) { + await setPriv(uid, PRIV.PRIV_ALL); + return uid; +} + +export async function setJudge(uid: number) { + await setPriv(uid, PRIV.PRIV_JUDGE); + return uid; +} + export function ban(uid: number) { return Promise.all([ setPriv(uid, PRIV.PRIV_NONE), @@ -252,5 +262,7 @@ global.Hydro.model.user = { getPrefixList, setPriv, getList, + setSuperAdmin, + setJudge, ban, }; diff --git a/packages/hydrooj/src/script/rating.ts b/packages/hydrooj/src/script/rating.ts index 30230b94f..0573d2a56 100644 --- a/packages/hydrooj/src/script/rating.ts +++ b/packages/hydrooj/src/script/rating.ts @@ -9,6 +9,7 @@ import * as record from '../model/record'; import { STATUS } from '../model/builtin'; import rating from '../lib/rating'; import paginate from '../lib/paginate'; +import ranked from '../lib/rank'; export const description = 'Calculate rp of a domain, or all domains'; @@ -83,6 +84,41 @@ async function runContest(...arg: any[]) { }); } +export async function calcLevel(domainId: string, report: Function) { + const dudocs = await domain.getMultiInDomain(domainId).sort('rp', -1).toArray(); + let last = { rp: null }; + let rank = 0; + let count = 0; + const coll = global.Hydro.service.db.collection('domain.user'); + let bulk = coll.initializeUnorderedBulkOp(); + for (const dudoc of dudocs) { + count++; + if (!dudoc.rp) dudoc.rp = null; + if (dudoc.rp !== last.rp) rank = count; + bulk.find({ _id: dudoc._id }).updateOne({ $set: { rank } }); + last = dudoc; + if (count % 1000 === 0) report({ message: `#${count}: Rank ${rank}` }); + await bulk.execute(); + } + if (!rank) { + report({ message: 'No one has rp' }); + return; + } + const levels = global.Hydro.model.builtin.LEVELS; + bulk = coll.initializeUnorderedBulkOp(); + for (let i = 0; i < levels.length; i++) { + report({ message: 'Updating users levelled {0}'.format(levels[i][0]) }); + bulk.find({ + domainId, + $and: [{ rank: { $lte: levels[i][1] } }, { rank: { $gt: levels[i + 1][1] } }], + }).update({ $set: { level: levels[i][0] } }); + } + const i = levels.length - 1; + report({ message: 'Updating users levelled {0}'.format(levels[i][0]) }); + bulk.find({ domainId, rank: { $lte: levels[i][1] } }).update({ $set: { level: levels[i][0] } }); + await bulk.execute(); +} + async function runInDomain(domainId: string, isSub: boolean, report: Function) { const udict: ND = {}; const contests = await contest.getMulti(domainId, { rated: true }, -1).sort('endAt', -1).toArray(); @@ -114,6 +150,7 @@ async function runInDomain(domainId: string, isSub: boolean, report: Function) { tasks.push(domain.setUserInDomain(domainId, parseInt(uid, 10), { rp: udict[uid] })); } await Promise.all(tasks); + await calcLevel(domainId, report); } export async function run({ domainId }, report: Function) { diff --git a/packages/hydrooj/src/script/setSuperadmin.ts b/packages/hydrooj/src/script/setSuperadmin.ts deleted file mode 100644 index 5eb05142f..000000000 --- a/packages/hydrooj/src/script/setSuperadmin.ts +++ /dev/null @@ -1,18 +0,0 @@ -// TODO add a set_priv interface -import * as user from '../model/user'; -import { PRIV } from '../model/builtin'; - -export const description = 'Set a user as superadmin.'; - -export async function run({ uid }) { - uid = parseInt(uid, 10); - if (Number.isNaN(uid)) throw new Error('uid'); - await user.setPriv(uid, PRIV.PRIV_ALL); - return uid; -} - -export const validate = { - uid: { $type: 'number' }, -}; - -global.Hydro.script.setSuperadmin = { run, description, validate };