|
|
|
const { STATUS_ACCEPTED } = require('./builtin').STATUS;
|
|
|
|
const file = require('./file');
|
|
|
|
const document = require('./document');
|
|
|
|
const domain = require('./domain');
|
|
|
|
const { ProblemNotFoundError } = require('../error');
|
|
|
|
const readConfig = require('../lib/readConfig');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {import('../interface').Pdoc} Pdoc
|
|
|
|
* @typedef {import('bson').ObjectID} ObjectID
|
|
|
|
* @typedef {import('mongodb').Cursor} Cursor
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} domainId
|
|
|
|
* @param {string} title
|
|
|
|
* @param {string} content
|
|
|
|
* @param {number} owner
|
|
|
|
* @param {number} pid
|
|
|
|
* @param {import('bson').ObjectID} data
|
|
|
|
* @param {string[]} category
|
|
|
|
* @param {string[]} tag
|
|
|
|
* @param {boolean} hidden
|
|
|
|
*/
|
|
|
|
async function add(domainId, title, content, owner, {
|
|
|
|
pid = null,
|
|
|
|
data = null,
|
|
|
|
category = [],
|
|
|
|
tag = [],
|
|
|
|
hidden = false,
|
|
|
|
}) {
|
|
|
|
const d = await domain.inc(domainId, 'pidCounter', 1);
|
|
|
|
if (!pid) pid = d.pidCounter.toString();
|
|
|
|
// eslint-disable-next-line no-return-await
|
|
|
|
return await document.add(
|
|
|
|
domainId, content, owner, document.TYPE_PROBLEM, d.pidCounter, null, null,
|
|
|
|
{
|
|
|
|
pid, title, data, category, tag, hidden, nSubmit: 0, nAccept: 0,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} domainId
|
|
|
|
* @param {string|number} pid
|
|
|
|
* @param {number} uid
|
|
|
|
* @returns {Promise<Pdoc>}
|
|
|
|
*/
|
|
|
|
async function get(domainId, pid, uid = null, doThrow = true) {
|
|
|
|
const pdoc = Number.isInteger(pid)
|
|
|
|
? await document.get(domainId, document.TYPE_PROBLEM, pid)
|
|
|
|
: (await document.getMulti(domainId, document.TYPE_PROBLEM, { pid }).toArray())[0];
|
|
|
|
if (!pdoc) {
|
|
|
|
if (doThrow) throw new ProblemNotFoundError(domainId, pid);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (uid) {
|
|
|
|
pdoc.psdoc = await document.getStatus(domainId, document.TYPE_PROBLEM, pdoc.docId, uid);
|
|
|
|
}
|
|
|
|
return pdoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} domainId
|
|
|
|
* @param {object} query
|
|
|
|
* @param {object} sort
|
|
|
|
* @param {number} page
|
|
|
|
* @param {number} limit
|
|
|
|
* @returns {Promise<Pdoc[]>}
|
|
|
|
*/
|
|
|
|
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(domainId, query) {
|
|
|
|
return document.getMulti(domainId, document.TYPE_PROBLEM, query);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} domainId
|
|
|
|
* @param {object} query
|
|
|
|
* @returns {Cursor}
|
|
|
|
*/
|
|
|
|
function getMultiStatus(domainId, query) {
|
|
|
|
return document.getMultiStatus(domainId, document.TYPE_PROBLEM, query);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} domainId
|
|
|
|
* @param {ObjectID} _id
|
|
|
|
* @param {object} query
|
|
|
|
* @returns {Pdoc}
|
|
|
|
*/
|
|
|
|
function edit(domainId, _id, $set) {
|
|
|
|
return document.set(domainId, document.TYPE_PROBLEM, _id, $set);
|
|
|
|
}
|
|
|
|
|
|
|
|
function inc(domainId, _id, field, n) {
|
|
|
|
return document.inc(domainId, document.TYPE_PROBLEM, _id, field, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
function count(domainId, query) {
|
|
|
|
return document.count(domainId, 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(domainId, pids, doThrow = true) {
|
|
|
|
pids = Array.from(new Set(pids));
|
|
|
|
const r = {};
|
|
|
|
const pdocs = await document.getMulti(
|
|
|
|
domainId, document.TYPE_PROBLEM,
|
|
|
|
{ $or: [{ docId: { $in: pids } }, { pid: { $in: pids } }] },
|
|
|
|
).toArray();
|
|
|
|
for (const pdoc of pdocs) {
|
|
|
|
r[pdoc.docId] = r[pdoc.pid] = pdoc;
|
|
|
|
}
|
|
|
|
if (pdocs.length !== pids.length) {
|
|
|
|
if (doThrow) {
|
|
|
|
for (const pid of pids) {
|
|
|
|
if (!r[pid]) throw new ProblemNotFoundError(domainId, pid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
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, filePath) {
|
|
|
|
const pdoc = await get(domainId, _id);
|
|
|
|
const config = await readConfig(filePath);
|
|
|
|
const id = await file.add(filePath, 'data.zip');
|
|
|
|
if (pdoc.data && typeof pdoc.data === 'object') file.dec(pdoc.data);
|
|
|
|
return await edit(domainId, _id, { data: id, config });
|
|
|
|
}
|
|
|
|
|
|
|
|
global.Hydro.model.problem = module.exports = {
|
|
|
|
add,
|
|
|
|
inc,
|
|
|
|
get,
|
|
|
|
getMany,
|
|
|
|
edit,
|
|
|
|
count,
|
|
|
|
random,
|
|
|
|
getMulti,
|
|
|
|
getList,
|
|
|
|
getListStatus,
|
|
|
|
getMultiStatus,
|
|
|
|
setTestdata,
|
|
|
|
updateStatus,
|
|
|
|
};
|