SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit e8dadc8a authored by Jean-Sébastien Caux's avatar Jean-Sébastien Caux
Browse files

Add admissibility step to incoming phase

parent fe4e3553
No related branches found
No related tags found
No related merge requests found
Showing
with 189 additions and 24 deletions
__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"
from .plagiarism import (
InternalPlagiarismAssessmentForm,
iThenticatePlagiarismAssessmentForm,
)
from .submission_admissibility import SubmissionAdmissibilityForm
__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 SubmissionAdmissibilityForm(forms.Form):
admissibility = forms.ChoiceField(
label="Can we proceed with consideration of this Submission?",
choices=(
("pass", "Pass, carry on with plagiarism"),
("fail", "Fail: desk reject 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("admissibility"),
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["admissibility"] == "fail" and
self.cleaned_data["comments_for_authors"] is None):
self.add_error(
None,
"Comments for authors must not be empty if marked as inadmissible"
)
{% load crispy_forms_tags %}
<h3>Assess admissibility of this Submission</h3>
<form
class="mt-3"
hx-post="{% url 'edadmin:_hx_submission_admissibility' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-target="#submission-{{ submission.pk }}-admissibility-form"
>
{% crispy form %}
</form>
......@@ -6,6 +6,7 @@
{% include "edadmin/_hx_submission_incoming.html" with submission=submission %}
{% endif %}
<hr class="my-2">
<h1>Workflow diagram</h1>
<button class="m-2 btn btn-primary workflowDiagram"
id="submission-{{ submission.pk }}-workflow-diagram"
......
<h1>Plagiarism</h1>
<div class="p-2">
<div id="submission-{{ submission.pk }}-plagiarism-internal"
class="m-2"
hx-get="{% url 'edadmin:_hx_plagiarism_internal' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-trigger="load, {{ submission.pk }}-plagiarism-internal-updated"
>
</div>
<h1>Admissibility</h1>
<div class="p-2 mb-4" id="submission-{{ submission.pk }}-admissibility">
{% if submission.status == submission.INCOMING %}
<div id="submission-{{ submission.pk }}-admissibility-form"
class="m-2"
hx-get="{% url 'edadmin:_hx_submission_admissibility' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-trigger="load"
>
</div>
{% elif submission.status == submission.ADMISSIBLE %}
<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>
<div class="p-2">
<div id="submission-{{ submission.pk }}-plagiarism-iThenticate"
class="m-2"
hx-get="{% url 'edadmin:_hx_plagiarism_iThenticate' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-trigger="load, {{ submission.pk }}-plagiarism-iThenticate-updated"
>
{% if submission.status == submission.ADMISSIBLE %}
<h1>Plagiarism</h1>
<div class="p-2 mb-4">
<div id="submission-{{ submission.pk }}-plagiarism-internal"
class="m-2"
hx-get="{% url 'edadmin:_hx_plagiarism_internal' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-trigger="load, {{ submission.pk }}-plagiarism-internal-updated"
>
</div>
</div>
</div>
<div class="p-2">
<div id="submission-{{ submission.pk }}-plagiarism-iThenticate"
class="m-2"
hx-get="{% url 'edadmin:_hx_plagiarism_iThenticate' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-trigger="load, {{ submission.pk }}-plagiarism-iThenticate-updated"
>
</div>
</div>
{% endif %}
......@@ -22,15 +22,16 @@
</li>
<li class="list-inline-item float-end">
<ul class="list list-unstyled">
<li class="mb-4"><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-4"><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"><strong>Status</strong>:&nbsp;{{ 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>
</ul>
</li>
</ul>
</summary>
<div id="submission-{{ submission.pk }}-details-contents"
hx-get="{% url 'edadmin:_hx_submission_details_contents' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}"
hx-trigger="toggle once from:#submission-{{ submission.pk }}-details"
hx-trigger="toggle once from:#submission-{{ submission.pk }}-details, submission-{{ submission.pk }}-details-updated"
>
</div>
</details>
......
......@@ -16,6 +16,11 @@ urlpatterns = [
path(
"<identifier:identifier_w_vn_nr>/",
include([
path(
"_hx_submission_admissibility",
incoming._hx_submission_admissibility,
name="_hx_submission_admissibility",
),
path(
"_hx_submission_details_contents",
incoming._hx_submission_details_contents,
......
......@@ -4,7 +4,7 @@ __license__ = "AGPL v3"
from django.contrib.auth.decorators import login_required, user_passes_test
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from guardian.shortcuts import get_objects_for_user
......@@ -17,9 +17,10 @@ from submissions.models import (
)
from submissions.forms import iThenticateReportForm
from edadmin.forms.plagiarism import (
from edadmin.forms import (
InternalPlagiarismAssessmentForm,
iThenticatePlagiarismAssessmentForm,
SubmissionAdmissibilityForm,
)
......@@ -31,9 +32,9 @@ def _hx_incoming_list(request):
"""
submissions = get_objects_for_user(request.user, "submissions.take_edadmin_actions")
context = {
"phase": "incoming",
"submissions": submissions.incoming(),
"submissions": submissions.in_stage_incoming(),
}
print(f"{len(submissions.in_stage_incoming()) = }")
return render(request, "edadmin/_hx_submissions_list.html", context)
......@@ -47,6 +48,36 @@ def _hx_submission_details_contents(request, identifier_w_vn_nr):
return render(request, "edadmin/_hx_submission_details_contents.html", context)
#################
# Admissibility #
#################
@login_required
@user_passes_test(is_edadmin)
def _hx_submission_admissibility(request, identifier_w_vn_nr):
submission = get_object_or_404(
Submission, preprint__identifier_w_vn_nr=identifier_w_vn_nr
)
form = SubmissionAdmissibilityForm(request.POST or None)
if form.is_valid():
if form.cleaned_data["admissibility"] == "pass":
Submission.objects.filter(pk=submission.id).update(
status=Submission.ADMISSIBLE
)
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
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_admissibility_form.html", context)
########################
# Plagiarism: internal #
########################
......
......@@ -195,6 +195,10 @@ class SubmissionPoolSearchForm(forms.Form):
"Incoming",
(
(Submission.INCOMING, "Incoming: awaiting EdAdmin checks"),
(
Submission.ADMISSIBLE,
"Admissible; undergoing plagiarism checks",
),
),
),
(
......
......@@ -18,6 +18,9 @@ class SubmissionQuerySet(models.QuerySet):
def incoming(self):
return self.filter(status=self.model.INCOMING)
def admissible(self):
return self.filter(status=self.model.ADMISSIBLE)
def admission_failed(self):
return self.filter(status=self.model.ADMISSION_FAILED)
......@@ -78,8 +81,9 @@ class SubmissionQuerySet(models.QuerySet):
return self.filter(status=self.model.PUBLISHED)
### Managers for stages ####
def in_stage_incoming(self):
return self.filter(status=self.model.STAGE_INCOMING)
return self.filter(status__in=self.model.STAGE_INCOMING)
def stage_incoming_completed(self):
return self.filter(status__in=self.model.stage_incoming_completed_statuses)
......
# Generated by Django 3.2.16 on 2022-12-05 18:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('submissions', '0128_auto_20221205_0500'),
]
operations = [
migrations.AlterField(
model_name='submission',
name='status',
field=models.CharField(choices=[('incoming', 'Submission incoming, awaiting EdAdmin'), ('admissible', 'Admissible, undergoing further admission checks'), ('admission_failed', 'Admission failed'), ('preassignment', 'In preassignment'), ('preassignment_failed', 'Preassignment failed'), ('seeking_assignment', 'Seeking assignment'), ('assignment_failed', 'Failed to assign Editor-in-charge; manuscript rejected'), ('refereeing_in_preparation', 'Refereeing in preparation'), ('in_refereeing', 'In refereeing'), ('refereeing_closed', 'Refereeing closed (awaiting author replies and EdRec)'), ('awaiting_resubmission', 'Awaiting resubmission'), ('resubmitted', 'Has been resubmitted'), ('voting_in_preparation', 'Voting in preparation'), ('in_voting', 'In voting'), ('awaiting_decision', 'Awaiting decision'), ('accepted_in_target', 'Accepted in target Journal'), ('accepted_alt_puboffer_waiting', 'Accepted in alternative Journal; awaiting puboffer acceptance'), ('accepted_alt', 'Accepted in alternative Journal'), ('rejected', 'Publication decision taken: reject'), ('withdrawn', 'Withdrawn by the Authors'), ('published', 'Published')], default='incoming', max_length=30),
),
]
......@@ -49,6 +49,7 @@ class Submission(models.Model):
# Possible statuses
INCOMING = "incoming"
ADMISSIBLE = "admissible"
ADMISSION_FAILED = "admission_failed"
PREASSIGNMENT = "preassignment"
PREASSIGNMENT_FAILED = "preassignment_failed"
......@@ -71,6 +72,7 @@ class Submission(models.Model):
SUBMISSION_STATUSES = (
(INCOMING, "Submission incoming, awaiting EdAdmin"),
(ADMISSIBLE, "Admissible, undergoing further admission checks"),
(ADMISSION_FAILED, "Admission failed"),
(PREASSIGNMENT, "In preassignment"),
(PREASSIGNMENT_FAILED, "Preassignment failed"),
......@@ -101,6 +103,7 @@ class Submission(models.Model):
# Submissions which are currently under consideration
UNDER_CONSIDERATION = (
INCOMING,
ADMISSIBLE,
PREASSIGNMENT,
SEEKING_ASSIGNMENT,
REFEREEING_IN_PREPARATION,
......@@ -115,7 +118,7 @@ class Submission(models.Model):
)
# Further handy sets
STAGE_INCOMING = (INCOMING, ADMISSION_FAILED)
STAGE_INCOMING = (INCOMING, ADMISSIBLE, ADMISSION_FAILED)
STAGE_PREASSIGNMENT = (PREASSIGNMENT, PREASSIGNMENT_FAILED)
STAGE_ASSIGNMENT = (SEEKING_ASSIGNMENT, ASSIGNMENT_FAILED)
STAGE_REFEREEING_IN_PREPARATION = (REFEREEING_IN_PREPARATION,)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment