mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
!UNSTABLE 优化数据库结构,为domain功能准备
This commit is contained in:
1 parent
7d27e56018
commit
fff2172c38
40 files changed
+1411
-1012
No files matched your search
@@ -15,10 +15,10 @@ function del(ip) {
|
||||
return coll.deleteOne({ _id: ip });
|
||||
}
|
||||
|
||||
function index() {
|
||||
function ensureIndexes() {
|
||||
return coll.createIndex('expireAt', { expireAfterSeconds: 0 });
|
||||
}
|
||||
|
||||
global.Hydro.model.blacklist = module.exports = {
|
||||
add, get, del, index,
|
||||
add, get, del, ensureIndexes,
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
const perm = require('../permission');
|
||||
|
||||
const BUILTIN_ROLES = [
|
||||
{ _id: 'guest', perm: perm.PERM_BASIC },
|
||||
{ _id: 'default', perm: perm.PERM_DEFAULT, count: 0 },
|
||||
{ _id: 'root', perm: perm.PERM_ALL, count: 0 },
|
||||
];
|
||||
const BUILTIN_ROLES = {
|
||||
guest: { perm: perm.PERM_BASIC },
|
||||
default: { perm: perm.PERM_DEFAULT },
|
||||
admin: { perm: perm.PERM_ADMIN },
|
||||
};
|
||||
|
||||
const DEFAULT_NODES = {
|
||||
探索: [
|
||||
|
||||
+53
-42
@@ -7,10 +7,7 @@ const {
|
||||
const { PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD } = require('../permission');
|
||||
const validator = require('../lib/validator');
|
||||
const ranked = require('../lib/rank');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('contest');
|
||||
const collStatus = db.collection('contest.status');
|
||||
const document = require('./document');
|
||||
|
||||
const acm = {
|
||||
TEXT: 'ACM/ICPC',
|
||||
@@ -197,6 +194,7 @@ const RULES = {
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @param {number} owner
|
||||
@@ -207,7 +205,7 @@ const RULES = {
|
||||
* @param {object} data
|
||||
* @returns {ObjectID} tid
|
||||
*/
|
||||
async function add(title, content, owner, rule,
|
||||
function add(domainId, title, content, owner, rule,
|
||||
beginAt = new Date(), endAt = new Date(), pids = [], data = {}) {
|
||||
validator.checkTitle(title);
|
||||
validator.checkContent(content);
|
||||
@@ -217,15 +215,18 @@ async function add(title, content, owner, rule,
|
||||
content, owner, title, rule, beginAt, endAt, pids, attend: 0,
|
||||
});
|
||||
this.RULES[rule].check(data);
|
||||
const res = await coll.insertOne(data);
|
||||
return res.insertedId;
|
||||
return document.add(domainId, content, owner, document.TYPE_CONTEST, null, null, null, {
|
||||
...data, title, rule, beginAt, endAt, pids, attend: 0,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {ObjectID} tid
|
||||
* @param {object} $set
|
||||
* @returns {Tdoc} tdoc after modification
|
||||
*/
|
||||
async function edit(tid, $set) {
|
||||
async function edit(domainId, 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'); }
|
||||
@@ -234,53 +235,55 @@ async function edit(tid, $set) {
|
||||
throw new ValidationError('beginAt', 'endAt');
|
||||
}
|
||||
}
|
||||
const tdoc = await coll.findOne({ tid });
|
||||
const tdoc = await document.get(domainId, document.TYPE_CONTEST, 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;
|
||||
return await document.set(domainId, document.TYPE_CONTEST, tid, $set);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {ObjectID} tid
|
||||
* @returns {Tdoc}
|
||||
*/
|
||||
async function get(tid) {
|
||||
const tdoc = await coll.findOne({ _id: tid });
|
||||
async function get(domainId, tid) {
|
||||
const tdoc = await document.get(domainId, document.TYPE_CONTEST, tid);
|
||||
if (!tdoc) throw new ContestNotFoundError(tid);
|
||||
return tdoc;
|
||||
}
|
||||
async function updateStatus(tid, uid, rid, pid, accept, score) {
|
||||
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 });
|
||||
async function updateStatus(domainId, tid, uid, rid, pid, accept, score) {
|
||||
await get(domainId, tid);
|
||||
const tsdoc = await document.revPushStatus(domainId, document.TYPE_CONTEST, tid, uid, 'journal', {
|
||||
rid, pid, accept, score,
|
||||
});
|
||||
if (!tsdoc.value.attend) throw new ContestNotAttendedError(tid, uid);
|
||||
}
|
||||
function getStatus(tid, uid) {
|
||||
return collStatus.findOne({ tid, uid });
|
||||
|
||||
function getStatus(domainId, tid, uid) {
|
||||
return document.getStatus(domainId, tid, uid);
|
||||
}
|
||||
async function getListStatus(uid, tids) {
|
||||
|
||||
async function getListStatus(domainId, uid, tids) {
|
||||
const r = {};
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const tid of tids) r[tid] = await getStatus(tid, uid);
|
||||
for (const tid of tids) r[tid] = await getStatus(domainId, tid, uid);
|
||||
return r;
|
||||
}
|
||||
async function attend(tid, uid) {
|
||||
|
||||
async function attend(domainId, tid, uid) {
|
||||
try {
|
||||
await collStatus.insertOne({ tid, uid, attend: 1 });
|
||||
await document.cappedIncStatus(domainId, document.TYPE_CONTEST, tid, uid, 'attend', 1, 0, 1);
|
||||
} catch (e) {
|
||||
throw new ContestAlreadyAttendedError(tid, uid);
|
||||
}
|
||||
await coll.findOneAndUpdate({ _id: tid }, { $inc: { attend: 1 } });
|
||||
await document.inc(domainId, document, document.TYPE_CONTEST, tid, 'attend', 1);
|
||||
return {};
|
||||
}
|
||||
|
||||
function getMultiStatus(query) {
|
||||
return collStatus.find(query);
|
||||
return document.getMultiStatus(query);
|
||||
}
|
||||
|
||||
function isNew(tdoc, days = 1) {
|
||||
const now = new Date().getTime();
|
||||
const readyAt = tdoc.beginAt.getTime();
|
||||
@@ -319,29 +322,37 @@ const ContestHandlerMixin = (c) => class extends c {
|
||||
return false;
|
||||
}
|
||||
|
||||
async getScoreboard(tid, isExport = false) {
|
||||
const tdoc = await get(tid);
|
||||
async getScoreboard(domainId, tid, isExport = false) {
|
||||
const tdoc = await get(domainId, tid);
|
||||
if (!this.canShowScoreboard(tdoc)) throw new ContestScoreboardHiddenError(tid);
|
||||
const tsdocs = await getMultiStatus(tid).sort(RULES[tdoc.rule].statusSort).toArray();
|
||||
const tsdocs = await getMultiStatus(domainId, 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 [udict, pdict] = await Promise.all([
|
||||
user.getList(uids),
|
||||
problem.getList(domainId, 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) { // eslint-disable-line class-methods-use-this
|
||||
async verifyProblems(domainId, 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);
|
||||
const res = await problem.get(domainId, pid); // eslint-disable-line no-await-in-loop
|
||||
if (res) r.push(res.docId);
|
||||
else throw new ProblemNotFoundError(pid);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
function setStatus(domainId, tid, uid, $set) {
|
||||
return document.setStatus(domainId, document.TYPE_CONTEST, tid, uid, $set);
|
||||
}
|
||||
|
||||
global.Hydro.model.contest = module.exports = {
|
||||
RULES,
|
||||
ContestHandlerMixin,
|
||||
@@ -352,9 +363,9 @@ global.Hydro.model.contest = module.exports = {
|
||||
get,
|
||||
updateStatus,
|
||||
getStatus,
|
||||
count: (query) => coll.find(query).count(),
|
||||
getMulti: (query) => coll.find(query),
|
||||
setStatus: (tid, uid, $set) => collStatus.findOneAndUpdate({ tid, uid }, { $set }),
|
||||
count: (query) => document.count({ ...query, docType: document.TYPE_CONTEST }),
|
||||
getMulti: (query = {}) => document.getMulti({ ...query, docType: document.TYPE_CONTEST }),
|
||||
setStatus,
|
||||
isNew,
|
||||
isUpcoming,
|
||||
isNotStarted,
|
||||
@@ -390,7 +401,7 @@ async def recalc_status(domainId: str, doc_type: int, cid: objeccid.Objeccid):
|
||||
tdoc = await document.get(domainId, doc_type, cid)
|
||||
async with document.get_multi_status(domainId=domainId,
|
||||
doc_type=doc_type,
|
||||
doc_id=tdoc._id) as tsdocs:
|
||||
doc_id=tdoc.docId) as tsdocs:
|
||||
async for tsdoc in tsdocs:
|
||||
if 'journal' not in tsdoc or not tsdoc['journal']:
|
||||
continue
|
||||
|
||||
+75
-92
@@ -1,157 +1,140 @@
|
||||
const { ObjectID } = require('bson');
|
||||
const problem = require('./problem');
|
||||
const document = require('./document');
|
||||
const contest = require('./contest');
|
||||
const { PERM_VIEW_PROBLEM_HIDDEN } = require('../permission');
|
||||
const { DocumentNotFoundError } = require('../error');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('discussion');
|
||||
const collReply = db.collection('discussion.reply');
|
||||
const collStatus = db.collection('discussion.status');
|
||||
const collNode = db.collection('discussion.node');
|
||||
|
||||
async function add(parentType, parentId, owner, title, content, ip = null, highlight = false) {
|
||||
const res = await coll.insertOne({
|
||||
owner,
|
||||
title,
|
||||
content,
|
||||
ip,
|
||||
highlight,
|
||||
parentType,
|
||||
parentId,
|
||||
nReply: 0,
|
||||
updateAt: new Date(),
|
||||
});
|
||||
return res.insertedId;
|
||||
function add(domainId, parentType, parentId, owner, title, content, ip = null, highlight = false) {
|
||||
return document.add(
|
||||
domainId, content, owner, document.TYPE_DISCUSSION,
|
||||
null, parentType, parentId,
|
||||
{
|
||||
title,
|
||||
ip,
|
||||
highlight,
|
||||
nReply: 0,
|
||||
updateAt: new Date(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function get(did) {
|
||||
return coll.findOne({ _id: did });
|
||||
function get(domainId, did) {
|
||||
return document.get(domainId, document.TYPE_DISCUSSION, did);
|
||||
}
|
||||
|
||||
function edit(did, title, content, highlight) {
|
||||
return coll.findOneAndUpdate({ _id: did }, { $set: { title, content, highlight } });
|
||||
function edit(domainId, did, title, content, highlight) {
|
||||
return document.set(domainId, document.TYPE_DISCUSSION, did, { title, content, highlight });
|
||||
}
|
||||
|
||||
function del(did) {
|
||||
function del(domainId, did) {
|
||||
// TODO(masnn) delete status
|
||||
return Promise.all([
|
||||
coll.deleteOne({ _id: did }),
|
||||
collReply.deleteMany({ did }),
|
||||
collStatus.deleteMany({ did }),
|
||||
document.deleteOne(domainId, document.TYPE_DISCUSSION, did),
|
||||
document.deleteMulti(domainId, document.TYPE_DISCUSSION_REPLY, {
|
||||
parentType: document.TYPE_DISCUSSION, parentId: did,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
function count(domainId, query) {
|
||||
return document.count(domainId, document.TYPE_DISCUSSION, query);
|
||||
}
|
||||
|
||||
function getMulti(query) {
|
||||
return coll.find(query).sort('updateAt', -1);
|
||||
function getMulti(domainId, query) {
|
||||
return document.getMulti(domainId, document.TYPE_DISCUSSION, query).sort('updateAt', -1);
|
||||
}
|
||||
|
||||
async function addReply(did, owner, content, ip) {
|
||||
async function addReply(domainId, did, owner, content, ip) {
|
||||
const [drdoc] = await Promise.all([
|
||||
collReply.insertOne({
|
||||
owner, did, content, ip,
|
||||
}),
|
||||
coll.updateOne({ _id: did }, { $inc: { nReply: 1 }, $set: { updateAt: new Date() } }),
|
||||
document.add(
|
||||
domainId, content, owner, document.TYPE_DISCUSSION_REPLY,
|
||||
null, document.TYPE_DISCUSSION, did, { ip },
|
||||
),
|
||||
document.incAndSet(domainId, document.TYPE_DISCUSSION, did, 'nReply', 1, { updateAt: new Date() }),
|
||||
]);
|
||||
return drdoc;
|
||||
}
|
||||
|
||||
function getReply(drid) {
|
||||
return collReply.findOne({ _id: drid });
|
||||
function getReply(domainId, drid) {
|
||||
return document.get(domainId, document.TYPE_DISCUSSION_REPLY, drid);
|
||||
}
|
||||
|
||||
function editReply(drid, content) {
|
||||
return collReply.updateOne({ _id: drid }, { $set: { content } });
|
||||
function editReply(domainId, drid, content) {
|
||||
return document.set(domainId, document.TYPE_DISCUSSION_REPLY, drid, { content });
|
||||
}
|
||||
|
||||
async function delReply(drid) {
|
||||
const drdoc = await getReply(drid);
|
||||
async function delReply(domainId, drid) {
|
||||
const drdoc = await getReply(domainId, drid);
|
||||
if (!drdoc) throw new DocumentNotFoundError(drid);
|
||||
return await Promise.all([ // eslint-disable-line no-return-await
|
||||
collReply.deleteOne({ _id: drid }),
|
||||
coll.updateOne({ _id: drdoc.did }, { $inc: { nReply: -1 } }),
|
||||
document.deleteOne(domainId, document.TYPE_DISCUSSION_REPLY, drid),
|
||||
document.inc(domainId, document.TYPE_DISCUSSION, drdoc.parentId, 'nReply', -1),
|
||||
]);
|
||||
}
|
||||
|
||||
function getMultiReply(did) {
|
||||
return coll.find({ did }).sort('_id', -1);
|
||||
function getMultiReply(domainId, did) {
|
||||
return document.getMulti(
|
||||
domainId, document.TYPE_DISCUSSION_REPLY,
|
||||
{ parentType: document.TYPE_DISCUSSION, parentId: did },
|
||||
).sort('_id', -1);
|
||||
}
|
||||
|
||||
function getListReply(did) {
|
||||
return getMultiReply({ did }).toArray();
|
||||
function getListReply(domainId, did) {
|
||||
return getMultiReply(domainId, did).toArray();
|
||||
}
|
||||
|
||||
async function addTailReply(drid, owner, content, ip) {
|
||||
let drdoc = await collReply.findOne({ _id: drid });
|
||||
async function addTailReply(domainId, drid, owner, content, ip) {
|
||||
let drdoc = await document.get(domainId, document.TYPE_DISCUSSION_REPLY, drid);
|
||||
const sid = new ObjectID();
|
||||
await Promise.all([
|
||||
collReply.updateOne({ _id: drid }, {
|
||||
$push: {
|
||||
reply: {
|
||||
_id: sid, content, owner, ip,
|
||||
},
|
||||
},
|
||||
}),
|
||||
coll.updateOne({ _id: drdoc.did }, { $set: { updateAt: new Date() } }),
|
||||
[drdoc] = await Promise.all([
|
||||
document.push(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', content, owner, { ip }),
|
||||
document.set(domainId, document.TYPE_DISCUSSION, drdoc.parentId, { updateAt: new Date() }),
|
||||
]);
|
||||
drdoc = await collReply.findOne({ _id: drid });
|
||||
return [drdoc, sid];
|
||||
}
|
||||
|
||||
async function getTailReply(drid, drrid) {
|
||||
const drdoc = await collReply.findOne({ _id: drid, reply: { $elemMatch: { _id: drrid } } });
|
||||
if (!drdoc) return [null, null];
|
||||
for (const drrdoc of drdoc) if (drrdoc._id === drrid) return [drdoc, drrdoc];
|
||||
return [drdoc, null];
|
||||
function getTailReply(domainId, drid, drrid) {
|
||||
return document.getSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid);
|
||||
}
|
||||
|
||||
async function editTailReply(drid, drrid, content) {
|
||||
const drdoc = await collReply.findOne({ _id: drid, reply: { $elemMatch: { _id: drrid } } });
|
||||
const { reply } = drdoc;
|
||||
for (const i in reply) {
|
||||
if (reply[i]._id === drrid) {
|
||||
reply[i].content = content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-return-await
|
||||
return await collReply.findOneAndUpdate({ _id: drdoc._id }, { $set: { reply } });
|
||||
function editTailReply(domainId, drid, drrid, content) {
|
||||
return document.setSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid, { content });
|
||||
}
|
||||
|
||||
function delTailReply(drid, drrid) {
|
||||
return coll.findOneAndUpdate({ _id: drid }, { $pull: { reply: { _id: drrid } } });
|
||||
function delTailReply(domainId, drid, drrid) {
|
||||
return document.deleteSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid);
|
||||
}
|
||||
|
||||
function setStar(did, uid, star) {
|
||||
return collStatus.findOneAndUpdate({ did, uid }, { $set: { star } }, { upsert: true });
|
||||
function setStar(domainId, did, uid, star) {
|
||||
return document.setStatus(domainId, document.TYPE_DISCUSSION, did, uid, { star });
|
||||
}
|
||||
|
||||
function getStatus(did, uid) {
|
||||
return collStatus.findOne({ did, uid });
|
||||
function getStatus(domainId, did, uid) {
|
||||
return document.getStatus(domainId, document.TYPE_DISCUSSION, did, uid);
|
||||
}
|
||||
|
||||
function addNode(_id, category) {
|
||||
return collNode.insertOne({ _id, category });
|
||||
function addNode(domainId, _id, category) {
|
||||
return document.add(
|
||||
domainId, _id, 1, document.TYPE_DISCUSSION_NODE, null, null, null, { category },
|
||||
);
|
||||
}
|
||||
|
||||
function getNode(_id) {
|
||||
return collNode.findOne({ _id });
|
||||
function getNode(domainId, _id) {
|
||||
return document.get(domainId, document.TYPE_DISCUSSION_NODE, _id);
|
||||
}
|
||||
|
||||
async function getVnode(ddoc, handler) {
|
||||
async function getVnode(domainId, ddoc, handler) {
|
||||
if (ddoc.parentType === 'problem') {
|
||||
const pdoc = await problem.getById(ddoc.parentId);
|
||||
const pdoc = await problem.getById(domainId, ddoc.parentId);
|
||||
if (!pdoc) return null;
|
||||
if (pdoc.hidden && handler) handler.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||
return { ...pdoc, type: ddoc.parentType, id: ddoc.parentId };
|
||||
} if (ddoc.parentType === 'contest') {
|
||||
const tdoc = await contest.get(ddoc.parentId);
|
||||
const tdoc = await contest.get(domainId, ddoc.parentId);
|
||||
return { ...tdoc, type: ddoc.parentType, id: ddoc.parentId };
|
||||
} if (ddoc.parentType === 'node') {
|
||||
const ndoc = await getNode(ddoc.parentId);
|
||||
const ndoc = await getNode(domainId, ddoc.parentId);
|
||||
return { title: ndoc._id, type: ddoc.parentType, id: ddoc.parentId };
|
||||
}
|
||||
return {
|
||||
@@ -161,11 +144,11 @@ async function getVnode(ddoc, handler) {
|
||||
};
|
||||
}
|
||||
|
||||
async function getListVnodes(ddocs, handler) {
|
||||
async function getListVnodes(domainId, ddocs, handler) {
|
||||
const res = {};
|
||||
for (const ddoc of ddocs) {
|
||||
// FIXME no-await-in-loop
|
||||
res[ddoc._id] = await getVnode(ddoc, handler); // eslint-disable-line no-await-in-loop
|
||||
res[ddoc._id] = await getVnode(domainId, ddoc, handler); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
const assert = require('assert');
|
||||
const { ObjectID } = require('bson');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('document');
|
||||
const collStatus = db.collection('document.status');
|
||||
|
||||
const TYPE_DOMAIN_ROLE = 0;
|
||||
const TYPE_PROBLEM = 10;
|
||||
const TYPE_PROBLEM_SOLUTION = 11;
|
||||
const TYPE_PROBLEM_LIST = 12;
|
||||
const TYPE_DISCUSSION_NODE = 20;
|
||||
const TYPE_DISCUSSION = 21;
|
||||
const TYPE_DISCUSSION_REPLY = 22;
|
||||
const TYPE_CONTEST = 30;
|
||||
const TYPE_TRAINING = 40;
|
||||
const TYPE_FILE = 50;
|
||||
const TYPE_HOMEWORK = 60;
|
||||
|
||||
async function add(
|
||||
domainId, content, owner, docType, docId,
|
||||
parentType = null, parentId = null, args = {},
|
||||
) {
|
||||
const _id = new ObjectID();
|
||||
const doc = {
|
||||
content,
|
||||
owner,
|
||||
domainId,
|
||||
docType,
|
||||
docId: docId || _id,
|
||||
...args,
|
||||
};
|
||||
if (parentType || parentId) {
|
||||
assert(parentType && parentId);
|
||||
doc.parentType = parentType;
|
||||
doc.parentId = parentId;
|
||||
}
|
||||
const res = await coll.insertOne(doc);
|
||||
return docId || res.insertedId;
|
||||
}
|
||||
|
||||
function get(domainId, docType, docId) {
|
||||
return coll.findOne({ domainId, docType, docId });
|
||||
}
|
||||
|
||||
async function set(domainId, docType, docId, args) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $set: { args } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
function deleteOne(domainId, docType, docId) {
|
||||
// TODO(twd2): delete status?
|
||||
return coll.deleteOne({ domainId, docType, docId });
|
||||
}
|
||||
|
||||
function deleteMulti(domainId, docType, args = {}) {
|
||||
return coll.deleteMany({ ...args, domainId, docType });
|
||||
}
|
||||
|
||||
function deleteMultiStatus(domainId, docType, args = {}) {
|
||||
return collStatus.deleteMany({ ...args, domainId, docType });
|
||||
}
|
||||
|
||||
function getMulti(domainId, docType, args = {}) {
|
||||
return coll.find({ ...args, docType, domainId });
|
||||
}
|
||||
|
||||
async function inc(domainId, docType, docId, key, value) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $inc: { [key]: value } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function incAndSet(domainId, docType, docId, key, value, args) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $inc: { [key]: value }, $set: args },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
function count(domainId, docType, query) {
|
||||
return coll.find({ ...query, docType, domainId }).count();
|
||||
}
|
||||
|
||||
async function push(domainId, docType, docId, key, content, owner, args) {
|
||||
const _id = new ObjectID();
|
||||
const doc = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{
|
||||
$push: {
|
||||
[key]: {
|
||||
...args, content, owner, _id,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return [doc.value, _id];
|
||||
}
|
||||
|
||||
async function pull(domainId, docType, docId, setKey, contents) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $pull: { [setKey]: { $in: contents } } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function deleteSub(domainId, docType, docId, key, subId) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $pull: { [key]: { _id: subId } } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function getSub(domainId, docType, docId, key, subId) {
|
||||
const doc = await coll.findOne({
|
||||
domainId,
|
||||
docType,
|
||||
docId,
|
||||
[key]: { $elemMatch: { _id: subId } },
|
||||
});
|
||||
if (!doc) return [null, null];
|
||||
for (const sdoc of doc[key] || []) {
|
||||
if (sdoc._id === subId) {
|
||||
return [doc, sdoc];
|
||||
}
|
||||
}
|
||||
return [doc, null];
|
||||
}
|
||||
|
||||
async function setSub(domainId, docType, docId, key, subId, args) {
|
||||
const $set = {};
|
||||
for (const k in args) {
|
||||
$set[`${key}.$.${k}`] = args[k];
|
||||
}
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{
|
||||
domainId,
|
||||
docType,
|
||||
docId,
|
||||
[key]: { $elemMatch: { _id: subId } },
|
||||
},
|
||||
{ $set },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function addToSet(domainId, docType, docId, setKey, content) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $addToSet: { [setKey]: content } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
function getStatus(domainId, docType, docId, uid) {
|
||||
return collStatus.findOne({
|
||||
domainId, docType, docId, uid,
|
||||
});
|
||||
}
|
||||
|
||||
function getMultiStatus(domainId, docType, args) {
|
||||
return collStatus.find({ ...args, docType, domainId });
|
||||
}
|
||||
|
||||
async function setStatus(domainId, docType, docId, uid, args) {
|
||||
const res = await collStatus.findOneAndUpdate(
|
||||
{
|
||||
domainId, docType, docId, uid,
|
||||
},
|
||||
{ $set: args },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function setIfNotStatus(domainId, docType, docId, uid, key, value, ifNot, args) {
|
||||
const res = await collStatus.findOneAndUpdate(
|
||||
{
|
||||
domainId, docType, docId, uid, key: { $not: { $eq: ifNot } },
|
||||
},
|
||||
{ $set: { [key]: value, args } },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function cappedIncStatus(
|
||||
domainId, docType, docId, uid,
|
||||
key, value, minValue = -1, maxValue = 1,
|
||||
) {
|
||||
assert(value !== 0);
|
||||
const $not = value > 0 ? { $gte: maxValue } : { $lte: minValue };
|
||||
const res = await collStatus.findOneAndUpdate(
|
||||
{
|
||||
domainId, docType, docId, uid, [key]: { $not },
|
||||
},
|
||||
{ $inc: { key: value } },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function incStatus(domainId, docType, docId, uid, key, value) {
|
||||
const res = await collStatus.findOneAndUpdate(
|
||||
{
|
||||
domainId, docType, docId, uid,
|
||||
},
|
||||
{ $inc: { [key]: value } },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function revPushStatus(domainId, docType, docId, uid, key, value) {
|
||||
const res = await collStatus.findOneAndUpdate(
|
||||
{
|
||||
domainId, docType, docId, uid,
|
||||
},
|
||||
{ $push: { [key]: value }, $inc: { rev: 1 } },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function revInitStatus(domainId, docType, docId, uid) {
|
||||
const res = await collStatus.findOneAndUpdate(
|
||||
{
|
||||
domainId, docType, docId, uid,
|
||||
},
|
||||
{ $inc: { rev: 1 } },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function revSetStatus(domainId, docType, docId, uid, rev, args, returnDoc = true) {
|
||||
const filter = {
|
||||
domainId, docType, docId, uid, rev,
|
||||
};
|
||||
const update = { $set: args, $inc: { rev: 1 } };
|
||||
if (returnDoc) {
|
||||
const res = await coll.findOneAndUpdate(filter, update, { returnOriginal: false });
|
||||
return res.value;
|
||||
}
|
||||
const res = await coll.updateOne(filter, update);
|
||||
return res;
|
||||
}
|
||||
|
||||
async function ensureIndexes() {
|
||||
await coll.createIndex({ domainId: 1, docType: 1, docId: 1 }, { unique: true });
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, owner: 1, docId: -1,
|
||||
});
|
||||
// For problem
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, category: 1, docId: 1,
|
||||
}, { sparse: true });
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, hidden: 1, category: 1, docId: 1,
|
||||
}, { sparse: true });
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, tag: 1, docId: 1,
|
||||
}, { sparse: true });
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, hidden: 1, tag: 1, docId: 1,
|
||||
}, { sparse: true });
|
||||
// For problem solution
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, parentType: 1, parentId: 1, vote: -1, docId: -1,
|
||||
}, { sparse: true });
|
||||
// For discussion
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, updateAt: -1, docId: -1,
|
||||
}, { sparse: true });
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, parentType: 1, parentId: 1, updateAt: -1, docId: -1,
|
||||
}, { sparse: true });
|
||||
// Hidden doc
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, hidden: 1, docId: -1,
|
||||
}, { sparse: true });
|
||||
// For contest
|
||||
await coll.createIndex({ domainId: 1, docType: 1, pids: 1 }, { sparse: true });
|
||||
await coll.createIndex({
|
||||
domainId: 1, docType: 1, rule: 1, docId: -1,
|
||||
}, { sparse: true });
|
||||
// For training
|
||||
await coll.createIndex({ domainId: 1, docType: 1, 'dag.pids': 1 }, { sparse: true });
|
||||
|
||||
await collStatus.createIndex({
|
||||
domainId: 1, docType: 1, uid: 1, docId: 1,
|
||||
}, { unique: true });
|
||||
// For rp system
|
||||
await collStatus.createIndex({
|
||||
domainId: 1, docType: 1, docId: 1, status: 1, rid: 1, rp: 1,
|
||||
}, { sparse: true });
|
||||
// For contest rule OI
|
||||
await collStatus.createIndex({
|
||||
domainId: 1, docType: 1, docId: 1, score: -1,
|
||||
}, { sparse: true });
|
||||
// For contest rule ACM
|
||||
await collStatus.createIndex({
|
||||
domainId: 1, docType: 1, docId: 1, accept: -1, time: 1,
|
||||
}, { sparse: true });
|
||||
// For training
|
||||
await collStatus.createIndex({
|
||||
domainId: 1, docType: 1, uid: 1, enroll: 1, docId: 1,
|
||||
}, { sparse: true });
|
||||
}
|
||||
|
||||
global.Hydro.model.document = module.exports = {
|
||||
add,
|
||||
addToSet,
|
||||
cappedIncStatus,
|
||||
count,
|
||||
deleteMulti,
|
||||
deleteMultiStatus,
|
||||
deleteOne,
|
||||
deleteSub,
|
||||
ensureIndexes,
|
||||
get,
|
||||
getMulti,
|
||||
getMultiStatus,
|
||||
getStatus,
|
||||
getSub,
|
||||
inc,
|
||||
incAndSet,
|
||||
incStatus,
|
||||
pull,
|
||||
push,
|
||||
revInitStatus,
|
||||
revPushStatus,
|
||||
revSetStatus,
|
||||
set,
|
||||
setIfNotStatus,
|
||||
setStatus,
|
||||
setSub,
|
||||
|
||||
TYPE_DOMAIN_ROLE,
|
||||
TYPE_CONTEST,
|
||||
TYPE_DISCUSSION,
|
||||
TYPE_DISCUSSION_NODE,
|
||||
TYPE_DISCUSSION_REPLY,
|
||||
TYPE_HOMEWORK,
|
||||
TYPE_PROBLEM,
|
||||
TYPE_PROBLEM_LIST,
|
||||
TYPE_PROBLEM_SOLUTION,
|
||||
TYPE_FILE,
|
||||
TYPE_TRAINING,
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
const builtin = require('./builtin');
|
||||
const document = require('./document');
|
||||
const db = require('../service/db');
|
||||
const validator = require('../lib/validator');
|
||||
|
||||
const coll = db.collection('domain');
|
||||
|
||||
/**
|
||||
* @typedef {import('../interface').Pdoc} Pdoc
|
||||
* @typedef {import('bson').ObjectID} ObjectID
|
||||
* @typedef {import('mongodb').Cursor} Cursor
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {number} owner
|
||||
*/
|
||||
function add(domainId, owner) {
|
||||
const tasks = [
|
||||
coll.insertOne({ _id: domainId, owner, bulletin: '' }),
|
||||
];
|
||||
for (const id in builtin.BUILTIN_ROLES) {
|
||||
tasks.push(
|
||||
document.add(
|
||||
domainId, builtin.BUILTIN_ROLES[id].perm, owner,
|
||||
document.TYPE_DOMAIN_ROLE, id,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Promise.all(tasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @returns {Ddoc}
|
||||
*/
|
||||
async function get(domainId) {
|
||||
return coll.findOne({ _id: domainId });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} query
|
||||
* @param {object} sort
|
||||
* @param {number} page
|
||||
* @param {number} limit
|
||||
* @returns {Ddoc[]}
|
||||
*/
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} query
|
||||
* @returns {Cursor}
|
||||
*/
|
||||
function getMulti(query) {
|
||||
return coll.find(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {object} $set
|
||||
* @returns {Ddoc}
|
||||
*/
|
||||
function edit(domainId, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkContent($set.content);
|
||||
return coll.updateOne({ _id: domainId }, { $set });
|
||||
}
|
||||
|
||||
async function inc(domainId, field, n) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ _id: domainId },
|
||||
{ $inc: { [field]: n } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function getList(domainIds) {
|
||||
const r = {};
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const domainId of domainIds) r[domainId] = await get(domainId);
|
||||
return r;
|
||||
}
|
||||
|
||||
global.Hydro.model.domain = module.exports = {
|
||||
add,
|
||||
inc,
|
||||
get,
|
||||
getMany,
|
||||
edit,
|
||||
getMulti,
|
||||
getList,
|
||||
};
|
||||
@@ -2,6 +2,7 @@ module.exports = {
|
||||
blacklist: require('./blacklist'),
|
||||
builtin: require('./builtin'),
|
||||
contest: require('./contest'),
|
||||
document: require('./document'),
|
||||
opcount: require('./opcount'),
|
||||
problem: require('./problem'),
|
||||
record: require('./record'),
|
||||
|
||||
@@ -55,7 +55,7 @@ function getMulti(uid) {
|
||||
return coll.find({ $or: [{ from: uid }, { to: uid }] });
|
||||
}
|
||||
|
||||
function index() {
|
||||
function ensureIndexes() {
|
||||
return Promise.all([
|
||||
coll.createIndex({ to: 1, _id: -1 }),
|
||||
coll.createIndex({ from: 1, _id: -1 }),
|
||||
@@ -69,5 +69,5 @@ global.Hydro.model.message = module.exports = {
|
||||
getMany,
|
||||
getMulti,
|
||||
send,
|
||||
index,
|
||||
ensureIndexes,
|
||||
};
|
||||
+70
-92
@@ -1,12 +1,10 @@
|
||||
const { ObjectID } = require('bson');
|
||||
const { STATUS_ACCEPTED } = require('./builtin').STATUS;
|
||||
const file = require('./file');
|
||||
const document = require('./document');
|
||||
const domain = require('./domain');
|
||||
const { ProblemNotFoundError } = require('../error');
|
||||
const validator = require('../lib/validator');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('problem');
|
||||
const collStatus = db.collection('problem.status');
|
||||
|
||||
/**
|
||||
* @typedef {import('../interface').Pdoc} Pdoc
|
||||
@@ -15,6 +13,7 @@ const collStatus = db.collection('problem.status');
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @param {number} owner
|
||||
@@ -24,10 +23,7 @@ const collStatus = db.collection('problem.status');
|
||||
* @param {string[]} tag
|
||||
* @param {boolean} hidden
|
||||
*/
|
||||
async function add({
|
||||
title,
|
||||
content,
|
||||
owner,
|
||||
async function add(domainId, title, content, owner, {
|
||||
pid = null,
|
||||
data = null,
|
||||
category = [],
|
||||
@@ -36,134 +32,118 @@ async function add({
|
||||
}) {
|
||||
validator.checkTitle(title);
|
||||
validator.checkContent(content);
|
||||
const res = await coll.insertOne({
|
||||
content,
|
||||
owner,
|
||||
pid,
|
||||
title,
|
||||
data,
|
||||
category,
|
||||
tag,
|
||||
hidden,
|
||||
nSubmit: 0,
|
||||
nAccept: 0,
|
||||
const d = await domain.inc(domainId, 'pidCounter', 1);
|
||||
if (!pid) pid = d.pidCounter.toString();
|
||||
return await document.add(domainId, content, owner, document.TYPE_PROBLEM, d.pidCounter, null, null, {
|
||||
pid, title, data, category, tag, hidden, nSubmit: 0, nAccept: 0,
|
||||
});
|
||||
return res.insertedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|ObjectID} pid
|
||||
* @param {string} domainId
|
||||
* @param {string|number} pid
|
||||
* @param {number} uid
|
||||
* @returns {Pdoc}
|
||||
*/
|
||||
async function get(pid, uid = null) {
|
||||
let query = {};
|
||||
if (pid.generationTime || pid.length === 24) query = { _id: new ObjectID(pid) };
|
||||
else query = { pid };
|
||||
const pdoc = await coll.findOne(query);
|
||||
async function get(domainId, pid, uid = null) {
|
||||
const pdoc = await document.get(domainId, document.TYPE_PROBLEM, pid);
|
||||
if (!pdoc) throw new ProblemNotFoundError(pid);
|
||||
if (uid) {
|
||||
query.uid = uid;
|
||||
pdoc.psdoc = await collStatus.findOne(query);
|
||||
pdoc.psdoc = await document.getStatus(domainId, document.TYPE_PROBLEM, pdoc.docId, uid);
|
||||
}
|
||||
return pdoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectID} pid
|
||||
* @returns {Pdoc}
|
||||
*/
|
||||
async function getById(_id) {
|
||||
_id = new ObjectID(_id);
|
||||
const pdoc = await coll.findOne({ _id });
|
||||
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||
return pdoc;
|
||||
}
|
||||
/**
|
||||
* @param {string|ObjectID} pid
|
||||
* @param {number} uid
|
||||
* @param {string} domainId
|
||||
* @param {object} query
|
||||
* @param {object} sort
|
||||
* @param {number} page
|
||||
* @param {number} limit
|
||||
* @returns {Pdoc[]}
|
||||
*/
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
function getMany(domainId, query, sort, page, limit) {
|
||||
return document.getMulti(domainId, query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {object} query
|
||||
* @returns {Cursor}
|
||||
*/
|
||||
function getMulti(query) {
|
||||
return coll.find(query);
|
||||
function getMulti(domainId, query) {
|
||||
return document.getMulti(domainId, document.TYPE_PROBLEM, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {object} query
|
||||
* @returns {Cursor}
|
||||
*/
|
||||
function getMultiStatus(query) {
|
||||
return collStatus.find(query);
|
||||
function getMultiStatus(domainId, query) {
|
||||
return document.getMultiStatus(domainId, document.TYPE_PROBLEM, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {ObjectID} _id
|
||||
* @param {object} query
|
||||
* @returns {Pdoc}
|
||||
*/
|
||||
async function edit(_id, $set) {
|
||||
function edit(domainId, _id, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkContent($set.content);
|
||||
await coll.findOneAndUpdate({ _id }, { $set });
|
||||
const pdoc = await getById(_id);
|
||||
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||
return pdoc;
|
||||
return document.set(domainId, document.TYPE_CONTEST, _id, $set);
|
||||
}
|
||||
async function inc(_id, field, n) {
|
||||
await coll.findOneAndUpdate({ _id }, { $inc: { [field]: n } });
|
||||
const pdoc = await getById(_id);
|
||||
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||
return pdoc;
|
||||
|
||||
function inc(domainId, _id, field, n) {
|
||||
return document.inc(domainId, document.TYPE_PROBLEM, _id, field, n);
|
||||
}
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
|
||||
function count(domainId, query) {
|
||||
return document.count(domainId, query);
|
||||
}
|
||||
async function random(query) {
|
||||
const cursor = coll.find(query);
|
||||
|
||||
async function random(domainId, query) {
|
||||
const cursor = document.getMulti(domainId, query);
|
||||
const pcount = await cursor.count();
|
||||
if (pcount) {
|
||||
const pdoc = await cursor.skip(Math.floor(Math.random() * pcount)).limit(1).toArray();
|
||||
return pdoc[0].pid;
|
||||
} return null;
|
||||
}
|
||||
async function getList(pids) {
|
||||
|
||||
async function getList(domainId, pids) {
|
||||
const r = {};
|
||||
for (const pid of pids) r[pid] = await get(pid); // eslint-disable-line no-await-in-loop
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const pid of pids) r[pid] = await get(domainId, pid);
|
||||
return r;
|
||||
}
|
||||
async function getListStatus(uid, pids) {
|
||||
const psdocs = await getMultiStatus({ uid, pid: { $in: Array.from(new Set(pids)) } }).toArray();
|
||||
const r = {};
|
||||
for (const psdoc of psdocs) r[psdoc.pid] = psdoc;
|
||||
return r;
|
||||
}
|
||||
async function updateStatus(pid, uid, rid, status) {
|
||||
const cur = collStatus.findOne({ pid, uid });
|
||||
if (cur && status !== STATUS_ACCEPTED) {
|
||||
if (cur.status !== STATUS_ACCEPTED) return false;
|
||||
}
|
||||
await collStatus.updateOne(
|
||||
{ pid, uid },
|
||||
{ $set: { rid, status } },
|
||||
{ upsert: true },
|
||||
);
|
||||
return true;
|
||||
}
|
||||
async function setTestdata(_id, readStream) {
|
||||
const pdoc = await getById(_id);
|
||||
const id = await file.add(readStream, 'data.zip');
|
||||
if (pdoc.data && typeof pdoc.data === 'object') file.dec(this.pdoc.data);
|
||||
return await edit(_id, { data: id }); // eslint-disable-line no-return-await
|
||||
}
|
||||
|
||||
async function getData(pid) {
|
||||
const pdoc = await get(pid);
|
||||
if (!pdoc.data) return null;
|
||||
return file.get(pdoc.data);
|
||||
async function getListStatus(domainId, uid, pids) {
|
||||
const psdocs = await getMultiStatus(
|
||||
domainId, { uid, docId: { $in: Array.from(new Set(pids)) } },
|
||||
).toArray();
|
||||
const r = {};
|
||||
for (const psdoc of psdocs) r[psdoc.docId] = psdoc;
|
||||
return r;
|
||||
}
|
||||
|
||||
async function updateStatus(domainId, pid, uid, rid, status) {
|
||||
try {
|
||||
await document.setIfNotStatus(domainId, document.TYPE_PROBLEM, pid, uid, 'status', status, STATUS_ACCEPTED, { rid });
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function setTestdata(domainId, _id, readStream) {
|
||||
const pdoc = await get(domainId, _id);
|
||||
const id = await file.add(readStream, 'data.zip');
|
||||
if (pdoc.data && typeof pdoc.data === 'object') file.dec(this.pdoc.data);
|
||||
return await edit(domainId, _id, { data: id }); // eslint-disable-line no-return-await
|
||||
}
|
||||
|
||||
global.Hydro.model.problem = module.exports = {
|
||||
@@ -174,12 +154,10 @@ global.Hydro.model.problem = module.exports = {
|
||||
edit,
|
||||
count,
|
||||
random,
|
||||
getById,
|
||||
getMulti,
|
||||
getList,
|
||||
getListStatus,
|
||||
getMultiStatus,
|
||||
setTestdata,
|
||||
updateStatus,
|
||||
getData,
|
||||
};
|
||||
+40
-27
@@ -9,11 +9,13 @@ const db = require('../service/db');
|
||||
const coll = db.collection('record');
|
||||
|
||||
/**
|
||||
* @param {string} domainId
|
||||
* @param {import('../interface').Record} data
|
||||
*/
|
||||
async function add(data) {
|
||||
async function add(domainId, data) {
|
||||
_.defaults(data, {
|
||||
status: STATUS_WAITING,
|
||||
domainId,
|
||||
score: 0,
|
||||
time: 0,
|
||||
memory: 0,
|
||||
@@ -27,32 +29,37 @@ async function add(data) {
|
||||
const res = await coll.insertOne(data);
|
||||
return res.insertedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} rid
|
||||
* @param {string} domainId
|
||||
* @param {ObjectID} rid
|
||||
* @returns {import('../interface').Record}
|
||||
*/
|
||||
async function get(rid) {
|
||||
async function get(domainId, rid) {
|
||||
const _id = new ObjectID(rid);
|
||||
const rdoc = await coll.findOne({ _id });
|
||||
const rdoc = await coll.findOne({ domainId, _id });
|
||||
if (!rdoc) throw new RecordNotFoundError(rid);
|
||||
return rdoc;
|
||||
}
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
|
||||
function getMany(domainId, query, sort, page, limit) {
|
||||
return coll.find({ ...query, domainId }).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
async function update(rid, $set, $push) {
|
||||
|
||||
async function update(domainId, rid, $set, $push) {
|
||||
const _id = new ObjectID(rid);
|
||||
const upd = {};
|
||||
if ($set && Object.keys($set).length) upd.$set = $set;
|
||||
if ($push && Object.keys($push).length) upd.$push = $push;
|
||||
await coll.findOneAndUpdate({ _id }, upd);
|
||||
await coll.findOneAndUpdate({ domainId, _id }, upd);
|
||||
const rdoc = await coll.findOne({ _id });
|
||||
if (!rdoc) throw new RecordNotFoundError(rid);
|
||||
return rdoc;
|
||||
}
|
||||
function reset(rid) {
|
||||
return update(rid, {
|
||||
|
||||
function reset(domainId, rid) {
|
||||
return update(domainId, rid, {
|
||||
score: 0,
|
||||
status: STATUS_WAITING,
|
||||
time: 0,
|
||||
@@ -65,24 +72,29 @@ function reset(rid) {
|
||||
rejudged: true,
|
||||
});
|
||||
}
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
async function getList(rids) {
|
||||
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) {
|
||||
return coll.find({ owner: uid, pid });
|
||||
|
||||
function count(domainId, query) {
|
||||
return coll.find({ domainId, ...query }).count();
|
||||
}
|
||||
|
||||
async function judge(rid) {
|
||||
const rdoc = await get(rid);
|
||||
const pdoc = await problem.getById(rdoc.pid);
|
||||
async function getList(domainId, rids) {
|
||||
const r = {};
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const rid of rids) r[rid] = await get(domainId, rid);
|
||||
return r;
|
||||
}
|
||||
|
||||
function getUserInProblemMulti(domainId, uid, pid) {
|
||||
return coll.find({ domainId, owner: uid, pid });
|
||||
}
|
||||
|
||||
async function judge(domainId, rid) {
|
||||
const rdoc = await get(domainId, rid);
|
||||
const pdoc = await problem.get(domainId, rdoc.pid);
|
||||
await task.add({
|
||||
type: 'judge',
|
||||
rid,
|
||||
domainId,
|
||||
pid: rdoc.pid,
|
||||
data: pdoc.data,
|
||||
lang: rdoc.lang,
|
||||
@@ -90,13 +102,14 @@ async function judge(rid) {
|
||||
});
|
||||
}
|
||||
|
||||
async function rejudge(rid) {
|
||||
await reset(rid);
|
||||
const rdoc = await get(rid);
|
||||
const pdoc = await problem.getById(rdoc.pid);
|
||||
async function rejudge(domainId, rid) {
|
||||
await reset(domainId, rid);
|
||||
const rdoc = await get(domainId, rid);
|
||||
const pdoc = await problem.get(domainId, rdoc.pid);
|
||||
await task.add({
|
||||
type: 'judge',
|
||||
rid,
|
||||
domainId,
|
||||
pid: rdoc.pid,
|
||||
data: pdoc.data,
|
||||
lang: rdoc.lang,
|
||||
|
||||
+39
-66
@@ -1,107 +1,80 @@
|
||||
const { ObjectID } = require('bson');
|
||||
const document = require('./document');
|
||||
const { SolutionNotFoundError } = require('../error');
|
||||
const validator = require('../lib/validator');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('solution');
|
||||
const collStatus = db.collection('solution.status');
|
||||
|
||||
/**
|
||||
* @param {string} pid
|
||||
* @param {number} owner
|
||||
* @param {string} content
|
||||
*/
|
||||
async function add(pid, owner, content) {
|
||||
validator.checkContent(content);
|
||||
pid = new ObjectID(pid);
|
||||
const res = await coll.insertOne({
|
||||
content, owner, pid, reply: [], vote: 0,
|
||||
});
|
||||
return res.insertedId;
|
||||
function add(domainId, pid, owner, content) {
|
||||
return document.add(
|
||||
domainId, content, owner, document.TYPE_PROBLEM_SOLUTION,
|
||||
null, document.TYPE_PROBLEM, pid, { reply: [], vote: 0 },
|
||||
);
|
||||
}
|
||||
|
||||
async function get(psid) {
|
||||
psid = new ObjectID(psid);
|
||||
const psdoc = await coll.findOne({ _id: psid });
|
||||
async function get(domainId, psid) {
|
||||
const psdoc = await document.get(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
||||
if (!psdoc) throw new SolutionNotFoundError();
|
||||
return psdoc;
|
||||
}
|
||||
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort)
|
||||
function getMany(domainId, query, sort, page, limit) {
|
||||
return document.getMulti(domainId, document.TYPE_PROBLEM_SOLUTION, query)
|
||||
.sort(sort)
|
||||
.skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
async function edit(_id, content) {
|
||||
validator.checkContent(content);
|
||||
await coll.updateOne({ _id }, { $set: { content } });
|
||||
const psdoc = await get(_id);
|
||||
if (!psdoc) throw new SolutionNotFoundError(_id);
|
||||
return psdoc;
|
||||
function edit(domainId, psid, content) {
|
||||
return document.set(domainId, document.TYPE_PROBLEM_SOLUTION, psid, { content });
|
||||
}
|
||||
|
||||
function del(psid) {
|
||||
return coll.deleteOne({ _id: psid });
|
||||
function del(domainId, psid) {
|
||||
return document.deleteOne(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
||||
}
|
||||
|
||||
function count(query) {
|
||||
return coll.find(query).count();
|
||||
function count(domainId, query) {
|
||||
return document.count(domainId, document.TYPE_PROBLEM_SOLUTION, query);
|
||||
}
|
||||
|
||||
function getMulti(pid) {
|
||||
return coll.find({ pid }).sort({ vote: -1 });
|
||||
function getMulti(domainId, pid) {
|
||||
return document.getMulti(
|
||||
domainId, document.TYPE_PROBLEM_SOLUTION,
|
||||
{ parentType: document.TYPE_PROBLEM, parentId: pid },
|
||||
).sort({ vote: -1 });
|
||||
}
|
||||
|
||||
function reply(psid, owner, content) {
|
||||
validator.checkContent(content);
|
||||
return coll.findOneAndUpdate(
|
||||
{ _id: psid },
|
||||
{ $push: { reply: { content, owner, _id: new ObjectID() } } },
|
||||
);
|
||||
function reply(domainId, psid, owner, content) {
|
||||
return document.push(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', content, owner);
|
||||
}
|
||||
|
||||
async function getReply(psid, psrid) {
|
||||
const psdoc = await coll.findOne({ _id: psid, reply: { $elemMatch: { _id: psrid } } });
|
||||
if (!psdoc) return [null, null];
|
||||
for (const psrdoc of psdoc) if (psrdoc._id === psrid) return [psdoc, psrdoc];
|
||||
return [psdoc, null];
|
||||
function getReply(domainId, psid, psrid) {
|
||||
return document.getSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||
}
|
||||
|
||||
async function editReply(psid, psrid, content) {
|
||||
validator.checkContent(content);
|
||||
psid = new ObjectID(psid);
|
||||
psrid = new ObjectID(psrid);
|
||||
const psdoc = await coll.findOne({ _id: psid, reply: { $elemMatch: { _id: psrid } } });
|
||||
const { reply } = psdoc; // eslint-disable-line no-shadow
|
||||
for (const i in reply) {
|
||||
if (reply[i]._id === psrid) {
|
||||
reply[i].content = content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-return-await
|
||||
return await coll.updateOne({ _id: psdoc._id }, { $set: { reply } });
|
||||
function editReply(domainId, psid, psrid, content) {
|
||||
return document.setSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid, { content });
|
||||
}
|
||||
|
||||
function delReply(psid, psrid) {
|
||||
return coll.findOneAndUpdate({ _id: psid }, { $pull: { reply: { _id: psrid } } });
|
||||
function delReply(domainId, psid, psrid) {
|
||||
return document.deleteSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||
}
|
||||
|
||||
async function vote(psid, uid, value) {
|
||||
let pssdoc = await collStatus.findOne({ psid, uid });
|
||||
if (pssdoc) await collStatus.deleteOne({ psid, uid });
|
||||
await collStatus.insertOne({ psid, uid, vote: value });
|
||||
async function vote(domainId, psid, uid, value) {
|
||||
let pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||
await document.setStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, { vote: value });
|
||||
if (pssdoc) value += -pssdoc.vote;
|
||||
await coll.updateOne({ _id: psid }, { $inc: { vote: value } });
|
||||
pssdoc = await collStatus.findOne({ psid, uid });
|
||||
const psdoc = await coll.findOne({ _id: psid });
|
||||
const psdoc = await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', value);
|
||||
pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||
return [psdoc, pssdoc];
|
||||
}
|
||||
|
||||
async function getListStatus(list, uid) {
|
||||
async function getListStatus(domainId, list, uid) {
|
||||
const result = {};
|
||||
const res = await collStatus.find({ uid, psid: { $in: list } }).toArray();
|
||||
const res = await document.getMultiStatus(
|
||||
domainId, document.TYPE_PROBLEM_SOLUTION, { uid, psid: { $in: list } },
|
||||
).toArray();
|
||||
for (const i of res) result[i.psid] = i;
|
||||
return result;
|
||||
}
|
||||
|
||||
+56
-58
@@ -1,38 +1,67 @@
|
||||
const assert = require('assert');
|
||||
const document = require('./document');
|
||||
const validator = require('../lib/validator');
|
||||
const { ValidationError, TrainingNotFoundError, TrainingAlreadyEnrollError } = require('../error');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('traning');
|
||||
const collStatus = db.collection('training.status');
|
||||
|
||||
function getStatus(tid, uid) {
|
||||
return collStatus.findOne({ tid, uid });
|
||||
function getStatus(domainId, tid, uid) {
|
||||
return document.getStatus(domainId, document.TYPE_TRAINING, tid, uid);
|
||||
}
|
||||
|
||||
function getMultiStatus(query) {
|
||||
return collStatus.find(query);
|
||||
function getMultiStatus(domainId, query) {
|
||||
return document.getMultiStatus(domainId, document.TYPE_TRAINING, query);
|
||||
}
|
||||
|
||||
async function getListStatus(uid, tids) {
|
||||
const tsdocs = await getMultiStatus({ uid, tid: { $in: Array.from(new Set(tids)) } }).toArray();
|
||||
async function getListStatus(domainId, uid, tids) {
|
||||
const tsdocs = await getMultiStatus(
|
||||
domainId, { uid, tid: { $in: Array.from(new Set(tids)) } },
|
||||
).toArray();
|
||||
const r = {};
|
||||
for (const tsdoc of tsdocs) r[tsdoc.pid] = tsdoc;
|
||||
return r;
|
||||
}
|
||||
|
||||
async function enroll(tid, uid) {
|
||||
async function enroll(domainId, tid, uid) {
|
||||
try {
|
||||
await collStatus.insertOne({ tid, uid, enroll: 1 });
|
||||
await document.setStatus(domainId, document.TYPE_TRAINING, tid, uid, { enroll: 1 });
|
||||
} catch (e) {
|
||||
throw new TrainingAlreadyEnrollError(tid, uid);
|
||||
}
|
||||
await coll.updateOne({ _id: tid }, { $inc: { enroll: 1 } });
|
||||
return await document.inc(domainId, document.TYPE_TRAINING, tid, 'enroll', 1);
|
||||
}
|
||||
|
||||
async function setStatus(tid, uid, $set) {
|
||||
await collStatus.updateOne({ tid, uid }, { $set });
|
||||
return await collStatus.findOne({ tid, uid }); // eslint-disable-line no-return-await
|
||||
function setStatus(domainId, tid, uid, $set) {
|
||||
return document.setStatus(domainId, document.TYPE_TRAINING, tid, uid, $set);
|
||||
}
|
||||
|
||||
function add(domainId, title, content, owner, dag = [], description = '') {
|
||||
validator.checkTitle(title);
|
||||
validator.checkIntro(content);
|
||||
validator.checkDescription(description);
|
||||
for (const node of dag) {
|
||||
for (const nid of node.requireNids) {
|
||||
if (nid >= node._id) throw new ValidationError('dag');
|
||||
}
|
||||
}
|
||||
return document.add(domainId, content, owner, document.TYPE_TRAINING, null, null, null, {
|
||||
dag,
|
||||
title,
|
||||
description,
|
||||
enroll: 0,
|
||||
});
|
||||
}
|
||||
|
||||
function edit(domainId, tid, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkIntro($set.content);
|
||||
if ($set.desc) validator.checkDescription($set.description);
|
||||
if ($set.dag) {
|
||||
for (const node of $set.dag) {
|
||||
for (const nid of node.requireNids) {
|
||||
assert(nid >= node._id, new ValidationError('dag'));
|
||||
}
|
||||
}
|
||||
}
|
||||
return document.set(domainId, document.TYPE_TRAINING, tid, $set);
|
||||
}
|
||||
|
||||
global.Hydro.model.training = module.exports = {
|
||||
@@ -66,54 +95,23 @@ global.Hydro.model.training = module.exports = {
|
||||
isInvalid(node, doneNids) {
|
||||
return (!Set.isSuperset(new Set(doneNids), new Set(node.requireNids)));
|
||||
},
|
||||
async add(title, content, owner, dag = [], description = '') {
|
||||
validator.checkTitle(title);
|
||||
validator.checkIntro(content);
|
||||
validator.checkDescription(description);
|
||||
for (const node of dag) {
|
||||
for (const nid of node.requireNids) {
|
||||
if (nid >= node._id) throw new ValidationError('dag');
|
||||
}
|
||||
}
|
||||
const res = await coll.insertOne({
|
||||
content,
|
||||
owner,
|
||||
dag,
|
||||
title,
|
||||
description,
|
||||
enroll: 0,
|
||||
});
|
||||
return res.insertedId;
|
||||
},
|
||||
count: (query) => coll.find(query).count(),
|
||||
async edit(tid, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkIntro($set.content);
|
||||
if ($set.desc) validator.checkDescription($set.description);
|
||||
if ($set.dag) {
|
||||
for (const node of $set.dag) {
|
||||
for (const nid of node.requireNids) {
|
||||
assert(nid >= node._id, new ValidationError('dag'));
|
||||
}
|
||||
}
|
||||
}
|
||||
await coll.findOneAndUpdate({ _id: tid }, { $set });
|
||||
const tdoc = await coll.findOne({ _id: tid });
|
||||
add,
|
||||
edit,
|
||||
count: (domainId, query) => document.count(domainId, document.TYPE_TRAINING, query),
|
||||
async get(domainId, tid) {
|
||||
const tdoc = await document.get(domainId, document.TYPE_TRAINING, tid);
|
||||
if (!tdoc) throw new TrainingNotFoundError(tid);
|
||||
return tdoc;
|
||||
},
|
||||
async get(tid) {
|
||||
const tdoc = await coll.findOne({ _id: tid });
|
||||
if (!tdoc) throw new TrainingNotFoundError(tid);
|
||||
return tdoc;
|
||||
},
|
||||
async getList(tids) {
|
||||
const tdocs = await this.getMulti({ _id: { $in: Array.from(new Set(tids)) } }).toArray();
|
||||
async getList(domainId, tids) {
|
||||
const tdocs = await this.getMulti(
|
||||
domainId, { _id: { $in: Array.from(new Set(tids)) } },
|
||||
).toArray();
|
||||
const r = {};
|
||||
for (const tdoc of tdocs) r[tdoc._id] = tdoc;
|
||||
for (const tdoc of tdocs) r[tdoc.docId] = tdoc;
|
||||
return r;
|
||||
},
|
||||
getMulti: (query) => coll.find(query),
|
||||
getMulti: (domainId, query) => document.getMulti(domainId, document.TYPE_TRAINING, query),
|
||||
getMultiStatus,
|
||||
getStatus,
|
||||
enroll,
|
||||
|
||||
+59
-60
@@ -1,3 +1,4 @@
|
||||
const document = require('./document');
|
||||
const system = require('./system');
|
||||
const { UserNotFoundError, UserAlreadyExistError } = require('../error');
|
||||
const perm = require('../permission');
|
||||
@@ -5,7 +6,6 @@ const pwhash = require('../lib/hash.hydro');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('user');
|
||||
const collRole = db.collection('role');
|
||||
|
||||
class USER {
|
||||
constructor(user) {
|
||||
@@ -37,38 +37,46 @@ class USER {
|
||||
}
|
||||
}
|
||||
|
||||
async function getById(_id) {
|
||||
async function getPerm(domainId, udoc) {
|
||||
if (udoc.priv === 1) {
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_ROLE, 'admin');
|
||||
return p.content;
|
||||
}
|
||||
const role = await document.getStatus(domainId, document.TYPE_DOMAIN_ROLE, 0, udoc._id);
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_ROLE, role || 'default');
|
||||
return p.content;
|
||||
}
|
||||
|
||||
async function getById(domainId, _id) {
|
||||
const udoc = await coll.findOne({ _id });
|
||||
if (!udoc) throw new UserNotFoundError(_id);
|
||||
const role = await collRole.findOne({ _id: udoc.role || 'default' });
|
||||
udoc.perm = role.perm;
|
||||
udoc.perm = await getPerm(domainId, udoc);
|
||||
return new USER(udoc);
|
||||
}
|
||||
|
||||
async function getList(uids) {
|
||||
async function getList(domainId, uids) {
|
||||
const r = {};
|
||||
for (const uid of uids) r[uid] = await getById(uid); // eslint-disable-line no-await-in-loop
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const uid of uids) r[uid] = await getById(domainId, uid);
|
||||
return r;
|
||||
}
|
||||
|
||||
async function getByUname(uname) {
|
||||
async function getByUname(domainId, uname) {
|
||||
const unameLower = uname.trim().toLowerCase();
|
||||
const udoc = await coll.findOne({ unameLower });
|
||||
if (!udoc) throw new UserNotFoundError(uname);
|
||||
const role = await collRole.findOne({ _id: udoc.role || 'default' });
|
||||
udoc.perm = role.perm;
|
||||
udoc.perm = await getPerm(domainId, udoc);
|
||||
return new USER(udoc);
|
||||
}
|
||||
|
||||
async function getByEmail(mail, ignoreMissing = false) {
|
||||
async function getByEmail(domainId, mail, ignoreMissing = false) {
|
||||
const mailLower = mail.trim().toLowerCase();
|
||||
const udoc = await coll.findOne({ mailLower });
|
||||
if (!udoc) {
|
||||
if (ignoreMissing) return null;
|
||||
throw new UserNotFoundError(mail);
|
||||
}
|
||||
const role = await collRole.findOne({ _id: udoc.role || 'default' });
|
||||
udoc.perm = role.perm;
|
||||
udoc.perm = await getPerm(domainId, udoc);
|
||||
return new USER(udoc);
|
||||
}
|
||||
|
||||
@@ -106,30 +114,27 @@ async function inc(_id, field, n = 1) {
|
||||
}
|
||||
|
||||
async function create({
|
||||
uid, mail, uname, password, regip = '127.0.0.1', role = 'default',
|
||||
uid, mail, uname, password, regip = '127.0.0.1', priv = perm.PRIV_NONE,
|
||||
}) {
|
||||
const salt = String.random();
|
||||
if (!uid) uid = system.inc('user');
|
||||
try {
|
||||
await Promise.all([
|
||||
coll.insertOne({
|
||||
_id: uid,
|
||||
mail,
|
||||
mailLower: mail.trim().toLowerCase(),
|
||||
uname,
|
||||
unameLower: uname.trim().toLowerCase(),
|
||||
password: pwhash.hash(password, salt),
|
||||
salt,
|
||||
hashType: 'hydro',
|
||||
regat: new Date(),
|
||||
regip,
|
||||
loginat: new Date(),
|
||||
loginip: regip,
|
||||
role,
|
||||
gravatar: mail,
|
||||
}),
|
||||
collRole.updateOne({ _id: role }, { $inc: { count: 1 } }),
|
||||
]);
|
||||
await coll.insertOne({
|
||||
_id: uid,
|
||||
mail,
|
||||
mailLower: mail.trim().toLowerCase(),
|
||||
uname,
|
||||
unameLower: uname.trim().toLowerCase(),
|
||||
password: pwhash.hash(password, salt),
|
||||
salt,
|
||||
hashType: 'hydro',
|
||||
regat: new Date(),
|
||||
regip,
|
||||
loginat: new Date(),
|
||||
loginip: regip,
|
||||
priv,
|
||||
gravatar: mail,
|
||||
});
|
||||
} catch (e) {
|
||||
throw new UserAlreadyExistError([uid, uname, mail]);
|
||||
}
|
||||
@@ -146,37 +151,31 @@ async function getPrefixList(prefix, limit = 50) {
|
||||
return udocs;
|
||||
}
|
||||
|
||||
async function setRole(uid, role) {
|
||||
const udoc = await getById(uid);
|
||||
return await Promise.all([ // eslint-disable-line no-return-await
|
||||
coll.findOneAndUpdate({ _id: uid }, { $set: { role } }),
|
||||
collRole.updateOne({ _id: udoc.role }, { $inc: { count: -1 } }),
|
||||
collRole.updateOne({ _id: role }, { $inc: { count: 1 } }),
|
||||
function setRole(domainId, uid, role) {
|
||||
return document.setStatus(domainId, document.TYPE_DOMAIN_ROLE, 0, uid, { role });
|
||||
}
|
||||
|
||||
function getRoles(domainId) {
|
||||
return document.getMulti(domainId, document.TYPE_DOMAIN_ROLE).sort('_id', 1).toArray();
|
||||
}
|
||||
|
||||
function getRole(domainId, name) {
|
||||
return document.get(domainId, document.TYPE_DOMAIN_ROLE, name);
|
||||
}
|
||||
|
||||
function addRole(domainId, name, permission) {
|
||||
return document.add(domainId, permission, 1, document.TYPE_DOMAIN_ROLE, name);
|
||||
}
|
||||
|
||||
function deleteRoles(domainId, roles) {
|
||||
return Promise.all([
|
||||
document.deleteMulti(domainId, document.TYPE_DOMAIN_ROLE, { docId: { $in: roles } }),
|
||||
document.deleteMultiStatus(domainId, document.TYPE_DOMAIN_ROLE, { role: { $in: roles } }),
|
||||
]);
|
||||
}
|
||||
|
||||
function getRoles() {
|
||||
return collRole.find().sort('_id', 1).toArray();
|
||||
}
|
||||
|
||||
function getRole(name) {
|
||||
return collRole.findOne({ _id: name });
|
||||
}
|
||||
|
||||
function addRole(name, permission) {
|
||||
return collRole.insertOne({ _id: name, perm: permission, count: 0 });
|
||||
}
|
||||
|
||||
function deleteRoles(roles) {
|
||||
function ensureIndexes() {
|
||||
return Promise.all([
|
||||
coll.updateMany({ role: { $in: roles } }, { $set: { role: 'default' } }),
|
||||
collRole.deleteMany({ _id: { $in: roles } }),
|
||||
]);
|
||||
}
|
||||
|
||||
function index() {
|
||||
return Promise.all([
|
||||
collRole.updateOne({ _id: 'root' }, { $set: { perm: perm.PERM_ALL } }),
|
||||
coll.createIndex('unameLower', { unique: true }),
|
||||
coll.createIndex('mailLower', { sparse: true }),
|
||||
]);
|
||||
@@ -200,5 +199,5 @@ global.Hydro.model.user = module.exports = {
|
||||
getRoles,
|
||||
addRole,
|
||||
deleteRoles,
|
||||
index,
|
||||
ensureIndexes,
|
||||
};
|
||||
Reference in new issue
Block a user