!UNSTABLE 优化数据库结构,为domain功能准备

This commit is contained in:
masnn committed 2020-05-29 13:05:52 +08:00
1 parent 7d27e56018
commit fff2172c38
40 files changed
+1411 -1012

No files matched your search

+53 -42
View File
@@ -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