From b5066d51c84f34eaedaa4fb66eccb749adf33594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org> Date: Tue, 6 Dec 2022 07:46:40 +0100 Subject: [PATCH] Add admission decision facilities --- scipost_django/edadmin/forms/__init__.py | 2 + scipost_django/edadmin/forms/plagiarism.py | 15 +- .../edadmin/forms/submission_admission.py | 55 +++++ .../_hx_submission_admission_form.html | 8 + .../edadmin/_hx_submission_incoming.html | 30 ++- .../edadmin/_hx_submissions_list.html | 4 +- scipost_django/edadmin/urls/incoming.py | 5 + scipost_django/edadmin/views/incoming.py | 44 +++- .../submissions/models/submission.py | 21 ++ .../submissions/_submission_summary.html | 204 ++++++++++-------- .../email/authors/acknowledge_submission.html | 1 - .../email/authors/admission_failed.json | 2 +- .../email/authors/admission_passed.html | 17 ++ .../email/authors/admission_passed.json | 11 + 14 files changed, 312 insertions(+), 107 deletions(-) create mode 100644 scipost_django/edadmin/forms/submission_admission.py create mode 100644 scipost_django/edadmin/templates/edadmin/_hx_submission_admission_form.html create mode 100644 scipost_django/templates/email/authors/admission_passed.html create mode 100644 scipost_django/templates/email/authors/admission_passed.json diff --git a/scipost_django/edadmin/forms/__init__.py b/scipost_django/edadmin/forms/__init__.py index eb4736b71..45a73b4da 100644 --- a/scipost_django/edadmin/forms/__init__.py +++ b/scipost_django/edadmin/forms/__init__.py @@ -8,3 +8,5 @@ from .plagiarism import ( ) from .submission_admissibility import SubmissionAdmissibilityForm + +from .submission_admission import SubmissionAdmissionForm diff --git a/scipost_django/edadmin/forms/plagiarism.py b/scipost_django/edadmin/forms/plagiarism.py index 69f1c7d30..5da5ad972 100644 --- a/scipost_django/edadmin/forms/plagiarism.py +++ b/scipost_django/edadmin/forms/plagiarism.py @@ -26,12 +26,19 @@ class PlagiarismAssessmentForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.fields["comments_for_edadmin"].widget.attrs.update({"rows": 5, "cols": 80}) + self.fields["comments_for_authors"].widget.attrs.update({"rows": 5, "cols": 80}) self.helper = FormHelper() self.helper.layout = Layout( - Field("status"), - Field("comments_for_edadmin"), - Field("comments_for_authors"), - ButtonHolder(Submit("submit", "Submit", css_class="btn btn-primary")), + Div(Div(Field("status"), css_class="col col-lg-6"), css_class="row"), + Div( + Div(Field("comments_for_edadmin"), css_class="col col-lg-6"), + Div(Field("comments_for_authors"), css_class="col col-lg-6"), + css_class="row", + ), + ButtonHolder( + Submit("submit", "Submit", css_class="btn btn-primary"), + ), ) def save(self): diff --git a/scipost_django/edadmin/forms/submission_admission.py b/scipost_django/edadmin/forms/submission_admission.py new file mode 100644 index 000000000..ba04224a2 --- /dev/null +++ b/scipost_django/edadmin/forms/submission_admission.py @@ -0,0 +1,55 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django import forms + +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout, Div, Field, ButtonHolder, Submit + + +class SubmissionAdmissionForm(forms.Form): + choice = forms.ChoiceField( + label="Admission of this Submission: pass to the Preassignment stage?", + choices=( + ("pass", "Pass"), + ("fail", "Fail and email authors"), + ), + widget=forms.RadioSelect, + required=True, + ) + comments_for_authors = forms.CharField( + widget=forms.Textarea(attrs={ + "placeholder": "For fail: message to be included in email for authors", + "rows": 5, + "cols": 80, + }), + required=False, + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.layout = Layout( + Div( + Div( + Field("choice"), + ButtonHolder(Submit("submit", "Submit", css_class="btn btn-primary")), + css_class="col col-lg-4", + ), + Div( + Field("comments_for_authors"), + css_class="col col-lg-8", + ), + css_class="row", + ) + ) + + def clean(self): + data = super().clean() + if (self.cleaned_data["choice"] == "fail" and + self.cleaned_data["comments_for_authors"] is None): + self.add_error( + None, + "Comments for authors must not be empty if marked as failed" + ) diff --git a/scipost_django/edadmin/templates/edadmin/_hx_submission_admission_form.html b/scipost_django/edadmin/templates/edadmin/_hx_submission_admission_form.html new file mode 100644 index 000000000..da5a508ac --- /dev/null +++ b/scipost_django/edadmin/templates/edadmin/_hx_submission_admission_form.html @@ -0,0 +1,8 @@ +{% load crispy_forms_tags %} +<form + class="mt-3" + hx-post="{% url 'edadmin:_hx_submission_admission' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-target="#submission-{{ submission.pk }}-admission-form" +> + {% crispy form %} +</form> diff --git a/scipost_django/edadmin/templates/edadmin/_hx_submission_incoming.html b/scipost_django/edadmin/templates/edadmin/_hx_submission_incoming.html index c4a1e5835..89bf99d71 100644 --- a/scipost_django/edadmin/templates/edadmin/_hx_submission_incoming.html +++ b/scipost_django/edadmin/templates/edadmin/_hx_submission_incoming.html @@ -1,3 +1,4 @@ +<hr> <h1>Admissibility</h1> <div class="p-2 mb-4" id="submission-{{ submission.pk }}-admissibility"> {% if submission.status == submission.INCOMING %} @@ -11,16 +12,11 @@ <span class="px-2 py-1 bg-success text-white"> Marked as admissible </span> - {% elif submission.status == submission.ADMISSION_FAILED %} - <span class="px-2 py-1 bg-danger text-white"> - Admission failed (authors informed) - </span> - {% else %} - Inconsistent status: {{ submission.status }} {% endif %} </div> {% if submission.status == submission.ADMISSIBLE %} + <hr> <h1>Plagiarism</h1> <div class="p-2 mb-4"> <div id="submission-{{ submission.pk }}-plagiarism-internal" @@ -38,4 +34,26 @@ > </div> </div> + + {% if submission.plagiarism_tests_passed %} + <h1>Admission decision</h1> + <div class="p-2 mb-4" id="submission-{{ submission.pk }}-admission"> + <div id="submission-{{ submission.pk }}-admission-form" + class="m-2" + hx-get="{% url 'edadmin:_hx_submission_admission' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-trigger="load" + > + </div> + </div> + {% endif %} +{% elif submission.status == submission.PREASSIGNMENT %} + <span class="px-2 py-1 bg-success text-white"> + Admission passed: admitted to next stage, Preassignment + </span> +{% elif submission.status == submission.ADMISSION_FAILED %} + <span class="px-2 py-1 bg-danger text-white"> + Admission failed (authors informed) + </span> +{% elif submission.status != submission.INCOMING %} + <h1 class="text-danger">Submission not in incoming stage: status is {{ submission.get_status_display }}</h1> {% endif %} diff --git a/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html b/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html index f93ad210b..534030fe5 100644 --- a/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html +++ b/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html @@ -23,8 +23,8 @@ <li class="list-inline-item float-end"> <ul class="list list-unstyled"> <li class="mb-2"><strong>Status</strong>: {{ submission.get_status_display }}</li> - <li class="mb-2"><a href="{% url 'submissions:submission' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}">{% include "bi/arrow-right-square-fill.html" %}submission page</a></li> - <li class="mb-2"><a href="{% url 'submissions:editorial_page' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" class="text-danger">{% include "bi/arrow-right-square-fill.html" %}editorial page</a></li> + <li class="mb-2"><a href="{% url 'submissions:submission' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" target="_blank">{% include "bi/arrow-right-square-fill.html" %}submission page</a></li> + <li class="mb-2"><a href="{% url 'submissions:editorial_page' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" target="_blank" class="text-danger">{% include "bi/arrow-right-square-fill.html" %}editorial page</a></li> </ul> </li> </ul> diff --git a/scipost_django/edadmin/urls/incoming.py b/scipost_django/edadmin/urls/incoming.py index 3724d492c..7128119f7 100644 --- a/scipost_django/edadmin/urls/incoming.py +++ b/scipost_django/edadmin/urls/incoming.py @@ -46,6 +46,11 @@ urlpatterns = [ incoming._hx_plagiarism_iThenticate_assess, name="_hx_plagiarism_iThenticate_assess", ), + path( + "_hx_submission_admission", + incoming._hx_submission_admission, + name="_hx_submission_admission", + ), ]) ), ] diff --git a/scipost_django/edadmin/views/incoming.py b/scipost_django/edadmin/views/incoming.py index e4c52d9ad..5aaf139f9 100644 --- a/scipost_django/edadmin/views/incoming.py +++ b/scipost_django/edadmin/views/incoming.py @@ -22,6 +22,7 @@ from edadmin.forms import ( InternalPlagiarismAssessmentForm, iThenticatePlagiarismAssessmentForm, SubmissionAdmissibilityForm, + SubmissionAdmissionForm, ) @@ -35,7 +36,6 @@ def _hx_incoming_list(request): context = { "submissions": submissions.in_stage_incoming(), } - print(f"{len(submissions.in_stage_incoming()) = }") return render(request, "edadmin/_hx_submissions_list.html", context) @@ -203,3 +203,45 @@ def _hx_plagiarism_iThenticate_assess(request, identifier_w_vn_nr): "form": form, } return render(request, "edadmin/_hx_plagiarism_iThenticate_assess.html", context) + + +############# +# Admission # +############# + +@login_required +@user_passes_test(is_edadmin) +def _hx_submission_admission(request, identifier_w_vn_nr): + submission = get_object_or_404( + Submission, preprint__identifier_w_vn_nr=identifier_w_vn_nr + ) + form = SubmissionAdmissionForm(request.POST or None) + if form.is_valid(): + if form.cleaned_data["choice"] == "pass": + Submission.objects.filter(pk=submission.id).update( + status=Submission.PREASSIGNMENT + ) + # send authors admission passed email + mail_util = DirectMailUtil( + "authors/admission_passed", + submission=submission, + comments_for_authors=form.cleaned_data["comments_for_authors"], + ) + else: # inadmissible, inform authors and set status to ADMISSION_FAILED + Submission.objects.filter(pk=submission.id).update( + status=Submission.ADMISSION_FAILED + ) + # send authors admission failed email + mail_util = DirectMailUtil( + "authors/admission_failed", + submission=submission, + comments_for_authors=form.cleaned_data["comments_for_authors"], + ) + mail_util.send_mail() + submission.refresh_from_db() + # trigger re-rendering of the details-contents div + response = HttpResponse() + response["HX-Trigger"] = f"submission-{submission.pk}-details-updated" + return response + context = {"submission": submission, "form": form,} + return render(request, "edadmin/_hx_submission_admission_form.html", context) diff --git a/scipost_django/submissions/models/submission.py b/scipost_django/submissions/models/submission.py index a293a3f4c..55cdc6674 100644 --- a/scipost_django/submissions/models/submission.py +++ b/scipost_django/submissions/models/submission.py @@ -524,6 +524,27 @@ class Submission(models.Model): def is_resubmission(self): return self.is_resubmission_of is not None + @property + def plagiarism_internal_tests_passed(self): + from submissions.models import InternalPlagiarismAssessment + try: + return self.internal_plagiarism_assessment.passed + except InternalPlagiarismAssessment.DoesNotExist: + return False + + @property + def plagiarism_iThenticate_tests_passed(self): + from submissions.models import iThenticatePlagiarismAssessment + try: + return self.iThenticate_plagiarism_assessment.passed + except iThenticatePlagiarismAssessment.DoesNotExist: + return False + + @property + def plagiarism_tests_passed(self): + return (self.plagiarism_internal_tests_passed and + self.plagiarism_iThenticate_tests_passed) + @property def eic_recommendation_required(self): """Return if Submission requires a EICRecommendation to be formulated.""" diff --git a/scipost_django/submissions/templates/submissions/_submission_summary.html b/scipost_django/submissions/templates/submissions/_submission_summary.html index bc8110642..a3fc7f87e 100644 --- a/scipost_django/submissions/templates/submissions/_submission_summary.html +++ b/scipost_django/submissions/templates/submissions/_submission_summary.html @@ -10,7 +10,7 @@ </tr> {% endif %} <tr> - <td>As Contributors:</td> + <td>Authors (as Contributors):</td> <td> {% for author in submission.authors.all %} {% if not forloop.first %}<span class="text-blue">·</span> {% endif %}<a href="{% url 'scipost:contributor_info' author.id %}">{{ author.user.first_name }} {{ author.user.last_name }}</a> @@ -19,98 +19,118 @@ {% endfor %} </td> </tr> - {% if "arxiv.org" in submission.preprint.url %} - <tr> - <td>Arxiv Link:</td> - <td> - <a href="{{ submission.preprint.url }}" target="_blank" rel="noopener">{{ submission.preprint.url }}</a> (<a href="{{ submission.preprint.citation_pdf_url }}" target="_blank" rel="noopener">pdf</a>) - </td> - </tr> - {% elif submission.preprint.get_absolute_url %} - <tr> - <td>Preprint link:</td> - <td> - <a href="{{ submission.preprint.get_absolute_url }}" target="_blank">{{ submission.preprint.identifier_w_vn_nr }}</a> - </td> - </tr> - {% endif %} - {% if submission.code_repository_url %} - <tr> - <td>Code repository:</td> - <td> - <a href="{{ submission.code_repository_url }}" target="_blank" rel="noopener">{{ submission.code_repository_url }}</a> - </td> - </tr> - {% endif %} - {% if submission.data_repository_url %} - <tr> - <td>Data repository:</td> - <td> - <a href="{{ submission.data_repository_url }}" target="_blank" rel="noopener">{{ submission.data_repository_url }}</a> - </td> - </tr> - {% endif %} - {% if submission.acceptance_date %} - <tr> - <td>Date accepted:</td> - <td>{{ submission.acceptance_date }}</td> - </tr> - {% endif %} - <tr> - <td>Date submitted:</td> - <td>{{ submission.submission_date }}</td> - </tr> - <tr> - <td>Submitted by:</td> - <td>{{ submission.submitted_by }}</td> - </tr> - <tr> - <td>Submitted to:</td> - <td>{{ submission.submitted_to }}</td> - </tr> - {% if submission.proceedings %} - <tr> - <td>Proceedings issue:</td> - <td>{{ submission.proceedings }}</td> - </tr> - {% endif %} - {% with ncollections=submission.collection_set.all|length %} - {% if ncollections > 0 %} - <tr> - <td></td> - <td> for consideration in Collection{{ ncollections|pluralize }}: - <ul class="mb-0 pb-0"> - {% for collection in submission.collection_set.all %} - <li> - <a href="{{ collection.get_absolute_url }}" target="_blank">{{ collection }}</a> - </li> - {% endfor %} - </ul> - </td> - </tr> - {% endif %} - {% endwith %} - <tr> - <td>Academic field:</td> - <td>{{ submission.acad_field }}</td> - </tr> - <tr> - <td>Specialties:</td> - <td> - <ul class="m-0 ps-4"> - {% for specialty in submission.specialties.all %} - <li>{{ specialty }}</li> - {% endfor %} - </ul> - </td> - </tr> - {% if submission.approaches %} - <tr> - <td>Approach{% if submission.approaches|length > 1 %}es{% endif %}:</td> - <td>{% for approach in submission.approaches %}{% if not forloop.first %}, {% endif %}{{ approach|capfirst }}{% endfor %}</td> - </tr> - {% endif %} </table> +<div class="row mt-2"> + <div class="mt-2 col col-xl-6"> + <table class="submission summary"> + <thead> + <th colspan="2" class="px-1 bg-info">Submission information</th> + </thead> + <tbody> + {% if "arxiv.org" in submission.preprint.url %} + <tr> + <td>Arxiv Link:</td> + <td> + <a href="{{ submission.preprint.url }}" target="_blank" rel="noopener">{{ submission.preprint.url }}</a> (<a href="{{ submission.preprint.citation_pdf_url }}" target="_blank" rel="noopener">pdf</a>) + </td> + </tr> + {% elif submission.preprint.get_absolute_url %} + <tr> + <td>Preprint link:</td> + <td> + <a href="{{ submission.preprint.get_absolute_url }}" target="_blank">{{ submission.preprint.identifier_w_vn_nr }}</a> + </td> + </tr> + {% endif %} + {% if submission.code_repository_url %} + <tr> + <td>Code repository:</td> + <td> + <a href="{{ submission.code_repository_url }}" target="_blank" rel="noopener">{{ submission.code_repository_url }}</a> + </td> + </tr> + {% endif %} + {% if submission.data_repository_url %} + <tr> + <td>Data repository:</td> + <td> + <a href="{{ submission.data_repository_url }}" target="_blank" rel="noopener">{{ submission.data_repository_url }}</a> + </td> + </tr> + {% endif %} + {% if submission.acceptance_date %} + <tr> + <td>Date accepted:</td> + <td>{{ submission.acceptance_date }}</td> + </tr> + {% endif %} + <tr> + <td>Date submitted:</td> + <td>{{ submission.submission_date }}</td> + </tr> + <tr> + <td>Submitted by:</td> + <td>{{ submission.submitted_by }}</td> + </tr> + <tr> + <td>Submitted to:</td> + <td>{{ submission.submitted_to }}</td> + </tr> + {% if submission.proceedings %} + <tr> + <td>Proceedings issue:</td> + <td>{{ submission.proceedings }}</td> + </tr> + {% endif %} + {% with ncollections=submission.collection_set.all|length %} + {% if ncollections > 0 %} + <tr> + <td></td> + <td> for consideration in Collection{{ ncollections|pluralize }}: + <ul class="mb-0 pb-0"> + {% for collection in submission.collection_set.all %} + <li> + <a href="{{ collection.get_absolute_url }}" target="_blank">{{ collection }}</a> + </li> + {% endfor %} + </ul> + </td> + </tr> + {% endif %} + {% endwith %} + </tbody> + </table> + </div> + <div class="mt-2 col col-xl-6"> + <table class="submission summary"> + <thead class="bg-info"> + <th colspan="2" class="px-1 bg-info">Ontological classification</th> + </thead> + <tbody> + <tr> + <td>Academic field:</td> + <td>{{ submission.acad_field }}</td> + </tr> + <tr> + <td>Specialties:</td> + <td> + <ul class="m-0 ps-4"> + {% for specialty in submission.specialties.all %} + <li>{{ specialty }}</li> + {% endfor %} + </ul> + </td> + </tr> + {% if submission.approaches %} + <tr> + <td>Approach{% if submission.approaches|length > 1 %}es{% endif %}:</td> + <td>{% for approach in submission.approaches %}{% if not forloop.first %}, {% endif %}{{ approach|capfirst }}{% endfor %}</td> + </tr> + {% endif %} + </tbody> + </table> + </div> +</div> {% if show_abstract %} {% if submission.pdf_refereeing_pack %} diff --git a/scipost_django/templates/email/authors/acknowledge_submission.html b/scipost_django/templates/email/authors/acknowledge_submission.html index 1d15f7b2c..d483d8962 100644 --- a/scipost_django/templates/email/authors/acknowledge_submission.html +++ b/scipost_django/templates/email/authors/acknowledge_submission.html @@ -5,7 +5,6 @@ {{ submission.title }} <br>by {{ submission.author_list }}. </p> - <p>We will update you on the initial processing within the next 5 working days.</p> <p>You can track your Submission at any time from your <a href="https://{{ domain }}{% url 'scipost:personal_page' %}">personal page</a>.</p> <p>With many thanks,</p> diff --git a/scipost_django/templates/email/authors/admission_failed.json b/scipost_django/templates/email/authors/admission_failed.json index 94fae4989..936259805 100644 --- a/scipost_django/templates/email/authors/admission_failed.json +++ b/scipost_django/templates/email/authors/admission_failed.json @@ -1,5 +1,5 @@ { - "subject": "SciPost: submission admission failed", + "subject": "SciPost: Submission admission failed", "recipient_list": [ "submitted_by.user.email" ], diff --git a/scipost_django/templates/email/authors/admission_passed.html b/scipost_django/templates/email/authors/admission_passed.html new file mode 100644 index 000000000..5421a5257 --- /dev/null +++ b/scipost_django/templates/email/authors/admission_passed.html @@ -0,0 +1,17 @@ +{% load automarkup %} +<p>Dear {{ object.submitted_by.profile.get_title_display }} {{ object.submitted_by.user.last_name }},</p> +<p>We would like to inform you that your recent Submission to {{ object.submitted_to }},</p> +<p>{{ object.title }}</p> +<p>by {{ object.author_list }}</p> +<p>has passed the admission stage, and moved on to the Preassignment stage.</p> +{% if comments_for_authors %} + {% automarkup comments_for_authors %} +{% endif %} +<p>We will keep you updated on further processing within the next 5 working days.</p> +<p>You can track your Submission at any time from your <a href="https://{{ domain }}{% url 'scipost:personal_page' %}">personal page</a>.</p> +<p>Sincerely,</p> +<p>The SciPost Team.</p> + +{% include 'email/_footer.html' %} + +{% include 'email/_submission_thread_uuid.html' with submission=object %} diff --git a/scipost_django/templates/email/authors/admission_passed.json b/scipost_django/templates/email/authors/admission_passed.json new file mode 100644 index 000000000..a2b617ce4 --- /dev/null +++ b/scipost_django/templates/email/authors/admission_passed.json @@ -0,0 +1,11 @@ +{ + "subject": "SciPost: Submission admission passed", + "recipient_list": [ + "submitted_by.user.email" + ], + "bcc": [ + "submissions@" + ], + "from_name": "SciPost Editorial Admin", + "from_email": "submissions@" +} -- GitLab