Skip to content

Commit

Permalink
feat: 添加犇犇功能(未完成)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gingmzmzx committed Oct 3, 2024
1 parent a0436ad commit 7b467f2
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 51 deletions.
130 changes: 89 additions & 41 deletions vj4/handler/discussion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from vj4.model import domain
from vj4.model import oplog
from vj4.model import user
from vj4.model import system
from vj4.model.adaptor import discussion
from vj4.model.adaptor import contest
from vj4.handler import base
Expand All @@ -24,19 +25,93 @@ def node_url(handler, name, node_or_dtuple):
return handler.reverse_url(name, **kwargs)


class DiscussionMixin(object):
def __init__(self, domain_id, remote_ip, user, own, check_perm):
self.domain_id = domain_id
self.remote_ip = remote_ip
self.user = user
self.own = own
self.check_perm = check_perm

async def post_reply(self, did: document.convert_doc_id, content: str):
ddoc = await discussion.get(self.domain_id, did)
await discussion.add_reply(self.domain_id, ddoc['doc_id'], self.user['_id'], content,
self.remote_ip)

async def post_tail_reply(self,
did: document.convert_doc_id,
drid: document.convert_doc_id,
content: str):
ddoc = await discussion.get(self.domain_id, did)
drdoc = await discussion.get_reply(self.domain_id, drid, ddoc['doc_id'])
await discussion.add_tail_reply(self.domain_id, drdoc['doc_id'], self.user['_id'], content,
self.remote_ip)

async def post_edit_reply(self, did: document.convert_doc_id,
drid: document.convert_doc_id, content: str):
ddoc = await discussion.get(self.domain_id, did)
drdoc = await discussion.get_reply(self.domain_id, drid, ddoc['doc_id'])
if (not self.own(ddoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drdoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_EDIT_DISCUSSION_REPLY)
drdoc = await discussion.edit_reply(self.domain_id, drdoc['doc_id'],
content=content)

async def post_delete_reply(self, did: document.convert_doc_id,
drid: document.convert_doc_id):
ddoc = await discussion.get(self.domain_id, did)
drdoc = await discussion.get_reply(self.domain_id, drid, ddoc['doc_id'])
if (not self.own(ddoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drdoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_DELETE_DISCUSSION_REPLY)
await oplog.add(self.user['_id'], oplog.TYPE_DELETE_DOCUMENT, doc=drdoc)
drdoc = await discussion.delete_reply(self.domain_id, drdoc['doc_id'])

async def post_edit_tail_reply(self, did: document.convert_doc_id,
drid: document.convert_doc_id, drrid: document.convert_doc_id,
content: str):
ddoc = await discussion.get(self.domain_id, did)
drdoc, drrdoc = await discussion.get_tail_reply(self.domain_id, drid, drrid)
if not drdoc or drdoc['parent_doc_id'] != ddoc['doc_id']:
raise error.DocumentNotFoundError(domain_id, document.TYPE_DISCUSSION_REPLY, drid)
if (not self.own(ddoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drrdoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_EDIT_DISCUSSION_REPLY)
await discussion.edit_tail_reply(self.domain_id, drid, drrid, content)

async def post_delete_tail_reply(self, did: document.convert_doc_id,
drid: document.convert_doc_id, drrid: objectid.ObjectId):
ddoc = await discussion.get(self.domain_id, did)
drdoc, drrdoc = await discussion.get_tail_reply(self.domain_id, drid, drrid)
if not drdoc or drdoc['parent_doc_id'] != ddoc['doc_id']:
raise error.DocumentNotFoundError(domain_id, document.TYPE_DISCUSSION_REPLY, drid)
if (not self.own(ddoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drrdoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_DELETE_DISCUSSION_REPLY)
await oplog.add(self.user['_id'], oplog.TYPE_DELETE_SUB_DOCUMENT, sub_doc=drrdoc,
doc_type=drdoc['doc_type'], doc_id=drdoc['doc_id'])
await discussion.delete_tail_reply(self.domain_id, drid, drrid)


@app.route('/discuss', 'discussion_main')
class DiscussionMainHandler(base.Handler):
DISCUSSIONS_PER_PAGE = 15
DISCUSSIONS_PER_PAGE = 20

@base.require_perm(builtin.PERM_VIEW_DISCUSSION)
@base.get_argument
@base.sanitize
async def get(self, *, page: int=1):
benbenid = None
for dom in builtin.DOMAINS:
if dom['_id'] == self.domain_id:
benbenid = await system.get_benbenid()
break

# TODO(iceboy): continuation based pagination.
nodes, (ddocs, dpcount, _) = await asyncio.gather(
discussion.get_nodes(self.domain_id),
# TODO(twd2): exclude problem/contest discussions?
pagination.paginate(discussion.get_multi(self.domain_id), page, self.DISCUSSIONS_PER_PAGE))
pagination.paginate(discussion.get_multi(self.domain_id, doc_id={"$ne":objectid.ObjectId(benbenid)}), page, self.DISCUSSIONS_PER_PAGE))
udict, dudict, vndict = await asyncio.gather(
user.get_dict(ddoc['owner_uid'] for ddoc in ddocs),
domain.get_dict_user_by_uid(domain_id=self.domain_id, uids=(ddoc['owner_uid'] for ddoc in ddocs)),
Expand Down Expand Up @@ -185,9 +260,8 @@ async def get(self, *, did: document.convert_doc_id, page: int=1):
@base.sanitize
@base.limit_rate('add_discussion', 3600, 30)
async def post_reply(self, *, did: document.convert_doc_id, content: str):
ddoc = await discussion.get(self.domain_id, did)
await discussion.add_reply(self.domain_id, ddoc['doc_id'], self.user['_id'], content,
self.remote_ip)
discussionMixin = DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_reply(did, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
Expand All @@ -200,10 +274,8 @@ async def post_tail_reply(self, *,
did: document.convert_doc_id,
drid: document.convert_doc_id,
content: str):
ddoc = await discussion.get(self.domain_id, did)
drdoc = await discussion.get_reply(self.domain_id, drid, ddoc['doc_id'])
await discussion.add_tail_reply(self.domain_id, drdoc['doc_id'], self.user['_id'], content,
self.remote_ip)
discussionMixin = DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_tail_reply(did, drid, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
Expand All @@ -212,13 +284,8 @@ async def post_tail_reply(self, *,
@base.sanitize
async def post_edit_reply(self, *, did: document.convert_doc_id,
drid: document.convert_doc_id, content: str):
ddoc = await discussion.get(self.domain_id, did)
drdoc = await discussion.get_reply(self.domain_id, drid, ddoc['doc_id'])
if (not self.own(ddoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drdoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_EDIT_DISCUSSION_REPLY)
drdoc = await discussion.edit_reply(self.domain_id, drdoc['doc_id'],
content=content)
discussionMixin = DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_edit_reply(did, drid, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
Expand All @@ -227,13 +294,8 @@ async def post_edit_reply(self, *, did: document.convert_doc_id,
@base.sanitize
async def post_delete_reply(self, *, did: document.convert_doc_id,
drid: document.convert_doc_id):
ddoc = await discussion.get(self.domain_id, did)
drdoc = await discussion.get_reply(self.domain_id, drid, ddoc['doc_id'])
if (not self.own(ddoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drdoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_DELETE_DISCUSSION_REPLY)
await oplog.add(self.user['_id'], oplog.TYPE_DELETE_DOCUMENT, doc=drdoc)
drdoc = await discussion.delete_reply(self.domain_id, drdoc['doc_id'])
discussionMixin = DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_delete_reply(did, drid)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
Expand All @@ -243,14 +305,8 @@ async def post_delete_reply(self, *, did: document.convert_doc_id,
async def post_edit_tail_reply(self, *, did: document.convert_doc_id,
drid: document.convert_doc_id, drrid: document.convert_doc_id,
content: str):
ddoc = await discussion.get(self.domain_id, did)
drdoc, drrdoc = await discussion.get_tail_reply(self.domain_id, drid, drrid)
if not drdoc or drdoc['parent_doc_id'] != ddoc['doc_id']:
raise error.DocumentNotFoundError(domain_id, document.TYPE_DISCUSSION_REPLY, drid)
if (not self.own(ddoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drrdoc, builtin.PERM_EDIT_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_EDIT_DISCUSSION_REPLY)
await discussion.edit_tail_reply(self.domain_id, drid, drrid, content)
discussionMixin = DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_edit_tail_reply(did, drid, drrid, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
Expand All @@ -259,16 +315,8 @@ async def post_edit_tail_reply(self, *, did: document.convert_doc_id,
@base.sanitize
async def post_delete_tail_reply(self, *, did: document.convert_doc_id,
drid: document.convert_doc_id, drrid: objectid.ObjectId):
ddoc = await discussion.get(self.domain_id, did)
drdoc, drrdoc = await discussion.get_tail_reply(self.domain_id, drid, drrid)
if not drdoc or drdoc['parent_doc_id'] != ddoc['doc_id']:
raise error.DocumentNotFoundError(domain_id, document.TYPE_DISCUSSION_REPLY, drid)
if (not self.own(ddoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION)
and not self.own(drrdoc, builtin.PERM_DELETE_DISCUSSION_REPLY_SELF)):
self.check_perm(builtin.PERM_DELETE_DISCUSSION_REPLY)
await oplog.add(self.user['_id'], oplog.TYPE_DELETE_SUB_DOCUMENT, sub_doc=drrdoc,
doc_type=drdoc['doc_type'], doc_id=drdoc['doc_id'])
await discussion.delete_tail_reply(self.domain_id, drid, drrid)
discussionMixin = DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_delete_tail_reply(did, drid, drrid)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
Expand Down
115 changes: 107 additions & 8 deletions vj4/handler/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import datetime
import functools
import random
from bson import objectid

from vj4 import app
from vj4 import constant
Expand All @@ -12,11 +13,13 @@
from vj4.model import document
from vj4.model import domain
from vj4.model import user
from vj4.model import system
from vj4.model.adaptor import discussion
from vj4.model.adaptor import contest
from vj4.model.adaptor import training
from vj4.handler import base
from vj4.handler import training as training_handler
from vj4.handler import discussion as discussion_handler
from vj4.util import validator
from vj4.util import misc
from vj4.util import options
Expand All @@ -29,12 +32,13 @@ async def get(self):
self.render('bsod.html', args=self.request.headers)

@app.route('/', 'domain_main')
class DomainMainHandler(contest.ContestStatusMixin, base.Handler):
class DomainMainHandler(contest.ContestStatusMixin, base.OperationHandler):
CONTESTS_ON_MAIN = 5
HOMEWORK_ON_MAIN = 5
TRAININGS_ON_MAIN = 5
DISCUSSIONS_ON_MAIN = 20
DISCUSSIONS_ON_MAIN = 12
USERS_PER_PAGE = 10
REPLIES_PER_PAGE = 30

async def prepare_contest(self):
if self.has_perm(builtin.PERM_VIEW_CONTEST):
Expand Down Expand Up @@ -75,9 +79,9 @@ async def prepare_training(self):
tsdict = {}
return tdocs, tsdict

async def prepare_discussion(self):
async def prepare_discussion(self, benbenid=None):
if self.has_perm(builtin.PERM_VIEW_DISCUSSION):
ddocs = await discussion.get_multi(self.domain_id) \
ddocs = await discussion.get_multi(self.domain_id, doc_id={"$ne":objectid.ObjectId(benbenid)}) \
.limit(self.DISCUSSIONS_ON_MAIN) \
.to_list()
vndict = await discussion.get_dict_vnodes(self.domain_id, map(discussion.node_id, ddocs))
Expand All @@ -86,11 +90,17 @@ async def prepare_discussion(self):
vndict = {}
return ddocs, vndict

async def get(self):
async def get(self, page: int=1):
benbenid = None
for dom in builtin.DOMAINS:
if dom['_id'] == self.domain_id:
benbenid = await system.get_benbenid()
break

(tdocs, tsdict), (htdocs, htsdict),\
(trdocs, trsdict), (ddocs, vndict) = await asyncio.gather(
self.prepare_contest(), self.prepare_homework(),
self.prepare_training(), self.prepare_discussion())
self.prepare_training(), self.prepare_discussion(benbenid))

dudocs, _, _ = await pagination.paginate(
domain.get_multi_user(domain_id=self.domain_id, rp={'$gt': 0.0}).sort([('rank', 1)]),
Expand All @@ -105,6 +115,7 @@ async def get(self):
spdocs = await domain.get_suggest_problem(self.domain_id)
sdocs = await domain.get_swiper(self.domain_id)

# 处理运势
if self.has_priv(builtin.PRIV_USER_PROFILE):
rnd = random.Random()
rnd.seed(int(datetime.date.today().strftime("%y%m%d")) + int(self.user["_id"]))
Expand All @@ -114,17 +125,105 @@ async def get(self):
lucknum = "未登录"
wdudoc = {}

drdocs, udictd, pcount, drcount = None, None, None, None
if benbenid:
did = benbenid
ddoc = await discussion.get(self.domain_id, did)
vnode, (drdocs, pcount, drcount) = await asyncio.gather(
discussion.get_vnode(self.domain_id, discussion.node_id(ddoc)),
pagination.paginate(discussion.get_multi_reply(self.domain_id, ddoc['doc_id']),
page, self.REPLIES_PER_PAGE))
if not vnode:
vnode = builtin.VNODE_MISSING
elif vnode['doc_type'] == document.TYPE_PROBLEM and vnode.get('hidden', False):
self.check_perm(builtin.PERM_VIEW_PROBLEM_HIDDEN)
# TODO(twd2): do more visibility check eg. contest
uids = {ddoc['owner_uid']}
uids.update(drdoc['owner_uid'] for drdoc in drdocs)
for drdoc in drdocs:
if 'reply' in drdoc:
uids.update(drrdoc['owner_uid'] for drrdoc in drdoc['reply'])
if 'owner_uid' in vnode:
uids.add(vnode['owner_uid'])
udictd = await user.get_dict(uids)

self.render('domain_main.html', discussion_nodes=await discussion.get_nodes(self.domain_id),
tdocs=tdocs, tsdict=tsdict,
htdocs=htdocs, htsdict=htsdict,
trdocs=trdocs, trsdict=trsdict,
training=training_handler.TrainingMixin(),
ddocs=ddocs, vndict=vndict,
ddocs=ddocs, vndict=vndict, discussions_per_page=self.DISCUSSIONS_ON_MAIN,
udict=udict, dudict=dudict, datetime_stamp=self.datetime_stamp,
blessing=builtin.BLESSING, blessing_content=builtin.BLESSING_CONTENT,
lucknum=lucknum, wdudoc=wdudoc, dudocs=dudocs, udoc=self.user, users_per_page=self.USERS_PER_PAGE,
rudict=rudict, rdudict=rdudict,
spdocs=spdocs, sdocs=sdocs)
spdocs=spdocs, sdocs=sdocs,
benbenid=benbenid, drdocs=drdocs, udictd=udictd, pcount=pcount, drcount=drcount)

@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_perm(builtin.PERM_REPLY_DISCUSSION)
@base.require_csrf_token
@base.sanitize
@base.limit_rate('add_discussion', 3600, 30)
async def post_reply(self, *, content: str):
did = await system.get_benbenid()
discussionMixin = discussion_handler.DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_reply(did, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_perm(builtin.PERM_REPLY_DISCUSSION)
@base.require_csrf_token
@base.sanitize
@base.limit_rate('add_discussion', 3600, 30)
async def post_tail_reply(self, *,
drid: document.convert_doc_id,
content: str):
did = await system.get_benbenid()
discussionMixin = discussion_handler.DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_tail_reply(did, drid, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_csrf_token
@base.sanitize
async def post_edit_reply(self, *,
drid: document.convert_doc_id, content: str):
did = await system.get_benbenid()
discussionMixin = discussion_handler.DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_edit_reply(did, drid, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_csrf_token
@base.sanitize
async def post_delete_reply(self, *,
drid: document.convert_doc_id):
did = await system.get_benbenid()
discussionMixin = discussion_handler.DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_delete_reply(did, drid)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_csrf_token
@base.sanitize
async def post_edit_tail_reply(self, *,
drid: document.convert_doc_id, drrid: document.convert_doc_id,
content: str):
did = await system.get_benbenid()
discussionMixin = discussion_handler.DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_edit_tail_reply(did, drid, drrid, content)
self.json_or_redirect(self.url)

@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_csrf_token
@base.sanitize
async def post_delete_tail_reply(self, *,
drid: document.convert_doc_id, drrid: objectid.ObjectId):
did = await system.get_benbenid()
discussionMixin = discussion_handler.DiscussionMixin(self.domain_id, self.remote_ip, self.user, self.own, self.check_perm)
await discussionMixin.post_delete_tail_reply(did, drid, drrid)
self.json_or_redirect(self.url)


@app.route('/domain', 'domain_manage')
Expand Down
Loading

0 comments on commit 7b467f2

Please sign in to comment.