From 2e5e8c16c151b582a312c6037e1aa1a9def42c4a Mon Sep 17 00:00:00 2001 From: George Katsikas <giorgakis.katsikas@gmail.com> Date: Tue, 20 Feb 2024 14:16:42 +0100 Subject: [PATCH] allow custom refusal reason for ref. invitations fix #64 (first part) --- .../scipost/referee-accept-or-refuse.js | 20 +++++++---- scipost_django/submissions/forms/__init__.py | 34 +++++++++++++++++++ .../migrations/0147_auto_20240220_1404.py | 28 +++++++++++++++ .../submissions/models/assignment.py | 2 ++ .../submissions/models/referee_invitation.py | 1 + .../submissions/_refereeing_status_card.html | 3 ++ scipost_django/submissions/views/__init__.py | 9 +++-- .../templates/email/eic/referee_response.html | 3 ++ .../confirmation_invitation_response.html | 3 ++ 9 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 scipost_django/submissions/migrations/0147_auto_20240220_1404.py diff --git a/scipost_django/scipost/static/scipost/referee-accept-or-refuse.js b/scipost_django/scipost/static/scipost/referee-accept-or-refuse.js index 8bd1a0e9e..60912463d 100644 --- a/scipost_django/scipost/static/scipost/referee-accept-or-refuse.js +++ b/scipost_django/scipost/static/scipost/referee-accept-or-refuse.js @@ -1,10 +1,18 @@ -$(document).ready(function(){ - $('[name="accept"]').on('change', function() { - if($('[name="accept"]:checked').val() == 'False') { +$(document).ready(function () { + $('[name="accept"]').on('change', function () { + if ($('[name="accept"]:checked').val() == 'False') { $('#id_refusal_reason').parents('.form-group').show(); - } - else { + } + else { $('#id_refusal_reason').parents('.form-group').hide(); - } + } + }).trigger('change'); + $('[name="refusal_reason"]').on('change', function () { + if ($('[name="refusal_reason"]').val() == 'OTH') { + $('#id_other_refusal_reason').parents('.form-group').show(); + } + else { + $('#id_other_refusal_reason').parents('.form-group').hide(); + } }).trigger('change'); }); diff --git a/scipost_django/submissions/forms/__init__.py b/scipost_django/submissions/forms/__init__.py index c24875bd3..0eac0a986 100644 --- a/scipost_django/submissions/forms/__init__.py +++ b/scipost_django/submissions/forms/__init__.py @@ -2266,6 +2266,40 @@ class ConsiderRefereeInvitationForm(forms.Form): refusal_reason = forms.ChoiceField( choices=EditorialAssignment.REFUSAL_REASONS, required=False ) + other_refusal_reason = forms.CharField( + required=False, + widget=forms.Textarea( + { + "placeholder": "Please shortly describe your reason for declining. (255 characters max)" + } + ), + max_length=255, + ) + + def clean(self): + accepted = self.cleaned_data.get("accept", None) + reason = self.cleaned_data.get("refusal_reason", None) + other_refusal_reason = self.cleaned_data.get("other_refusal_reason", None) + + if accepted == "False": + if reason is None: + self.add_error( + "refusal_reason", "Please select a reason for declining." + ) + if reason == "other" and other_refusal_reason is None: + self.add_error( + "other_refusal_reason", "Please specify your reason for declining." + ) + elif reason != "other" and other_refusal_reason is not None: + self.add_error( + "other_refusal_reason", + 'Please select "Other" to specify your reason for declining.', + ) + elif reason is not None: + self.add_error( + "refusal_reason", + "You cannot select a refusal reason if you accept.", + ) class SetRefereeingDeadlineForm(forms.Form): diff --git a/scipost_django/submissions/migrations/0147_auto_20240220_1404.py b/scipost_django/submissions/migrations/0147_auto_20240220_1404.py new file mode 100644 index 000000000..4e3f17904 --- /dev/null +++ b/scipost_django/submissions/migrations/0147_auto_20240220_1404.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.18 on 2024-02-20 13:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('submissions', '0146_submission_lifetime_dates'), + ] + + operations = [ + migrations.AddField( + model_name='refereeinvitation', + name='other_refusal_reason', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='editorialassignment', + name='refusal_reason', + field=models.CharField(blank=True, choices=[('OFE', 'Outside of my field of expertise'), ('BUS', 'Too busy'), ('VAC', 'Away on vacation'), ('COI', 'Conflict of interest: coauthor in last 5 years'), ('CCC', 'Conflict of interest: close colleague'), ('CCM', 'Conflict of interest: close competitor'), ('COT', 'Conflict of interest: other'), ('NIR', 'Cannot give an impartial assessment'), ('NIE', 'Not interested enough'), ('DNP', 'SciPost should desk reject this paper'), ('OTH', 'Other')], max_length=3, null=True), + ), + migrations.AlterField( + model_name='refereeinvitation', + name='refusal_reason', + field=models.CharField(blank=True, choices=[('OFE', 'Outside of my field of expertise'), ('BUS', 'Too busy'), ('VAC', 'Away on vacation'), ('COI', 'Conflict of interest: coauthor in last 5 years'), ('CCC', 'Conflict of interest: close colleague'), ('CCM', 'Conflict of interest: close competitor'), ('COT', 'Conflict of interest: other'), ('NIR', 'Cannot give an impartial assessment'), ('NIE', 'Not interested enough'), ('DNP', 'SciPost should desk reject this paper'), ('OTH', 'Other')], max_length=3, null=True), + ), + ] diff --git a/scipost_django/submissions/models/assignment.py b/scipost_django/submissions/models/assignment.py index f93656a7e..f73e5c39d 100644 --- a/scipost_django/submissions/models/assignment.py +++ b/scipost_django/submissions/models/assignment.py @@ -27,6 +27,7 @@ class EditorialAssignment(SubmissionRelatedObjectMixin, models.Model): REFUSE_NOT_IMPARTIAL = "NIR" REFUSE_NOT_INTERESTED = "NIE" REFUSE_DESK_REJECT = "DNP" + REFUSE_OTHER = "OTH" REFUSAL_REASONS = ( (REFUSE_OUTSIDE_EXPERTISE, "Outside of my field of expertise"), (REFUSE_TOO_BUSY, "Too busy"), @@ -41,6 +42,7 @@ class EditorialAssignment(SubmissionRelatedObjectMixin, models.Model): REFUSE_DESK_REJECT, "SciPost should desk reject this paper", ), + (REFUSE_OTHER, "Other"), ) STATUS_PREASSIGNED = "preassigned" diff --git a/scipost_django/submissions/models/referee_invitation.py b/scipost_django/submissions/models/referee_invitation.py index 5063e8aa5..15a8c7cce 100644 --- a/scipost_django/submissions/models/referee_invitation.py +++ b/scipost_django/submissions/models/referee_invitation.py @@ -71,6 +71,7 @@ class RefereeInvitation(SubmissionRelatedObjectMixin, models.Model): blank=True, null=True, ) + other_refusal_reason = models.CharField(max_length=255, blank=True, null=True) fulfilled = models.BooleanField( default=False ) # True if a Report has been submitted diff --git a/scipost_django/submissions/templates/submissions/_refereeing_status_card.html b/scipost_django/submissions/templates/submissions/_refereeing_status_card.html index e3109323b..72092d1ea 100644 --- a/scipost_django/submissions/templates/submissions/_refereeing_status_card.html +++ b/scipost_django/submissions/templates/submissions/_refereeing_status_card.html @@ -47,5 +47,8 @@ <h3>Your Referee Invitation</h3> <p>You have declined to contribute a Report. Nonetheless, we thank you very much for considering this refereeing invitation.</p> <p>Reason: {{ invitation.get_refusal_reason_display }}</p> + {% if invitation.refusal_reason == 'OTH' %} + <p>{{ invitation.other_refusal_reason }}</p> + {% endif %} {% endif %} </div> diff --git a/scipost_django/submissions/views/__init__.py b/scipost_django/submissions/views/__init__.py index 2f19bc680..ba971351b 100644 --- a/scipost_django/submissions/views/__init__.py +++ b/scipost_django/submissions/views/__init__.py @@ -1418,6 +1418,7 @@ def accept_or_decline_ref_invitations(request, invitation_id=None): invitation.accepted = False decision_string = "declined" invitation.refusal_reason = form.cleaned_data["refusal_reason"] + invitation.other_refusal_reason = form.cleaned_data["other_refusal_reason"] messages.success( request, ( @@ -2964,9 +2965,11 @@ def submissions_versus_fellows(submissions): "fellows_senior": fellows_senior, "fellows_regular": fellows_regular, "fellows_guest": fellows_guest, - "ratio": nr_streams / fellows_total - if fellows_total > 0 - else nr_streams, + "ratio": ( + nr_streams / fellows_total + if fellows_total > 0 + else nr_streams + ), } ) return sorted(stats, key=lambda tup: tup["ratio"], reverse=True) diff --git a/scipost_django/templates/email/eic/referee_response.html b/scipost_django/templates/email/eic/referee_response.html index bde0688f6..a0296d4d1 100644 --- a/scipost_django/templates/email/eic/referee_response.html +++ b/scipost_django/templates/email/eic/referee_response.html @@ -3,6 +3,9 @@ <p> Referee {% if invitation.referee %}{{ invitation.referee.profile.get_title_display }} {{ invitation.referee.user.last_name }}{% else %}{{ invitation.get_title_display }} {{ invitation.first_name }} {{ invitation.last_name }}{% endif %} has {% if invitation.accepted %}accepted{% else %}declined (due to reason: {{ invitation.get_refusal_reason_display }}){% endif %} to referee Submission </p> +{% if invitation.other_refusal_reason %} + <p>Their "other" refusal reason states: {{ invitation.other_refusal_reason }}</p> +{% endif %} <p> {{ invitation.submission.title }} <br/> diff --git a/scipost_django/templates/email/referees/confirmation_invitation_response.html b/scipost_django/templates/email/referees/confirmation_invitation_response.html index d8183c155..327356917 100644 --- a/scipost_django/templates/email/referees/confirmation_invitation_response.html +++ b/scipost_django/templates/email/referees/confirmation_invitation_response.html @@ -3,6 +3,9 @@ <p> We hereby confirm your choice to {% if invitation.accepted %}accept{% else %}decline (due to reason: {{ invitation.get_refusal_reason_display }}){% endif %} to referee Submission </p> +{% if invitation.other_refusal_reason %} + <p>Your "other" refusal reason states: {{ invitation.other_refusal_reason }}</p> +{% endif %} <p> {{ invitation.submission.title }} <br/> -- GitLab