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
Paper assignment page #2756
Paper assignment page #2756
Conversation
c4d3194
to
8daf1ed
Compare
@@ -34,6 +34,7 @@ | |||
methods=('GET', 'POST')) | |||
_bp.add_url_rule('/manage/papers/enable/<any(content,layout):reviewing_type>', 'switch', | |||
management.RHSwitchReviewingType, methods=('PUT', 'DELETE')) | |||
_bp.add_url_rule('/manage/papers/assign', 'assignment', management.RHPapersAssignment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use RHPaperAssignmentList
and /manage/papers/assignment-list/
{% if contrib.paper_revisions %} | ||
{{ contrib.paper_revisions.0.state.title }} | ||
{% else %} | ||
{%- trans %}Paper not yet submitted{% endtrans -%} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some places you use -
to remove the whitespace and in others you don't. I'd suggest to stick to one of the two conventions. The best IMO is to remove the whitespace because it creates an ugly HTML structure.
{% for contrib in contribs %} | ||
{% set last_revision_state %} | ||
{% if contrib.paper_revisions %} | ||
{{ contrib.paper_revisions.0.state.title }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this even work? ❗
Why not {{ contrib.paper_revisions[0].state.title }}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have a property in the contribution model to retrieve the latest revision...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, please do not use .0.
in jinja but [0]
instead. And yes, we should have a property/relationship that takes care of it. Since the relationship is slighly tricky - but albeit very useful so we can joinedload it e.g. for the listing - I would first go for a simple property and then change it to a relationship later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ThiefMaster, muy importante.
{% block content %} | ||
<div class="toolbars space-after"> | ||
<div class="toolbar"> | ||
<div class="group"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As explained in our toolbars wiki page, single buttons in a toolbar don't need to be wrapped by the .group
element anymore. Apply this to the rest of your templates as well! We currently have some (quite many actually) templates in Indico that still use the .group
element even if it includes 1 button, but we'll remove them eventually. We just gotta make sure that any new code doesn't increase the amount of code we need to change!
data-title="{{ contrib.title }}"> | ||
<td class="i-table id-column"> | ||
<span class="vertical-aligner"> | ||
<input type="checkbox" class="select-row" name="contribution_id" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from the class
and id
attributes, i'd put the rest in a new line each, similar to the way you did it in lines 44-46. Same applies for the data-searchable
and data-text
below and in general anywhere where the list of attributes needs to wrap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a strong opinion but I would definitely not put type
on a new line since it's the most relevant attribute on an <input>
tag.
<div class="group"> | ||
<a href="#" class="i-button icon-checkmark js-enable-if-checked disabled" | ||
data-href="#"> | ||
{%- trans %}Accept{% endtrans -%} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd group the accept, reject and to be corrected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move them into a dropdown
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it but wasn't sure about the button label: Mark as, Change state? Suggestions are welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering if sending papers back for corrections make sense... Shouldn't we enforce leaving some feedback for the submitter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment field should become mandatory in that case.
</a> | ||
</div> | ||
<div class="group"> | ||
<a href="#" class="i-button icon-quill js-enable-if-checked disabled" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about the quill
icon. Maybe edit
would be better? We use the quill
in a complete different context on Indico...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
icon-undo
maybe? 😕
<a class="i-button icon-checkbox-checked arrow js-dropdown" data-toggle="dropdown"></a> | ||
<ul class="dropdown"> | ||
<li> | ||
<a href="#" data-select-all="#assignment-list input:checkbox">{% trans %}All{% endtrans %}</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Selecting a row doesn't highlight it. Make sure the handleRowSelection
method is executed (is should be executed by calling setupListGenerator
as we do in the setupContributionList
function of the contribution list (contributions/templates/management/contributions.html
)
<ul class="dropdown"> | ||
<li><a href="#">{% trans %}Judge{% endtrans %}</a></li> | ||
<li><a href="#">{% trans %}Content reviewer{% endtrans %}</a></li> | ||
<li><a href="#">{% trans %}Layout reviewer{% endtrans %}</a></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Content and layout reviewer options should be available only if the setting is enabled.
</div> | ||
<div class="toolbar"> | ||
<div class="group" id="filter-statistics"> | ||
{{ render_displayed_entries_fragment(contribs|length, total_entries) }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to mention that is WIP, my bad. I'm currently working on the list generator that will solve it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just tends to infinity.
</div> | ||
<div class="group"> | ||
<span class="i-button label icon-search"></span> | ||
<input type="text" id="search-input" placeholder="{% trans %}Enter #id or search string{% endtrans %}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The live search is not functional.
</div> | ||
<div class="group"> | ||
<a class="i-button arrow js-dropdown" data-toggle="dropdown"> | ||
{%- trans %}Assign{% endtrans -%} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Assign and Unassign buttons should be disabled unless there are checked rows. Use:
js-enable-if-checked disabled
placeholder: '#filter-placeholder' | ||
}; | ||
|
||
$('.list-section [data-toggle=dropdown]').closest('.group').dropdown(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
js-dropdown
doesn't work?
"""Assign contrubutions to reviewers and judges""" | ||
|
||
def _process(self): | ||
contribs = sorted(self.event_new.contributions, key=lambda x: x.friendly_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key=attrgetter('friendly_id')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, you could do that in the Jinja template. event.contributions|sort(attribute='friendly_id')
|
||
{% block description %} | ||
{%- trans -%} | ||
Assign <strong>judges</strong>, <strong>content reviewers</strong> and <strong>layout reviewers</strong> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
judges and reviewers to avoid having to use conditionals depending on what's enabled (for such conditionals you'd need to repeat the whole sentence since you cannot have them inside trans blocks)
</div> | ||
<div class="group"> | ||
<button class="i-button icon-settings js-dialog-action js-customize-list highlight" | ||
data-href="#" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is WIP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, forgot to mention in the PR title. I just worked on the table basic structure so far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would leave {# TODO: ... #}
commets not to forget. It is ok to commit those into devel
in early stages of a new release when the blueprint/page is still missing.
<div class="group"> | ||
<button class="i-button icon-settings js-dialog-action js-customize-list highlight" | ||
data-href="#" | ||
data-title="{% trans %}Paper assignment list configuration{% endtrans %}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just "Customize list" or something like that? The title doesn't need to be super verbose
<div class="group"> | ||
<a href="#" class="i-button icon-checkmark js-enable-if-checked disabled" | ||
data-href="#"> | ||
{%- trans %}Accept{% endtrans -%} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move them into a dropdown
</table> | ||
</form> | ||
{%- else %} | ||
{%- call message_box('info') %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would move this to be the first block. This helps see more clearly the implications of the if
block.
{% if not contribs %}
{%- call message_box('info') %}
...
{% else %}
<form method="POST">
...
{% endif %}
{% for contrib in contribs %} | ||
{% set last_revision_state %} | ||
{% if contrib.paper_revisions %} | ||
{{ contrib.paper_revisions.0.state.title }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ThiefMaster, muy importante.
</thead> | ||
<tbody> | ||
{% for contrib in contribs %} | ||
{% set last_revision_state %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we want to start using set
blocks with logic inside... Opinions?
Another way to write this would be:
{% if contrib.paper_revisions %}
{% set last_revision_state = contrib.paper_revisions.0.state.title %}
{% else %}
{% set last_revision_state %}
{%- trans %}Paper not yet submitted{% endtrans -%}
{% endset %}
{% endif %}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd avoid set blocks except where useful. If there's lots of logic inside it might be better suited in a macro.
data-title="{{ contrib.title }}"> | ||
<td class="i-table id-column"> | ||
<span class="vertical-aligner"> | ||
<input type="checkbox" class="select-row" name="contribution_id" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a strong opinion but I would definitely not put type
on a new line since it's the most relevant attribute on an <input>
tag.
{% from 'events/management/_lists.html' import render_displayed_entries_fragment %} | ||
|
||
{% block title %} | ||
{% trans %}Paper Assignment{% endtrans %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title should be the same in all paper-related pages. In this case, Call for Papers
I believe.
This we can move to the subtitle
block.
</div> | ||
<div class="group"> | ||
<button class="i-button icon-settings js-dialog-action js-customize-list highlight" | ||
data-href="#" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would leave {# TODO: ... #}
commets not to forget. It is ok to commit those into devel
in early stages of a new release when the blueprint/page is still missing.
</a> | ||
</div> | ||
<div class="group"> | ||
<a href="#" class="i-button icon-quill js-enable-if-checked disabled" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
icon-undo
maybe? 😕
</div> | ||
<div class="toolbar"> | ||
<div class="group" id="filter-statistics"> | ||
{{ render_displayed_entries_fragment(contribs|length, total_entries) }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just tends to infinity.
<div class="group"> | ||
<a href="#" class="i-button icon-checkmark js-enable-if-checked disabled" | ||
data-href="#"> | ||
{%- trans %}Accept{% endtrans -%} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering if sending papers back for corrections make sense... Shouldn't we enforce leaving some feedback for the submitter?
0653c09
to
9521130
Compare
@@ -36,6 +36,9 @@ | |||
methods=('GET', 'POST')) | |||
_bp.add_url_rule('/manage/papers/enable/<any(content,layout):reviewing_type>', 'switch', | |||
management.RHSwitchReviewingType, methods=('PUT', 'DELETE')) | |||
_bp.add_url_rule('/manage/papers/assignment-list', 'assignment', management.RHPapersAssignmentList) | |||
_bp.add_url_rule('/manage/papers/assign/customize', 'customize_assignment_list', management.RHAssignmentListCustomize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use /manage/papers/assignment-list/customize
here and in the line above /manage/papers/assignment-list/
(slash at the end)
|
||
from collections import OrderedDict | ||
from operator import attrgetter | ||
from flask import request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flask < operator
from indico.modules.events.papers.models.revisions import PaperRevisionState, PaperRevision | ||
from indico.modules.events.util import ListGeneratorBase | ||
from indico.web.flask.templating import get_template_module | ||
from indico.util.i18n import _ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
util < web
super(PaperAssignmentListGenerator, self).__init__(event) | ||
self.default_list_config = { | ||
'items': ('state', ), | ||
'filters': {'items': {}}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.default_list_config = {
'items': ('state', ),
'filters': {'items': {}}
}
'items': ('state', ), | ||
'filters': {'items': {}}} | ||
|
||
state_not_submitted = {None: 'Not yet submitted'} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add translations everywhere: _('Not yet submitted')
"""Render the contribution list template components. | ||
|
||
:return: dict containing the list's entries, the fragment of | ||
displayed entries and whether the contrib passed is displayed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"...whether the contribution...", it's docstring, no need for abbreviations!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, I'd change it also in the contribution list files as well ;)
{% block description %} | ||
{%- trans -%} | ||
Assign <strong>judges</strong> and <strong>reviewers</strong> to contributions in order to allow assessing | ||
its paper revisions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its or theirs? I am not sure which one fits the best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of them 😄, I think their fits better
data-dialog-classes="list-filter-dialog" | ||
data-update='{"html": "#assignment-list", "filter_statistics": "#filter-statistics"}' | ||
data-ajax-dialog> | ||
{% trans %}Customize list{% endtrans %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{%- trans %}Customize list{% endtrans -%}
<div class="section"> | ||
<div class="icon icon-wrench"></div> | ||
<div class="text"> | ||
<div class="label">Customize paper asssignment list</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{% trans %}
7a82af3
to
e131297
Compare
from __future__ import unicode_literals | ||
|
||
from collections import OrderedDict | ||
from flask import request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flask and sqlalchemy are not stdlib
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(he means they should be in a separate block)
uselist=False, | ||
lazy=True, | ||
viewonly=True, | ||
primaryjoin=((PaperRevision.contribution_id == cls.id) & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use db.and_()
instead of &
- more readable IMO when wrapped
@@ -332,6 +332,21 @@ def __table_args__(cls): | |||
) | |||
) | |||
|
|||
@declared_attr | |||
def paper_last_revision(cls): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
latest_paper_revision
or current_paper_revision
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed on IRC, paper_last_revision
has the upside of namespacing things, which is quite useful to people who (like me) use auto-complete on indico shell.
'session': Contribution.session_id, | ||
'type': Contribution.type_id} | ||
for key, column in filter_cols.iteritems(): | ||
ids = set(filters['items'].get(key, ())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the , ()
is not needed since you check for falsiness in the next line anyway, so the default None
is fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set(None)
-> 'NoneType' object is not iterable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, didn't spot the set() around it
{% from 'message_box.html' import message_box %} | ||
|
||
{% macro render_paper_assignment_list(event, total_entries, contribs, static_columns) %} | ||
{% set tz = event.display_tzinfo %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused. also, management wouldn't use display_tzinfo
but just tzinfo
<span class="vertical-aligner"> | ||
<input type="checkbox" class="select-row" | ||
name="contribution_id" | ||
value="{{ contrib.id }}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fits in the previous line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, I've changed it because of #2756 (comment)
</span> | ||
</td> | ||
<td class="i-table person-row-cell" | ||
data-searchable="{{ contrib.paper_judges|map(attribute='name')|join(', ')|lower }}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|join(', ', attribute='name')
- no need for the separate |map()
<li> | ||
<input type="checkbox" name="field_{{ item_id }}" value="{{ value }}" | ||
id="field_{{ item_id }}_option_{{ value }}" | ||
{% if value|string in filters[item_id]|string %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{{ 'checked' if value|string in filters[item_id] }}
?
Also, filters[item_id]|string
looks very wrong to me. Are you by any chance converting a list/set to a string and then check whether another string is in it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is when the value is None
(in cases like "Not yet submitted", "No track", etc.), then the check is if "None" in [None, ...]
which is false and must be true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like we should find a better solution then.
{% set value = none if value is none else value|string %}
How about that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that works! 👍
</div> | ||
</div> | ||
</div> | ||
<div class="success-message-box js-clear-filters-message" style="display: none"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
none;
def _build_query(self): | ||
return (Contribution.query.with_parent(self.event) | ||
.order_by(Contribution.friendly_id) | ||
.options(subqueryload('paper_last_revision'))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It almost looks easy now.
e131297
to
3f4ef8f
Compare
(PaperRevision.submitted_dt == (db.select([db.func.max(PaperRevision.submitted_dt)]) | ||
.where(PaperRevision.contribution_id == cls.id) | ||
.correlate_except(PaperRevision) | ||
.as_scalar())))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation seems wrong.
ac458b7
to
0d6983d
Compare
lazy=True, | ||
viewonly=True, | ||
primaryjoin=(db.and_((PaperRevision.contribution_id == cls.id), | ||
(PaperRevision.submitted_dt == (db.select([db.func.max(PaperRevision.submitted_dt)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would assign the subquery to a subquery
variable and use PaperRevision.submitted_dt == subquery.as_scalar()
here (or even move the as_scalar()
to the subquery = ...
too)
uselist=False, | ||
lazy=True, | ||
viewonly=True, | ||
primaryjoin=(db.and_((PaperRevision.contribution_id == cls.id), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for the innermost ()
now; they were only needed because of the precedence of &
0d6983d
to
df9f4df
Compare
@@ -22,6 +22,7 @@ | |||
from indico.modules.events.papers.forms import PaperTeamsForm, make_competences_form | |||
from indico.modules.events.papers.operations import (set_reviewing_state, update_team_members, create_competences, | |||
update_competences) | |||
from indico.modules.events.papers.lists import PaperAssignmentListGenerator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lists < operations
@@ -122,7 +122,7 @@ def render_list(self, contrib=None): | |||
:param contrib: Used in RHs responsible for CRUD operations on a | |||
contribution. | |||
:return: dict containing the list's entries, the fragment of | |||
displayed entries and whether the contrib passed is displayed | |||
displayed entries and whether the contribution passed is displayed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstrings should wrap after 80 characters and python code after 120. Make sure you setup your editor to indicate that 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😞 http://stackoverflow.com/questions/24125957/multiple-right-margins-in-pycharm
I'll take it into account tho
def __init__(self, event): | ||
super(PaperAssignmentListGenerator, self).__init__(event) | ||
self.default_list_config = { | ||
'items': ('state', ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra space after 'state',
df9f4df
to
6a2f447
Compare
@@ -39,6 +39,8 @@ | |||
_bp.add_url_rule('/manage/papers/assignment-list/', 'assignment', management.RHPapersAssignmentList) | |||
_bp.add_url_rule('/manage/papers/assignment-list/customize', 'customize_assignment_list', | |||
management.RHAssignmentListCustomize, methods=('GET', 'POST')) | |||
_bp.add_url_rule('/manage/papers/assignment-list/change-state', 'manage_papers_state', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we call this "judging" in the abstracts module (RH name, URL, endpoint name, etc)? In that case I'd use similar naming here for consistency.
|
||
def _process(self): | ||
form = BulkPaperJudgmentForm(event=self.event_new, judgment=request.form.get('judgment'), | ||
contribution_id=[a.id for a in self.contributions]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copied from abstracts I guess? ;)
a
doesn't fit here much, I'd use c
or the generic x
(but usually I go for c
for contributions)
@@ -57,3 +61,21 @@ def update_competences(user_competences, competences): | |||
event.log(EventLogRealm.management, EventLogKind.positive, 'Papers', | |||
"Updated competences for user {}".format(user_competences.user.full_name), session.user, | |||
data={'Competences': ', '.join(competences)}) | |||
|
|||
|
|||
def paper_change_state(contribution, contrib_data, judgment, judge, send_notifications=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
judge_paper
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just clarifying, the rationale is to use verbs for functions/methods as much as possible.
num_judged_contribs = len(submitted_contributions) | ||
num_prejudged_contribs = len(self.contributions) - num_judged_contribs | ||
if num_judged_contribs: | ||
flash(ngettext("One paper contribution has been judged.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just "paper" or "contribution's paper" - "paper contribution" sounds rather weird.
if kwargs['judgment']: | ||
self._remove_unused_fields(kwargs['judgment']) | ||
|
||
def _remove_unused_fields(self, judgment): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can go away if we don't have any fields that are specific to certain judgment actions.
|
||
|
||
def paper_change_state(contribution, contrib_data, judgment, judge, send_notifications=False): | ||
log_data = {'New state': orig_string(judgment.title)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move that down so all the logging stuff is at the end
contribution.paper_last_revision.state = PaperRevisionState.rejected | ||
elif judgment == PaperAction.to_be_corrected: | ||
contribution.paper_last_revision.state = PaperRevisionState.to_be_corrected | ||
PaperReviewComment(paper_revision=contribution.paper_last_revision, user=judge, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we do want to save the judgment comment as a normal comment in the end and not in a separate field on the revision?
Anyway, while this works (due to being added to the SA session since you link it to he prevision) I think it's slighly ugly to create an instance without using it anywhere. I'd rather do it like this:
if contrib_data['judgment_comment']:
comment = PaperReviewComment(user=judge, text=contrib_data['judgment_comment'])
contribution.paper_last_revision.comments.append(comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also thought we settled for adding the judgment comment as a field in the revision. Not that I disagree with this approach, but just wondering if I missed something.
log_data['Sent notifications'] = send_notifications | ||
if send_notifications: | ||
pass # TODO: manage notifications | ||
logger.info('Paper contribution %s changed state by %s', contribution.title, judge) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%r
for the second one. I'd also include the new state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
like before, "paper contribution" sounds really strange.
@@ -57,3 +61,21 @@ def update_competences(user_competences, competences): | |||
event.log(EventLogRealm.management, EventLogKind.positive, 'Papers', | |||
"Updated competences for user {}".format(user_competences.user.full_name), session.user, | |||
data={'Competences': ', '.join(competences)}) | |||
|
|||
|
|||
def paper_change_state(contribution, contrib_data, judgment, judge, send_notifications=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just clarifying, the rationale is to use verbs for functions/methods as much as possible.
judgment_data, contrib_data = form.split_data | ||
# TODO: For now, I'm considering that any submitted paper contribution can change | ||
# its state (even rejected ones) | ||
submitted_contributions = [c for c in self.contributions if c.paper_last_revision] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually how many papers have been submitted. Why not num_papers
?
submitted_contributions = [c for c in self.contributions if c.paper_last_revision] | ||
for contrib in submitted_contributions: | ||
paper_change_state(contrib, contrib_data, judge=session.user, **judgment_data) | ||
num_judged_contribs = len(submitted_contributions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the papers that are judged, not the contributions. I would name these num_judged_papers
.
for contrib in submitted_contributions: | ||
paper_change_state(contrib, contrib_data, judge=session.user, **judgment_data) | ||
num_judged_contribs = len(submitted_contributions) | ||
num_prejudged_contribs = len(self.contributions) - num_judged_contribs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this has anything to do with the paper having been prejudged. Rather, it's simply contributions that haven't received a paper submission. What about renaming the variable num_missing_paper
?
contribution.paper_last_revision.state = PaperRevisionState.rejected | ||
elif judgment == PaperAction.to_be_corrected: | ||
contribution.paper_last_revision.state = PaperRevisionState.to_be_corrected | ||
PaperReviewComment(paper_revision=contribution.paper_last_revision, user=judge, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also thought we settled for adding the judgment comment as a field in the revision. Not that I disagree with this approach, but just wondering if I missed something.
75c11d7
to
5e37ee0
Compare
@@ -99,8 +98,7 @@ def judge_paper(contribution, contrib_data, judgment, judge, send_notifications= | |||
elif judgment == PaperAction.to_be_corrected: | |||
contribution.paper_last_revision.state = PaperRevisionState.to_be_corrected | |||
if contrib_data['judgment_comment']: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this check is needed - assigning an empty comment does no harm
@@ -15,7 +15,26 @@ | |||
* along with Indico; if not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
|
|||
(function() { | |||
/* global setupListGenerator:false, applySearchFilters:false, setupTableSorter: false */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no space after the last :
for consistency
|
||
@no_autoflush | ||
def judge_paper(contribution, contrib_data, judgment, judge, send_notifications=False): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there shouldn't be an empty line here
contribution.paper_last_revision.state = PaperRevisionState.rejected | ||
elif judgment == PaperAction.to_be_corrected: | ||
contribution.paper_last_revision.state = PaperRevisionState.to_be_corrected | ||
if contrib_data['judgment_comment']: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can always set the comment. that way judging it again (even though this shouldn't happen) would properly overwrite an existing comment
logger.info('Paper %s changed state by %r to %s', contribution.title, judge, | ||
orig_string(judgment.title)) | ||
contribution.event_new.log(EventLogRealm.management, EventLogKind.change, 'Papers', | ||
'Paper "{}" changed state'.format(contribution.title), judge, data=log_data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
".. was judged .." and I'd include the friendly id in this log message and similar ones: Paper #123 ("foo") was judged...
Might be a good idea to add this property to Contribution
(we also have it in Abstract
) to make it easier/cleaner:
@property
def verbose_title(self):
return '#{} ({})'.format(self.friendly_id, self.title)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use orig_string()
here, too. we don't want translated messages in logs
log_data = {'New state': orig_string(judgment.title), 'Sent notifications': send_notifications} | ||
if send_notifications: | ||
pass # TODO: manage notifications | ||
logger.info('Paper %s changed state by %r to %s', contribution.title, judge, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
".. was judged .."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Paper %r ..
and use contribution
instead of contribution.title
.
This is for the logfile, having the repr is much more useful there than just the title
cbc6595
to
f417061
Compare
f417061
to
d0bba5e
Compare
and allow to hide these columns
caused by flexbox
d0bba5e
to
66779c8
Compare
session_empty = {None: _('No session')} | ||
type_empty = {None: _('No type')} | ||
state_choices = {state.value: state.title for state in PaperRevisionState} | ||
track_choices = OrderedDict((unicode(t.id), t.title) for t in sorted(self.event.tracks, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, why do we need to unicode
the IDs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most likely it goes through json encoding at some point and JSON only supports string keys
WIP:
Extra filters: Material submittedpython bin/maintenance/update_header.py 2017