core: strict discussion visiblility check (#537)

This commit is contained in:
panda authored and GitHub committed 2023-03-12 20:11:11 +08:00
1 parent f39a28bfec
commit b80c80d9b2
4 files changed
+44 -18

No files matched your search

+14 -14
View File
@@ -1,7 +1,7 @@
import { isSafeInteger } from 'lodash';
import { ObjectId } from 'mongodb';
import {
DiscussionLockedError, DiscussionNotFoundError, DocumentNotFoundError,
DiscussionLockedError, DiscussionNodeNotFoundError, DiscussionNotFoundError, DocumentNotFoundError,
PermissionError,
} from '../error';
import { DiscussionDoc, DiscussionReplyDoc, DiscussionTailReplyDoc } from '../interface';
@@ -30,7 +30,7 @@ class DiscussionHandler extends Handler {
vnode?: any;
@param('type', Types.Range(Object.keys(typeMapper)), true)
@param('name', Types.Name, true)
@param('name', Types.String, true)
@param('did', Types.ObjectId, true)
@param('drid', Types.ObjectId, true)
@param('drrid', Types.ObjectId, true)
@@ -55,15 +55,10 @@ class DiscussionHandler extends Handler {
}
}
}
// TODO(twd2): do more visibility check eg. contest
// TODO(twd2): exclude problem/contest discussions?
// TODO(iceboy): continuation based pagination.
this.vnode = await discussion.getVnode(domainId, typeMapper[type], name, this.user._id);
if (this.vnode.assign?.length && !this.user.own(this.vnode)) {
if (!Set.intersection(this.vnode.assign, this.user.group).size) {
throw new PermissionError(PERM.PERM_VIEW_PROBLEM_HIDDEN);
}
}
if (!discussion.checkVNodeVisibility(typeMapper[type], this.vnode, this.user)) throw new DiscussionNodeNotFoundError(this.vnode.id);
if (this.ddoc) {
this.ddoc.parentType ||= this.vnode.type;
this.ddoc.parentId ||= this.vnode.id;
@@ -73,11 +68,13 @@ class DiscussionHandler extends Handler {
class DiscussionMainHandler extends Handler {
@param('page', Types.PositiveInt, true)
async get(domainId: string, page = 1) {
@param('all', Types.Boolean)
async get(domainId: string, page = 1, all = false) {
// Limit to known types
const parentType = { $in: Object.keys(typeMapper).map((i) => typeMapper[i]) };
all &&= this.user.hasPerm(PERM.PERM_MOD_BADGE);
const [ddocs, dpcount] = await paginate(
discussion.getMulti(domainId, { parentType }),
discussion.getMulti(domainId, { parentType, ...all ? {} : { hidden: false } }),
page,
system.get('pagination.discussion'),
);
@@ -95,15 +92,16 @@ class DiscussionMainHandler extends Handler {
class DiscussionNodeHandler extends DiscussionHandler {
@param('type', Types.Range(Object.keys(typeMapper)))
@param('name', Types.Name)
@param('name', Types.String)
@param('page', Types.PositiveInt, true)
async get(domainId: string, type: string, _name: string, page = 1) {
let name: ObjectId | string | number;
if (ObjectId.isValid(_name)) name = new ObjectId(_name);
else if (isSafeInteger(parseInt(_name, 10))) name = parseInt(_name, 10);
else name = _name;
const hidden = this.user.own(this.vnode) || this.user.hasPerm(PERM.PERM_EDIT_DISCUSSION) ? {} : { hidden: false };
const [ddocs, dpcount] = await paginate(
discussion.getMulti(domainId, { parentType: typeMapper[type], parentId: name }),
discussion.getMulti(domainId, { parentType: typeMapper[type], parentId: name, ...hidden }),
page,
system.get('pagination.discussion'),
);
@@ -152,9 +150,10 @@ class DiscussionCreateHandler extends DiscussionHandler {
await this.limitRate('add_discussion', 3600, 60);
if (highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
if (pin) this.checkPerm(PERM.PERM_PIN_DISCUSSION);
const hidden = this.vnode.hidden ?? false;
const did = await discussion.add(
domainId, typeMapper[type], this.vnode.id, this.user._id,
title, content, this.request.ip, highlight, pin,
title, content, this.request.ip, highlight, pin, hidden,
);
this.response.body = { did };
this.response.redirect = this.url('discussion_detail', { did });
@@ -397,9 +396,10 @@ class DiscussionEditHandler extends DiscussionHandler {
else this.checkPerm(PERM.PERM_EDIT_DISCUSSION_SELF);
if (!this.user.hasPerm(PERM.PERM_HIGHLIGHT_DISCUSSION)) highlight = this.ddoc.highlight;
if (!this.user.hasPerm(PERM.PERM_PIN_DISCUSSION)) pin = this.ddoc.pin;
const hidden = this.vnode.hidden ?? false;
await Promise.all([
discussion.edit(domainId, did, {
title, highlight, pin, content, editor: this.user._id, edited: true,
title, highlight, pin, content, editor: this.user._id, edited: true, hidden,
}),
oplog.log(this, 'discussion.edit', this.ddoc),
]);