const assert = require('assert'); const validator = require('../lib/validator'); const { ValidationError, TrainingNotFoundError, TrainingAlreadyEnrollError } = require('../error'); const db = require('../service/db.js'); const coll = db.collection('traning'); const collStatus = db.collection('training.status'); function getStatus(tid, uid) { return collStatus.findOne({ tid, uid }); } function getMultiStatus(query) { return collStatus.find(query); } async function getListStatus(uid, tids) { const tsdocs = await getMultiStatus({ 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) { try { await collStatus.insertOne({ tid, uid, enroll: 1 }); } catch (e) { throw new TrainingAlreadyEnrollError(tid, uid); } await coll.updateOne({ _id: tid }, { $inc: { 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 } global.Hydro.model.training = module.exports = { getPids(tdoc) { const pids = new Set(); for (const node of tdoc.dag) { for (const pid of node.pids) pids.add(pid); } return Array.from(pids); }, isDone(node, doneNids, donePids) { return (Set.isSuperset(new Set(doneNids), new Set(node.requireNids)) && Set.isSuperset(new Set(donePids), new Set(node.pids))); }, isProgress(node, doneNids, donePids, progPids) { return (Set.isSuperset(new Set(doneNids), new Set(node.requireNids)) && !Set.isSuperset(new Set(donePids), new Set(node.pids)) && Set.intersection( Set.union(new Set(donePids), new Set(progPids)), new Set(node.pids), ).size); }, isOpen(node, doneNids, donePids, progPids) { return (Set.isSuperset(new Set(doneNids), new Set(node.requireNids)) && !Set.isSuperset(new Set(donePids), new Set(node.pids)) && !Set.intersection( Set.union(new Set(donePids), new Set(progPids)), new Set(node.pids), ).size); }, 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 }); 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(); const r = {}; for (const tdoc of tdocs) r[tdoc._id] = tdoc; return r; }, getMulti: (query) => coll.find(query), getMultiStatus, getStatus, enroll, setStatus, getListStatus, };