Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String pid #514

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fac3a93
String PID support
undefined-moe May 13, 2019
316f5ce
fix spaces
undefined-moe May 13, 2019
a6c531a
String PID validator
undefined-moe May 13, 2019
0515be6
Help-Wanted:
undefined-moe May 13, 2019
68ce0c9
Fix tests
undefined-moe May 13, 2019
43755a0
UnittestFix1
undefined-moe May 13, 2019
38b7ec0
This is a backup version and it's **not** finished
undefined-moe May 14, 2019
d3bdbc8
0x02
undefined-moe May 14, 2019
536dc33
0x03
undefined-moe May 14, 2019
e5af567
0x04
undefined-moe May 14, 2019
fde8f43
0x05
undefined-moe May 14, 2019
bbbedc5
Merge branch 'master' into stringPID
undefined-moe May 14, 2019
7778e02
0x06
undefined-moe May 14, 2019
10b3ecd
0x07
undefined-moe May 14, 2019
60e6374
0x08
undefined-moe May 14, 2019
35e4aef
0x09
undefined-moe May 15, 2019
7a8bd75
0x0a
undefined-moe May 15, 2019
c1d83c3
Merge branch 'master' into stringPID
undefined-moe May 15, 2019
6c2fd17
0x0b
undefined-moe May 15, 2019
2d66a76
0x0c
undefined-moe May 15, 2019
a18e83a
0x0d
undefined-moe May 16, 2019
c6cf315
fix solution
undefined-moe May 24, 2019
e3e2e6f
bug fix
undefined-moe May 27, 2019
523cf83
Merge pull request #1 from vijos/master
undefined-moe May 27, 2019
8e9b68c
Merge branch 'master' into stringPID
undefined-moe May 29, 2019
3132019
to lowercase
undefined-moe May 29, 2019
69e7e62
Merge branch 'stringPID' of https://github.com/masnn0/vj4 into stringPID
undefined-moe May 29, 2019
c2838e9
Merge branch 'master' into stringPID
undefined-moe May 31, 2019
35c7080
Merge pull request #3 from vijos/master
undefined-moe May 31, 2019
27da508
Merge pull request #4 from masnn0/master
undefined-moe May 31, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions vj4/handler/contest.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ async def get(self, *, tid: objectid.ObjectId):
file_name='{}.zip'.format(tdoc['title']))


@app.route('/contest/{tid}/{pid:-?\d+|\w{24}}', 'contest_detail_problem')
@app.route('/contest/{tid}/p/{pid}', 'contest_detail_problem')
undefined-moe marked this conversation as resolved.
Show resolved Hide resolved
class ContestDetailProblemHandler(contest.ContestMixin, base.Handler):
@base.route_argument
@base.require_perm(builtin.PERM_VIEW_CONTEST)
Expand Down Expand Up @@ -163,7 +163,7 @@ async def get(self, *, tid: objectid.ObjectId, pid: document.convert_doc_id):
page_title=pdoc['title'], path_components=path_components)


@app.route('/contest/{tid}/{pid}/submit', 'contest_detail_problem_submit')
@app.route('/contest/{tid}/p/{pid}/submit', 'contest_detail_problem_submit')
class ContestDetailProblemSubmitHandler(contest.ContestMixin, base.Handler):
@base.route_argument
@base.require_perm(builtin.PERM_VIEW_CONTEST)
Expand Down
4 changes: 2 additions & 2 deletions vj4/handler/homework.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ async def get(self, *, tid: objectid.ObjectId):
file_name='{}.zip'.format(tdoc['title']))


@app.route('/homework/{tid}/{pid:-?\d+|\w{24}}', 'homework_detail_problem')
@app.route('/homework/{tid}/p/{pid}', 'homework_detail_problem')
class HomeworkDetailProblemHandler(contest.ContestMixin, base.Handler):
@base.route_argument
@base.require_perm(builtin.PERM_VIEW_HOMEWORK)
Expand Down Expand Up @@ -188,7 +188,7 @@ async def get(self, *, tid: objectid.ObjectId, pid: document.convert_doc_id):
page_title=pdoc['title'], path_components=path_components)


@app.route('/homework/{tid}/{pid}/submit', 'homework_detail_problem_submit')
@app.route('/homework/{tid}/p/{pid}/submit', 'homework_detail_problem_submit')
class HomeworkDetailProblemSubmitHandler(contest.ContestMixin, base.Handler):
@base.route_argument
@base.require_perm(builtin.PERM_VIEW_HOMEWORK)
Expand Down
25 changes: 11 additions & 14 deletions vj4/handler/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async def get(self, *, page: int=1):
f = {}
pdocs, ppcount, pcount = await pagination.paginate(problem.get_multi(domain_id=self.domain_id,
**f) \
.sort([('doc_id', 1)]),
.sort([('pname', 1), ('doc_id', 1)]),
page, self.PROBLEMS_PER_PAGE)
if self.has_priv(builtin.PRIV_USER_PROFILE):
# TODO(iceboy): projection.
Expand All @@ -90,7 +90,7 @@ async def star_unstar(self, *, pid: document.convert_doc_id, star: bool):
post_unstar = functools.partialmethod(star_unstar, star=False)


@app.route('/p/random', 'problem_random')
@app.route('/problem/random', 'problem_random')
iceboy233 marked this conversation as resolved.
Show resolved Hide resolved
class ProblemRandomHandler(base.Handler):
@base.require_perm(builtin.PERM_VIEW_PROBLEM)
@base.route_argument
Expand Down Expand Up @@ -185,7 +185,7 @@ async def get(self, *, category: str):
self.json_or_redirect(self.referer_or_main)


@app.route('/p/{pid:-?\d+|\w{24}}', 'problem_detail')
@app.route('/p/{pid}', 'problem_detail')
class ProblemDetailHandler(base.OperationHandler):
async def _get_related_trainings(self, pid):
if self.has_perm(builtin.PERM_VIEW_TRAINING):
Expand Down Expand Up @@ -568,7 +568,7 @@ async def get(self, *, pid: document.convert_doc_id):
secret=fdoc['metadata']['secret']))


@app.route('/p/create', 'problem_create')
@app.route('/problem/create', 'problem_create')
class ProblemCreateHandler(base.Handler):
@base.require_priv(builtin.PRIV_USER_PROFILE)
@base.require_perm(builtin.PERM_CREATE_PROBLEM)
Expand All @@ -580,16 +580,13 @@ async def get(self):
@base.post_argument
@base.require_csrf_token
@base.sanitize
async def post(self, *, title: str, content: str, hidden: bool=False, numeric_pid: bool=False):
pid = None
if numeric_pid:
pid = await domain.inc_pid_counter(self.domain_id)
async def post(self, *, title: str, content: str, hidden: bool=False, pname: str=None):
undefined-moe marked this conversation as resolved.
Show resolved Hide resolved
pid = await problem.add(self.domain_id, title, content, self.user['_id'],
hidden=hidden, pid=pid)
hidden=hidden, pname=pname)
self.json_or_redirect(self.reverse_url('problem_settings', pid=pid))


@app.route('/p/copy', 'problem_copy')
@app.route('/problem/copy', 'problem_copy')
class ProblemCopyHandler(base.Handler):
MAX_PROBLEMS_PER_REQUEST = 20

Expand Down Expand Up @@ -668,12 +665,12 @@ async def get(self, *, pid: document.convert_doc_id):
@base.post_argument
@base.require_csrf_token
@base.sanitize
async def post(self, *, pid: document.convert_doc_id, title: str, content: str):
async def post(self, *, pid: document.convert_doc_id, title: str, content: str, pname: str=None):
pdoc = await problem.get(self.domain_id, pid)
if not self.own(pdoc, builtin.PERM_EDIT_PROBLEM_SELF):
self.check_perm(builtin.PERM_EDIT_PROBLEM)
await problem.edit(self.domain_id, pdoc['doc_id'], title=title, content=content)
self.json_or_redirect(self.reverse_url('problem_detail', pid=pid))
pdoc = await problem.edit(self.domain_id, pdoc['doc_id'], title=title, content=content, pname=pname)
self.json_or_redirect(self.reverse_url('problem_detail', pid=pdoc.get('pname', pdoc['doc_id'])))


@app.route('/p/{pid}/settings', 'problem_settings')
Expand Down Expand Up @@ -791,7 +788,7 @@ async def get(self, *, pid: document.convert_doc_id):
page_title=pdoc['title'], path_components=path_components)


@app.route('/p/search', 'problem_search')
@app.route('/problem/search', 'problem_search')
class ProblemSearchHandler(base.Handler):
@base.get_argument
@base.route_argument
Expand Down
3 changes: 2 additions & 1 deletion vj4/locale/zh_CN.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,8 @@ display_name: 显示名
home_domain_account: 当前域的设置
'The value `{1}` of {0} already exists.': '{0} 的值 `{1}` 已经存在。'
Display name {1} you want to set is used by others.: 您想要设置的显示名 {1} 已经被其他人使用了。
Numeric PID: 数字题号
Leave blank to use numeric pid.: 留空以使用数字题号
PNAME: 题号
undefined-moe marked this conversation as resolved.
Show resolved Hide resolved
Only {0} problems can be copied in one request, got {1}.: 一次请求只能复制 {0} 个题目,但是您输入了 {1} 个。
Problem is successfully copied.: 题目复制完成。
problem_copy: 复制题目
Expand Down
48 changes: 39 additions & 9 deletions vj4/model/adaptor/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,27 @@ def get_categories():

@argmethod.wrap
async def add(domain_id: str, title: str, content: str, owner_uid: int,
pid: document.convert_doc_id=None, data: objectid.ObjectId=None,
pid: document.convert_doc_id=None, pname: str=None, data: objectid.ObjectId=None,
category: list=[], tag: list=[], hidden: bool=False):
validator.check_title(title)
validator.check_content(content)
pid = await document.add(domain_id, content, owner_uid, document.TYPE_PROBLEM,
pid, title=title, data=data, category=category, tag=tag,
hidden=hidden, num_submit=0, num_accept=0)
if not pid:
pid = await domain.inc_pid_counter(domain_id)
try:
undefined-moe marked this conversation as resolved.
Show resolved Hide resolved
pid = int(pid)
except ValueError:
pass
if pname == "":
pname = None
if pname:
validator.check_string_pname(pname)
pid = await document.add(domain_id, content, owner_uid, document.TYPE_PROBLEM,
pid, pname=pname, title=title, data=data, category=category, tag=tag,
hidden=hidden, num_submit=0, num_accept=0)
else:
pid = await document.add(domain_id, content, owner_uid, document.TYPE_PROBLEM,
pid, title=title, data=data, category=category, tag=tag,
hidden=hidden, num_submit=0, num_accept=0)
await domain.inc_user(domain_id, owner_uid, num_problems=1)
return pid

Expand All @@ -65,10 +79,10 @@ async def copy(pdoc, dest_domain_id: str, owner_uid: int,

@argmethod.wrap
async def get(domain_id: str, pid: document.convert_doc_id, uid: int = None):
pid = await document.get_pid(domain_id, pid)
pdoc = await document.get(domain_id, document.TYPE_PROBLEM, pid)
if not pdoc:
raise error.ProblemNotFoundError(domain_id, pid)
# TODO(twd2): move out:
if uid is not None:
pdoc['psdoc'] = await document.get_status(domain_id, document.TYPE_PROBLEM,
doc_id=pid, uid=uid)
Expand All @@ -78,12 +92,19 @@ async def get(domain_id: str, pid: document.convert_doc_id, uid: int = None):


@argmethod.wrap
async def edit(domain_id: str, pid: document.convert_doc_id, **kwargs):
async def edit(domain_id: str, pid: document.convert_doc_id, pname: str=None, **kwargs):
pid = await document.get_pid(domain_id, pid)
if 'title' in kwargs:
validator.check_title(kwargs['title'])
validator.check_title(kwargs['title'])
if 'content' in kwargs:
validator.check_content(kwargs['content'])
pdoc = await document.set(domain_id, document.TYPE_PROBLEM, pid, **kwargs)
validator.check_content(kwargs['content'])
if pname == "":
pname = None
if pname:
validator.check_string_pname(pname)
pdoc = await document.set(domain_id, document.TYPE_PROBLEM, pid, pname=pname, **kwargs)
else:
pdoc = await document.set(domain_id, document.TYPE_PROBLEM, pid, **kwargs)
if not pdoc:
raise error.DocumentNotFoundError(domain_id, document.TYPE_PROBLEM, pid)
return pdoc
Expand Down Expand Up @@ -134,12 +155,14 @@ async def get_dict_multi_domain(pdom_and_ids, *, fields=None):

@argmethod.wrap
async def get_status(domain_id: str, pid: document.convert_doc_id, uid: int, fields=None):
pid = await document.get_pid(domain_id, pid)
return await document.get_status(domain_id, document.TYPE_PROBLEM, pid, uid, fields=fields)


@argmethod.wrap
async def inc_status(domain_id: str, pid: document.convert_doc_id, uid: int,
key: str, value: int):
pid = await document.get_pid(domain_id, pid)
return await document.inc_status(domain_id, document.TYPE_PROBLEM, pid, uid, key, value)


Expand All @@ -159,12 +182,14 @@ async def get_dict_status(domain_id, uid, pids, *, fields=None):

@argmethod.wrap
async def set_star(domain_id: str, pid: document.convert_doc_id, uid: int, star: bool):
pid = await document.get_pid(domain_id, pid)
return await document.set_status(domain_id, document.TYPE_PROBLEM, pid, uid, star=star)


@argmethod.wrap
async def add_solution(domain_id: str, pid: document.convert_doc_id, uid: int, content: str):
validator.check_content(content)
pid = await document.get_pid(domain_id, pid)
return await document.add(domain_id, content, uid, document.TYPE_PROBLEM_SOLUTION, None,
document.TYPE_PROBLEM, pid, vote=0, reply=[])

Expand Down Expand Up @@ -214,6 +239,7 @@ async def delete_solution(domain_id: str, psid: document.convert_doc_id):
@argmethod.wrap
async def get_list_solution(domain_id: str, pid: document.convert_doc_id,
fields=None, skip: int = 0, limit: int = 0):
pid = await document.get_pid(domain_id, pid)
return await document.get_multi(domain_id=domain_id,
doc_type=document.TYPE_PROBLEM_SOLUTION,
parent_doc_type=document.TYPE_PROBLEM,
Expand Down Expand Up @@ -293,6 +319,7 @@ async def get_data(pdoc):

@argmethod.wrap
async def set_data(domain_id: str, pid: document.convert_doc_id, data: objectid.ObjectId):
pid = await document.get_pid(domain_id, pid)
pdoc = await document.set(domain_id, document.TYPE_PROBLEM, pid, data=data)
if not pdoc:
raise error.DocumentNotFoundError(domain_id, document.TYPE_PROBLEM, pid)
Expand All @@ -302,6 +329,7 @@ async def set_data(domain_id: str, pid: document.convert_doc_id, data: objectid.

@argmethod.wrap
async def set_hidden(domain_id: str, pid: document.convert_doc_id, hidden: bool):
pid = await document.get_pid(domain_id, pid)
pdoc = await document.set(domain_id, document.TYPE_PROBLEM, pid, hidden=hidden)
if not pdoc:
raise error.DocumentNotFoundError(domain_id, document.TYPE_PROBLEM, pid)
Expand Down Expand Up @@ -329,12 +357,14 @@ async def get_data_list(last: int):

@argmethod.wrap
async def inc(domain_id: str, pid: document.convert_doc_id, key: str, value: int):
pid = await document.get_pid(domain_id, pid)
return await document.inc(domain_id, document.TYPE_PROBLEM, pid, key, value)


@argmethod.wrap
async def update_status(domain_id: str, pid: document.convert_doc_id, uid: int,
rid: objectid.ObjectId, status: int):
pid = await document.get_pid(domain_id, pid)
try:
return await document.set_if_not_status(domain_id, document.TYPE_PROBLEM, pid, uid,
'status', status, constant.record.STATUS_ACCEPTED,
Expand Down
28 changes: 27 additions & 1 deletion vj4/model/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pymongo import ReturnDocument

from vj4 import db
from vj4 import error
from vj4.util import argmethod

TYPE_PROBLEM = 10
Expand Down Expand Up @@ -39,6 +40,20 @@ def convert_doc_id(doc_id):
return str(doc_id)


@argmethod.wrap
async def get_pid(domain_id, key):
if objectid.ObjectId.is_valid(key):
pdoc = await get(domain_id, TYPE_PROBLEM, objectid.ObjectId(key))
try:
key = int(key)
pdoc = await get(domain_id, TYPE_PROBLEM, key)
except ValueError:
pdoc = await get_by_pname(domain_id, TYPE_PROBLEM, key)
if not pdoc:
raise error.ProblemNotFoundError(domain_id, key)
return pdoc['doc_id']


@argmethod.wrap
async def add(domain_id: str, content: str, owner_uid: int,
doc_type: int, doc_id: convert_doc_id = None,
Expand All @@ -57,7 +72,7 @@ async def add(domain_id: str, content: str, owner_uid: int,
assert parent_doc_type and parent_doc_id
doc['parent_doc_type'], doc['parent_doc_id'] = parent_doc_type, parent_doc_id
await coll.insert_one(doc)
return doc['doc_id']
return doc.get('pname', doc['doc_id'])


@argmethod.wrap
Expand All @@ -68,6 +83,14 @@ async def get(domain_id: str, doc_type: int, doc_id: convert_doc_id, fields=None
'doc_id': doc_id}, projection=fields)


@argmethod.wrap
async def get_by_pname(domain_id: str, doc_type: int, pname: str, fields=None):
coll = db.coll('document')
return await coll.find_one({'domain_id': domain_id,
'doc_type': doc_type,
'pname': pname}, projection=fields)


async def set(domain_id: str, doc_type: int, doc_id: convert_doc_id, **kwargs):
coll = db.coll('document')
doc = await coll.find_one_and_update(filter={'domain_id': domain_id,
Expand Down Expand Up @@ -408,6 +431,9 @@ async def ensure_indexes():
await coll.create_index([('domain_id', 1),
('doc_type', 1),
('dag.pids', 1)], sparse=True)
await coll.create_index([('domain_id', 1),
('doc_type', 1),
('pname', 1)], sparse=True)
status_coll = db.coll('document.status')
await status_coll.create_index([('domain_id', 1),
('doc_type', 1),
Expand Down
6 changes: 5 additions & 1 deletion vj4/ui/templates/components/problem.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
{%- if not invalid %}
<a
{%- if tdoc is none %}
{% if pdoc['pname'] %}
href="{{ reverse_url('problem_detail', domain_id=pdoc['domain_id'], pid=pdoc['pname']) }}"
{% else %}
href="{{ reverse_url('problem_detail', domain_id=pdoc['domain_id'], pid=pdoc['doc_id']) }}"
{% endif %}
{%- elif tdoc['doc_type'] == vj4.model.document.TYPE_CONTEST %}
href="{{ reverse_url('contest_detail_problem', domain_id=pdoc['domain_id'], pid=pdoc['doc_id'], tid=tdoc['doc_id']) }}"
{%- elif tdoc['doc_type'] == vj4.model.document.TYPE_HOMEWORK %}
href="{{ reverse_url('homework_detail_problem', domain_id=pdoc['domain_id'], pid=pdoc['doc_id'], tid=tdoc['doc_id']) }}"
{%- endif %}
>
{%- endif %}
{% if pdoc['doc_id']|string|length < 10 %}P{{ pdoc['doc_id'] }} {% endif %}{{ pdoc['title'] }}
{% if pdoc['pname'] %}{{ pdoc['pname'] }} {% elif pdoc['doc_id']|string|length < 24 %}P{{ pdoc['doc_id'] }} {% endif %}{{ pdoc['title'] }}
{%- if not invalid %}
</a>
{%- endif %}
Expand Down
2 changes: 1 addition & 1 deletion vj4/ui/templates/partials/problem_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<td class="col--name col--problem-name">
{% if handler.has_priv(vj4.model.builtin.PRIV_USER_PROFILE) %}
<form class="form--inline" action="{{ reverse_url('problem_main') }}" method="post">
<input type="hidden" name="pid" value="{{ pdoc['doc_id'] }}">
<input type="hidden" name="pid" value="{{ pdoc['pname'] }}">
<input type="hidden" name="operation" value="{% if not psdoc['star'] %}star{% else %}unstar{% endif %}">
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
<button class="star{% if psdoc['star'] %} activated{% endif %}" type="submit">
Expand Down
12 changes: 5 additions & 7 deletions vj4/ui/templates/problem_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
<div class="section__body">
<form method="post">
<div class="row">
<div class="medium-8 columns">
<div class="medium-7 columns">
<label>
{{ _('Title') }}
<input name="title" placeholder="{{ _('title') }}" value="{{ pdoc['title']|default('') }}" class="textbox" autofocus>
</label>
</div>
{% if page_name == 'problem_create' %}
<div class="medium-2 columns">
<div class="medium-3 columns">
<label>
{{ _('Settings') }}
{{ _('PNAME') }}
<br>
<label class="checkbox">
<input type="checkbox" name="numeric_pid" value="on" checked>{{ _('Numeric PID') }}
<label>
<input name="pname" placeholder="{{ _('Leave blank to use numeric pid.') }}" value="{{ pdoc['pname']|default('') }}" class="textbox">
</label>
</label>
</div>
Expand All @@ -30,7 +29,6 @@
</label>
</label>
</div>
{% endif %}
</div>
<div class="row"><div class="columns">
<label>
Expand Down
Loading