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} */ 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} */ 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, };