diff --git a/scipost_django/edadmin/templates/edadmin/_hx_plagiarism_iThenticate.html b/scipost_django/edadmin/templates/edadmin/_hx_plagiarism_iThenticate.html new file mode 100644 index 0000000000000000000000000000000000000000..5076870e70bae5462267c3c02957d428340e45b9 --- /dev/null +++ b/scipost_django/edadmin/templates/edadmin/_hx_plagiarism_iThenticate.html @@ -0,0 +1,49 @@ +{% load bootstrap %} + +{% if submission.iThenticate_plagiarism_report %} + <table> + <tr> + <td style="min-width: 150px;">iThenticate document</td> + <td>{{ submission.iThenticate_plagiarism_report.doc_id }}</td> + </tr> + <tr> + <td>Percent match</td> + <td>{{ submission.iThenticate_plagiarism_report.percent_match }}%</td> + </tr> + <tr> + <td>Processed</td> + <td>{{ submission.iThenticate_plagiarism_report.processed_time }}</td> + </tr> + <tr> + <td>Uploaded</td> + <td>{{ submission.iThenticate_plagiarism_report.uploaded_time }}</td> + </tr> + <tr> + <td>Latest update</td> + <td>{{ submission.iThenticate_plagiarism_report.latest_activity }}</td> + </tr> + </table> +{% else %} + No Plagiarism Report found. +{% endif %} + +<form + class="mt-3" enctype="multipart/form-data" + hx-post="{% url 'edadmin:_hx_plagiarism_iThenticate' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-target="#submission-{{ submission.pk }}-iThenticate" + hx-indicator="#indicator-{{ submission.pk }}-iThenticate" +> + {% csrf_token %} + {{ form|bootstrap }} + <input type="submit" class="btn btn-primary" value="{% if submission.iThenticate_plagiarism_report %}Update report status{% else %}Submit submission for plagiarism check{% endif %}"> +</form> +<div id="indicator-{{ submission.pk }}-iThenticate" class="htmx-indicator"> + <button class="btn btn-sm btn-warning" type="button" disabled> + <strong>Loading...</strong> + <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div> + </button> +</div> + +{% if submission.iThenticate_plagiarism_report %} + <a href="{% url 'submissions:iThenticate_plagiarism_report' submission.preprint.identifier_w_vn_nr %}" class="ms-2 btn btn-default">Download report pdf</a> +{% endif %} diff --git a/scipost_django/edadmin/templates/edadmin/_hx_plagiarism_internal.html b/scipost_django/edadmin/templates/edadmin/_hx_plagiarism_internal.html new file mode 100644 index 0000000000000000000000000000000000000000..498f23c4238809173462ad09c21048f06dd1ad3c --- /dev/null +++ b/scipost_django/edadmin/templates/edadmin/_hx_plagiarism_internal.html @@ -0,0 +1,72 @@ +<details open> + <summary class="m-2 p-2"> + Submission matches + {% if not "submission_matches" in submission.internal_plagiarism_matches %} + <span class="text-danger border border-danger m-2 p-2">This automated internal plagiarism check has not finished running yet; please come back later!</span> + {% endif %} + </summary> + <table class="table"> + <thead> + <tr> + <th>Submission</th> + <th>Title match %</th> + <th>Authors match %</th> + <th>Abstract match %</th> + </tr> + </thead> + <tbody> + {% for match in submission_matches %} + <tr> + <td> + {{ match.submission.preprint.identifier_w_vn_nr }} +  <small class="text-muted">Thread hash: {{ match.submission.thread_hash }}</small> + <br> + <a href="{{ match.submission.get_absolute_url }}" target="_blank">{{ match.submission.title }}</a><br> + {{ match.submission.author_list }} + </td> + <td>{{ match.ratio_title|floatformat:2 }}</td> + <td>{{ match.ratio_authors|floatformat:2 }}</td> + <td>{{ match.ratio_abstract|floatformat:2 }}</td> + </tr> + {% empty %} + <tr><td>No matching Submissions</td></tr> + {% endfor %} + </tbody> + </table> +</details> + + +<details open> + <summary class="m-2 p-2"> + Publication matches + {% if not "publication_matches" in submission.internal_plagiarism_matches %} + <span class="text-danger border border-danger m-2 p-2">This automated internal plagiarism check has not finished running yet; please come back later!</span> + {% endif %} + </summary> + <table class="table"> + <thead> + <tr> + <th>Publication</th> + <th>Title match %</th> + <th>Authors match %</th> + <th>Abstract match %</th> + </tr> + </thead> + <tbody> + {% for match in publication_matches %} + <tr> + <td> + {{ match.publication.doi_label }}<br> + <a href="{{ match.publication.get_absolute_url }}" target="_blank">{{ match.publication.title }}</a><br> + {{ match.publication.author_list }} + </td> + <td>{{ match.ratio_title|floatformat:2 }}</td> + <td>{{ match.ratio_authors|floatformat:2 }}</td> + <td>{{ match.ratio_abstract|floatformat:2 }}</td> + </tr> + {% empty %} + <tr><td>No matching Publications</td></tr> + {% endfor %} + </tbody> + </table> +</details> diff --git a/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html b/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html new file mode 100644 index 0000000000000000000000000000000000000000..cf0ca8b1dec8b00446ec1c72a82b7e6c6d267821 --- /dev/null +++ b/scipost_django/edadmin/templates/edadmin/_hx_submissions_list.html @@ -0,0 +1,52 @@ +{% for submission in submissions %} + + <details class="border border-2 my-2"> + <summary class="px-4 py-2"> + <table> + <tbody> + <tr> + <td><a href="{% url 'submissions:submission' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}">{{ submission.title }}</a></td> + </tr> + <tr> + <td>{{ submission.author_list }}</td> + </tr> + <tr> + <td>Submitted {{ submission.submission_date|date:"Y-m-d" }} to {{ submission.submitted_to }}</td> + </tr> + </tbody> + </table> + </summary> + <div class="p-2"> + <h1>Summary</h1> + {% include 'submissions/_submission_summary.html' with submission=submission hide_title=1 show_abstract=1 %} + + <h1>Plagiarism</h1> + <div class="p-2"> + <h2>Internal plagiarism checks</h2> + <button class="m-2 btn btn-primary" + id="submission-{{ submission.preprint.identifier_w_vn_nr }}" + hx-get="{% url 'edadmin:_hx_plagiarism_internal' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-swap="outerHTML" + hx-trigger="revealed" + >load internal plagiarism info</button> + </div> + <div class="p-2"> + <h2>iThenticate checks</h2> + <div id="submission-{{ submission.pk }}-iThenticate"> + <button class="m-2 btn btn-primary" + hx-get="{% url 'edadmin:_hx_plagiarism_iThenticate' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-swap="outerHTML" + hx-trigger="revealed" + >load iThenticate plagiarism info</button> + </div> + </div> + + <h1>Workflow diagram</h1> + <button class="m-2 btn btn-primary workflowDiagram" + id="submission-{{ submission.preprint.identifier_w_vn_nr }}-workflow-diagram" + hx-get="{% url 'submissions:_hx_submission_workflow_diagram' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-swap="outerHTML" + >Load Submission processing workflow graphs</button> + </div> + </details> +{% endfor %} diff --git a/scipost_django/edadmin/templates/edadmin/edadmin.html b/scipost_django/edadmin/templates/edadmin/edadmin.html index f864ececd775993f79c327555416143f1668408f..36d1eb8bf1551440abc5abdeeaa083082a71e60b 100644 --- a/scipost_django/edadmin/templates/edadmin/edadmin.html +++ b/scipost_django/edadmin/templates/edadmin/edadmin.html @@ -16,20 +16,36 @@ {% block content %} - <h2 class="highlight">Preassignment</h2> - {% for submission in preassignment %} - {% include 'submissions/_submission_events.html' with events=submission.events.for_edadmin %} - - <details> - <summary>{{ submission }}</summary> - <button class="m-2 btn btn-primary workflowDiagram" - id="submission-{{ submission.preprint.identifier_w_vn_nr }}-workflow-diagram" - hx-get="{% url 'submissions:_hx_submission_workflow_diagram' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + <details class="border border-2 my-4"> + <summary class="bg-info px-4 py-2"> + <h1>Incoming</h1> + </summary> + <div class="p-2"> + <button class="m-2 btn btn-primary" + id="incoming" + hx-get="{% url 'edadmin:_hx_incoming_list' %}" hx-swap="outerHTML" - >Load Submission processing workflow graphs</button> - </details> - {% endfor %} + >Load incoming Submissions</button> + </div> + </details> + + <details> + <summary>Preassignment</summary> + {% for submission in preassignment %} + + {% include 'submissions/_submission_events.html' with events=submission.events.for_edadmin %} + + <details> + <summary>{{ submission }}</summary> + <button class="m-2 btn btn-primary workflowDiagram" + id="submission-{{ submission.preprint.identifier_w_vn_nr }}-workflow-diagram" + hx-get="{% url 'submissions:_hx_submission_workflow_diagram' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr %}" + hx-swap="outerHTML" + >Load Submission processing workflow graphs</button> + </details> + {% endfor %} + </details> {% endblock content %} diff --git a/scipost_django/edadmin/urls.py b/scipost_django/edadmin/urls.py deleted file mode 100644 index 9caf5624b1bfdf0dc78ca3632780b63bcb6f8ea5..0000000000000000000000000000000000000000 --- a/scipost_django/edadmin/urls.py +++ /dev/null @@ -1,15 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -from django.urls import path, re_path -from django.views.generic import TemplateView - -from . import views - -app_name = "edadmin" - - -urlpatterns = [ - path("", views.edadmin, name="edadmin"), -] diff --git a/scipost_django/edadmin/urls/__init__.py b/scipost_django/edadmin/urls/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c1ae4f9db0478f0d00e69fc7fb4fd767c9864d01 --- /dev/null +++ b/scipost_django/edadmin/urls/__init__.py @@ -0,0 +1,15 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.urls import include, path + +from ..views import base + +app_name = "edadmin" + + +urlpatterns = [ + path("", base.edadmin, name="edadmin"), + path("incoming/", include("edadmin.urls.incoming")), +] diff --git a/scipost_django/edadmin/urls/incoming.py b/scipost_django/edadmin/urls/incoming.py new file mode 100644 index 0000000000000000000000000000000000000000..d7815dc60769af2aee68d802a86424c92339922b --- /dev/null +++ b/scipost_django/edadmin/urls/incoming.py @@ -0,0 +1,31 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.urls import include, path + +from ..views import incoming + + +urlpatterns = [ + path( + "_hx_incoming_list", + incoming._hx_incoming_list, + name="_hx_incoming_list", + ), + path( + "<identifier:identifier_w_vn_nr>/", + include([ + path( + "_hx_plagiarism_internal", + incoming._hx_plagiarism_internal, + name="_hx_plagiarism_internal", + ), + path( + "_hx_plagiarism_iThenticate", + incoming._hx_plagiarism_iThenticate, + name="_hx_plagiarism_iThenticate", + ), + ]) + ), +] diff --git a/scipost_django/edadmin/views/__init__.py b/scipost_django/edadmin/views/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5dfd5d6b69c3f6bb2ad0234397fb362d5d963cdb --- /dev/null +++ b/scipost_django/edadmin/views/__init__.py @@ -0,0 +1,2 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" diff --git a/scipost_django/edadmin/views.py b/scipost_django/edadmin/views/base.py similarity index 100% rename from scipost_django/edadmin/views.py rename to scipost_django/edadmin/views/base.py diff --git a/scipost_django/edadmin/views/incoming.py b/scipost_django/edadmin/views/incoming.py new file mode 100644 index 0000000000000000000000000000000000000000..f78658efaf353aee9793629beef9e3b81358aeb3 --- /dev/null +++ b/scipost_django/edadmin/views/incoming.py @@ -0,0 +1,72 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.contrib.auth.decorators import login_required, user_passes_test +from django.shortcuts import get_object_or_404, render + +from guardian.shortcuts import get_objects_for_user + +from colleges.permissions import is_edadmin +from submissions.models import Submission +from submissions.forms import iThenticateReportForm + + +@login_required +@user_passes_test(is_edadmin) +def _hx_incoming_list(request): + """ + EdAdmin page for incoming Submissions. + """ + submissions = get_objects_for_user(request.user, "submissions.take_edadmin_actions") + context = { "submissions": submissions.incoming() } + return render(request, "edadmin/_hx_submissions_list.html", context) + + +@login_required +@user_passes_test(is_edadmin) +def _hx_plagiarism_internal(request, identifier_w_vn_nr): + submission = get_object_or_404( + Submission, preprint__identifier_w_vn_nr=identifier_w_vn_nr + ) + context = {"submission_matches": [], "publication_matches": []} + if "submission_matches" in submission.internal_plagiarism_matches: + for sub_match in submission.internal_plagiarism_matches["submission_matches"]: + context["submission_matches"].append( + { + "submission": Submission.objects.get( + preprint__identifier_w_vn_nr=sub_match["identifier_w_vn_nr"], + ), + "ratio_title": sub_match["ratio_title"], + "ratio_authors": sub_match["ratio_authors"], + "ratio_abstract": sub_match["ratio_abstract"], + } + ) + if "publication_matches" in submission.internal_plagiarism_matches: + for pub_match in submission.internal_plagiarism_matches["publication_matches"]: + context["publication_matches"].append( + { + "publication": Publication.objects.get(doi_label=pub_match["doi_label"]), + "ratio_title": pub_match["ratio_title"], + "ratio_authors": pub_match["ratio_authors"], + "ratio_abstract": pub_match["ratio_abstract"], + } + ) + return render(request, "edadmin/_hx_plagiarism_internal.html", context) + + +@login_required +@user_passes_test(is_edadmin) +def _hx_plagiarism_iThenticate(request, identifier_w_vn_nr): + submission = get_object_or_404( + Submission, preprint__identifier_w_vn_nr=identifier_w_vn_nr + ) + form = iThenticateReportForm(submission, request.POST or None) + if form.is_valid(): + form.save() + submission.refresh_from_db() + context = { + "submission": submission, + "form": form, + } + return render(request, "edadmin/_hx_plagiarism_iThenticate.html", context) diff --git a/scipost_django/scipost/models.py b/scipost_django/scipost/models.py index 952f9af40a29076203a3f2db4260a5d5779a62e1..f6d259ce51358780aca79ff8ee1c42722b2f37d5 100644 --- a/scipost_django/scipost/models.py +++ b/scipost_django/scipost/models.py @@ -192,7 +192,7 @@ class Contributor(models.Model): @property def is_active_senior_fellow(self): - return self.fellowships.active().senior().exists() + return self.fellowships.active().senior().exists() or self.user.is_superuser def session_fellowship(self, request): """Return session's fellowship, if any; if Fellow, set session_fellowship_id if not set.""" diff --git a/scipost_django/submissions/admin.py b/scipost_django/submissions/admin.py index 7cc43db976365375acd7160d8fede8e582d290bf..78fc925a8ce67efd03647a813bb8c7bff003c61c 100644 --- a/scipost_django/submissions/admin.py +++ b/scipost_django/submissions/admin.py @@ -96,7 +96,7 @@ class SubmissionAdmin(GuardedModelAdmin): "authors", "authors_claims", "authors_false_claims", - "plagiarism_report", + "iThenticate_plagiarism_report", "topics", ] inlines = [ diff --git a/scipost_django/submissions/forms.py b/scipost_django/submissions/forms.py index 5cd343173bcd861ae5528e323b552bf60258193e..77716af803c3b4b419edfb48a5d59d176cfe4c9b 100644 --- a/scipost_django/submissions/forms.py +++ b/scipost_django/submissions/forms.py @@ -2789,7 +2789,7 @@ class iThenticateReportForm(forms.ModelForm): else: report.save() Submission.objects.filter(id=self.submission.id).update( - plagiarism_report=report + iThenticate_plagiarism_report=report ) return report diff --git a/scipost_django/submissions/managers/submission.py b/scipost_django/submissions/managers/submission.py index 9c02988ef2a351eb5c4e73ba0887b3454b9fb82f..1eb8f2057509dd635a84f716d2d1474c32b087d8 100644 --- a/scipost_django/submissions/managers/submission.py +++ b/scipost_django/submissions/managers/submission.py @@ -183,8 +183,10 @@ class SubmissionQuerySet(models.QuerySet): f_ids = user.contributor.fellowships.active() qs = qs.filter(fellows__in=f_ids) + if user.contributor.is_scipost_admin: + pass # Fellows can't see incoming and (non-Senior) preassignment - if user.contributor.is_active_senior_fellow: + elif user.contributor.is_active_senior_fellow: qs = qs.exclude(status__in=[self.model.INCOMING,]) elif user.contributor.is_active_fellow: qs = qs.exclude(status__in=[self.model.INCOMING, self.model.PREASSIGNMENT]) @@ -338,13 +340,13 @@ class SubmissionEventQuerySet(models.QuerySet): created__gte=timezone.now() - datetime.timedelta(hours=hours) ) - def plagiarism_report_to_be_uploaded(self): + def iThenticate_plagiarism_report_to_be_uploaded(self): """Return Submissions that has not been sent to iThenticate for their plagiarism check.""" return self.filter( - models.Q(plagiarism_report__isnull=True) - | models.Q(plagiarism_report__status=constants.STATUS_WAITING) + models.Q(iThenticate_plagiarism_report__isnull=True) + | models.Q(iThenticate_plagiarism_report__status=constants.STATUS_WAITING) ).distinct() - def plagiarism_report_to_be_updated(self): + def iThenticate_plagiarism_report_to_be_updated(self): """Return Submissions for which their iThenticateReport has not received a report yet.""" - return self.filter(plagiarism_report__status=constants.STATUS_SENT) + return self.filter(iThenticate_plagiarism_report__status=constants.STATUS_SENT) diff --git a/scipost_django/submissions/migrations/0127_auto_20221204_1327.py b/scipost_django/submissions/migrations/0127_auto_20221204_1327.py new file mode 100644 index 0000000000000000000000000000000000000000..c7cba23531d6314bda2ace1bced8ec56c4800927 --- /dev/null +++ b/scipost_django/submissions/migrations/0127_auto_20221204_1327.py @@ -0,0 +1,57 @@ +# Generated by Django 3.2.16 on 2022-12-04 12:27 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('submissions', '0126_alter_submission_status'), + ] + + operations = [ + migrations.CreateModel( + name='PlagiarismAssessment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(choices=[('ongoing', 'Ongoing'), ('passed', 'Passed'), ('failed_temporary', 'Failed (temporary: author action needed)'), ('failed_permanent', 'Failed (permanent: not solvable)')], default='ongoing', max_length=16)), + ('passed_on', models.DateTimeField(blank=True, null=True)), + ('comments_for_edadmin', models.TextField()), + ('comments_for_authors', models.TextField()), + ], + ), + migrations.RenameField( + model_name='submission', + old_name='plagiarism_report', + new_name='iThenticate_plagiarism_report', + ), + migrations.CreateModel( + name='InternalPlagiarismAssessment', + fields=[ + ('plagiarismassessment_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='submissions.plagiarismassessment')), + ], + bases=('submissions.plagiarismassessment',), + ), + migrations.CreateModel( + name='iThenticatePlagiarismAssessment', + fields=[ + ('plagiarismassessment_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='submissions.plagiarismassessment')), + ], + options={ + 'verbose_name': 'iThenticate plagiarism assessment', + 'verbose_name_plural': 'iThenticate plagiarism assessments', + }, + bases=('submissions.plagiarismassessment',), + ), + migrations.AddField( + model_name='submission', + name='iThenticate_plagiarism_assessment', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='submissions.ithenticateplagiarismassessment'), + ), + migrations.AddField( + model_name='submission', + name='internal_plagiarism_assessment', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='submissions.internalplagiarismassessment'), + ), + ] diff --git a/scipost_django/submissions/mixins.py b/scipost_django/submissions/mixins.py index 4a30e923600869209b22316ea24109f605b60f6b..2149b3aa3113b769346286139e94e730568a8054 100644 --- a/scipost_django/submissions/mixins.py +++ b/scipost_django/submissions/mixins.py @@ -101,7 +101,7 @@ class SubmissionAdminViewMixin(FriendlyPermissionMixin, SubmissionFormViewMixin) qs = super().get_queryset() if self.pool: return qs.pool(self.request.user) - return qs.filter_for_eic(self.request.user) + return qs.in_pool_filter_for_eic(self.request.user) def get_object(self): """ diff --git a/scipost_django/submissions/models/__init__.py b/scipost_django/submissions/models/__init__.py index aea07c0a851b2ba07232cc2a229ce114176829fb..5bd066ac4d4df46729399428ffda79c7f72616c6 100644 --- a/scipost_django/submissions/models/__init__.py +++ b/scipost_django/submissions/models/__init__.py @@ -4,7 +4,13 @@ __license__ = "AGPL v3" from .submission import Submission, SubmissionEvent, SubmissionTiering -from .plagiarism import iThenticateReport +from .plagiarism_assessment import ( + PlagiarismAssessment, + InternalPlagiarismAssessment, + iThenticatePlagiarismAssessment, +) + +from .iThenticate_report import iThenticateReport from .assignment import EditorialAssignment diff --git a/scipost_django/submissions/models/plagiarism.py b/scipost_django/submissions/models/iThenticate_report.py similarity index 100% rename from scipost_django/submissions/models/plagiarism.py rename to scipost_django/submissions/models/iThenticate_report.py diff --git a/scipost_django/submissions/models/plagiarism_assessment.py b/scipost_django/submissions/models/plagiarism_assessment.py new file mode 100644 index 0000000000000000000000000000000000000000..6f9b5262925b97be4654b26c5b2072bf56c2161e --- /dev/null +++ b/scipost_django/submissions/models/plagiarism_assessment.py @@ -0,0 +1,40 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.db import models + + +class PlagiarismAssessment(models.Model): + STATUS_ONGOING = "ongoing" + STATUS_PASSED = "passed" + STATUS_FAILED_TEMPORARY = "failed_temporary" + STATUS_FAILED_PERMANENT = "failed_permanent" + STATUS_CHOICES = ( + (STATUS_ONGOING, "Ongoing"), + (STATUS_PASSED, "Passed"), + (STATUS_FAILED_TEMPORARY, "Failed (temporary: author action needed)"), + (STATUS_FAILED_PERMANENT, "Failed (permanent: not solvable)"), + ) + status = models.CharField( + max_length=16, + choices=STATUS_CHOICES, + default=STATUS_ONGOING, + ) + passed_on = models.DateTimeField(blank=True, null=True) + comments_for_edadmin = models.TextField() + comments_for_authors = models.TextField() + + @property + def passed(self): + return self.status == self.STATUS_PASSED + + +class InternalPlagiarismAssessment(PlagiarismAssessment): + pass + + +class iThenticatePlagiarismAssessment(PlagiarismAssessment): + class Meta: + verbose_name = "iThenticate plagiarism assessment" + verbose_name_plural = "iThenticate plagiarism assessments" diff --git a/scipost_django/submissions/models/submission.py b/scipost_django/submissions/models/submission.py index b0e152c4aebb8df3191303a7f4fcdc02eb7465f7..8fa980d88cf80f15fcecbdb6da2cb1cd55c57308 100644 --- a/scipost_django/submissions/models/submission.py +++ b/scipost_django/submissions/models/submission.py @@ -250,21 +250,36 @@ class Submission(models.Model): # Comments can be added to a Submission comments = GenericRelation("comments.Comment", related_query_name="submissions") - # iThenticate and conflicts + # Conflicts of interest needs_conflicts_update = models.BooleanField(default=True) - plagiarism_report = models.OneToOneField( + + # Plagiarism + internal_plagiarism_matches = models.JSONField( + default=dict, + blank=True, + null=True, + ) + internal_plagiarism_assessment = models.OneToOneField( + "submissions.InternalPlagiarismAssessment", + on_delete=models.CASCADE, + blank=True, + null=True, + ) + iThenticate_plagiarism_report = models.OneToOneField( "submissions.iThenticateReport", on_delete=models.SET_NULL, - null=True, blank=True, + null=True, related_name="to_submission", ) - internal_plagiarism_matches = models.JSONField( - default=dict, + iThenticate_plagiarism_assessment = models.OneToOneField( + "submissions.iThenticatePlagiarismAssessment", + on_delete=models.CASCADE, blank=True, null=True, ) + # Refereeing pack pdf_refereeing_pack = models.FileField( upload_to="UPLOADS/REFEREE/%Y/%m/", max_length=200, blank=True ) @@ -563,7 +578,7 @@ class Submission(models.Model): @property def can_reset_reporting_deadline(self): """Check if reporting deadline is allowed to be reset.""" - if self.status in STAGE_DECIDED: + if self.status in self.STAGE_DECIDED: return False if self.refereeing_cycle == CYCLE_DIRECT_REC: diff --git a/scipost_django/submissions/tasks.py b/scipost_django/submissions/tasks.py index c67da652f772cfb57c6ae72ce80db722a597dda6..eaf8e42f2952ab2cacd69db02f694e79272bac76 100644 --- a/scipost_django/submissions/tasks.py +++ b/scipost_django/submissions/tasks.py @@ -45,15 +45,15 @@ def send_editorial_assignment_invitations(self): @app.task(bind=True) def submit_submission_document_for_plagiarism(self): """Upload a new Submission document to iThenticate.""" - submissions_to_upload = Submission.objects.plagiarism_report_to_be_uploaded() - submission_to_update = Submission.objects.plagiarism_report_to_be_updated() + submissions_to_upload = Submission.objects.iThenticate_plagiarism_report_to_be_uploaded() + submission_to_update = Submission.objects.iThenticate_plagiarism_report_to_be_updated() for submission in submissions_to_upload: report, __ = iThenticate.objects.get_or_create(to_submission=submission) # do it... for submission in submission_to_update: - report = submission.plagiarism_report + report = submission.iThenticate_plagiarism_report # do it... diff --git a/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html b/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html index be09739fef01a25941540efa9f1c4ebec4fa5a59..c99d3fe9ea4837b861dd585451f75ff0768be128 100644 --- a/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html +++ b/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html @@ -31,11 +31,14 @@ flowchart LR Sub([Submission{% if submission %}<br>{{ submission.submission_date }}<br>{{ submission.submission_date|timesince }} ago{% endif %}]) subgraph Admission - Admiss(Admissibility<br>and plagiarism<br>checks) + Admiss(Admissibility<br>check) + Admiss --> PlagInt(internal plagiarism<br>check) + PlagInt --> PlagExt(external plagiarism<br>check) end Sub --> Admiss - Admiss --fail--> AdmissFailed("Admission<br>failed ✉<small>A</small>") --> Close([Processing<br>closed]) - Admiss --pass--> AdmissPassed("Admission<br>passed ✉<small>A</small>") --> Preassignment[[Goto:<br>Preassignment]] + PlagExt --fail--> AdmissFailed("Admission<br>failed ✉<small>A</small>") --> Close([Processing<br>closed]) + PlagExt --pass--> AdmissPassed("Admission<br>passed ✉<small>A</small>") --> Preassignment[[Goto:<br>Preassignment]] + PlagInt --"pass<br>(authors created new submission<br>but this is a resubmission)"--> LinkResub("Link resubmission<br>to earlier thread") --> AdmissPassed2("Admission<br>passed ✉<small>A</small>") --> RefPrep[[Goto:<br>Refereeing<br>in preparation]] </pre> </details> </div> diff --git a/scipost_django/submissions/templates/submissions/admin/plagiarism_report.html b/scipost_django/submissions/templates/submissions/admin/plagiarism_report.html index 18ec45c65a1406abb5a68c3fea907553a681caf1..cbbc30365c248b7898a251f3342109fc12257ae8 100644 --- a/scipost_django/submissions/templates/submissions/admin/plagiarism_report.html +++ b/scipost_django/submissions/templates/submissions/admin/plagiarism_report.html @@ -13,27 +13,27 @@ <h1>iThenticate Plagiarism Report for <a href="{{ submission.get_absolute_url }}">{{ submission.preprint.identifier_w_vn_nr }}</a></h1> <h2>{{ submission.title }}</h2> <h3 class="mb-4">by {{ submission.author_list }}</h3> - {% if submission.plagiarism_report %} + {% if submission.iThenticate_plagiarism_report %} <table> <tr> <td style="min-width: 150px;">iThenticate document</td> - <td>{{ submission.plagiarism_report.doc_id }}</td> + <td>{{ submission.iThenticate_plagiarism_report.doc_id }}</td> </tr> <tr> <td>Percent match</td> - <td>{{ submission.plagiarism_report.percent_match }}%</td> + <td>{{ submission.iThenticate_plagiarism_report.percent_match }}%</td> </tr> <tr> <td>Processed</td> - <td>{{ submission.plagiarism_report.processed_time }}</td> + <td>{{ submission.iThenticate_plagiarism_report.processed_time }}</td> </tr> <tr> <td>Uploaded</td> - <td>{{ submission.plagiarism_report.uploaded_time }}</td> + <td>{{ submission.iThenticate_plagiarism_report.uploaded_time }}</td> </tr> <tr> <td>Latest update</td> - <td>{{ submission.plagiarism_report.latest_activity }}</td> + <td>{{ submission.iThenticate_plagiarism_report.latest_activity }}</td> </tr> </table> {% else %} @@ -43,9 +43,9 @@ <form method="post" class="mt-3" enctype="multipart/form-data"> {% csrf_token %} {{ form|bootstrap }} - <input type="submit" class="btn btn-primary" value="{% if submission.plagiarism_report %}Update report status{% else %}Submit submission for plagiarism check{% endif %}"> - {% if submission.plagiarism_report %} - <a href="{% url 'submissions:plagiarism_report' submission.preprint.identifier_w_vn_nr %}" class="ms-2 btn btn-default">Download report pdf</a> + <input type="submit" class="btn btn-primary" value="{% if submission.iThenticate_plagiarism_report %}Update report status{% else %}Submit submission for plagiarism check{% endif %}"> + {% if submission.iThenticate_plagiarism_report %} + <a href="{% url 'submissions:iThenticate_plagiarism_report' submission.preprint.identifier_w_vn_nr %}" class="ms-2 btn btn-default">Download report pdf</a> {% endif %} </form> diff --git a/scipost_django/submissions/templates/submissions/admin/submission_preassignment.html b/scipost_django/submissions/templates/submissions/admin/submission_preassignment.html index bdced0586351767fe7cb42b8a41a01f66159f65d..30a8601a0e8183e5aa99c45a9833e762bf052dd2 100644 --- a/scipost_django/submissions/templates/submissions/admin/submission_preassignment.html +++ b/scipost_django/submissions/templates/submissions/admin/submission_preassignment.html @@ -39,29 +39,29 @@ <a href="{% url 'submissions:plagiarism_internal' submission.preprint.identifier_w_vn_nr %}">Check internal plagiarism</a> </li> <li> - {% if submission.plagiarism_report %} + {% if submission.iThenticate_plagiarism_report %} <span class="text-success">{% include 'bi/check-square-fill.html' %}</span> <a class="d-inline-block" href="{% url 'submissions:plagiarism' submission.preprint.identifier_w_vn_nr %}">Update plagiarism report</a> <table> <tr> <td style="min-width: 150px;">iThenticate document</td> - <td>{{ submission.plagiarism_report.doc_id }}</td> + <td>{{ submission.iThenticate_plagiarism_report.doc_id }}</td> </tr> <tr> <td>Percent match</td> - <td>{{ submission.plagiarism_report.percent_match|default:'?' }}%</td> + <td>{{ submission.iThenticate_plagiarism_report.percent_match|default:'?' }}%</td> </tr> <tr> <td>Processed</td> - <td>{{ submission.plagiarism_report.processed_time }}</td> + <td>{{ submission.iThenticate_plagiarism_report.processed_time }}</td> </tr> <tr> <td>Uploaded</td> - <td>{{ submission.plagiarism_report.uploaded_time }}</td> + <td>{{ submission.iThenticate_plagiarism_report.uploaded_time }}</td> </tr> <tr> <td>Latest update</td> - <td>{{ submission.plagiarism_report.latest_activity }}</td> + <td>{{ submission.iThenticate_plagiarism_report.latest_activity }}</td> </tr> </table> {% else %} diff --git a/scipost_django/submissions/templates/submissions/pool/_submission_info_table.html b/scipost_django/submissions/templates/submissions/pool/_submission_info_table.html index 1da291f91c6efa7b51a2ef55b77e6cf9524b6214..6a81fca121ea07d48363c8d444208e83071c84ca 100644 --- a/scipost_django/submissions/templates/submissions/pool/_submission_info_table.html +++ b/scipost_django/submissions/templates/submissions/pool/_submission_info_table.html @@ -101,9 +101,9 @@ <tr> <td>iThenticate plagiarism score</td> <td> - {% if submission.plagiarism_report %} - {{ submission.plagiarism_report.score }}% -  <a href="{% url 'submissions:plagiarism_report' submission.preprint.identifier_w_vn_nr %}" class="ms-2 btn btn-default" target="_blank">View report pdf</a> + {% if submission.iThenticate_plagiarism_report %} + {{ submission.iThenticate_plagiarism_report.score }}% +  <a href="{% url 'submissions:iThenticate_plagiarism_report' submission.preprint.identifier_w_vn_nr %}" class="ms-2 btn btn-default" target="_blank">View report pdf</a> {% else %} <a href="{% url 'submissions:plagiarism' submission.preprint.identifier_w_vn_nr %}">Run plagiarism check</a> {% endif %} diff --git a/scipost_django/submissions/templates/submissions/pool/editorial_page.html b/scipost_django/submissions/templates/submissions/pool/editorial_page.html index a4a14d1d6f6d7bfb341e9ca37983177e1c4896e2..e8a2d7fc22cd16b39667c0e655e8db664914c303 100644 --- a/scipost_django/submissions/templates/submissions/pool/editorial_page.html +++ b/scipost_django/submissions/templates/submissions/pool/editorial_page.html @@ -159,13 +159,13 @@ {% endif %} </td> </tr> - {% if submission.plagiarism_report or perms.scipost.can_do_plagiarism_checks %} + {% if submission.iThenticate_plagiarism_report or perms.scipost.can_do_plagiarism_checks %} <tr> <td>Plagiarism report:</td> <td> - {% if submission.plagiarism_report %} - {% if submission.plagiarism_report.percent_match %} - <b>{{ submission.plagiarism_report.percent_match }}%</b> + {% if submission.iThenticate_plagiarism_report %} + {% if submission.iThenticate_plagiarism_report.percent_match %} + <b>{{ submission.iThenticate_plagiarism_report.percent_match }}%</b> {% else %} <em>Scan in progress</em> {% if perms.scipost.can_do_plagiarism_checks %} diff --git a/scipost_django/submissions/urls.py b/scipost_django/submissions/urls.py index 02c5045c07b893304e072f5a0c815313cc1234ea..f946a8a71a40a860b188e56447fc8ac672612f0a 100644 --- a/scipost_django/submissions/urls.py +++ b/scipost_django/submissions/urls.py @@ -140,9 +140,9 @@ urlpatterns = [ name="plagiarism", ), path( - "admin/<identifier:identifier_w_vn_nr>/plagiarism/report", + "admin/<identifier:identifier_w_vn_nr>/plagiarism/iThenticate_report", views.PlagiarismReportPDFView.as_view(), - name="plagiarism_report", + name="iThenticate_plagiarism_report", ), path( "admin/<identifier:identifier_w_vn_nr>/plagiarism/internal", diff --git a/scipost_django/submissions/views.py b/scipost_django/submissions/views.py index 0330b4ca0bb2286e35b8e5426a442babea9084bb..2a61f63d4f4ee29072815e4574b21c44d5979f7c 100644 --- a/scipost_django/submissions/views.py +++ b/scipost_django/submissions/views.py @@ -2950,14 +2950,14 @@ class PlagiarismView(SubmissionAdminViewMixin, UpdateView): """Administration detail page of Plagiarism report.""" permission_required = "scipost.can_do_plagiarism_checks" - template_name = "submissions/admin/plagiarism_report.html" + template_name = "submissions/admin/iThenticate_plagiarism_report.html" editorial_page = True form_class = iThenticateReportForm def get_object(self): - """Get the plagiarism_report as a linked object from the Submission.""" + """Get the iThenticate_plagiarism_report as a linked object from the Submission.""" submission = super().get_object() - return submission.plagiarism_report + return submission.iThenticate_plagiarism_report class PlagiarismReportPDFView( @@ -2971,9 +2971,9 @@ class PlagiarismReportPDFView( def get_redirect_url(self, *args, **kwargs): """Get the temporary url provided by the iThenticate API.""" submission = self.get_object() - if not submission.plagiarism_report: + if not submission.iThenticate_plagiarism_report: raise Http404 - url = submission.plagiarism_report.get_report_url() + url = submission.iThenticate_plagiarism_report.get_report_url() if not url: raise Http404