priv (unstable)

This commit is contained in:
undefined committed 2020-06-29 13:33:44 +08:00
1 parent 554698189c
commit e092efca20
63 files changed
+706 -397

No files matched your search

+302 -5
View File
@@ -1,9 +1,293 @@
const perm = require('../permission');
/* eslint-disable no-bitwise */
const PERM = {
PERM_NONE: '',
// Domain Settings
PERM_VIEW: '0',
PERM_EDIT_DOMAIN: '1',
PERM_MOD_BADGE: '2',
// Problem and Record
PERM_CREATE_PROBLEM: '3',
PERM_EDIT_PROBLEM: '4',
PERM_EDIT_PROBLEM_SELF: '5',
PERM_VIEW_PROBLEM: '6',
PERM_VIEW_PROBLEM_HIDDEN: '7',
PERM_SUBMIT_PROBLEM: '8',
PERM_READ_PROBLEM_DATA: '9',
PERM_READ_PROBLEM_DATA_SELF: 'A',
PERM_READ_RECORD_CODE: 'B',
PERM_REJUDGE_PROBLEM: 'C',
PERM_REJUDGE: 'D',
// Problem Solution
PERM_VIEW_PROBLEM_SOLUTION: 'E',
PERM_CREATE_PROBLEM_SOLUTION: 'F',
PERM_VOTE_PROBLEM_SOLUTION: 'G',
PERM_EDIT_PROBLEM_SOLUTION: 'H',
PERM_EDIT_PROBLEM_SOLUTION_SELF: 'I',
PERM_DELETE_PROBLEM_SOLUTION: 'J',
PERM_DELETE_PROBLEM_SOLUTION_SELF: 'K',
PERM_REPLY_PROBLEM_SOLUTION: 'L',
PERM_EDIT_PROBLEM_SOLUTION_REPLY: 'M',
PERM_EDIT_PROBLEM_SOLUTION_REPLY_SELF: 'N',
PERM_DELETE_PROBLEM_SOLUTION_REPLY: 'O',
PERM_DELETE_PROBLEM_SOLUTION_REPLY_SELF: 'P',
// Discussion
PERM_VIEW_DISCUSSION: 'Q',
PERM_CREATE_DISCUSSION: 'R',
PERM_HIGHLIGHT_DISCUSSION: 'S',
PERM_EDIT_DISCUSSION: 'T',
PERM_EDIT_DISCUSSION_SELF: 'U',
PERM_DELETE_DISCUSSION: 'V',
PERM_DELETE_DISCUSSION_SELF: 'W',
PERM_REPLY_DISCUSSION: 'X',
PERM_EDIT_DISCUSSION_REPLY: 'Y',
PERM_EDIT_DISCUSSION_REPLY_SELF: 'Z',
PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION: 'a',
PERM_DELETE_DISCUSSION_REPLY: 'b',
PERM_DELETE_DISCUSSION_REPLY_SELF: 'c',
PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION: 'd',
// Contest
PERM_VIEW_CONTEST: 'e',
PERM_VIEW_CONTEST_SCOREBOARD: 'f',
PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD: 'g',
PERM_CREATE_CONTEST: 'h',
PERM_ATTEND_CONTEST: 'i',
PERM_EDIT_CONTEST: 'j',
PERM_EDIT_CONTEST_SELF: 'k',
// Homework
PERM_VIEW_HOMEWORK: 'l',
PERM_VIEW_HOMEWORK_SCOREBOARD: 'm',
PERM_VIEW_HOMEWORK_HIDDEN_SCOREBOARD: 'n',
PERM_CREATE_HOMEWORK: 'o',
PERM_ATTEND_HOMEWORK: 'p',
PERM_EDIT_HOMEWORK: 'q',
PERM_EDIT_HOMEWORK_SELF: 'r',
// Training
PERM_VIEW_TRAINING: 's',
PERM_CREATE_TRAINING: 't',
PERM_EDIT_TRAINING: 'u',
PERM_EDIT_TRAINING_SELF: 'v',
};
const Permission = (family, key, desc) => ({ family, key, desc });
const PERMS = [
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
Permission('perm_general', PERM.PERM_EDIT_DOMAIN, 'Edit domain settings'),
Permission('perm_general', PERM.PERM_MOD_BADGE, 'Show MOD badge'),
Permission('perm_problem', PERM.PERM_CREATE_PROBLEM, 'Create problems'),
Permission('perm_problem', PERM.PERM_EDIT_PROBLEM, 'Edit problems'),
Permission('perm_problem', PERM.PERM_EDIT_PROBLEM_SELF, 'Edit own problems'),
Permission('perm_problem', PERM.PERM_VIEW_PROBLEM, 'View problems'),
Permission('perm_problem', PERM.PERM_VIEW_PROBLEM_HIDDEN, 'View hidden problems'),
Permission('perm_problem', PERM.PERM_SUBMIT_PROBLEM, 'Submit problem'),
Permission('perm_problem', PERM.PERM_READ_PROBLEM_DATA, 'Read data of problem'),
Permission('perm_problem', PERM.PERM_READ_PROBLEM_DATA_SELF, 'Read data of own problems'),
Permission('perm_record', PERM.PERM_READ_RECORD_CODE, 'Read record codes'),
Permission('perm_record', PERM.PERM_REJUDGE_PROBLEM, 'Rejudge problems'),
Permission('perm_record', PERM.PERM_REJUDGE, 'Rejudge records'),
Permission('perm_problem_solution', PERM.PERM_VIEW_PROBLEM_SOLUTION, 'View problem solutions'),
Permission('perm_problem_solution', PERM.PERM_CREATE_PROBLEM_SOLUTION, 'Create problem solutions'),
Permission('perm_problem_solution', PERM.PERM_VOTE_PROBLEM_SOLUTION, 'Vote problem solutions'),
Permission('perm_problem_solution', PERM.PERM_EDIT_PROBLEM_SOLUTION, 'Edit problem solutions'),
Permission('perm_problem_solution', PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF, 'Edit own problem solutions'),
Permission('perm_problem_solution', PERM.PERM_DELETE_PROBLEM_SOLUTION, 'Delete problem solutions'),
Permission('perm_problem_solution', PERM.PERM_DELETE_PROBLEM_SOLUTION_SELF, 'Delete own problem solutions'),
Permission('perm_problem_solution', PERM.PERM_REPLY_PROBLEM_SOLUTION, 'Reply problem solutions'),
Permission('perm_problem_solution', PERM.PERM_EDIT_PROBLEM_SOLUTION_REPLY, 'Edit problem solution replies'),
Permission('perm_problem_solution', PERM.PERM_EDIT_PROBLEM_SOLUTION_REPLY_SELF, 'Edit own problem solution replies'),
Permission('perm_problem_solution', PERM.PERM_DELETE_PROBLEM_SOLUTION_REPLY, 'Delete problem solution replies'),
Permission('perm_problem_solution', PERM.PERM_DELETE_PROBLEM_SOLUTION_REPLY_SELF, 'Delete own problem solution replies'),
Permission('perm_discussion', PERM.PERM_VIEW_DISCUSSION, 'View discussions'),
Permission('perm_discussion', PERM.PERM_CREATE_DISCUSSION, 'Create discussions'),
Permission('perm_discussion', PERM.PERM_HIGHLIGHT_DISCUSSION, 'Highlight discussions'),
Permission('perm_discussion', PERM.PERM_EDIT_DISCUSSION, 'Edit discussions'),
Permission('perm_discussion', PERM.PERM_EDIT_DISCUSSION_SELF, 'Edit own discussions'),
Permission('perm_discussion', PERM.PERM_DELETE_DISCUSSION, 'Delete discussions'),
Permission('perm_discussion', PERM.PERM_DELETE_DISCUSSION_SELF, 'Delete own discussions'),
Permission('perm_discussion', PERM.PERM_REPLY_DISCUSSION, 'Reply discussions'),
Permission('perm_discussion', PERM.PERM_EDIT_DISCUSSION_REPLY, 'Edit discussion replies'),
Permission('perm_discussion', PERM.PERM_EDIT_DISCUSSION_REPLY_SELF, 'Edit own discussion replies'),
Permission('perm_discussion', PERM.PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION, 'Edit discussion replies of own discussion'),
Permission('perm_discussion', PERM.PERM_DELETE_DISCUSSION_REPLY, 'Delete discussion replies'),
Permission('perm_discussion', PERM.PERM_DELETE_DISCUSSION_REPLY_SELF, 'Delete own discussion replies'),
Permission('perm_discussion', PERM.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION, 'Delete discussion replies of own discussion'),
Permission('perm_contest', PERM.PERM_VIEW_CONTEST, 'View contests'),
Permission('perm_contest', PERM.PERM_VIEW_CONTEST_SCOREBOARD, 'View contest scoreboard'),
Permission('perm_contest', PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD, 'View hidden contest submission status and scoreboard'),
Permission('perm_contest', PERM.PERM_CREATE_CONTEST, 'Create contests'),
Permission('perm_contest', PERM.PERM_ATTEND_CONTEST, 'Attend contests'),
Permission('perm_contest', PERM.PERM_EDIT_CONTEST, 'Edit any contests'),
Permission('perm_contest', PERM.PERM_EDIT_CONTEST_SELF, 'Edit own contests'),
Permission('perm_homework', PERM.PERM_VIEW_HOMEWORK, 'View homework'),
Permission('perm_homework', PERM.PERM_VIEW_HOMEWORK_SCOREBOARD, 'View homework scoreboard'),
Permission('perm_homework', PERM.PERM_VIEW_HOMEWORK_HIDDEN_SCOREBOARD, 'View hidden homework submission status and scoreboard'),
Permission('perm_homework', PERM.PERM_CREATE_HOMEWORK, 'Create homework'),
Permission('perm_homework', PERM.PERM_ATTEND_HOMEWORK, 'Claim homework'),
Permission('perm_homework', PERM.PERM_EDIT_HOMEWORK, 'Edit any homework'),
Permission('perm_homework', PERM.PERM_EDIT_HOMEWORK_SELF, 'Edit own homework'),
Permission('perm_training', PERM.PERM_VIEW_TRAINING, 'View training plans'),
Permission('perm_training', PERM.PERM_CREATE_TRAINING, 'Create training plans'),
Permission('perm_training', PERM.PERM_EDIT_TRAINING, 'Edit training plans'),
Permission('perm_training', PERM.PERM_EDIT_TRAINING_SELF, 'Edit own training plans'),
Permission('perm_ranking', PERM.PERM_VIEW_RANKING, 'View ranking'),
];
let PERM_ALL = '';
for (const p in PERM) PERM_ALL += PERM[p];
PERM.PERM_ALL = PERM_ALL;
const PERMS_BY_FAMILY = {};
for (const p of PERMS) {
if (!PERMS_BY_FAMILY[p.family]) PERMS_BY_FAMILY[p.family] = [p];
else PERMS_BY_FAMILY[p.family].push(p);
}
PERM.PERM_BASIC = PERM.PERM_VIEW
+ PERM.PERM_VIEW_PROBLEM
+ PERM.PERM_VIEW_PROBLEM_SOLUTION
+ PERM.PERM_VIEW_DISCUSSION
+ PERM.PERM_VIEW_CONTEST
+ PERM.PERM_VIEW_CONTEST_SCOREBOARD
+ PERM.PERM_VIEW_HOMEWORK
+ PERM.PERM_VIEW_HOMEWORK_SCOREBOARD
+ PERM.PERM_VIEW_TRAINING;
PERM.PERM_DEFAULT = PERM.PERM_VIEW
+ PERM.PERM_VIEW_PROBLEM
+ PERM.PERM_EDIT_PROBLEM_SELF
+ PERM.PERM_SUBMIT_PROBLEM
+ PERM.PERM_READ_PROBLEM_DATA_SELF
+ PERM.PERM_VIEW_PROBLEM_SOLUTION
+ PERM.PERM_CREATE_PROBLEM_SOLUTION
+ PERM.PERM_VOTE_PROBLEM_SOLUTION
+ PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF
+ PERM.PERM_DELETE_PROBLEM_SOLUTION_SELF
+ PERM.PERM_REPLY_PROBLEM_SOLUTION
+ PERM.PERM_EDIT_PROBLEM_SOLUTION_REPLY_SELF
+ PERM.PERM_DELETE_PROBLEM_SOLUTION_REPLY_SELF
+ PERM.PERM_VIEW_DISCUSSION
+ PERM.PERM_CREATE_DISCUSSION
+ PERM.PERM_EDIT_DISCUSSION_SELF
+ PERM.PERM_REPLY_DISCUSSION
+ PERM.PERM_EDIT_DISCUSSION_REPLY_SELF
// PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION
+ PERM.PERM_DELETE_DISCUSSION_REPLY_SELF
+ PERM.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION
+ PERM.PERM_VIEW_CONTEST
+ PERM.PERM_VIEW_CONTEST_SCOREBOARD
+ PERM.PERM_ATTEND_CONTEST
+ PERM.PERM_EDIT_CONTEST_SELF
+ PERM.PERM_VIEW_HOMEWORK
+ PERM.PERM_VIEW_HOMEWORK_SCOREBOARD
+ PERM.PERM_ATTEND_HOMEWORK
+ PERM.PERM_EDIT_HOMEWORK_SELF
+ PERM.PERM_VIEW_TRAINING
+ PERM.PERM_CREATE_TRAINING
+ PERM.PERM_EDIT_TRAINING_SELF
+ PERM.PERM_VIEW_RANKING
+ PERM.PERM_SUBMIT_PROBLEM
+ PERM.PERM_CREATE_PROBLEM_SOLUTION
+ PERM.PERM_VOTE_PROBLEM_SOLUTION
+ PERM.PERM_REPLY_PROBLEM_SOLUTION
+ PERM.PERM_CREATE_DISCUSSION
+ PERM.PERM_REPLY_DISCUSSION
+ PERM.PERM_ATTEND_CONTEST
+ PERM.PERM_CREATE_TRAINING
+ PERM.PERM_ATTEND_HOMEWORK;
PERM.PERM_ADMIN = PERM.PERM_ALL;
const PRIV = {
PRIV_NONE: 0,
PRIV_SET_PRIV: 1 << 0,
PRIV_SET_PERM: 1 << 1,
PRIV_USER_PROFILE: 1 << 2,
PRIV_REGISTER_USER: 1 << 3,
PRIV_READ_PROBLEM_DATA: 1 << 4,
PRIV_READ_PRETEST_DATA: 1 << 5, // deprecated
PRIV_READ_PRETEST_DATA_SELF: 1 << 6, // deprecated
PRIV_READ_RECORD_CODE: 1 << 7,
PRIV_VIEW_HIDDEN_RECORD: 1 << 8,
PRIV_JUDGE: 1 << 9, // (renamed)
PRIV_CREATE_DOMAIN: 1 << 10,
PRIV_VIEW_ALL_DOMAIN: 1 << 11,
PRIV_MANAGE_ALL_DOMAIN: 1 << 12,
PRIV_REJUDGE: 1 << 13,
PRIV_VIEW_USER_SECRET: 1 << 14,
PRIV_VIEW_JUDGE_STATISTICS: 1 << 15,
PRIV_CREATE_FILE: 1 << 16,
PRIV_UNLIMITED_QUOTA: 1 << 17,
PRIV_DELETE_FILE: 1 << 18,
PRIV_DELETE_FILE_SELF: 1 << 19,
PRIV_ALL: -1,
};
PRIV.PRIV_DETAULT = PRIV.PRIV_USER_PROFILE
+ PRIV.PRIV_REGISTER_USER
+ PRIV.PRIV_READ_PRETEST_DATA_SELF
+ PRIV.PRIV_CREATE_DOMAIN
+ PRIV.PRIV_CREATE_FILE
+ PRIV.PRIV_DELETE_FILE_SELF
+ PRIV.PRIV_USERFILE;
// [10, 1] means that people whose rank is less than 1% will get Level 10
const LEVELS = [
[10, 1],
[9, 2],
[8, 10],
[7, 20],
[6, 30],
[5, 40],
[4, 70],
[3, 90],
[2, 95],
[1, 100],
];
const BUILTIN_USERS = [
{
_id: 0,
mail: 'Guest@hydro.local',
mailLower: 'guest@hydro.local',
uname: 'Guest',
unameLower: 'guest',
salt: '',
hash: '',
hashType: 'hydro',
regat: new Date(0),
regip: '127.0.0.1',
loginat: new Date(0),
loginip: '127.0.0.1',
priv: PRIV.PRIV_NONE,
},
{
_id: 1,
mail: 'Hydro@hydro.local',
mailLower: 'hydro@hydro.local',
uname: 'Hydro',
unameLower: 'hydro',
salt: '',
hash: '',
hashType: 'hydro',
regat: new Date(0),
regip: '127.0.0.1',
loginat: new Date(0),
loginip: '127.0.0.1',
priv: PRIV.PRIV_USER_PROFILE,
},
];
const BUILTIN_ROLES = {
guest: { perm: perm.PERM_BASIC },
default: { perm: perm.PERM_DEFAULT },
admin: { perm: perm.PERM_ADMIN },
guest: { perm: PERM.PERM_BASIC },
default: { perm: PERM.PERM_DEFAULT },
admin: { perm: PERM.PERM_ADMIN },
};
const DEFAULT_NODES = {
@@ -13,7 +297,7 @@ const DEFAULT_NODES = {
{ pic: 'solution', name: '题解' },
],
Vijos: [
{ pic: 'vijos', name: 'Vijos' },
{ pic: 'hydro', name: 'Hydro' },
{ pic: null, name: '团队' },
{ pic: null, name: '月赛' },
{ pic: 'advice', name: '建议' },
@@ -201,12 +485,15 @@ const CATEGORIES = {
'构造',
],
};
const FOOTER_EXTRA_HTMLS = [];
const VIEW_LANGS = [
{ code: 'zh_CN', name: '简体中文' },
{ code: 'zh_TW', name: '正體中文' },
{ code: 'en', name: 'English' },
];
const LANG_TEXTS = {
c: 'C',
cc: 'C++',
@@ -222,6 +509,7 @@ const LANG_TEXTS = {
go: 'Go',
rb: 'Ruby',
};
const LANG_HIGHLIGHT_ID = {
c: 'c',
cc: 'cpp',
@@ -237,6 +525,7 @@ const LANG_HIGHLIGHT_ID = {
go: 'go',
rb: 'ruby',
};
const STATUS = {
STATUS_WAITING: 0,
STATUS_ACCEPTED: 1,
@@ -254,6 +543,7 @@ const STATUS = {
STATUS_FETCHED: 22,
STATUS_IGNORED: 30,
};
const STATUS_TEXTS = {
[STATUS.STATUS_WAITING]: 'Waiting',
[STATUS.STATUS_ACCEPTED]: 'Accepted',
@@ -271,6 +561,7 @@ const STATUS_TEXTS = {
[STATUS.STATUS_FETCHED]: 'Fetched',
[STATUS.STATUS_IGNORED]: 'Ignored',
};
const STATUS_CODES = {
0: 'pending',
1: 'pass',
@@ -290,6 +581,12 @@ const STATUS_CODES = {
};
global.Hydro.model.builtin = module.exports = {
PERM,
PERMS,
PERMS_BY_FAMILY,
PRIV,
LEVELS,
BUILTIN_USERS,
BUILTIN_ROLES,
DEFAULT_NODES,
CATEGORIES,
+2 -2
View File
@@ -4,7 +4,7 @@ const {
ValidationError, ContestNotFoundError, ContestAlreadyAttendedError,
ContestNotAttendedError, ContestScoreboardHiddenError,
} = require('../error');
const { PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD } = require('../permission');
const { PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD } = require('./builtin').PERM;
const validator = require('../lib/validator');
const ranked = require('../lib/rank');
const document = require('./document');
@@ -339,7 +339,7 @@ const ContestHandlerMixin = (c) => class extends c {
for (const tsdoc of tsdocs) uids.push(tsdoc.uid);
const [udict, pdict] = await Promise.all([
user.getList(domainId, uids),
problem.getList(domainId, tdoc.pids),
problem.getList(domainId, tdoc.pids, true),
]);
const rankedTsdocs = RULES[tdoc.rule].rank(tsdocs);
const rows = RULES[tdoc.rule].scoreboard(isExport, (str) => (str ? str.toString().translate(this.user.language) : ''), tdoc, rankedTsdocs, udict, pdict);
+1 -1
View File
@@ -3,7 +3,7 @@ const problem = require('./problem');
const document = require('./document');
const contest = require('./contest');
const training = require('./training');
const { PERM_VIEW_PROBLEM_HIDDEN } = require('../permission');
const { PERM_VIEW_PROBLEM_HIDDEN } = require('./builtin').PERM;
const { DocumentNotFoundError } = require('../error');
const typeDisplay = {
-19
View File
@@ -1,19 +0,0 @@
module.exports = {
blacklist: require('./blacklist'),
builtin: require('./builtin'),
contest: require('./contest'),
document: require('./document'),
opcount: require('./opcount'),
problem: require('./problem'),
record: require('./record'),
solution: require('./solution'),
system: require('./system'),
token: require('./token'),
training: require('./training'),
user: require('./user'),
task: require('./task'),
message: require('./message'),
setting: require('./setting'),
discussion: require('./discussion'),
file: require('./file'),
};
+65 -21
View File
@@ -4,6 +4,7 @@ const document = require('./document');
const domain = require('./domain');
const { ProblemNotFoundError } = require('../error');
const readConfig = require('../lib/readConfig');
const { ObjectId } = require('bson');
/**
* @typedef {import('../interface').Pdoc} Pdoc
@@ -11,16 +12,50 @@ const readConfig = require('../lib/readConfig');
* @typedef {import('mongodb').Cursor} Cursor
*/
class Problem {
constructor(pdoc) {
this.docType = document.TYPE_PROBLEM;
if (pdoc) {
this._id = pdoc._id;
this.docId = pdoc.docId;
this.pid = pdoc.pid;
this.title = pdoc.title;
this.content = pdoc.content;
this.owner = pdoc.owner;
this.config = pdoc.config;
this.data = pdoc.data;
this.nSubmit = pdoc.nSubmit;
this.nAccept = pdoc.nAccept;
this.difficulty = pdoc.difficulty || 0;
this.tag = pdoc.tag || [];
this.category = pdoc.category || [];
this.hidden = pdoc.hidden || false;
} else {
this._id = new ObjectId();
this.docId = this._id;
this.pid = String.random(8);
this.title = '*';
this.content = '';
this.owner = 1;
this.config = '';
this.data = null;
this.nSubmit = 0;
this.nAccept = 0;
this.difficulty = 0;
this.tag = [];
this.category = [];
this.hidden = true;
}
}
}
/**
* @param {string} domainId
* @param {string} title
* @param {string} content
* @param {number} owner
* @param {number} pid
* @param {import('bson').ObjectID} data
* @param {string[]} category
* @param {string[]} tag
* @param {boolean} hidden
* @param {object} args
* @returns {Promise<ObjectID>} docId
*/
async function add(domainId, title, content, owner, {
pid = null,
@@ -43,7 +78,7 @@ async function add(domainId, title, content, owner, {
* @param {string} domainId
* @param {string|number} pid
* @param {number} uid
* @returns {Promise<Pdoc>}
* @returns {Promise<Problem>}
*/
async function get(domainId, pid, uid = null, doThrow = true) {
if (!Number.isNaN(parseInt(pid, 10))) pid = parseInt(pid, 10);
@@ -57,7 +92,7 @@ async function get(domainId, pid, uid = null, doThrow = true) {
if (uid) {
pdoc.psdoc = await document.getStatus(domainId, document.TYPE_PROBLEM, pdoc.docId, uid);
}
return pdoc;
return new Problem(pdoc);
}
/**
@@ -66,11 +101,16 @@ async function get(domainId, pid, uid = null, doThrow = true) {
* @param {object} sort
* @param {number} page
* @param {number} limit
* @returns {Promise<Pdoc[]>}
* @returns {Promise<Problem[]>}
*/
function getMany(domainId, query, sort, page, limit) {
return document.getMulti(domainId, query).sort(sort).skip((page - 1) * limit).limit(limit)
async function getMany(domainId, query, sort, page, limit) {
const pdocs = await document.getMulti(domainId, query)
.sort(sort).skip((page - 1) * limit).limit(limit)
.toArray();
for (let i = 0; i < pdocs.length; i++) {
pdocs[i] = new Problem(pdocs[i]);
}
return pdocs;
}
/**
@@ -95,10 +135,11 @@ function getMultiStatus(domainId, query) {
* @param {string} domainId
* @param {ObjectID} _id
* @param {object} query
* @returns {Promise<Pdoc>}
* @returns {Promise<Problem>}
*/
function edit(domainId, _id, $set) {
return document.set(domainId, document.TYPE_PROBLEM, _id, $set);
async function edit(domainId, _id, $set) {
const pdoc = await document.set(domainId, document.TYPE_PROBLEM, _id, $set);
return new Problem(pdoc);
}
function inc(domainId, _id, field, n) {
@@ -118,20 +159,23 @@ async function random(domainId, query) {
} return null;
}
async function getList(domainId, pids, doThrow = true) {
async function getList(domainId, pids, getHidden = false, doThrow = true) {
pids = Array.from(new Set(pids));
const r = {};
const pdocs = await document.getMulti(
domainId, document.TYPE_PROBLEM,
{ $or: [{ docId: { $in: pids } }, { pid: { $in: pids } }] },
).toArray();
const q = { $or: [{ docId: { $in: pids } }, { pid: { $in: pids } }] };
if (!getHidden) q.hidden = false;
const pdocs = await document.getMulti(domainId, document.TYPE_PROBLEM, q).toArray();
for (const pdoc of pdocs) {
r[pdoc.docId] = r[pdoc.pid] = pdoc;
}
if (pdocs.length !== pids.length) {
if (doThrow) {
for (const pid of pids) {
if (!r[pid]) throw new ProblemNotFoundError(domainId, pid);
for (const pid of pids) {
if (!r[pid]) {
if (doThrow) {
throw new ProblemNotFoundError(domainId, pid);
} else {
r[pid] = new Problem();
}
}
}
}
-2
View File
@@ -88,8 +88,6 @@ DomainSetting(
);
SystemSetting(
Setting('setting_basic', 'user.register', null, false, 'checkbox', 'Allow register'),
Setting('setting_basic', 'user.create_domain', null, true, 'checkbox', 'Allow domain creation'),
Setting('setting_smtp', 'smtp.user', null, null, 'text', 'SMTP Username'),
Setting('setting_smtp', 'smtp.pass', null, null, 'password', 'SMTP Password'),
Setting('setting_smtp', 'smtp.host', null, null, 'text', 'SMTP Server Host'),
+28 -7
View File
@@ -4,9 +4,9 @@ const system = require('./system');
const token = require('./token');
const setting = require('./setting');
const { UserNotFoundError, UserAlreadyExistError, LoginError } = require('../error');
const perm = require('../permission');
const pwhash = require('../lib/hash.hydro');
const db = require('../service/db');
const { PRIV } = require('./builtin');
const coll = db.collection('user');
@@ -42,6 +42,11 @@ class USER {
return this.perm.includes(p);
}
hasPriv(p) {
// eslint-disable-next-line no-bitwise
return this.priv & p;
}
checkPassword(password) {
const h = global.Hydro.lib[`hash.${this.hashType || 'hydro'}`];
if (!h) throw new Error('Unknown hash method');
@@ -55,14 +60,17 @@ async function getInDomain(domainId, udoc) {
let dudoc = await document.getStatus(domainId, document.TYPE_DOMAIN_USER, 0, udoc._id);
dudoc = dudoc || {};
if (udoc._id === 1) dudoc.role = 'guest';
if (udoc.priv === 1) dudoc.role = 'admin';
// eslint-disable-next-line no-bitwise
if (udoc.priv & PRIV.PRIV_MANAGE_ALL_DOMAIN) dudoc.role = 'admin';
const p = await document.get(domainId, document.TYPE_DOMAIN_USER, dudoc.role || 'default');
dudoc.perm = p ? p.content : builtin.BUILTIN_ROLES[dudoc.role || 'default'].perm;
return dudoc;
}
async function getById(domainId, _id, throwError = false) {
const udoc = await coll.findOne({ _id });
const udoc = _id === 0 || _id === 1
? builtin.BUILTIN_USERS[_id]
: await coll.findOne({ _id });
if (!udoc) {
if (throwError) throw new UserNotFoundError(_id);
else return null;
@@ -81,7 +89,11 @@ async function getList(domainId, uids) {
async function getByUname(domainId, uname, ignoreMissing = false) {
const unameLower = uname.trim().toLowerCase();
const udoc = await coll.findOne({ unameLower });
const udoc = (unameLower === 'guest')
? builtin.BUILTIN_USERS[0]
: unameLower === 'hydro'
? builtin.BUILTIN_USERS[1]
: await coll.findOne({ unameLower });
if (!udoc) {
if (ignoreMissing) return null;
throw new UserNotFoundError(uname);
@@ -92,7 +104,11 @@ async function getByUname(domainId, uname, ignoreMissing = false) {
async function getByEmail(domainId, mail, ignoreMissing = false) {
const mailLower = mail.trim().toLowerCase();
const udoc = await coll.findOne({ mailLower });
const udoc = (mailLower === 'guest@hydro.local')
? builtin.BUILTIN_USERS[0]
: mailLower === 'hydro@hydro.local'
? builtin.BUILTIN_USERS[1]
: await coll.findOne({ mailLower });
if (!udoc) {
if (ignoreMissing) return null;
throw new UserNotFoundError(mail);
@@ -121,7 +137,7 @@ function setEmail(uid, mail) {
}
async function changePassword(uid, currentPassword, newPassword) {
const udoc = await getById(uid);
const udoc = await getById('system', uid);
udoc.checkPassword(currentPassword);
const salt = String.random();
return await coll.findOneAndUpdate(
@@ -153,7 +169,7 @@ async function incDomain(domainId, uid, field, n = 1) {
* @returns {Promise<number>} uid
*/
async function create({
uid, mail, uname, password, regip = '127.0.0.1', priv = perm.PRIV_NONE,
uid, mail, uname, password, regip = '127.0.0.1', priv = PRIV.PRIV_DEFAULT,
}) {
const salt = String.random();
if (!uid) uid = await system.inc('user');
@@ -195,6 +211,10 @@ async function getPrefixList(prefix, limit = 50) {
return udocs;
}
function setPriv(uid, priv) {
return coll.findOneAndUpdate({ _id: uid }, { $set: priv }, { returnOriginal: false });
}
function setRole(domainId, uid, role) {
return document.setStatus(domainId, document.TYPE_DOMAIN_USER, 0, uid, { role });
}
@@ -271,6 +291,7 @@ global.Hydro.model.user = module.exports = {
setMultiInDomain,
getMultiInDomain,
getPrefixList,
setPriv,
setRole,
setRoles,
getRole,