mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
Hello airbnb
This commit is contained in:
1 parent
f9468536de
commit
8c195661d7
78 files changed
+2032
-1471
No files matched your search
@@ -1,9 +1,9 @@
|
||||
const
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('blacklist');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('blacklist');
|
||||
|
||||
async function add(ip) {
|
||||
let expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000);
|
||||
const expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000);
|
||||
return coll.findOneAndUpdate({ _id: ip }, { $set: { expireAt } }, { upsert: true });
|
||||
}
|
||||
function get(ip) {
|
||||
|
||||
+49
-40
@@ -1,20 +1,21 @@
|
||||
const perm = require('../permission');
|
||||
|
||||
const BUILTIN_ROLES = [
|
||||
{ _id: 'guest', perm: perm.PERM_BASIC },
|
||||
{ _id: 'default', perm: perm.PERM_DEFAULT },
|
||||
{ _id: 'admin', perm: perm.PERM_ADMIN }
|
||||
{ _id: 'admin', perm: perm.PERM_ADMIN },
|
||||
];
|
||||
const CATEGORIES = {
|
||||
'动态规划': [
|
||||
动态规划: [
|
||||
'LCS',
|
||||
'LIS',
|
||||
'背包',
|
||||
'单调性DP',
|
||||
'环形DP',
|
||||
'树形DP',
|
||||
'状态压缩DP'
|
||||
'状态压缩DP',
|
||||
],
|
||||
'搜索': [
|
||||
搜索: [
|
||||
'枚举',
|
||||
'搜索与剪枝',
|
||||
'启发式搜索',
|
||||
@@ -22,9 +23,9 @@ const CATEGORIES = {
|
||||
'双向搜索',
|
||||
'折半搜索',
|
||||
'记忆化搜索',
|
||||
'模拟退火'
|
||||
'模拟退火',
|
||||
],
|
||||
'计算几何': [
|
||||
计算几何: [
|
||||
'半平面交',
|
||||
'凸包',
|
||||
'几何图形的交与并',
|
||||
@@ -37,19 +38,19 @@ const CATEGORIES = {
|
||||
'平面图的对偶图',
|
||||
'三角剖分',
|
||||
'梯形剖分',
|
||||
'几何知识'
|
||||
'几何知识',
|
||||
],
|
||||
'贪心': [],
|
||||
'树结构': [
|
||||
贪心: [],
|
||||
树结构: [
|
||||
'最近公共祖先',
|
||||
'生成树',
|
||||
'DFS序列',
|
||||
'树上倍增',
|
||||
'树的分治',
|
||||
'树链剖分',
|
||||
'Link-Cut-Tree'
|
||||
'Link-Cut-Tree',
|
||||
],
|
||||
'图结构': [
|
||||
图结构: [
|
||||
'平面图',
|
||||
'二分图',
|
||||
'二分图匹配',
|
||||
@@ -60,9 +61,9 @@ const CATEGORIES = {
|
||||
'强连通分量',
|
||||
'割点割边',
|
||||
'欧拉回路',
|
||||
'2-SAT'
|
||||
'2-SAT',
|
||||
],
|
||||
'数论': [
|
||||
数论: [
|
||||
'素数判定',
|
||||
'欧几里得算法',
|
||||
'不定方程',
|
||||
@@ -73,10 +74,10 @@ const CATEGORIES = {
|
||||
'大整数质因数分解',
|
||||
'勾股方程',
|
||||
'积性函数',
|
||||
'Fibonacci数列'
|
||||
'Fibonacci数列',
|
||||
],
|
||||
'模拟': [],
|
||||
'数据结构': [
|
||||
模拟: [],
|
||||
数据结构: [
|
||||
'栈',
|
||||
'队列',
|
||||
'链表',
|
||||
@@ -93,41 +94,41 @@ const CATEGORIES = {
|
||||
'k-d树',
|
||||
'块状链表',
|
||||
'Hashing',
|
||||
'函数式编程'
|
||||
'函数式编程',
|
||||
],
|
||||
'博弈论': [],
|
||||
'字符串': [
|
||||
博弈论: [],
|
||||
字符串: [
|
||||
'KMP',
|
||||
'后缀数据结构',
|
||||
'Trie树',
|
||||
'AC自动机',
|
||||
'Manacher',
|
||||
'表达式处理',
|
||||
'最小表示法'
|
||||
'最小表示法',
|
||||
],
|
||||
'组合数学': [
|
||||
组合数学: [
|
||||
'生成函数',
|
||||
'容斥原理',
|
||||
'康托展开',
|
||||
'Catalan数列',
|
||||
'Stirling数',
|
||||
'差分',
|
||||
'Polya定理'
|
||||
'Polya定理',
|
||||
],
|
||||
'线性代数': [
|
||||
线性代数: [
|
||||
'矩阵乘法',
|
||||
'高斯消元',
|
||||
'线性规划'
|
||||
'线性规划',
|
||||
],
|
||||
'高精度': [
|
||||
'FFT'
|
||||
高精度: [
|
||||
'FFT',
|
||||
],
|
||||
'递推': [],
|
||||
'概率论': [
|
||||
'随机化'
|
||||
递推: [],
|
||||
概率论: [
|
||||
'随机化',
|
||||
],
|
||||
'NPC': [],
|
||||
'其他': [
|
||||
NPC: [],
|
||||
其他: [
|
||||
'二分查找',
|
||||
'三分查找',
|
||||
'双指针扫描',
|
||||
@@ -137,15 +138,15 @@ const CATEGORIES = {
|
||||
'快速幂',
|
||||
'数学',
|
||||
'排序',
|
||||
'构造'
|
||||
]
|
||||
'构造',
|
||||
],
|
||||
};
|
||||
const FOOTER_EXTRA_HTMLS = [];
|
||||
const VIEW_LANGS = [
|
||||
{ code: 'zh-CN', name: 'zh-CN' }
|
||||
{ code: 'zh-CN', name: 'zh-CN' },
|
||||
];
|
||||
const LANGS = {
|
||||
cc: 'cpp'
|
||||
cc: 'cpp',
|
||||
};
|
||||
const LANG_TEXTS = {
|
||||
c: 'C',
|
||||
@@ -192,7 +193,7 @@ const STATUS = {
|
||||
STATUS_JUDGING: 20,
|
||||
STATUS_COMPILING: 21,
|
||||
STATUS_FETCHED: 22,
|
||||
STATUS_IGNORED: 30
|
||||
STATUS_IGNORED: 30,
|
||||
};
|
||||
const STATUS_TEXTS = {
|
||||
[STATUS.STATUS_WAITING]: 'Waiting',
|
||||
@@ -226,9 +227,17 @@ const STATUS_CODES = {
|
||||
20: 'progress',
|
||||
21: 'progress',
|
||||
22: 'progress',
|
||||
30: 'ignored'
|
||||
30: 'ignored',
|
||||
};
|
||||
module.exports = {
|
||||
BUILTIN_ROLES, CATEGORIES, VIEW_LANGS, FOOTER_EXTRA_HTMLS, LANGS,
|
||||
LANG_TEXTS, LANG_HIGHLIGHT_ID, STATUS, STATUS_TEXTS, STATUS_CODES
|
||||
};
|
||||
BUILTIN_ROLES,
|
||||
CATEGORIES,
|
||||
VIEW_LANGS,
|
||||
FOOTER_EXTRA_HTMLS,
|
||||
LANGS,
|
||||
LANG_TEXTS,
|
||||
LANG_HIGHLIGHT_ID,
|
||||
STATUS,
|
||||
STATUS_TEXTS,
|
||||
STATUS_CODES,
|
||||
};
|
||||
+84
-64
@@ -1,18 +1,20 @@
|
||||
const
|
||||
user = require('./user'),
|
||||
problem = require('./problem'),
|
||||
{ ValidationError, ContestNotFoundError, ContestAlreadyAttendedError,
|
||||
ContestNotAttendedError, ProblemNotFoundError, ContestScoreboardHiddenError } = require('../error'),
|
||||
{ PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD } = require('../permission'),
|
||||
validator = require('../lib/validator'),
|
||||
db = require('../service/db'),
|
||||
coll = db.collection('contest'),
|
||||
coll_status = db.collection('contest.status');
|
||||
const user = require('./user');
|
||||
const problem = require('./problem');
|
||||
const {
|
||||
ValidationError, ContestNotFoundError, ContestAlreadyAttendedError,
|
||||
ContestNotAttendedError, ProblemNotFoundError, ContestScoreboardHiddenError,
|
||||
} = require('../error');
|
||||
const { PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD } = require('../permission');
|
||||
const validator = require('../lib/validator');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('contest');
|
||||
const collStatus = db.collection('contest.status');
|
||||
|
||||
const RULES = {
|
||||
homework: require('../module/contest/homework'),
|
||||
oi: require('../module/contest/oi'),
|
||||
acm: require('../module/contest/acm')
|
||||
acm: require('../module/contest/acm'),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -21,13 +23,13 @@ const RULES = {
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @param {number} owner
|
||||
* @param {string} rule
|
||||
* @param {Date} beginAt
|
||||
* @param {Date} endAt
|
||||
* @param {ObjectID[]} pids
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @param {number} owner
|
||||
* @param {string} rule
|
||||
* @param {Date} beginAt
|
||||
* @param {Date} endAt
|
||||
* @param {ObjectID[]} pids
|
||||
* @param {object} data
|
||||
* @returns {ObjectID} tid
|
||||
*/
|
||||
@@ -37,112 +39,120 @@ async function add(title, content, owner, rule,
|
||||
validator.checkContent(content);
|
||||
if (!this.RULES[rule]) throw new ValidationError('rule');
|
||||
if (beginAt >= endAt) throw new ValidationError('beginAt', 'endAt');
|
||||
Object.assign(data, { content, owner, title, rule, beginAt, endAt, pids, attend: 0 });
|
||||
Object.assign(data, {
|
||||
content, owner, title, rule, beginAt, endAt, pids, attend: 0,
|
||||
});
|
||||
this.RULES[rule].check(data);
|
||||
let res = await coll.insertOne(data);
|
||||
const res = await coll.insertOne(data);
|
||||
return res.insertedId;
|
||||
}
|
||||
/**
|
||||
* @param {ObjectID} tid
|
||||
* @param {object} $set
|
||||
* @param {ObjectID} tid
|
||||
* @param {object} $set
|
||||
* @returns {Tdoc} tdoc after modification
|
||||
*/
|
||||
async function edit(tid, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkIntro($set.content);
|
||||
if ($set.rule)
|
||||
if (!this.RULES[$set.rule]) throw new ValidationError('rule');
|
||||
if ($set.beginAt && $set.endAt)
|
||||
if ($set.beginAt >= $set.endAt) throw new ValidationError('beginAt', 'endAt');
|
||||
let tdoc = await coll.findOne({ tid });
|
||||
if ($set.rule) { if (!this.RULES[$set.rule]) throw new ValidationError('rule'); }
|
||||
if ($set.beginAt && $set.endAt) if ($set.beginAt >= $set.endAt) throw new ValidationError('beginAt', 'endAt');
|
||||
const tdoc = await coll.findOne({ tid });
|
||||
if (!tdoc) throw new ContestNotFoundError(tid);
|
||||
this.RULES[$set.rule || tdoc.rule].check(Object.assign(tdoc, $set));
|
||||
await coll.findOneAndUpdate({ tid }, { $set });
|
||||
return tdoc;
|
||||
}
|
||||
/**
|
||||
* @param {ObjectID} tid
|
||||
* @param {ObjectID} tid
|
||||
* @returns {Tdoc}
|
||||
*/
|
||||
async function get(tid) {
|
||||
let tdoc = await coll.findOne({ _id: tid });
|
||||
const tdoc = await coll.findOne({ _id: tid });
|
||||
if (!tdoc) throw new ContestNotFoundError(tid);
|
||||
return tdoc;
|
||||
}
|
||||
async function updateStatus(tid, uid, rid, pid, accept, score) {
|
||||
let tdoc = await get(tid);
|
||||
let tsdoc = await coll_status.findOneAndUpdate({ tid: tdoc._id, uid }, {
|
||||
$push: { journal: { rid, pid, accept, score } },
|
||||
$inc: { rev: 1 }
|
||||
const tdoc = await get(tid);
|
||||
const tsdoc = await collStatus.findOneAndUpdate({ tid: tdoc._id, uid }, {
|
||||
$push: {
|
||||
journal: {
|
||||
rid, pid, accept, score,
|
||||
},
|
||||
},
|
||||
$inc: { rev: 1 },
|
||||
}, { upsert: true });
|
||||
if (!tsdoc.value.attend) throw new ContestNotAttendedError(tid, uid);
|
||||
}
|
||||
async function getListStatus(uid, tids) {
|
||||
let r = {};
|
||||
for (let tid of tids) r[tid] = await this.getStatus(tid, uid);
|
||||
const r = {};
|
||||
for (const tid of tids) r[tid] = await this.getStatus(tid, uid); // eslint-disable-line no-await-in-loop
|
||||
return r;
|
||||
}
|
||||
async function attend(tid, uid) {
|
||||
try {
|
||||
await coll_status.insertOne({ tid, uid, attend: 1 });
|
||||
await collStatus.insertOne({ tid, uid, attend: 1 });
|
||||
} catch (e) {
|
||||
throw new ContestAlreadyAttendedError(tid, uid);
|
||||
}
|
||||
await coll.findOneAndUpdate({ _id: tid }, { $inc: { attend: 1 } });
|
||||
}
|
||||
function getMultiStatus(query) {
|
||||
return coll_status.find(query);
|
||||
return collStatus.find(query);
|
||||
}
|
||||
function is_new(tdoc, days = 1) {
|
||||
let now = new Date().getTime();
|
||||
let readyAt = tdoc.beginAt.getTime();
|
||||
const now = new Date().getTime();
|
||||
const readyAt = tdoc.beginAt.getTime();
|
||||
return (now < readyAt - days * 24 * 3600 * 1000);
|
||||
}
|
||||
function is_upcoming(tdoc, days = 1) {
|
||||
let now = new Date().getTime();
|
||||
let readyAt = tdoc.beginAt.getTime();
|
||||
const now = new Date().getTime();
|
||||
const readyAt = tdoc.beginAt.getTime();
|
||||
return (now > readyAt - days * 24 * 3600 * 1000 && now < tdoc.beginAt);
|
||||
}
|
||||
function is_not_started(tdoc) {
|
||||
return (new Date()) < tdoc.beginAt;
|
||||
}
|
||||
function is_ongoing(tdoc) {
|
||||
let now = new Date();
|
||||
const now = new Date();
|
||||
return (tdoc.beginAt <= now && now < tdoc.endAt);
|
||||
}
|
||||
function is_done(tdoc) {
|
||||
return tdoc.endAt <= new Date();
|
||||
}
|
||||
|
||||
const ContestHandlerMixin = c => class extends c {
|
||||
const ContestHandlerMixin = (c) => class extends c {
|
||||
canViewHiddenScoreboard() {
|
||||
return this.user.hasPerm(PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
||||
}
|
||||
|
||||
canShowRecord(tdoc, allowPermOverride = true) {
|
||||
if (RULES[tdoc.rule].showRecord(tdoc, new Date())) return true;
|
||||
if (allowPermOverride && this.canViewHiddenScoreboard(tdoc)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
canShowScoreboard(tdoc, allowPermOverride = true) {
|
||||
if (RULES[tdoc.rule].showScoreboard(tdoc, new Date())) return true;
|
||||
if (allowPermOverride && this.canViewHiddenScoreboard(tdoc)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
async getScoreboard(tid, isExport = false) {
|
||||
let tdoc = await get(tid);
|
||||
const tdoc = await get(tid);
|
||||
if (!this.canShowScoreboard(tdoc)) throw new ContestScoreboardHiddenError(tid);
|
||||
let tsdocs = await getMultiStatus(tid).sort(RULES[tdoc.rule].statusSort).toArray();
|
||||
let uids = [];
|
||||
for (let tsdoc of tsdocs) uids.push(tsdoc.uid);
|
||||
let [udict, pdict] = await Promise.all([user.getList(uids), problem.getList(tdoc['pids'])]);
|
||||
let ranked_tsdocs = RULES[tdoc.rule].rank(tsdocs);
|
||||
let rows = RULES[tdoc.rule].scoreboard(isExport, str => str ? str.toString().translate(this.user.language) : '', tdoc, ranked_tsdocs, udict, pdict);
|
||||
const tsdocs = await getMultiStatus(tid).sort(RULES[tdoc.rule].statusSort).toArray();
|
||||
const uids = [];
|
||||
for (const tsdoc of tsdocs) uids.push(tsdoc.uid);
|
||||
const [udict, pdict] = await Promise.all([user.getList(uids), problem.getList(tdoc.pids)]);
|
||||
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);
|
||||
return [tdoc, rows, udict];
|
||||
}
|
||||
async verifyProblems(pids) {
|
||||
let r = [];
|
||||
for (let pid of pids) {
|
||||
let res = await problem.get(pid);
|
||||
|
||||
async verifyProblems(pids) { // eslint-disable-line class-methods-use-this
|
||||
const r = [];
|
||||
for (const pid of pids) {
|
||||
const res = await problem.get(pid); // eslint-disable-line no-await-in-loop
|
||||
if (res) r.push(res._id);
|
||||
else throw new ProblemNotFoundError(pid);
|
||||
}
|
||||
@@ -151,26 +161,37 @@ const ContestHandlerMixin = c => class extends c {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
RULES, ContestHandlerMixin, add, getListStatus, attend, edit, get, updateStatus,
|
||||
count: query => coll.find(query).count(),
|
||||
getMulti: query => coll.find(query),
|
||||
RULES,
|
||||
ContestHandlerMixin,
|
||||
add,
|
||||
getListStatus,
|
||||
attend,
|
||||
edit,
|
||||
get,
|
||||
updateStatus,
|
||||
count: (query) => coll.find(query).count(),
|
||||
getMulti: (query) => coll.find(query),
|
||||
getStatus: (tid, uid) => coll_status.findOne({ tid, uid }),
|
||||
setStatus: (tid, uid, $set) => coll_status.findOneAndUpdate({ tid, uid }, { $set }),
|
||||
is_new, is_upcoming, is_not_started, is_ongoing, is_done,
|
||||
status_text: tdoc =>
|
||||
is_new,
|
||||
is_upcoming,
|
||||
is_not_started,
|
||||
is_ongoing,
|
||||
is_done,
|
||||
status_text: (tdoc) => (
|
||||
is_new(tdoc)
|
||||
? 'New'
|
||||
: is_upcoming(tdoc)
|
||||
? 'Ready (☆▽☆)'
|
||||
: is_ongoing(tdoc)
|
||||
? 'Live...'
|
||||
: 'Done',
|
||||
get_status: tdoc =>
|
||||
: 'Done'),
|
||||
get_status: (tdoc) => (
|
||||
is_not_started(tdoc)
|
||||
? 'not_started'
|
||||
: is_ongoing(tdoc)
|
||||
? 'ongoing'
|
||||
: 'finished',
|
||||
: 'finished'),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -336,7 +357,6 @@ def _format_pids(pids_list):
|
||||
return ','.join([str(pid) for pid in pids_list])
|
||||
|
||||
|
||||
|
||||
class ContestStatusMixin(object):
|
||||
@property
|
||||
@functools.lru_cache()
|
||||
@@ -447,4 +467,4 @@ class ContestCommonOperationMixin(object):
|
||||
class ContestMixin(ContestStatusMixin, ContestVisibilityMixin, ContestCommonOperationMixin):
|
||||
pass
|
||||
|
||||
*/
|
||||
*/
|
||||
@@ -9,5 +9,5 @@ module.exports = {
|
||||
system: require('./system'),
|
||||
token: require('./token'),
|
||||
training: require('./training'),
|
||||
user: require('./user')
|
||||
user: require('./user'),
|
||||
};
|
||||
+18
-25
@@ -1,35 +1,28 @@
|
||||
const
|
||||
{ OpcountExceededError } = require('../error'),
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('opcount');
|
||||
const { OpcountExceededError } = require('../error');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('opcount');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* @param {string} op
|
||||
* @param {string} ident
|
||||
* @param {number} period_secs
|
||||
* @param {number} max_operations
|
||||
* @param {string} op
|
||||
* @param {string} ident
|
||||
* @param {number} period_secs
|
||||
* @param {number} max_operations
|
||||
*/
|
||||
async inc(op, ident, period_secs, max_operations) {
|
||||
let cur_time = new Date().getTime();
|
||||
let begin_at = new Date(cur_time - cur_time % (period_secs * 1000));
|
||||
let expire_at = new Date(begin_at.getTime() + period_secs * 1000);
|
||||
async inc(op, ident, periodSecs, maxOperations) {
|
||||
const curTime = new Date().getTime();
|
||||
const beginAt = new Date(curTime - (curTime % (periodSecs * 1000)));
|
||||
const expireAt = new Date(beginAt.getTime() + periodSecs * 1000);
|
||||
try {
|
||||
await coll.findOneAndUpdate({
|
||||
ident, begin_at, expire_at,
|
||||
op: { $not: { $gte: max_operations } }
|
||||
ident,
|
||||
beginAt,
|
||||
expireAt,
|
||||
op: { $not: { $gte: maxOperations } },
|
||||
}, { $inc: { op: 1 } }, { upsert: true });
|
||||
} catch (e) {
|
||||
throw new OpcountExceededError(op, period_secs, max_operations);
|
||||
throw new OpcountExceededError(op, periodSecs, maxOperations);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
/*
|
||||
@argmethod.wrap
|
||||
async def ensure_indexes():
|
||||
coll = db.coll('opcount')
|
||||
await coll.create_index([('ident', 1),
|
||||
('begin_at', 1),
|
||||
('expire_at', 1)], unique=True)
|
||||
await coll.create_index('expire_at', expireAfterSeconds=0)
|
||||
*/
|
||||
+34
-37
@@ -1,10 +1,10 @@
|
||||
const
|
||||
{ ObjectID } = require('bson'),
|
||||
{ ProblemNotFoundError } = require('../error'),
|
||||
validator = require('../lib/validator'),
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('problem'),
|
||||
coll_status = db.collection('problem.status');
|
||||
const { ObjectID } = require('bson');
|
||||
const { ProblemNotFoundError } = require('../error');
|
||||
const validator = require('../lib/validator');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('problem');
|
||||
const collStatus = db.collection('problem.status');
|
||||
|
||||
/**
|
||||
* @typedef {import('../interface').Pdoc} Pdoc
|
||||
@@ -13,14 +13,14 @@ const
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 {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
|
||||
*/
|
||||
async function add({
|
||||
title,
|
||||
@@ -30,7 +30,7 @@ async function add({
|
||||
data = null,
|
||||
category = [],
|
||||
tag = [],
|
||||
hidden = false
|
||||
hidden = false,
|
||||
}) {
|
||||
validator.checkTitle(title);
|
||||
validator.checkContent(content);
|
||||
@@ -44,7 +44,7 @@ async function add({
|
||||
tag,
|
||||
hidden,
|
||||
nSubmit: 0,
|
||||
nAccept: 0
|
||||
nAccept: 0,
|
||||
});
|
||||
return pid;
|
||||
}
|
||||
@@ -55,13 +55,13 @@ async function add({
|
||||
*/
|
||||
async function get(pid, uid = null) {
|
||||
let query = {};
|
||||
if (pid.generationTime || pid.length == 24) query = { _id: new ObjectID(pid) };
|
||||
if (pid.generationTime || pid.length === 24) query = { _id: new ObjectID(pid) };
|
||||
else query = { pid: parseInt(pid) || pid };
|
||||
let pdoc = await coll.findOne(query);
|
||||
const pdoc = await coll.findOne(query);
|
||||
if (!pdoc) throw new ProblemNotFoundError(pid);
|
||||
if (uid) {
|
||||
query.uid = uid;
|
||||
pdoc.psdoc = await coll_status.findOne(query);
|
||||
pdoc.psdoc = await collStatus.findOne(query);
|
||||
}
|
||||
return pdoc;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ async function get(pid, uid = null) {
|
||||
*/
|
||||
async function getById(_id) {
|
||||
_id = new ObjectID(_id);
|
||||
let pdoc = await coll.findOne({ _id });
|
||||
const pdoc = await coll.findOne({ _id });
|
||||
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||
return pdoc;
|
||||
}
|
||||
@@ -81,7 +81,8 @@ async function getById(_id) {
|
||||
* @returns {Pdoc[]}
|
||||
*/
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit).toArray();
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
/**
|
||||
* @param {object} query
|
||||
@@ -99,28 +100,24 @@ async function edit(_id, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkContent($set.content);
|
||||
await coll.findOneAndUpdate({ _id }, { $set });
|
||||
let pdoc = await getById(_id);
|
||||
const pdoc = await getById(_id);
|
||||
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||
return pdoc;
|
||||
}
|
||||
/**
|
||||
* @param {object} query
|
||||
* @returns {number}
|
||||
*/
|
||||
async function count(query) {
|
||||
return await coll.find(query).count();
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
async function random(query) {
|
||||
let pdocs = coll.find(query);
|
||||
let pcount = await pdocs.count();
|
||||
const pdocs = coll.find(query);
|
||||
const pcount = await pdocs.count();
|
||||
if (pcount) {
|
||||
let pdoc = await pdocs.skip(Math.floor(Math.random() * pcount)).limit(1).toArray()[0];
|
||||
const pdoc = await pdocs.skip(Math.floor(Math.random() * pcount)).limit(1).toArray()[0];
|
||||
return pdoc.pid;
|
||||
} else return null;
|
||||
} return null;
|
||||
}
|
||||
async function getList(pids) {
|
||||
let r = {};
|
||||
for (let pid of pids) r[pid] = await get(pid);
|
||||
const r = {};
|
||||
for (const pid of pids) r[pid] = await get(pid); // eslint-disable-line no-await-in-loop
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -133,5 +130,5 @@ module.exports = {
|
||||
random,
|
||||
getById,
|
||||
getMulti,
|
||||
getList
|
||||
};
|
||||
getList,
|
||||
};
|
||||
+27
-26
@@ -1,13 +1,13 @@
|
||||
const
|
||||
_ = require('lodash'),
|
||||
{ ObjectID } = require('bson'),
|
||||
{ RecordNotFoundError } = require('../error'),
|
||||
{ STATUS_WAITING } = require('../model/builtin').STATUS,
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('record');
|
||||
const _ = require('lodash');
|
||||
const { ObjectID } = require('bson');
|
||||
const { RecordNotFoundError } = require('../error');
|
||||
const { STATUS_WAITING } = require('./builtin').STATUS;
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('record');
|
||||
|
||||
/**
|
||||
* @param {import('../interface').Record} data
|
||||
* @param {import('../interface').Record} data
|
||||
*/
|
||||
async function add(data) {
|
||||
_.defaults(data, {
|
||||
@@ -20,33 +20,34 @@ async function add(data) {
|
||||
compilerTexts: [],
|
||||
testCases: [],
|
||||
judger: null,
|
||||
judgeAt: null
|
||||
judgeAt: null,
|
||||
});
|
||||
let res = await coll.insertOne(data);
|
||||
const res = await coll.insertOne(data);
|
||||
return res.insertedId;
|
||||
}
|
||||
/**
|
||||
* @param {string} rid
|
||||
* @param {string} rid
|
||||
* @returns {import('../interface').Record}
|
||||
*/
|
||||
async function get(rid) {
|
||||
let _id = new ObjectID(rid);
|
||||
let rdoc = await coll.findOne({ _id });
|
||||
const _id = new ObjectID(rid);
|
||||
const rdoc = await coll.findOne({ _id });
|
||||
if (!rdoc) throw new RecordNotFoundError(rid);
|
||||
return rdoc;
|
||||
}
|
||||
async function getMany(query, sort, page, limit) {
|
||||
return await coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit).toArray();
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
async function update(rid, $set) {
|
||||
let _id = new ObjectID(rid);
|
||||
const _id = new ObjectID(rid);
|
||||
await coll.findOneAndUpdate({ _id }, { $set });
|
||||
let rdoc = await coll.findOne({ _id });
|
||||
const rdoc = await coll.findOne({ _id });
|
||||
if (!rdoc) throw new RecordNotFoundError(rid);
|
||||
return rdoc;
|
||||
}
|
||||
async function reset(rid) {
|
||||
return await update(rid, {
|
||||
function reset(rid) {
|
||||
return update(rid, {
|
||||
score: 0,
|
||||
status: STATUS_WAITING,
|
||||
time: 0,
|
||||
@@ -56,15 +57,15 @@ async function reset(rid) {
|
||||
compilerTexts: [],
|
||||
judgeAt: null,
|
||||
judger: null,
|
||||
rejudged: true
|
||||
rejudged: true,
|
||||
});
|
||||
}
|
||||
async function count(query) {
|
||||
return await coll.find(query).count();
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
async function getList(rids) {
|
||||
let r = {};
|
||||
for (let rid of rids) r[rid] = await get(rid);
|
||||
const r = {};
|
||||
for (const rid of rids) r[rid] = await get(rid); // eslint-disable-line no-await-in-loop
|
||||
return r;
|
||||
}
|
||||
function getUserInProblemMulti(uid, pid) {
|
||||
@@ -79,5 +80,5 @@ module.exports = {
|
||||
count,
|
||||
reset,
|
||||
getList,
|
||||
getUserInProblemMulti
|
||||
};
|
||||
getUserInProblemMulti,
|
||||
};
|
||||
+46
-45
@@ -1,93 +1,94 @@
|
||||
const
|
||||
{ ObjectID } = require('bson'),
|
||||
{ SolutionNotFoundError, AlreadyVotedError } = require('../error'),
|
||||
validator = require('../lib/validator'),
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('solution'),
|
||||
coll_status = db.collection('solution.status');
|
||||
const { ObjectID } = require('bson');
|
||||
const { SolutionNotFoundError } = require('../error');
|
||||
const validator = require('../lib/validator');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
/**
|
||||
const coll = db.collection('solution');
|
||||
const collStatus = db.collection('solution.status');
|
||||
|
||||
/**
|
||||
* @param {string} pid
|
||||
* @param {number} owner
|
||||
* @param {string} content
|
||||
* @param {number} owner
|
||||
* @param {string} content
|
||||
*/
|
||||
async function add(pid, owner, content) {
|
||||
validator.checkContent(content);
|
||||
pid = new ObjectID(pid);
|
||||
let res = await coll.insertOne({ content, owner, pid, reply: [], vote: 0 });
|
||||
const res = await coll.insertOne({
|
||||
content, owner, pid, reply: [], vote: 0,
|
||||
});
|
||||
return res.insertedId;
|
||||
}
|
||||
async function get(psid) {
|
||||
psid = new ObjectID(psid);
|
||||
let psdoc = await coll.findOne({ _id: psid });
|
||||
const psdoc = await coll.findOne({ _id: psid });
|
||||
if (!psdoc) throw new SolutionNotFoundError();
|
||||
return psdoc;
|
||||
}
|
||||
async function getMany(query, sort, page, limit) {
|
||||
return await coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit).toArray();
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
async function edit(_id, content) {
|
||||
validator.checkContent(content);
|
||||
await coll.findOneAndUpdate({ _id }, { $set: { content } });
|
||||
let psdoc = await get(_id);
|
||||
const psdoc = await get(_id);
|
||||
if (!psdoc) throw new SolutionNotFoundError(_id);
|
||||
return psdoc;
|
||||
}
|
||||
async function del(psid) {
|
||||
psid = new ObjectID(psid);
|
||||
return await coll.deleteOne({ _id: psid });
|
||||
function del(psid) {
|
||||
return coll.deleteOne({ _id: psid });
|
||||
}
|
||||
async function count(query) {
|
||||
return await coll.find(query).count();
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
function getMulti(pid) {
|
||||
return coll.find({ pid }).sort({ vote: -1 });
|
||||
}
|
||||
async function reply(psid, owner, content) {
|
||||
psid = new ObjectID(psid);
|
||||
function reply(psid, owner, content) {
|
||||
validator.checkContent(content);
|
||||
return await coll.findOneAndUpdate({ _id: psid }, { $push: { reply: { content, owner, _id: new ObjectID() } } });
|
||||
return coll.findOneAndUpdate(
|
||||
{ _id: psid },
|
||||
{ $push: { reply: { content, owner, _id: new ObjectID() } } },
|
||||
);
|
||||
}
|
||||
async function getReply(psid, psrid) {
|
||||
psid = new ObjectID(psid);
|
||||
psrid = new ObjectID(psrid);
|
||||
let psdoc = await coll.findOne({ _id: psid, reply: { $elemMatch: { _id: psrid } } });
|
||||
const psdoc = await coll.findOne({ _id: psid, reply: { $elemMatch: { _id: psrid } } });
|
||||
if (!psdoc) return [null, null];
|
||||
for (let psrdoc of psdoc)
|
||||
if (psrdoc._id == psrid)
|
||||
return [psdoc, psrdoc];
|
||||
for (const psrdoc of psdoc) if (psrdoc._id === psrid) return [psdoc, psrdoc];
|
||||
return [psdoc, null];
|
||||
}
|
||||
async function editReply(psid, psrid, content) {
|
||||
validator.checkContent(content);
|
||||
psid = new ObjectID(psid);
|
||||
psrid = new ObjectID(psrid);
|
||||
let psdoc = await coll.findOne({ _id: psid, reply: { $elemMatch: { _id: psrid } } });
|
||||
let reply = psdoc.reply;
|
||||
for (let i in reply)
|
||||
if (reply[i]._id == psrid) {
|
||||
const psdoc = await coll.findOne({ _id: psid, reply: { $elemMatch: { _id: psrid } } });
|
||||
const { reply } = psdoc;
|
||||
for (const i in reply) {
|
||||
if (reply[i]._id === psrid) {
|
||||
reply[i].content = content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return await coll.findOneAndUpdate({ _id: psdoc._id }, { $set: { reply } });
|
||||
}
|
||||
async function delReply(psid, psrid) {
|
||||
return await coll.findOneAndUpdate({ _id: psid }, { $pull: { reply: { _id: psrid } } });
|
||||
function delReply(psid, psrid) {
|
||||
return coll.findOneAndUpdate({ _id: psid }, { $pull: { reply: { _id: psrid } } });
|
||||
}
|
||||
async function vote(psid, uid, value) {
|
||||
let pssdoc = await coll_status.findOne({ psid, uid });
|
||||
if (pssdoc) await coll_status.deleteOne({ psid, uid });
|
||||
await coll_status.insertOne({ psid, uid, vote: value });
|
||||
let pssdoc = await collStatus.findOne({ psid, uid });
|
||||
if (pssdoc) await collStatus.deleteOne({ psid, uid });
|
||||
await collStatus.insertOne({ psid, uid, vote: value });
|
||||
if (pssdoc) value += -pssdoc.vote;
|
||||
await coll.findOneAndUpdate({ _id: psid }, { $inc: { vote: value } });
|
||||
pssdoc = await coll_status.findOne({ psid, uid });
|
||||
let psdoc = await coll.findOne({ _id: psid });
|
||||
pssdoc = await collStatus.findOne({ psid, uid });
|
||||
const psdoc = await coll.findOne({ _id: psid });
|
||||
return [psdoc, pssdoc];
|
||||
}
|
||||
async function getListStatus(list, uid) {
|
||||
let result = {};
|
||||
let res = await coll_status.find({ uid, psid: { $in: list } }).toArray();
|
||||
for (let i of res) result[i.psid] = i;
|
||||
const result = {};
|
||||
const res = await collStatus.find({ uid, psid: { $in: list } }).toArray();
|
||||
for (const i of res) result[i.psid] = i;
|
||||
return result;
|
||||
}
|
||||
module.exports = {
|
||||
@@ -103,5 +104,5 @@ module.exports = {
|
||||
editReply,
|
||||
delReply,
|
||||
vote,
|
||||
getListStatus
|
||||
};
|
||||
getListStatus,
|
||||
};
|
||||
+15
-82
@@ -1,42 +1,43 @@
|
||||
const
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('system');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('system');
|
||||
|
||||
async function get(_id) {
|
||||
let doc = await coll.findOne({ _id });
|
||||
const doc = await coll.findOne({ _id });
|
||||
if (doc) return doc.value;
|
||||
return null;
|
||||
}
|
||||
async function update(_id, update, config) {
|
||||
await coll.findOneAndUpdate({ _id }, update, config);
|
||||
return this.get(_id);
|
||||
return get(_id);
|
||||
}
|
||||
/**
|
||||
* Increments the user counter.
|
||||
* @returns {number} Integer value after increment.
|
||||
*/
|
||||
async function incUserCounter() {
|
||||
return await this.update('userCounter', { $inc: { value: 1 } }, { upsert: true });
|
||||
function incUserCounter() {
|
||||
return update('userCounter', { $inc: { value: 1 } }, { upsert: true });
|
||||
}
|
||||
/**
|
||||
* Increments the problem ID counter.
|
||||
* @returns {number} Integer value before increment.
|
||||
*/
|
||||
async function incPidCounter() {
|
||||
return await this.update('userCounter', { $inc: { value: 1 } }, { upsert: true });
|
||||
function incPidCounter() {
|
||||
return update('userCounter', { $inc: { value: 1 } }, { upsert: true });
|
||||
}
|
||||
async function acquireLock(name) {
|
||||
let value = Math.floor(Math.random() * 0xFFFFFFFF);
|
||||
const value = Math.floor(Math.random() * 0xFFFFFFFF);
|
||||
try {
|
||||
await coll.updateOne({ _id: 'lock_' + name, value: 0 }, { $set: { value } }, { upsert: true });
|
||||
await coll.updateOne({ _id: `lock_${name}`, value: 0 }, { $set: { value } }, { upsert: true });
|
||||
} catch (e) { return null; }
|
||||
return value;
|
||||
}
|
||||
async function releaseLock(name, value) {
|
||||
let result = await coll.updateOne({ _id: 'lock_' + name, value }, { $set: { value: 0 } });
|
||||
const result = await coll.updateOne({ _id: `lock_${name}`, value }, { $set: { value: 0 } });
|
||||
return !!result.matchedCount;
|
||||
}
|
||||
async function releaseLockAnyway(name) {
|
||||
await coll.updateOne({ _id: 'lock_' + name }, { $set: { value: 0 } });
|
||||
await coll.updateOne({ _id: `lock_${name}` }, { $set: { value: 0 } });
|
||||
return true;
|
||||
}
|
||||
module.exports = {
|
||||
@@ -46,73 +47,5 @@ module.exports = {
|
||||
incUserCounter,
|
||||
acquireLock,
|
||||
releaseLock,
|
||||
releaseLockAnyway
|
||||
releaseLockAnyway,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
EXPECTED_DB_VERSION = 1
|
||||
|
||||
|
||||
async def acquire_upgrade_lock():
|
||||
lock = await acquire_lock('upgrade')
|
||||
if not lock:
|
||||
raise error.UpgradeLockAcquireError()
|
||||
return lock
|
||||
|
||||
|
||||
async def release_upgrade_lock(lock: int):
|
||||
success = await release_lock('upgrade', lock)
|
||||
if not success:
|
||||
raise error.UpgradeLockReleaseError()
|
||||
return True
|
||||
|
||||
|
||||
@argmethod.wrap
|
||||
async def release_upgrade_lock_anyway():
|
||||
return await release_lock_anyway('upgrade')
|
||||
|
||||
|
||||
@argmethod.wrap
|
||||
async def get_db_version():
|
||||
coll = db.coll('system')
|
||||
doc = await coll.find_one({'_id': 'db_version'})
|
||||
if doc is None:
|
||||
return 0
|
||||
else:
|
||||
return doc['value']
|
||||
|
||||
|
||||
async def set_db_version(version: int):
|
||||
coll = db.coll('system')
|
||||
result = await coll.update_one(filter={'_id': 'db_version'},
|
||||
update={'$set': {'value': version}},
|
||||
upsert=True)
|
||||
return result.modified_count
|
||||
|
||||
|
||||
async def ensure_db_version(allowed_version=None):
|
||||
if allowed_version is None:
|
||||
allowed_version = EXPECTED_DB_VERSION
|
||||
current_version = await get_db_version()
|
||||
if current_version != allowed_version:
|
||||
raise error.DatabaseVersionMismatchError(current_version, allowed_version)
|
||||
|
||||
|
||||
@argmethod.wrap
|
||||
async def setup():
|
||||
"""
|
||||
Set up for fresh install
|
||||
"""
|
||||
coll = db.coll('system')
|
||||
fdoc = await coll.find_one({'_id': 'user_counter'})
|
||||
if fdoc:
|
||||
# skip if not fresh install
|
||||
return
|
||||
await set_db_version(EXPECTED_DB_VERSION)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
argmethod.invoke_by_args()
|
||||
|
||||
*/
|
||||
+20
-17
@@ -1,6 +1,6 @@
|
||||
const
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('token');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('token');
|
||||
|
||||
module.exports = {
|
||||
TYPE_SESSION: 0,
|
||||
@@ -14,15 +14,16 @@ module.exports = {
|
||||
* @returns {Array} token ID, token data
|
||||
*/
|
||||
async add(tokenType, expireSeconds, data) {
|
||||
let now = new Date();
|
||||
let str = String.random(32);
|
||||
let res = await coll.insertOne(Object.assign({}, data, {
|
||||
const now = new Date();
|
||||
const str = String.random(32);
|
||||
const res = await coll.insertOne({
|
||||
...data,
|
||||
_id: str,
|
||||
tokenType,
|
||||
createAt: now,
|
||||
updateAt: now,
|
||||
expireAt: new Date(now.getTime() + expireSeconds * 1000)
|
||||
}));
|
||||
expireAt: new Date(now.getTime() + expireSeconds * 1000),
|
||||
});
|
||||
return [str, res.ops];
|
||||
},
|
||||
|
||||
@@ -45,12 +46,14 @@ module.exports = {
|
||||
* @returns {object} The token document, or null.
|
||||
*/
|
||||
async update(tokenId, tokenType, expireSeconds, data) {
|
||||
let now = new Date();
|
||||
let res = await coll.findOneAndUpdate({ _id: tokenId, tokenType }, {
|
||||
$set: Object.assign({
|
||||
const now = new Date();
|
||||
const res = await coll.findOneAndUpdate({ _id: tokenId, tokenType }, {
|
||||
$set: {
|
||||
updateAt: now,
|
||||
expireAt: new Date(now.getTime() + expireSeconds * 1000)
|
||||
}, data, { tokenType })
|
||||
expireAt: new Date(now.getTime() + expireSeconds * 1000),
|
||||
...data,
|
||||
tokenType,
|
||||
},
|
||||
});
|
||||
return res.value;
|
||||
},
|
||||
@@ -62,10 +65,10 @@ module.exports = {
|
||||
* @returns {boolean} true if deleted, or false.
|
||||
*/
|
||||
async delete(tokenId, tokenType) {
|
||||
let result = await coll.deleteOne({ _id: tokenId, tokenType });
|
||||
const result = await coll.deleteOne({ _id: tokenId, tokenType });
|
||||
return !!result.deletedCount;
|
||||
},
|
||||
async getMostRecentSessionByUid(uid) {
|
||||
return await coll.findOne({ uid, token_type: this.TYPE_SESSION }, { sort: { updateAt: -1 } });
|
||||
}
|
||||
getMostRecentSessionByUid(uid) {
|
||||
return coll.findOne({ uid, token_type: this.TYPE_SESSION }, { sort: { updateAt: -1 } });
|
||||
},
|
||||
};
|
||||
+25
-27
@@ -1,26 +1,27 @@
|
||||
const
|
||||
validator = require('../lib/validator'),
|
||||
{ ValidationError, TrainingNotFoundError } = require('../error'),
|
||||
db = require('../service/db.js'),
|
||||
coll = db.collection('traning'),
|
||||
coll_status = db.collection('training.status');
|
||||
const validator = require('../lib/validator');
|
||||
const { ValidationError, TrainingNotFoundError } = require('../error');
|
||||
const db = require('../service/db.js');
|
||||
|
||||
const coll = db.collection('traning');
|
||||
const collStatus = db.collection('training.status');
|
||||
|
||||
module.exports = {
|
||||
SETTING_DIFFICULTY_ALGORITHM: 0,
|
||||
SETTING_DIFFICULTY_ADMIN: 1,
|
||||
SETTING_DIFFICULTY_AVERAGE: 2,
|
||||
|
||||
async add(title, content, owner_uid, dag = [], desc = '') {
|
||||
validator.check_title(title);
|
||||
validator.check_intro(content);
|
||||
validator.check_description(desc);
|
||||
for (let node of dag)
|
||||
for (let nid of node['require_nids'])
|
||||
if (nid >= node._id)
|
||||
throw new ValidationError('dag');
|
||||
async add(title, content, owner, dag = [], desc = '') {
|
||||
validator.checkTitle(title);
|
||||
validator.checkIntro(content);
|
||||
validator.checkDescription(desc);
|
||||
for (const node of dag) { for (const nid of node.require_nids) if (nid >= node._id) throw new ValidationError('dag'); }
|
||||
return await coll.insertOne({
|
||||
content, owner_uid,
|
||||
dag, title, desc, enroll: 0
|
||||
content,
|
||||
owner,
|
||||
dag,
|
||||
title,
|
||||
desc,
|
||||
enroll: 0,
|
||||
});
|
||||
},
|
||||
count: (query) => coll.find(query).count(),
|
||||
@@ -28,24 +29,21 @@ module.exports = {
|
||||
if ($set.title) validator.check_title($set.title);
|
||||
if ($set.content) validator.check_intro($set.content);
|
||||
if ($set.desc) validator.check_description($set.desc);
|
||||
if ($set.dag)
|
||||
for (let node of $set.dag)
|
||||
for (let nid of node.require_nids)
|
||||
if (nid >= node._id) throw new ValidationError('dag');
|
||||
if ($set.dag) { for (const node of $set.dag) for (const nid of node.require_nids) if (nid >= node._id) throw new ValidationError('dag'); }
|
||||
await coll.findOneAndUpdate({ tid }, { $set });
|
||||
let tdoc = await coll.findOne({ tid });
|
||||
const tdoc = await coll.findOne({ tid });
|
||||
if (!tdoc) throw new TrainingNotFoundError(tid);
|
||||
return tdoc;
|
||||
},
|
||||
async get(tid) {
|
||||
let tdoc = await coll.findOne({ tid });
|
||||
const tdoc = await coll.findOne({ tid });
|
||||
if (!tdoc) throw new TrainingNotFoundError(tid);
|
||||
return tdoc;
|
||||
},
|
||||
get_multi: (query) => coll.find( query),
|
||||
get_multi_status: (query) => coll_status.find(query),
|
||||
get_status: (tid, uid) => coll_status.findOne({ tid, uid }),
|
||||
set_status: (tid, uid, $set) => coll_status.findOneAndUpdate({ tid, uid }, { $set })
|
||||
get_multi: (query) => coll.find(query),
|
||||
get_multi_status: (query) => collStatus.find(query),
|
||||
get_status: (tid, uid) => collStatus.findOne({ tid, uid }),
|
||||
set_status: (tid, uid, $set) => collStatus.findOneAndUpdate({ tid, uid }, { $set }),
|
||||
|
||||
};
|
||||
|
||||
@@ -66,4 +64,4 @@ async def get_dict(domainId, tids, *, fields=None):
|
||||
fields=fields):
|
||||
result[tdoc['doc_id']] = tdoc
|
||||
return result
|
||||
*/
|
||||
*/
|
||||
+51
-42
@@ -1,11 +1,11 @@
|
||||
const
|
||||
system = require('./system'),
|
||||
{ UserNotFoundError, UserAlreadyExistError } = require('../error'),
|
||||
pwhash = require('../lib/pwhash'),
|
||||
validator = require('../lib/validator'),
|
||||
db = require('../service/db'),
|
||||
coll = db.collection('user'),
|
||||
coll_role = db.collection('role');
|
||||
const system = require('./system');
|
||||
const { UserNotFoundError, UserAlreadyExistError } = require('../error');
|
||||
const pwhash = require('../lib/pwhash');
|
||||
const validator = require('../lib/validator');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('user');
|
||||
const collRole = db.collection('role');
|
||||
|
||||
class USER {
|
||||
constructor(user) {
|
||||
@@ -24,75 +24,78 @@ class USER {
|
||||
this.nAccept = user.nAccept || 0;
|
||||
this.nSubmit = user.nSubmit || 0;
|
||||
}
|
||||
|
||||
hasPerm(perm) {
|
||||
return this.perm == '-' || (this.perm || '').includes(perm);
|
||||
return this.perm === '-' || (this.perm || '').includes(perm);
|
||||
}
|
||||
|
||||
checkPassword(password) {
|
||||
return pwhash.check(password, this.salt, this.hash);
|
||||
}
|
||||
}
|
||||
async function getById(_id) {
|
||||
let udoc = await coll.findOne({ _id });
|
||||
const udoc = await coll.findOne({ _id });
|
||||
if (!udoc) throw new UserNotFoundError(_id);
|
||||
let role = await coll_role.findOne({ _id: udoc.role || 'default' });
|
||||
const role = await collRole.findOne({ _id: udoc.role || 'default' });
|
||||
udoc.perm = role.perm;
|
||||
return new USER(udoc);
|
||||
}
|
||||
async function getList(uids) {
|
||||
let r = {};
|
||||
for (let uid of uids)
|
||||
r[uid] = await getById(uid);
|
||||
const r = {};
|
||||
for (const uid of uids) r[uid] = await getById(uid); // eslint-disable-line no-await-in-loop
|
||||
return r;
|
||||
}
|
||||
async function getByUname(uname) {
|
||||
let unameLower = uname.trim().toLowerCase();
|
||||
let udoc = await coll.findOne({ unameLower });
|
||||
const unameLower = uname.trim().toLowerCase();
|
||||
const udoc = await coll.findOne({ unameLower });
|
||||
if (!udoc) throw new UserNotFoundError(uname);
|
||||
let role = await coll_role.findOne({ _id: udoc.role || 'default' });
|
||||
const role = await collRole.findOne({ _id: udoc.role || 'default' });
|
||||
udoc.perm = role.perm;
|
||||
return new USER(udoc);
|
||||
}
|
||||
async function getByEmail(mail, ignoreMissing = false) {
|
||||
let mailLower = mail.trim().toLowerCase();
|
||||
let udoc = await coll.findOne({ mailLower });
|
||||
const mailLower = mail.trim().toLowerCase();
|
||||
const udoc = await coll.findOne({ mailLower });
|
||||
if (!udoc) {
|
||||
if (ignoreMissing) return null;
|
||||
else throw new UserNotFoundError(mail);
|
||||
throw new UserNotFoundError(mail);
|
||||
}
|
||||
let role = await coll_role.findOne({ _id: udoc.role || 'default' });
|
||||
const role = await collRole.findOne({ _id: udoc.role || 'default' });
|
||||
udoc.perm = role.perm;
|
||||
return new USER(udoc);
|
||||
}
|
||||
async function setPassword(uid, password) {
|
||||
function setPassword(uid, password) {
|
||||
validator.checkPassword(password);
|
||||
let salt = pwhash.salt();
|
||||
return await coll.findOneAndUpdate({ _id: uid }, {
|
||||
$set: { salt, hash: pwhash.hash(password, salt) }
|
||||
const salt = pwhash.salt();
|
||||
return coll.findOneAndUpdate({ _id: uid }, {
|
||||
$set: { salt, hash: pwhash.hash(password, salt) },
|
||||
});
|
||||
}
|
||||
async function setEmail(uid, mail) {
|
||||
validator.checkEmail(mail);
|
||||
return await setById(uid, { mail, mailLower: mail.trim().toLowerCase() });
|
||||
}
|
||||
function setById(uid, args) {
|
||||
coll.findOneAndUpdate({ _id: uid }, { $set: args });
|
||||
}
|
||||
function setEmail(uid, mail) {
|
||||
validator.checkEmail(mail);
|
||||
return setById(uid, { mail, mailLower: mail.trim().toLowerCase() });
|
||||
}
|
||||
async function changePassword(uid, currentPassword, newPassword) {
|
||||
validator.checkPassword(newPassword);
|
||||
let udoc = await getById(uid);
|
||||
const udoc = await getById(uid);
|
||||
udoc.checkPassword(currentPassword);
|
||||
let salt = pwhash.salt();
|
||||
const salt = pwhash.salt();
|
||||
return await coll.findOneAndUpdate({
|
||||
_id: udoc._id
|
||||
_id: udoc._id,
|
||||
}, {
|
||||
$set: { salt, hash: pwhash.hash(newPassword, salt) }
|
||||
$set: { salt, hash: pwhash.hash(newPassword, salt) },
|
||||
});
|
||||
}
|
||||
async function create({ uid, mail, uname, password, regip = '127.0.0.1', role = 'default' }) {
|
||||
async function create({
|
||||
uid, mail, uname, password, regip = '127.0.0.1', role = 'default',
|
||||
}) {
|
||||
validator.checkUname(uname);
|
||||
validator.checkPassword(password);
|
||||
validator.checkEmail(mail);
|
||||
let salt = pwhash.salt();
|
||||
const salt = pwhash.salt();
|
||||
if (!uid) uid = system.incUserCounter();
|
||||
try {
|
||||
await coll.insertOne({
|
||||
@@ -108,10 +111,10 @@ async function create({ uid, mail, uname, password, regip = '127.0.0.1', role =
|
||||
loginat: new Date(),
|
||||
loginip: regip,
|
||||
role,
|
||||
gravatar: mail
|
||||
gravatar: mail,
|
||||
});
|
||||
} catch (e) {
|
||||
throw new UserAlreadyExistError([uid, uname, email]);
|
||||
throw new UserAlreadyExistError([uid, uname, mail]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,8 +123,14 @@ function getMany(params) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
changePassword, create, getByEmail,
|
||||
getById, getByUname, getMany,
|
||||
setById, setEmail,
|
||||
setPassword, getList
|
||||
};
|
||||
changePassword,
|
||||
create,
|
||||
getByEmail,
|
||||
getById,
|
||||
getByUname,
|
||||
getMany,
|
||||
setById,
|
||||
setEmail,
|
||||
setPassword,
|
||||
getList,
|
||||
};
|
||||
Reference in new issue
Block a user