You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/hydro/model/discussion.ts

229 lines
7.5 KiB
TypeScript

import { ObjectID } from 'mongodb';
import * as problem from './problem';
import * as contest from './contest';
import * as training from './training';
import * as document from './document';
import { PERM } from './builtin';
import { DocumentNotFoundError } from '../error';
export const typeDisplay = {
[document.TYPE_PROBLEM]: 'problem',
[document.TYPE_CONTEST]: 'contest',
[document.TYPE_DISCUSSION_NODE]: 'node',
[document.TYPE_TRAINING]: 'training',
[document.TYPE_HOMEWORK]: 'homework',
};
export function add(
domainId: string, parentType: number, parentId: ObjectID,
owner: number, title: string, content: string,
ip: string | null = null, highlight: boolean = false,
) {
return document.add(
domainId, content, owner, document.TYPE_DISCUSSION,
null, parentType, parentId,
{
title,
ip,
highlight,
nReply: 0,
updateAt: new Date(),
views: 0,
},
);
}
export function get(domainId: string, did: ObjectID) {
return document.get(domainId, document.TYPE_DISCUSSION, did);
}
export function edit(
domainId: string, did: ObjectID,
title: string, content: string, highlight: boolean,
) {
return document.set(domainId, document.TYPE_DISCUSSION, did, { title, content, highlight });
}
export function del(domainId: string, did: ObjectID) {
return Promise.all([
document.deleteOne(domainId, document.TYPE_DISCUSSION, did),
document.deleteMulti(domainId, document.TYPE_DISCUSSION_REPLY, {
parentType: document.TYPE_DISCUSSION, parentId: did,
}),
document.deleteMultiStatus(domainId, document.TYPE_DISCUSSION, { docId: did }),
]);
}
export function count(domainId: string, query: any) {
return document.count(domainId, document.TYPE_DISCUSSION, query);
}
export function getMulti(domainId: string, query: any = {}) {
return document.getMulti(domainId, document.TYPE_DISCUSSION, query).sort('updateAt', -1);
}
export async function addReply(
domainId: string, did: ObjectID, owner: number,
content: string, ip: string,
) {
const [drdoc] = await Promise.all([
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;
}
export function getReply(domainId: string, drid: ObjectID) {
return document.get(domainId, document.TYPE_DISCUSSION_REPLY, drid);
}
export async function editReply(domainId: string, drid: ObjectID, content: string) {
return document.set(domainId, document.TYPE_DISCUSSION_REPLY, drid, { content });
}
export async function delReply(domainId: string, drid: ObjectID) {
const drdoc = await getReply(domainId, drid);
if (!drdoc) throw new DocumentNotFoundError(drid);
return await Promise.all([
document.deleteOne(domainId, document.TYPE_DISCUSSION_REPLY, drid),
document.inc(domainId, document.TYPE_DISCUSSION, drdoc.parentId, 'nReply', -1),
]);
}
export function getMultiReply(domainId: string, did: ObjectID) {
return document.getMulti(
domainId, document.TYPE_DISCUSSION_REPLY,
{ parentType: document.TYPE_DISCUSSION, parentId: did },
).sort('_id', -1);
}
export function getListReply(domainId: string, did: ObjectID) {
return getMultiReply(domainId, did).toArray();
}
export async function addTailReply(
domainId: string, drid: ObjectID,
owner: number, content: string, ip: string,
) {
let drdoc = await document.get(domainId, document.TYPE_DISCUSSION_REPLY, drid);
const sid = new ObjectID();
[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() }),
]);
return [drdoc, sid];
}
export function getTailReply(domainId: string, drid: ObjectID, drrid: ObjectID) {
return document.getSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid);
}
export function editTailReply(domainId: string, drid: ObjectID, drrid: ObjectID, content: string) {
return document.setSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid, { content });
}
export async function delTailReply(domainId: string, drid: ObjectID, drrid: ObjectID) {
return document.deleteSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid);
}
export function setStar(domainId: string, did: ObjectID, uid: number, star: boolean) {
return document.setStatus(domainId, document.TYPE_DISCUSSION, did, uid, { star });
}
export function getStatus(domainId: string, did: ObjectID, uid: number) {
return document.getStatus(domainId, document.TYPE_DISCUSSION, did, uid);
}
export function addNode(domainId: string, _id: string, category: string, args: any) {
return document.add(
domainId, category, 1, document.TYPE_DISCUSSION_NODE,
_id, null, null, args,
);
}
export function getNode(domainId: string, _id: string) {
return document.get(domainId, document.TYPE_DISCUSSION_NODE, _id);
}
export async function getVnode(domainId: string, ddoc: any, handler: any) {
if (ddoc.parentType === document.TYPE_PROBLEM) {
const pdoc = await problem.get(domainId, ddoc.parentId);
if (!pdoc) return null;
if (pdoc.hidden && handler) handler.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
return { ...pdoc, type: ddoc.parentType, id: ddoc.parentId };
}
if (ddoc.parentType === document.TYPE_CONTEST) {
const tdoc = await contest.get(domainId, ddoc.parentId);
return { ...tdoc, type: ddoc.parentType, id: ddoc.parentId };
}
if (ddoc.parentType === document.TYPE_DISCUSSION_NODE) {
const ndoc = await getNode(domainId, ddoc.parentId);
return {
...ndoc,
title: ddoc.parentId,
type: ddoc.parentType,
id: ddoc.parentId,
};
}
if (ddoc.parentType === document.TYPE_TRAINING) {
const tdoc = await training.get(domainId, ddoc.parentId);
return { ...tdoc, type: ddoc.parentType, id: ddoc.parentId };
}
if (ddoc.parentType === document.TYPE_HOMEWORK) {
const tdoc = await contest.get(domainId, ddoc.parentId, document.TYPE_HOMEWORK);
return { ...tdoc, type: ddoc.parentType, id: ddoc.parentId };
}
return {
title: 'Missing Node',
type: 'Unknown',
id: new ObjectID(),
};
}
export function getNodes(domainId: string) {
return document.getMulti(domainId, document.TYPE_DISCUSSION_NODE).toArray();
}
export async function getListVnodes(domainId: string, ddocs: any, handler: any) {
const tasks = [];
const res = {};
function task(ddoc) {
return getVnode(domainId, ddoc, handler).then((vnode) => {
if (!res[ddoc.parentType]) res[ddoc.parentType] = {};
res[ddoc.parentType][ddoc.parentId] = vnode;
});
}
for (const ddoc of ddocs) tasks.push(task(ddoc));
await Promise.all(tasks);
return res;
}
global.Hydro.model.discussion = {
typeDisplay,
add,
get,
edit,
del,
count,
getMulti,
addReply,
getReply,
editReply,
delReply,
getMultiReply,
getListReply,
addTailReply,
getTailReply,
editTailReply,
delTailReply,
setStar,
getStatus,
addNode,
getNodes,
getVnode,
getListVnodes,
};