core: discussion panel

This commit is contained in:
undefined committed 2021-07-04 10:57:12 +08:00
1 parent 18450dafea
commit 675e28abc5
5 files changed
+23 -27

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.29.17", "version": "2.29.18",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "dist/loader.js", "main": "dist/loader.js",
"typings": "dist/loader.d.ts", "typings": "dist/loader.d.ts",
+12 -22
View File
@@ -56,7 +56,7 @@ class DiscussionHandler extends Handler {
// TODO(twd2): do more visibility check eg. contest // TODO(twd2): do more visibility check eg. contest
// TODO(twd2): exclude problem/contest discussions? // TODO(twd2): exclude problem/contest discussions?
// TODO(iceboy): continuation based pagination. // TODO(iceboy): continuation based pagination.
this.vnode = await discussion.getVnode(domainId, typeMapper[type], name); this.vnode = await discussion.getVnode(domainId, typeMapper[type], name, this.user._id);
if (this.vnode.hidden) this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN); if (this.vnode.hidden) this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
if (this.ddoc) { if (this.ddoc) {
this.ddoc.parentType = this.ddoc.parentType || this.vnode.type; this.ddoc.parentType = this.ddoc.parentType || this.vnode.type;
@@ -68,8 +68,10 @@ class DiscussionHandler extends Handler {
class DiscussionMainHandler extends Handler { class DiscussionMainHandler extends Handler {
@param('page', Types.PositiveInt, true) @param('page', Types.PositiveInt, true)
async get(domainId: string, page = 1) { async get(domainId: string, page = 1) {
// Limit to known types
const parentType = { $in: Object.keys(typeMapper).map((i) => typeMapper[i]) };
const [ddocs, dpcount] = await paginate( const [ddocs, dpcount] = await paginate(
discussion.getMulti(domainId), discussion.getMulti(domainId, { parentType }),
page, page,
system.get('pagination.discussion'), system.get('pagination.discussion'),
); );
@@ -300,24 +302,12 @@ class DiscussionDetailHandler extends DiscussionHandler {
} }
} }
class DiscussionDetailRawHandler extends DiscussionHandler { class DiscussionRawHandler extends DiscussionHandler {
async get() { @param('drid', Types.ObjectID, true)
@param('drrid', Types.ObjectID, true)
async get(domainId: string, drid: ObjectID, drrid: ObjectID) {
this.response.type = 'text/markdown'; this.response.type = 'text/markdown';
this.response.body = this.ddoc.content; this.response.body = drrid ? this.drrdoc.content : drid ? this.drdoc.content : this.ddoc.content;
}
}
class DiscussionReplyRawHandler extends DiscussionHandler {
async get() {
this.response.type = 'text/markdown';
this.response.body = this.drdoc.content;
}
}
class DiscussionTailReplyRawHandler extends DiscussionHandler {
async get() {
this.response.type = 'text/markdown';
this.response.body = this.drrdoc.content;
} }
} }
@@ -375,9 +365,9 @@ export async function apply() {
Route('discussion_main', '/discuss', DiscussionMainHandler); Route('discussion_main', '/discuss', DiscussionMainHandler);
Route('discussion_detail', '/discuss/:did', DiscussionDetailHandler); Route('discussion_detail', '/discuss/:did', DiscussionDetailHandler);
Route('discussion_edit', '/discuss/:did/edit', DiscussionEditHandler); Route('discussion_edit', '/discuss/:did/edit', DiscussionEditHandler);
Route('discussion_detail', '/discuss/:did/raw', DiscussionDetailRawHandler); Route('discussion_detail', '/discuss/:did/raw', DiscussionRawHandler);
Route('discussion_reply_raw', '/discuss/:did/:drid/raw', DiscussionReplyRawHandler); Route('discussion_reply_raw', '/discuss/:did/:drid/raw', DiscussionRawHandler);
Route('discussion_tail_reply_raw', '/discuss/:did/:drid/:drrid/raw', DiscussionTailReplyRawHandler); Route('discussion_tail_reply_raw', '/discuss/:did/:drid/:drrid/raw', DiscussionRawHandler);
Route('discussion_node', '/discuss/:type/:name', DiscussionNodeHandler); Route('discussion_node', '/discuss/:type/:name', DiscussionNodeHandler);
Route('discussion_create', '/discuss/:type/:name/create', DiscussionCreateHandler, PRIV.PRIV_USER_PROFILE, PERM.PERM_CREATE_DISCUSSION); Route('discussion_create', '/discuss/:type/:name/create', DiscussionCreateHandler, PRIV.PRIV_USER_PROFILE, PERM.PERM_CREATE_DISCUSSION);
} }
+8 -2
View File
@@ -232,15 +232,21 @@ export function getNode(domainId: string, _id: string) {
return document.get(domainId, document.TYPE_DISCUSSION_NODE, _id); return document.get(domainId, document.TYPE_DISCUSSION_NODE, _id);
} }
export async function getVnode(domainId: string, type: number, id: string) { export async function getVnode(domainId: string, type: number, id: string, uid?: number) {
if (type === document.TYPE_PROBLEM) { if (type === document.TYPE_PROBLEM) {
const pdoc = await problem.get(domainId, Number.isSafeInteger(+id) ? +id : id); const pdoc = await problem.get(domainId, Number.isSafeInteger(+id) ? +id : id);
if (!pdoc) throw new DiscussionNodeNotFoundError(id); if (!pdoc) throw new DiscussionNodeNotFoundError(id);
return { ...pdoc, type, id }; return { ...pdoc, type, id };
} }
if ([document.TYPE_CONTEST, document.TYPE_TRAINING, document.TYPE_HOMEWORK].includes(type as any)) { if ([document.TYPE_CONTEST, document.TYPE_TRAINING, document.TYPE_HOMEWORK].includes(type as any)) {
const tdoc = await (type === document.TYPE_TRAINING ? training : contest).get(domainId, new ObjectID(id), type as any); const model = type === document.TYPE_TRAINING ? training : contest;
const _id = new ObjectID(id);
const tdoc = await model.get(domainId, _id, type as any);
if (!tdoc) throw new DiscussionNodeNotFoundError(id); if (!tdoc) throw new DiscussionNodeNotFoundError(id);
if (uid) {
const tsdoc = await model.getStatus(domainId, _id, uid);
tdoc.attend = tsdoc.attend || tsdoc.enroll;
}
return { ...tdoc, type, id }; return { ...tdoc, type, id };
} }
return { return {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@hydrooj/ui-default", "name": "@hydrooj/ui-default",
"version": "4.12.10", "version": "4.12.11",
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "hydro.js", "main": "hydro.js",
@@ -6,7 +6,7 @@
<div class="section__body"> <div class="section__body">
<h1>{{ tdoc.title }}</h1> <h1>{{ tdoc.title }}</h1>
<div class="contest-sidebar__status"> <div class="contest-sidebar__status">
{% if attended %} {% if attended or tdoc.attend %}
<span class="icon icon-check"></span> {{ _('Attended') }} <span class="icon icon-check"></span> {{ _('Attended') }}
{% else %} {% else %}
<span class="icon icon-schedule"></span> {{ _('Not Attended') }} <span class="icon icon-schedule"></span> {{ _('Not Attended') }}