Skip to content
New issue

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

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

Already on GitHub? # to your account

#4081 reviewers from past review rounds are now valid review assignment choices. #4101

Merged
merged 15 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 0 additions & 4 deletions src/core/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,6 @@ def get_settings_to_edit(display_group, journal, user):
'name': 'enable_suggested_reviewers',
'object': setting_handler.get_setting('general', 'enable_suggested_reviewers', journal),
},
{
'name': 'display_past_reviewers',
'object': setting_handler.get_setting('general', 'display_past_reviewers', journal),
},
{
'name': 'enable_peer_review_data_on_review_page',
'object': setting_handler.get_setting('general', 'enable_peer_review_data_on_review_page', journal),
Expand Down
46 changes: 46 additions & 0 deletions src/core/migrations/0089_auto_20240424_1005.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 3.2.20 on 2024-04-24 09:05

from django.db import migrations


def drop_past_reviewer_setting(apps, schema_editor):
Setting = apps.get_model("core", "Setting")
Setting.objects.filter(
name="display_past_reviewers",
).delete()


def create_past_reviewer_setting(apps, schema_editor):
# Recreate the setting enough that it won't bork anything in the event
# the migration needs to be reversed.
Setting = apps.get_model("core", "Setting")
SettingGroup = apps.get_model("core", "SettingGroup")
SettingValue = apps.get_model("core", "SettingValue")
group = SettingGroup.objects.get(name="general")
setting = Setting.objects.create(
group=group,
name="display_past_reviewers",
types="boolean",
pretty_name="Display List of Reviewers from Past Review Rounds",
description="When this setting is enabled the review assignment page "
"will show a table of reviewers who have completed a "
"review in past review rounds."
)
SettingValue.objects.create(
setting=setting,
value="",
)


class Migration(migrations.Migration):

dependencies = [
('core', '0088_merge_20240327_1910'),
]

operations = [
migrations.RunPython(
drop_past_reviewer_setting,
reverse_code=create_past_reviewer_setting
),
]
35 changes: 33 additions & 2 deletions src/review/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
OuterRef,
Prefetch,
Subquery,
Case,
When,
BooleanField,
Value,
)
from django.shortcuts import redirect, reverse
from django.utils import timezone
Expand Down Expand Up @@ -63,6 +67,11 @@ def get_reviewers(article, candidate_queryset, exclude_pks):
rating_average=Avg("rating"),
).values("rating_average")

completed_reviewer_pks_subquery = article.completed_reviews_with_decision.values_list(
'reviewer__pk',
flat=True,
)

# TODO swap the below subqueries with filtered annotations on Django 2.0+
reviewers = candidate_queryset.exclude(
pk__in=exclude_pks,
Expand All @@ -76,7 +85,25 @@ def get_reviewers(article, candidate_queryset, exclude_pks):
)
).annotate(
rating_average=Subquery(rating_average, output_field=IntegerField()),
is_past_reviewer=Case(
When(pk__in=Subquery(completed_reviewer_pks_subquery),
then=True),
default=False,
output_field=BooleanField(),
),
)

if article.journal.get_setting('general', 'enable_suggested_reviewers'):
article_keywords = [keyword.word for keyword in article.keywords.all()]
reviewers = reviewers.annotate(
is_suggested_reviewer=Case(
When(interest__name__in=article_keywords,
then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
)

return reviewers


Expand All @@ -86,8 +113,11 @@ def get_reviewer_candidates(article, user=None, reviewers_to_exclude=None):
:param user: The user requesting candidates who would be filtered out
:param reviewers_to_exclude: queryset of Account objects
"""
review_assignments = article.reviewassignment_set.filter(review_round=article.current_review_round_object())
reviewer_pks_to_exclude = [review.reviewer.pk for review in review_assignments]
reviewer_pks_to_exclude = [
review.reviewer.pk for review in article.reviewassignment_set.filter(
review_round=article.current_review_round_object(),
)
]
if user:
reviewer_pks_to_exclude.append(user.pk)

Expand Down Expand Up @@ -116,6 +146,7 @@ def get_suggested_reviewers(article, reviewers):

return suggested_reviewers


def get_previous_round_reviewers(article):
"""
Builds a queryset of candidates who have previously completed a review
Expand Down
18 changes: 0 additions & 18 deletions src/review/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1085,20 +1085,10 @@ def add_review_assignment(request, article_id):
:return: HttpResponse
"""
article = get_object_or_404(submission_models.Article, pk=article_id)

# if setting enabled, fetch reviewers who have completed a review
# in a past review round.
past_reviewers = []
if request.journal.get_setting('general', 'display_past_reviewers'):
past_reviewers = logic.get_previous_round_reviewers(
article,
)
reviewers = logic.get_reviewer_candidates(
article,
user=request.user,
reviewers_to_exclude=past_reviewers,
)

form = forms.ReviewAssignmentForm(
journal=request.journal,
article=article,
Expand Down Expand Up @@ -1181,15 +1171,7 @@ def add_review_assignment(request, article_id):
'form': form,
'reviewers': reviewers,
'new_reviewer_form': new_reviewer_form,
'past_reviewers': past_reviewers,
}

if request.journal.get_setting('general', 'enable_suggested_reviewers'):
context['suggested_reviewers'] = logic.get_suggested_reviewers(
article,
reviewers,
)

return render(request, template, context)


Expand Down
1 change: 1 addition & 0 deletions src/templates/admin/elements/datatables.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
{% if hide_length %}"bLengthChange": false,{% endif %}
{% if hide_page %}"bPaginate": false,{% endif %}
{% if sort and order %}"order": [[ {{ sort }}, "{{ order }}" ]],{% endif %}
{% if sort_list %}"order": [{{ sort_list }}],{% endif %}
{% if disable_ordering %}"ordering": false,{% endif %}
{% if page_length %}"pageLength": {{ page_length }},{% endif %}
});
Expand Down
1 change: 0 additions & 1 deletion src/templates/admin/elements/forms/group_review.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ <h2>General Review Settings</h2>
{% include "admin/elements/forms/field.html" with field=edit_form.enable_one_click_access %}
{% include "admin/elements/forms/field.html" with field=edit_form.draft_decisions %}
{% include "admin/elements/forms/field.html" with field=edit_form.enable_suggested_reviewers %}
{% include "admin/elements/forms/field.html" with field=edit_form.display_past_reviewers %}
</div>

<div class="title-area">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
<td>{% for interest in reviewer.interest.all %}{{ interest.name }}{% if not forloop.last %}, {% endif %}{% endfor %}</td>
<td>{{ reviewer.rating_average|default_if_none:"" }}</td>
<td>{{ reviewer.reviewer.all.0.date_complete }}</td>
{% if past_reviewers %}<td>{% if reviewer in past_reviewers %}Yes{% else %}No{% endif %}</td>{% endif %}
<td>{% if reviewer.is_past_reviewer %}Yes{% else %}No{% endif %}</td>
{% if journal_settings.general.enable_suggested_reviewers %}<td>{% if reviewer.is_suggested_reviewer %}Yes{% else %}No{% endif %}</td>{% endif %}
110 changes: 32 additions & 78 deletions src/templates/admin/review/add_review_assignment.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,28 @@ <h2>1. Select Reviewer</h2>
<a href="{% url 'core_manager_enrol_users' %}" class="button" target="_blank"><i class="fa fa-users">&nbsp;</i>Enroll Existing User</a>
</div>
<div class="content">

<p>
{% blocktrans %}
You can select a reviewer using the radio buttons in the first column and complete the section under "Set Options".
If you cannot find the reviewer you want in this list you can use "Enroll Existing User" to search the database and give users the Reviewer role, or "Add New Reviewer" to create a new account for a reviewer (this process is silent, they will not receive an account creation email).
{% endblocktrans %}
</p>

{% if past_reviewers %}
<div class="callout primary">
<p><span class="fa fa-info-circle"></span> Reviewers who have compeleted a review for this article in a previous round will appear at the top of this list, they will show with a <strong>Yes</strong> in the <strong>Has Reviewed Article</strong> column.</p>
</div>
{% endif %}
<div class="callout primary">
<p> <span class="fa fa-info-circle"></span>
{% blocktrans %}
You can select a reviewer using the radio
buttons in the first column and complete the
section under 'Set Options'.
If you cannot find the reviewer you want in
this list you can use 'Enroll Existing User' to
search the database and give users the Reviewer
role, or 'Add New Reviewer' to create a new
account for a reviewer (this process is silent,
so they will not receive an account creation
email).
{% endblocktrans %}
</p>
<p>
Reviewers who have completed a review for this
article in a previous round will appear at the top
of this list and will show 'Yes' in the 'Has
Reviewed Article' column.
</p>
</div>

<table class="small scroll" id="reviewers">
<thead>
Expand All @@ -46,35 +55,19 @@ <h2>1. Select Reviewer</h2>
<th width="30%">Interests</th>
<th>Average Score</th>
<th>Last Review Completed</th>
{% if past_reviewers %}<th>Has Reviewed Article</th>{% endif %}
<th>Has Reviewed Article</th>
{% if journal_settings.general.enable_suggested_reviewers %}<th>Suggested Reviewer</th>{% endif %}
</tr>
</thead>

<tbody>
{% for reviewer in past_reviewers %}
<tr>
{% include "admin/elements/review/add_reviewer_table_row.html" with reviewer=reviewer past_reviewers=past_reviewers %}
</tr>
{% endfor %}
{% for reviewer in suggested_reviewers %}
<tr class="green">
{% include "admin/elements/review/add_reviewer_table_row.html" with reviewer=reviewer past_reviewers=past_reviewers %}
</tr>
{% endfor %}
{% for reviewer in reviewers %}
{% if not journal_settings.general.enable_suggested_reviewers or not reviewer in suggested_reviewers %}
<tr>
{% include "admin/elements/review/add_reviewer_table_row.html" with reviewer=reviewer past_reviewers=past_reviewers %}
{% include "admin/elements/review/add_reviewer_table_row.html" with reviewer=reviewer %}
</tr>
{% endif %}
{% empty %}
<tr>
<td>No suitable reviewers.</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td colspan="10">No suitable reviewers.</td>
</tr>
{% endfor %}
</tbody>
Expand Down Expand Up @@ -125,62 +118,23 @@ <h4><i class="fa fa-plus">&nbsp;</i>Add New Reviewer</h4>
</div>
{% endif %}

<div class="reveal large" id="enroll" data-reveal data-animation-in="slide-in-up"
data-animation-out="slide-out-down">
<div class="card">
<div class="card-divider">
<h4><i class="fa fa-users">&nbsp;</i>Enroll Existing User as Reviewer</h4>
</div>
<div class="card-section">
<button class="close-button" data-close aria-label="Close reveal" type="button">
<span aria-hidden="true">&times;</span>
</button>
<div class="content">
<form method="POST">
{% include "elements/forms/errors.html" with form=new_reviewer_form %}
{% csrf_token %}
<table class="small scroll" id="enrolluser">
<thead>
<tr>
<th>Select</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email Address</th>
<th>Interests</th>
</tr>
</thead>
<tbody>
{% for user in user_list %}
<tr>
<td><input type="checkbox" name="user_id" value="{{ user.pk }}"></td>
<td>{{ user.first_name }}</td>
<td>{{ user.last_name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.interests.all }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="button success" name="enrollusers" id="enrollusers">Enroll as Reviewer</button>
</form>
</div>
</div>
</div>
</div>

{% if form.modal %}
{% include "admin/elements/confirm_modal.html" with modal=form.modal form_id="review_assignment_form" %}
{% endif %}

{% endblock body %}

{% block js %}
{% include "elements/datatables.html" with target="#reviewers" %}
{% if journal_settings.general.enable_suggested_reviewers %}
{% include "elements/datatables.html" with target="#reviewers" sort_list="[7, 'desc'], [8, 'desc']" %}
{% else %}
{% include "elements/datatables.html" with target="#reviewers" sort_list="[7, 'desc']" %}
{% endif %}

{% include "elements/datepicker.html" with target="#id_date_due" %}
{% if form.modal %}
{% include "admin/elements/open_modal.html" with target=form.modal.id %}
{% endif %}
{% include "elements/datatables.html" with target="#enrolluser" %}

<script lang="javascript">
function getQueryStrings()
Expand Down
19 changes: 0 additions & 19 deletions src/utils/install/journal_defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -4025,25 +4025,6 @@
"journal-manager"
]
},
{
"group": {
"name": "general"
},
"setting": {
"description": "When this setting is enabled the review assignment page will show a table of reviewers who have completed a review in past review rounds.",
"is_translatable": false,
"name": "display_past_reviewers",
"pretty_name": "Display List of Reviewers from Past Review Rounds",
"type": "boolean"
},
"value": {
"default": ""
},
"editable_by": [
"editor",
"journal-manager"
]
},
{
"group": {
"name": "general"
Expand Down