diff --git a/comments/migrations/0017_auto_20170729_0717.py b/comments/migrations/0017_auto_20170729_0717.py index db86be1347d9f1c75a3c61ef6d07bf5028ae94c9..8ac6202aae5df406daa83cbee1b9f94c043ded68 100644 --- a/comments/migrations/0017_auto_20170729_0717.py +++ b/comments/migrations/0017_auto_20170729_0717.py @@ -11,10 +11,10 @@ from guardian.shortcuts import assign_perm def update_all_contenttypes(**kwargs): from django.apps import apps - from django.contrib.contenttypes.management import update_contenttypes + from django.contrib.contenttypes.management import create_contenttypes for app_config in apps.get_app_configs(): - update_contenttypes(app_config, **kwargs) + create_contenttypes(app_config, **kwargs) def create_all_permissions(**kwargs): diff --git a/scipost/permissions.py b/scipost/permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..a9a936925fa6dc6560fc94c8f4d3340c2b9e6cff --- /dev/null +++ b/scipost/permissions.py @@ -0,0 +1,6 @@ + +def is_tester(user): + """ + This method checks if user is member of the Test Group. + """ + return user.groups.filter(name='Testers').exists() diff --git a/scipost/static/scipost/assets/css/_pool.scss b/scipost/static/scipost/assets/css/_pool.scss new file mode 100644 index 0000000000000000000000000000000000000000..5a59e0df5e3c27754ad7f0804bdc167be7f4c14e --- /dev/null +++ b/scipost/static/scipost/assets/css/_pool.scss @@ -0,0 +1,39 @@ +$pool-icons-width: 40px; +$pool-flex-width: calc(100% - 40px); + + +.editorial-admin, +.pool { + .pool-item { + .icons { + padding-left: 10px; + padding-right: 10px; + position: relative; + min-height: 1px; + flex: 0 0 $pool-icons-width; + max-width: $pool-icons-width; + } + + .item { + flex: 0 0 $pool-flex-width; + width: $pool-flex-width; + max-width: none; + } + } + + .card.submission-detail { + position: sticky; + top: 15px; + } + + #details .loading { + position: sticky; + top: 15px; + padding: 5rem 0 3rem 0; + text-align: center; + } + + li.active { + background-color: $gray-100; + } +} diff --git a/scipost/static/scipost/assets/css/_type.scss b/scipost/static/scipost/assets/css/_type.scss index 9f21c44547325bbbf1055366f00574a18cc4a3b2..056fe6dcb5bb8c21f77aee7affb8a68a0cfec105 100644 --- a/scipost/static/scipost/assets/css/_type.scss +++ b/scipost/static/scipost/assets/css/_type.scss @@ -112,28 +112,6 @@ hr.hr12 { margin-bottom: 0; } -.circle, -.circle-clickable { - display: inline-block; - background: #fff; - border: 2px solid #333; - color: #333; - border-radius: 100%; - width: 17px; - height: 17px; - line-height: 16px; - text-align: center; - font-size: 9px; - transition: 0.1s; -} - -.circle-clickable { - cursor: pointer; - color: #bbb; - border-color: #bbb; - - &:hover { - border-color: #333; - color: #333; - } +.fa[data-toggle="tooltip"] { + font-size: 1.5em; } diff --git a/scipost/static/scipost/assets/css/style.scss b/scipost/static/scipost/assets/css/style.scss index 5c8bb75eef61d1059c45fa6a2e6d1f86d20e8b1f..be68d319863f3b5d962c823aca10301be2f28b73 100644 --- a/scipost/static/scipost/assets/css/style.scss +++ b/scipost/static/scipost/assets/css/style.scss @@ -31,6 +31,7 @@ @import "navbar"; @import "nav"; @import "page_header"; +@import "pool"; @import "popover"; @import "tables"; @import "tooltip"; diff --git a/scipost/static/scipost/assets/js/scripts.js b/scipost/static/scipost/assets/js/scripts.js index e16263ae7d94b480e54096a08385c61e00e893ba..fcc6ddc4c8d8d56b05c1ad16940e917cccc6342c 100644 --- a/scipost/static/scipost/assets/js/scripts.js +++ b/scipost/static/scipost/assets/js/scripts.js @@ -20,6 +20,19 @@ var getUrlParameter = function getUrlParameter(sParam) { } }; +function init_page() { + // Show right tab if url contains `tab` GET request + var tab = getUrlParameter('tab') + if (tab) { + $('a[href="#' + tab + '"][data-toggle="tab"]').tab('show'); + } + + // Auto-submit hook for general form elements + $("form .auto-submit input, form.auto-submit input, form.auto-submit select").on('change', function(){ + $(this).parents('form').submit() + }); +} + $(function(){ // Remove all alerts in screen automatically after 15sec. setTimeout(function() {hide_all_alerts()}, 15000); @@ -29,20 +42,33 @@ $(function(){ $($(this).attr('data-target')).toggle(); }); - // Show right tab if url contains `tab` GET request - var tab = getUrlParameter('tab') - if (tab) { - $('a[href="#' + tab + '"][data-toggle="tab"]').tab('show'); - } - // Change `tab` GET parameter for page-reload $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { var tab_name = e.target.hash.substring(1) window.history.replaceState({}, null, '?tab=' + tab_name); }); - // Auto-submit hook for general form elements - $("form .auto-submit input").on('change', function(){ - $(this).parents('form').submit() + init_page(); + + // Simple simple Angular-like loading! + $('a[data-toggle="dynamic"]').on('click', function(event) { + event.preventDefault(); + var self = this, + url = $(this).attr('href'), + target = $(this).attr('data-target'); + // console.log('click', url, target); + + $(target).html('<div class="loading"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i></div>'); + + $.get(url + '?json=1').done(function(data) { + // console.log('done', data); + $(target).html(data); + $('[data-target="active-list"]') + .find('> li') + .removeClass('active') + $(self).parents('[data-target="active-list"] > li') + .addClass('active'); + init_page(); + }); }); }); diff --git a/scipost/templatetags/scipost_extras.py b/scipost/templatetags/scipost_extras.py index 25c81e2b02c48f6bed015b8762147284b36d828e..a378cf31277cdda85e8874504559044eeb7d42a1 100644 --- a/scipost/templatetags/scipost_extras.py +++ b/scipost/templatetags/scipost_extras.py @@ -12,7 +12,9 @@ register = template.Library() @register.filter(name='sort_by') def sort_by(queryset, order): - return queryset.order_by(order) + if queryset: + return queryset.order_by(order) + return None @register.filter(name='duration') diff --git a/submissions/__init__.py b/submissions/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1c2ca927d5cf740e7bfc6703a73f1e0f550ea623 100644 --- a/submissions/__init__.py +++ b/submissions/__init__.py @@ -0,0 +1 @@ +default_app_config = 'submissions.apps.SubmissionsConfig' diff --git a/submissions/apps.py b/submissions/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..51d7411cf0f3b4c3d4c41624e4b11733d3bded4f --- /dev/null +++ b/submissions/apps.py @@ -0,0 +1,19 @@ +from django.apps import AppConfig +from django.db.models.signals import post_save + + +class SubmissionsConfig(AppConfig): + name = 'submissions' + + def ready(self): + super().ready() + + from . import models, signals + post_save.connect(signals.notify_new_manuscript_submitted, + sender=models.Submission) + post_save.connect(signals.notify_new_editorial_recommendation, + sender=models.EICRecommendation) + post_save.connect(signals.notify_new_editorial_assignment, + sender=models.EditorialAssignment) + post_save.connect(signals.notify_new_referee_invitation, + sender=models.RefereeInvitation) diff --git a/submissions/forms.py b/submissions/forms.py index fe47475e57d4c1f80e52bd8bb1c246dddab27ba0..1fd5527db82fa9c742d3dc13888280e6852e2e85 100644 --- a/submissions/forms.py +++ b/submissions/forms.py @@ -12,7 +12,7 @@ from .constants import ASSIGNMENT_BOOL, ASSIGNMENT_REFUSAL_REASONS, STATUS_RESUB REPORT_ACTION_CHOICES, REPORT_REFUSAL_CHOICES, STATUS_REVISION_REQUESTED,\ STATUS_REJECTED, STATUS_REJECTED_VISIBLE, STATUS_RESUBMISSION_INCOMING,\ STATUS_DRAFT, STATUS_UNVETTED, REPORT_ACTION_ACCEPT, REPORT_ACTION_REFUSE,\ - STATUS_VETTED, EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS + STATUS_VETTED, EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS, SUBMISSION_STATUS from . import exceptions, helpers from .models import Submission, RefereeInvitation, Report, EICRecommendation, EditorialAssignment,\ iThenticateReport @@ -42,6 +42,22 @@ class SubmissionSearchForm(forms.Form): ) +class SubmissionPoolFilterForm(forms.Form): + status = forms.ChoiceField(choices=((None, 'All statuses'),) + SUBMISSION_STATUS, + required=False) + editor_in_charge = forms.BooleanField(label='Show only Submissions for which I am editor in charge.', required=False) + + def search(self, queryset, current_contributor=None): + if self.cleaned_data.get('status'): + # Do extra check on non-required field to never show errors on template + queryset = queryset.filter(status=self.cleaned_data['status']) + + if self.cleaned_data.get('editor_in_charge') and current_contributor: + queryset = queryset.filter(editor_in_charge=current_contributor) + + return queryset + + ############################### # Submission and resubmission # ############################### @@ -55,6 +71,7 @@ class SubmissionChecks: last_submission = None def __init__(self, *args, **kwargs): + self.requested_by = kwargs.pop('requested_by', None) super().__init__(*args, **kwargs) # Prefill `is_resubmission` property if data is coming from initial data if kwargs.get('initial', None): @@ -105,6 +122,11 @@ class SubmissionChecks: self.last_submission = submission if submission.status == STATUS_REVISION_REQUESTED: self.is_resubmission = True + if self.requested_by.contributor not in submission.authors.all(): + error_message = ('There exists a preprint with this arXiv identifier ' + 'but an earlier version number. Resubmission is only possible' + ' if you are a registered author of this manuscript.') + raise forms.ValidationError(error_message) elif submission.status in [STATUS_REJECTED, STATUS_REJECTED_VISIBLE]: error_message = ('This arXiv preprint has previously undergone refereeing ' 'and has been rejected. Resubmission is only possible ' @@ -222,7 +244,6 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm): } def __init__(self, *args, **kwargs): - self.requested_by = kwargs.pop('requested_by', None) super().__init__(*args, **kwargs) if not self.submission_is_resubmission(): diff --git a/submissions/managers.py b/submissions/managers.py index d9094c7e45b2796fc6fd382db27c487a5ac70709..6b90ccf671d91f07da6cd3514fa1a99c4cc39d4e 100644 --- a/submissions/managers.py +++ b/submissions/managers.py @@ -199,8 +199,8 @@ class EditorialAssignmentQuerySet(models.QuerySet): def ongoing(self): return self.filter(completed=False).accepted() - def in_consideration(self): - return self.filter(deprecated=False).ignored() + def open(self): + return self.filter(accepted=None, deprecated=False) class EICRecommendationManager(models.Manager): diff --git a/submissions/migrations/0061_auto_20170727_1012.py b/submissions/migrations/0061_auto_20170727_1012.py index af6a59d02f96680652df95d98b9354de9c0fd5fd..68ee18e4cbec33f3ad1ac06f40af4c36c704bbe9 100644 --- a/submissions/migrations/0061_auto_20170727_1012.py +++ b/submissions/migrations/0061_auto_20170727_1012.py @@ -6,8 +6,6 @@ from django.db import migrations from guardian.shortcuts import assign_perm -from ..models import Report - def do_nothing(apps, schema_editor): return @@ -18,7 +16,7 @@ def update_eic_permissions(apps, schema_editor): Grant EIC of submission related to unvetted Reports permission to vet his submission's Report. """ - # Report = apps.get_model('submissions', 'Report') -- This doesn't work due to shitty imports + Report = apps.get_model('submissions', 'Report') count = 0 for rep in Report.objects.filter(status='unvetted'): eic_user = rep.submission.editor_in_charge diff --git a/submissions/models.py b/submissions/models.py index 488e934f946f20f1b7bab4fa91f6afea7f58b3f0..401e6caef049192a906ea7e12a4d7cf2d41c4fa7 100644 --- a/submissions/models.py +++ b/submissions/models.py @@ -276,6 +276,9 @@ class EditorialAssignment(SubmissionRelatedObjectMixin, models.Model): self.submission.title[:30] + ' by ' + self.submission.author_list[:30] + ', requested on ' + self.date_created.strftime('%Y-%m-%d')) + def get_absolute_url(self): + return reverse('submissions:assignment_request', args=(self.id,)) + class RefereeInvitation(SubmissionRelatedObjectMixin, models.Model): submission = models.ForeignKey('submissions.Submission', on_delete=models.CASCADE, @@ -504,9 +507,11 @@ class EICRecommendation(SubmissionRelatedObjectMixin, models.Model): # Editorial Fellows who have assessed this recommendation: eligible_to_vote = models.ManyToManyField('scipost.Contributor', blank=True, related_name='eligible_to_vote') - voted_for = models.ManyToManyField(Contributor, blank=True, related_name='voted_for') - voted_against = models.ManyToManyField(Contributor, blank=True, related_name='voted_against') - voted_abstain = models.ManyToManyField(Contributor, blank=True, related_name='voted_abstain') + voted_for = models.ManyToManyField('scipost.Contributor', blank=True, related_name='voted_for') + voted_against = models.ManyToManyField('scipost.Contributor', blank=True, + related_name='voted_against') + voted_abstain = models.ManyToManyField('scipost.Contributor', blank=True, + related_name='voted_abstain') voting_deadline = models.DateTimeField('date submitted', default=timezone.now) objects = EICRecommendationManager() @@ -515,6 +520,10 @@ class EICRecommendation(SubmissionRelatedObjectMixin, models.Model): return (self.submission.title[:20] + ' by ' + self.submission.author_list[:30] + ', ' + self.get_recommendation_display()) + def get_absolute_url(self): + # TODO: Fix this weird redirect, but it's neccesary for the notifications to have one. + return self.submission.get_absolute_url() + @property def nr_for(self): return self.voted_for.count() diff --git a/submissions/signals.py b/submissions/signals.py new file mode 100644 index 0000000000000000000000000000000000000000..664ff585d5255a68d32b3ef6c949d79ab58edda3 --- /dev/null +++ b/submissions/signals.py @@ -0,0 +1,51 @@ +from django.contrib.auth.models import User, Group + +from notifications.signals import notify + + +def notify_new_manuscript_submitted(sender, instance, created, **kwargs): + """ + Notify the Editorial Administration about a new Submission submitted. + """ + if created: + administrators = User.objects.filter(groups__name='Editorial Administrators') + for user in administrators: + notify.send(sender=sender, recipient=user, actor=instance.submitted_by, + verb=' submitted a new manuscript.', target=instance) + + +def notify_new_editorial_recommendation(sender, instance, created, **kwargs): + """ + Notify the Editorial Recommendation about a new Submission submitted. + """ + if created: + administrators = User.objects.filter(groups__name='Editorial Administrators') + editor_in_charge = instance.submission.editor_in_charge + for user in administrators: + notify.send(sender=sender, recipient=user, actor=editor_in_charge, + verb=' formulated a new Editorial Recommendation.', target=instance) + + +def notify_new_editorial_assignment(sender, instance, created, **kwargs): + """ + Notify a College Fellow about a new EIC invitation. + """ + if created: + administration = Group.objects.get(name='Editorial Administrators') + if instance.accepted: + # A new assignment is auto-accepted if user assigned himself or on resubmission. + text = ' assigned you Editor-in-charge.' + else: + text = ' invited you to become Editor-in-charge.' + notify.send(sender=sender, recipient=instance.to.user, actor=administration, + verb=text, target=instance) + + +def notify_new_referee_invitation(sender, instance, created, **kwargs): + """ + Notify a Referee about a new refereeing invitation. + """ + if created: + notify.send(sender=sender, recipient=instance.referee.user, + actor=instance.submission.editor_in_charge, + verb=' would like to invite you to referee a Submission.', target=instance) diff --git a/submissions/templates/partials/submissions/admin/editorial_admin_summary.html b/submissions/templates/partials/submissions/admin/editorial_admin_summary.html deleted file mode 100644 index 65fdf4c9c44de594f708607afe66a71fbed717ca..0000000000000000000000000000000000000000 --- a/submissions/templates/partials/submissions/admin/editorial_admin_summary.html +++ /dev/null @@ -1,144 +0,0 @@ -{% load guardian_tags %} -{% load scipost_extras %} -{% load submissions_extras %} - - -<h5 class="pb-0">{{submission.get_subject_area_display}}</h5> -<h3 class="card-title"> - <a href="{{submission.get_absolute_url}}">{{submission.title}}</a> -</h3> - -<p class="card-text mb-3">by {{submission.author_list}}</p> -<h3>Info</h3> -<table class="text-muted w-100 mb-1"> - <tr> - <td style="min-width: 40%;">Version</td> - <td>{{submission.arxiv_vn_nr}} ({% if submission.is_current %}current version{% else %}deprecated version {{submission.arxiv_vn_nr}}{% endif %})</td> - </tr> - <tr> - <td>Submitted</td> - <td>{{submission.submission_date}} to {{submission.get_submitted_to_journal_display}}</td> - </tr> - - {% if submission.acceptance_date %} - <tr> - <td>Accepted</td> - <td>{{submission.acceptance_date}}</td> - </tr> - {% endif %} - - <tr> - <td>Latest activity</td> - <td>{{submission.latest_activity}}</td> - </tr> - <tr> - <td>Editor-in-charge</td> - <td> - {% if submission.editor_in_charge %} - {{ submission.editor_in_charge }} - {% elif perms.scipost.can_assign_submissions %} - <a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a new assignment request</a> - {% else %} - - - {% endif %} - </td> - </tr> - <tr> - <td>Status</td> - <td>{{ submission.get_status_display }}</td> - </tr> - <tr> - <td>Refereeing cycle</td> - <td>{{ submission.get_refereeing_cycle_display }}</td> - </tr> - - {% include 'partials/submissions/refereeing_status_as_tr.html' with submission=submission %} - - <tr> - <td>Comments</td> - <td> - {{submission.comments.vetted.count}} - <span class="circle-clickable" data-toggle="tooltip" data-placement='bottom' data-html="true" title="{{submission.comments.regular_comments.vetted.count}} comments<br>{{submission.comments.author_replies.vetted.count}} author replies<hr>{{submission.comments.awaiting_vetting.count}} awaiting vetting">?</span> - </td> - </tr> - - <tr> - <td>Reporting deadline</td> - <td> - {% if submission.reporting_deadline > now %} - in {{submission.reporting_deadline|timeuntil}} - {% else %} - {{submission.reporting_deadline|timesince}} ago - {% endif %} - </td> - </tr> - - <tr> - <td>Plagiarism score</td> - <td> - {% if submission.plagiarism_report %} - {{ submission.plagiarism_report.score }}% - {% else %} - <a href="{% url 'submissions:plagiarism' submission.arxiv_identifier_w_vn_nr %}">Run plagiarism check</a> - {% endif %} - </td> - </tr> - -</table> -<a href="{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}" class="d-inline-block mb-3">Go to Editorial Page</a> - -<h3>Actions</h3> - -<ul class="pl-4 mb-3"> - {# EIC Assignments #} - {% if perms.scipost.can_assign_submissions %} - {% if not submission.editor_in_charge %} - <li>EIC Assignment requests:</li> - <ul> - {% for assignment in submission.editorial_assignments.all %} - {% include 'submissions/_assignment_info.html' with assignment=assignment %} - {% empty %} - <li>None found. <a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a first assignment request</a></li> - {% endfor %} - </ul> - <li><a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a new assignment request</a></li> - <li><a href="{% url 'submissions:assignment_failed' submission.arxiv_identifier_w_vn_nr %}">Close pre-screening: failure to find EIC</a></li> - {% endif %} - {% endif %} - - {# Plagiarism #} - <li><a href="{% url 'submissions:plagiarism' submission.arxiv_identifier_w_vn_nr %}">Manage plagiarism report</a></li> - - {# Compile pdfs #} - {% if submission.reports.accepted.exists %} - <li><a href="{% url 'submissions:reports_accepted_list' %}?submission={{submission.arxiv_identifier_w_vn_nr}}">Compile accepted reports</a></li> - {% endif %} - - {# Communication #} - {% if submission.editor_in_charge %} - <li><a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='StoE' %}">Send a communication to the Editor-in-charge</a></li> - {% endif %} - - {# EIC Recommendations #} - {% if submission.eicrecommendations.exists %} - <li>See Editorial Recommendations:</li> - <ul> - {% for rec in submission.eicrecommendations.all %} - <li><a href="{% url 'submissions:eic_recommendation_detail' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr rec_id=rec.id %}">{{rec.get_recommendation_display}}</a></li> - {% endfor %} - </ul> - {% endif %} - - {# Accepted submission actions #} - {% if submission.status == 'accepted' %} - <li><a href="{% url 'submissions:treated_submission_pdf_compile' submission.arxiv_identifier_w_vn_nr %}">Update the Refereeing Package pdf</a></li> - <li>After proofs have been accepted, you can <a href="{% url 'journals:initiate_publication' %}">initiate the publication process</a> (leads to the validation page)</li> - {% endif %} -</ul> - - -<h3>Events</h3> -<a href="javascript:;" data-toggle="toggle" data-target="#eventslist">Show/hide events</a> -<div id="eventslist"> - {% include 'submissions/submission_event_list.html' with events=submission.events.for_eic %} -</div> diff --git a/submissions/templates/partials/submissions/admin/recommendation_tooltip.html b/submissions/templates/partials/submissions/admin/recommendation_tooltip.html new file mode 100644 index 0000000000000000000000000000000000000000..79e47405ebb8b2c351e301b36784232fccf40907 --- /dev/null +++ b/submissions/templates/partials/submissions/admin/recommendation_tooltip.html @@ -0,0 +1,9 @@ +<i class="fa fa-info-circle {{ classes }}" data-toggle="tooltip" data-html="true" title=" + Eligible to vote ({{ recommendation.eligible_to_vote.count }}) + <hr> + Agreed ({{ recommendation.voted_for.count }}) + <br> + Disagreed ({{ recommendation.voted_against.count }}) + <br> + Abstained ({{ recommendation.voted_abstain.count }}) +"></i> diff --git a/submissions/templates/partials/submissions/admin/submission_details.html b/submissions/templates/partials/submissions/admin/submission_details.html new file mode 100644 index 0000000000000000000000000000000000000000..39969bdc536c7e7dc0974c1fdb5ceaf89b2bd093 --- /dev/null +++ b/submissions/templates/partials/submissions/admin/submission_details.html @@ -0,0 +1,147 @@ +{% load guardian_tags %} +{% load scipost_extras %} +{% load submissions_extras %} + + +<div class="card border-secondary mt-2 submission-detail"> + <div class="card-body"> + <h5 class="pb-0">{{submission.get_subject_area_display}}</h5> + <h3 class="card-title"> + <a href="{{submission.get_absolute_url}}">{{submission.title}}</a> + </h3> + + <p class="card-text mb-3">by {{submission.author_list}}</p> + <h3>Info</h3> + <table class="text-muted w-100 mb-1"> + <tr> + <td style="min-width: 40%;">Version</td> + <td>{{submission.arxiv_vn_nr}} ({% if submission.is_current %}current version{% else %}deprecated version {{submission.arxiv_vn_nr}}{% endif %})</td> + </tr> + <tr> + <td>Submitted</td> + <td>{{submission.submission_date}} to {{submission.get_submitted_to_journal_display}}</td> + </tr> + + {% if submission.acceptance_date %} + <tr> + <td>Accepted</td> + <td>{{submission.acceptance_date}}</td> + </tr> + {% endif %} + + <tr> + <td>Latest activity</td> + <td>{{submission.latest_activity}}</td> + </tr> + <tr> + <td>Editor-in-charge</td> + <td> + {% if submission.editor_in_charge %} + {{ submission.editor_in_charge }} + {% elif perms.scipost.can_assign_submissions %} + <a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a new assignment request</a> + {% else %} + - + {% endif %} + </td> + </tr> + <tr> + <td>Status</td> + <td>{{ submission.get_status_display }}</td> + </tr> + <tr> + <td>Refereeing cycle</td> + <td>{{ submission.get_refereeing_cycle_display }}</td> + </tr> + + {% include 'partials/submissions/refereeing_status_as_tr.html' with submission=submission %} + + <tr> + <td>Comments</td> + <td> + {{submission.comments.vetted.count}} + <span class="circle-clickable" data-toggle="tooltip" data-placement='bottom' data-html="true" title="{{submission.comments.regular_comments.vetted.count}} comments<br>{{submission.comments.author_replies.vetted.count}} author replies<hr>{{submission.comments.awaiting_vetting.count}} awaiting vetting">?</span> + </td> + </tr> + + <tr> + <td>Reporting deadline</td> + <td> + {% if submission.reporting_deadline > now %} + in {{submission.reporting_deadline|timeuntil}} + {% else %} + {{submission.reporting_deadline|timesince}} ago + {% endif %} + </td> + </tr> + + <tr> + <td>Plagiarism score</td> + <td> + {% if submission.plagiarism_report %} + {{ submission.plagiarism_report.score }}% + {% else %} + <a href="{% url 'submissions:plagiarism' submission.arxiv_identifier_w_vn_nr %}">Run plagiarism check</a> + {% endif %} + </td> + </tr> + + </table> + <a href="{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}" class="d-inline-block mb-3">Go to Editorial Page</a> + + <h3>Actions</h3> + + <ul class="pl-4 mb-3"> + {# EIC Assignments #} + {% if perms.scipost.can_assign_submissions %} + {% if not submission.editor_in_charge %} + <li>EIC Assignment requests:</li> + <ul> + {% for assignment in submission.editorial_assignments.all %} + {% include 'submissions/_assignment_info.html' with assignment=assignment %} + {% empty %} + <li>None found. <a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a first assignment request</a></li> + {% endfor %} + </ul> + <li><a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a new assignment request</a></li> + <li><a href="{% url 'submissions:assignment_failed' submission.arxiv_identifier_w_vn_nr %}">Close pre-screening: failure to find EIC</a></li> + {% endif %} + {% endif %} + + {# Plagiarism #} + <li><a href="{% url 'submissions:plagiarism' submission.arxiv_identifier_w_vn_nr %}">Manage plagiarism report</a></li> + + {# Compile pdfs #} + {% if submission.reports.accepted.exists %} + <li><a href="{% url 'submissions:reports_accepted_list' %}?submission={{submission.arxiv_identifier_w_vn_nr}}">Compile accepted reports</a></li> + {% endif %} + + {# Communication #} + {% if submission.editor_in_charge %} + <li><a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='StoE' %}">Send a communication to the Editor-in-charge</a></li> + {% endif %} + + {# EIC Recommendations #} + {% if submission.eicrecommendations.exists %} + <li>See Editorial Recommendations:</li> + <ul> + {% for rec in submission.eicrecommendations.all %} + <li><a href="{% url 'submissions:eic_recommendation_detail' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr rec_id=rec.id %}">{{rec.get_recommendation_display}}</a></li> + {% endfor %} + </ul> + {% endif %} + + {# Accepted submission actions #} + {% if submission.status == 'accepted' %} + <li><a href="{% url 'submissions:treated_submission_pdf_compile' submission.arxiv_identifier_w_vn_nr %}">Update the Refereeing Package pdf</a></li> + <li>After proofs have been accepted, you can <a href="{% url 'journals:initiate_publication' %}">initiate the publication process</a> (leads to the validation page)</li> + {% endif %} + </ul> + + + <h3>Events</h3> + <div id="eventslist"> + {% include 'submissions/submission_event_list.html' with events=submission.events.for_eic %} + </div> + </div> +</div> diff --git a/submissions/templates/partials/submissions/admin/submission_li.html b/submissions/templates/partials/submissions/admin/submission_li.html index 863ad5c59ab3a4473c07d54e080daa2b8d5200fd..0581df05cb3f822992a09b38bb1357069bc57e87 100644 --- a/submissions/templates/partials/submissions/admin/submission_li.html +++ b/submissions/templates/partials/submissions/admin/submission_li.html @@ -1,5 +1,24 @@ -<a href="{% url 'submissions:admin' submission.arxiv_identifier_w_vn_nr %}">{{submission.title}}</a> -<div class="pl-md-4"> - <em>by {{submission.author_list}}</em><br> - latest activity: {{submission.latest_activity|timesince}} ago +<div class="row pool-item mb-0"> + <div class="icons{% if is_current %} text-info{% endif %}"> + {% include 'partials/submissions/admin/submission_tooltip.html' with submission=submission %} + + {% if submission.status == 'unassigned' %} + <i class="fa fa-exclamation mt-1 px-1 text-danger" data-toggle="tooltip" data-html="true" title="This Submission does not have a Editor-in-charge"></i> + {% endif %} + </div> + <div class="item col-auto"> + <p class="mb-1"> + <a href="{% url 'submissions:admin' submission.arxiv_identifier_w_vn_nr %}">{{ submission.title }}</a><br> + <em>by {{ submission.author_list }}</em> + </p> + + <p class="card-text mb-2"> + <a href="{% url 'submissions:admin' submission.arxiv_identifier_w_vn_nr %}" data-toggle="dynamic" data-target="#details" data-toggle="dynamic" data-target="">See details</a> + {% if submission.editor_in_charge == request.user.contributor %} + · <a href="{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}">Go directly to editorial page</a> + {% endif %} + </p> + + <p class="label label-{% if submission.status == 'unassigned' %}outline-danger{% else %}secondary{% endif %} label-sm">{{ submission.get_status_display }}</p> + </div> </div> diff --git a/submissions/templates/partials/submissions/admin/submission_tooltip.html b/submissions/templates/partials/submissions/admin/submission_tooltip.html index c2968b9a79145bbd96ea69ada144e497ee8f85a3..bdd541b910663d2361fb20b7bf4c1e85aa1ad565 100644 --- a/submissions/templates/partials/submissions/admin/submission_tooltip.html +++ b/submissions/templates/partials/submissions/admin/submission_tooltip.html @@ -1,4 +1,4 @@ -<span class="circle-clickable no-break" data-toggle="tooltip" data-html="true" +<i class="fa fa-info-circle" data-toggle="tooltip" data-html="true" title=" {{submission.arxiv_identifier_w_vn_nr}}<hr>Status: {{submission.get_status_display}}<br>Latest activity: {{submission.latest_activity}} -">?</span> +"></i> diff --git a/submissions/templates/partials/submissions/pool/required_actions_tooltip.html b/submissions/templates/partials/submissions/pool/required_actions_tooltip.html new file mode 100644 index 0000000000000000000000000000000000000000..1e9ce2a7234240d0a5ef96e121cb45c37f694b06 --- /dev/null +++ b/submissions/templates/partials/submissions/pool/required_actions_tooltip.html @@ -0,0 +1,10 @@ +{% if submission.cycle.has_required_actions and submission.cycle.get_required_actions %} + <i class="fa fa-exclamation-circle {{ classes }}" data-toggle="tooltip" data-html="true" title=" + Required Actions: + <ul class='mb-0 pl-3 text-left'> + {% for action in submission.cycle.get_required_actions %} + <li>{{action.1}}</li> + {% endfor %} + </ul> + "></i> +{% endif %} diff --git a/submissions/templates/partials/submissions/pool/submission_details.html b/submissions/templates/partials/submissions/pool/submission_details.html new file mode 100644 index 0000000000000000000000000000000000000000..7d8014f7785485d4fa6f3c248cba41d7e122d13a --- /dev/null +++ b/submissions/templates/partials/submissions/pool/submission_details.html @@ -0,0 +1,58 @@ +{% load guardian_tags %} +{% load scipost_extras %} +{% load submissions_extras %} + + +<div class="card submission-detail"> + {% include 'submissions/_submission_card_fellow_content.html' with submission=submission %} + + <div class="card-body"> + {% if submission.remarks.all %} + <h4>Remarks on this submission:</h4> + <ul> + {% for rem in submission.remarks.all %} + {% include 'scipost/_remark_li.html' with remark=rem %} + {% endfor %} + </ul> + {% endif %} + + {% if remark_form %} + {% include 'submissions/_remark_add_form.html' with submission=submission form=remark_form auto_show=1 %} + {% endif %} + + {% get_obj_perms request.user for submission as "sub_perms" %} + {% if "can_take_editorial_actions" in sub_perms or is_ECAdmin %} + {% include 'submissions/_required_actions_block.html' with submission=submission %} + <h4> + <a href="{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}">Go to this Submission's Editorial Page</a> + </h4> + {% endif %} + + {% if perms.scipost.can_assign_submissions %} + {% if submission.editorial_assignments.exists %} + <h4>EIC Assignment requests:</h4> + <ul> + {% for assignment in submission.editorial_assignments.all %} + {% include 'submissions/_assignment_info.html' with assignment=assignment %} + {% endfor %} + </ul> + {% endif %} + {% if submission.editor_in_charge == None %} + <h4>Actions:</h4> + <ul> + <li><a href="{% url 'submissions:assign_submission' submission.arxiv_identifier_w_vn_nr %}">Send a new assignment request</a></li> + <li><a href="{% url 'submissions:assignment_failed' submission.arxiv_identifier_w_vn_nr %}">Close pre-screening: failure to find EIC</a></li> + </ul> + {% endif %} + {% endif %} + + {% if is_ECAdmin %} + <h4> + <a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='StoE' %}">Send a communication to the Editor-in-charge</a> + </h4> + {% if submission.status == 'accepted' %} + <h4>After proofs have been accepted, you can <a href="{% url 'journals:initiate_publication' %}">initiate the publication process</a> (leads to the validation page)</h4> + {% endif %} + {% endif %} + </div> +</div> diff --git a/submissions/templates/partials/submissions/pool/submission_li.html b/submissions/templates/partials/submissions/pool/submission_li.html new file mode 100644 index 0000000000000000000000000000000000000000..73bc7fa516e69125906942aef32ac11b5fbac287 --- /dev/null +++ b/submissions/templates/partials/submissions/pool/submission_li.html @@ -0,0 +1,37 @@ +<div class="row pool-item mb-0"> + <div class="icons{% if is_current %} text-info{% endif %}"> + {% include 'partials/submissions/admin/submission_tooltip.html' with submission=submission %} + + {% if submission.status == 'unassigned' %} + <i class="fa fa-exclamation mt-1 px-1 text-danger" data-toggle="tooltip" data-html="true" title="You can volunteer to become Editor-in-charge"></i> + {% endif %} + </div> + <div class="item col-auto"> + <p class="mb-1"> + <a href="{% url 'submissions:pool' submission.arxiv_identifier_w_vn_nr %}">{{ submission.title }}</a><br> + <em>by {{ submission.author_list }}</em> + </p> + + <p class="card-text mb-3"> + <a href="{% url 'submissions:pool' submission.arxiv_identifier_w_vn_nr %}" data-toggle="dynamic" data-target="#details">See details</a> + {% if submission.editor_in_charge == request.user.contributor %} + · <a href="{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}">Go directly to editorial page</a> + {% endif %} + </p> + + {% if submission.cycle.has_required_actions and submission.cycle.get_required_actions %} + <p class="card-text bg-danger text-white p-1 px-2">This Submission contains required actions, <a href="{% url 'submissions:pool' submission.arxiv_identifier_w_vn_nr %}" class="text-white" data-toggle="dynamic" data-target="#details">click to see details.</a> {% include 'partials/submissions/pool/required_actions_tooltip.html' with submission=submission classes='text-white' %}</p> + {% endif %} + + {% if submission.status == 'unassigned' %} + <p class="card-text text-danger">You can volunteer to become Editor-in-charge by <a href="{% url 'submissions:volunteer_as_EIC' submission.arxiv_identifier_w_vn_nr %}">clicking here</a>.</p> + {% elif submission.editor_in_charge == request.user.contributor %} + <p class="card-text"><strong>You are Editor-in-charge</strong></p> + {% else %} + <p class="card-text">Editor-in-charge: <em>{{ submission.editor_in_charge }}</em></p> + {% endif %} + + <p class="label label-{% if submission.status == 'unassigned' %}outline-danger{% else %}secondary{% endif %} label-sm">{{ submission.get_status_display }}</p> + + </div> +</div> diff --git a/submissions/templates/submissions/_remark_add_form.html b/submissions/templates/submissions/_remark_add_form.html index 1541145e29fca3ec142bae5ec2d6fde733a54bea..f2872b2a19755ab5d12e5f230171d049ad97a865 100644 --- a/submissions/templates/submissions/_remark_add_form.html +++ b/submissions/templates/submissions/_remark_add_form.html @@ -16,11 +16,19 @@ $(document).ready(function(){ }); </script> -<button class="btn btn-secondary mb-2" data-toggle="toggle" data-target="#remarkForm{{ submission.id }}" id="remarkButton{{ submission.id }}">Add a remark on this Submission</button> -<div class="submitRemarkForm pb-2" id="remarkForm{{ submission.id }}" style="display:none;"> - <form action="{% url 'submissions:add_remark' submission.arxiv_identifier_w_vn_nr %}" method="post"> +{% if auto_show %} + <form action="{% url 'submissions:add_remark' submission.arxiv_identifier_w_vn_nr %}" method="post" class="pb-2"> {% csrf_token %} {{ form|bootstrap:'0,12' }} <input class="btn btn-secondary" type="submit" value="Submit" /> </form> -</div> +{% else %} + <button class="btn btn-secondary mb-2" data-toggle="toggle" data-target="#remarkForm{{ submission.id }}" id="remarkButton{{ submission.id }}">Add a remark on this Submission</button> + <div class="submitRemarkForm pb-2" id="remarkForm{{ submission.id }}" style="display:none;"> + <form action="{% url 'submissions:add_remark' submission.arxiv_identifier_w_vn_nr %}" method="post"> + {% csrf_token %} + {{ form|bootstrap:'0,12' }} + <input class="btn btn-secondary" type="submit" value="Submit" /> + </form> + </div> +{% endif %} diff --git a/submissions/templates/submissions/_submission_assignment_request.html b/submissions/templates/submissions/_submission_assignment_request.html index cceb540850b6a489ae5161372e3c018177ad76dd..4f274474ef169f87858842bf39fdadcec8618868 100644 --- a/submissions/templates/submissions/_submission_assignment_request.html +++ b/submissions/templates/submissions/_submission_assignment_request.html @@ -8,7 +8,7 @@ <h1>Accept or Decline this Assignment</h1> <h3 class="mb-2">By accepting, you will be required to start a refereeing round on the next screen.</h3> - <form action="{% url 'submissions:accept_or_decline_assignment_ack' assignment_id=assignment.id %}" method="post"> + <form action="{% url 'submissions:assignment_request' assignment_id=assignment.id %}" method="post"> {% csrf_token %} <div class="form-group row"> <div class="col-12"> diff --git a/submissions/templates/submissions/accept_or_decline_assignment_ack.html b/submissions/templates/submissions/accept_or_decline_assignment_ack.html deleted file mode 100644 index 67a7551cca06e5c12e852c533d727220874f89e1..0000000000000000000000000000000000000000 --- a/submissions/templates/submissions/accept_or_decline_assignment_ack.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends 'scipost/base.html' %} - -{% block pagetitle %}: accept or decline assignment (ack){% endblock pagetitle %} - -{% block content %} - - - {% if errormessage %} - <p>{{ errormessage }}</p> - <p>Return to the <a href="{% url 'submissions:pool' %}">Submissions Pool</a>.</p> - - {% elif assignment.accepted %} - <h1>Thank you for becoming Editor-in-charge of this submission.</h1> - <p>Please go to the <a href="{% url 'submissions:editorial_page' arxiv_identifier_w_vn_nr=assignment.submission.arxiv_identifier_w_vn_nr %}">Submission's editorial page</a> and select referees now.</p> - {% else %} - <h1>Thank you for considering.</h1> - <p>Return to the <a href="{% url 'submissions:pool' %}">Submissions Pool</a>.</p> - {% endif %} - -{% endblock content %} diff --git a/submissions/templates/submissions/admin/editorial_admin.html b/submissions/templates/submissions/admin/editorial_admin.html index bd5d36b3dc7ac131e9b0e4a2c1d443ca8b204d23..8c23d6beb54f3791e2f0fda8b08b3590c74bd77d 100644 --- a/submissions/templates/submissions/admin/editorial_admin.html +++ b/submissions/templates/submissions/admin/editorial_admin.html @@ -1,5 +1,7 @@ {% extends 'submissions/admin/base.html' %} +{% load scipost_extras %} + {% block pagetitle %}: Editorial Administration{% endblock pagetitle %} {% block breadcrumb_items %} @@ -7,6 +9,7 @@ <span class="breadcrumb-item">{% if submission %}{{ submission.arxiv_identifier_w_vn_nr }}{% else %}All events in the last 24 hours{% endif %}</span> {% endblock %} +{% block body_class %}{{ block.super }} editorial-admin{% endblock %} {% block content %} <div class="row"> @@ -20,18 +23,38 @@ <a href="{% url 'submissions:pool' %}">Go to the pool</a> </p> + {% if recommendations_to_prepare_for_voting %} + <h3>Recommendations to prepare for voting <i class="fa fa-exclamation-circle text-warning"></i></h3> + <ul> + {% for recommendation in recommendations_to_prepare_for_voting %} + <li>On Editorial Recommendation: {{ recommendation }}<br> + <a href="{% url 'submissions:prepare_for_voting' rec_id=recommendation.id %}">Prepare for voting</a> + </li> + {% endfor %} + </ul> + {% endif %} + + {% if recommendations_undergoing_voting %} + <h3>Recommendations undergoing voting <i class="fa fa-exclamation-circle text-warning"></i></h3> + <ul class="fa-ul"> + {% for recommendation in recommendations_undergoing_voting %} + <li>{% include 'partials/submissions/admin/recommendation_tooltip.html' with classes='fa-li' recommendation=recommendation %} + On Editorial Recommendation: {{ recommendation }}<br> + <a href="{% url 'submissions:admin_recommendation' recommendation.submission.arxiv_identifier_w_vn_nr %}">See Editorial Recommendation</a> + </li> + {% endfor %} + </ul> + {% endif %} + + {% if recommendations_to_prepare_for_voting or recommendations_undergoing_voting %} + <hr> + {% endif %} + <h3>Submissions currently in pre-screening</h3> - <ul class="list-unstyled"> + <ul class="list-unstyled" data-target="active-list"> {% for sub in submission_list.prescreening %} - <li> - {% include 'partials/submissions/admin/submission_tooltip.html' with submission=sub %} - {% if sub == submission %} - <strong> - {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} - </strong> - {% else %} - {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} - {% endif %} + <li class="p-2{% if sub == submission %} active{% endif %}"> + {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} </li> {% empty %} <li>No Submissions are currently in pre-screening</li> @@ -39,17 +62,10 @@ </ul> <h3>Submissions currently in refereeing round</h3> - <ul class="list-unstyled"> + <ul class="list-unstyled" data-target="active-list"> {% for sub in submission_list.actively_refereeing %} - <li> - {% include 'partials/submissions/admin/submission_tooltip.html' with submission=sub %} - {% if sub == submission %} - <strong> - {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} - </strong> - {% else %} - {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} - {% endif %} + <li class="p-2{% if sub == submission %} active{% endif %}"> + {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} </li> {% empty %} <li>No Submissions are currently in refereeing round</li> @@ -57,17 +73,10 @@ </ul> <h3>Submissions accepted</h3> - <ul class="list-unstyled"> + <ul class="list-unstyled" data-target="active-list"> {% for sub in submission_list.accepted %} - <li> - {% include 'partials/submissions/admin/submission_tooltip.html' with submission=sub %} - {% if sub == submission %} - <strong> - {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} - </strong> - {% else %} - {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} - {% endif %} + <li class="p-2{% if sub == submission %} active{% endif %}"> + {% include 'partials/submissions/admin/submission_li.html' with submission=sub %} </li> {% empty %} <li>All accepted Submissions are published</li> @@ -75,13 +84,9 @@ </ul> </div> - <div class="col-md-5"> + <div class="col-md-5" id="details"> {% if submission %} - <div class="card border-secondary mt-2"> - <div class="card-body"> - {% include 'partials/submissions/admin/editorial_admin_summary.html' with submission=submission %} - </div> - </div> + {% include 'partials/submissions/admin/submission_details.html' with submission=submission %} {% else %} <h3><em>Click on a submission to see its summary and actions</em></h3> <h2>All events in the last 24 hours</h2> diff --git a/submissions/templates/submissions/admin/recommendation.html b/submissions/templates/submissions/admin/recommendation.html new file mode 100644 index 0000000000000000000000000000000000000000..a4eed96cbcd805ad7f90cddf7655bfa75873fdae --- /dev/null +++ b/submissions/templates/submissions/admin/recommendation.html @@ -0,0 +1,84 @@ +{% extends 'submissions/pool/base.html' %} + +{% load bootstrap %} +{% load scipost_extras %} + +{% block breadcrumb_items %} + <a href="{% url 'submissions:admin' %}" class="breadcrumb-item">Editorial Administration</a> + <span class="breadcrumb-item">Editorial Recommendation</span> +{% endblock %} + +{% block pagetitle %}: Editorial Recommendation{% endblock pagetitle %} + +{% block content %} + <h1 class="highlight">Editorial Recommendation</h1> + + <div class="card card-outline-secondary"> + {% include 'submissions/_submission_card_fellow_content_sparse.html' with submission=object.submission %} + </div> + + <div class="card card-outline-secondary"> + {% include 'submissions/_recommendation_fellow_content.html' with recommendation=object %} + <div class="card-body"> + {% if object.remarks.exists %} + <h3 class="card-title">Remarks by Fellows:</h3> + <ul> + {% for remark in object.remarks.all|sort_by:'date' %} + {% include 'partials/submissions/remark_as_li.html' with remark=remark %} + {% endfor %} + </ul> + {% endif %} + + <h3 class="card-title">Fellows eligible to vote:</h3> + <ul> + <li> + {% for eligible in object.eligible_to_vote.all|sort_by:'user__last_name' %} + {{ eligible.user.last_name }}, + {% endfor %} + </li> + </ul> + + <h3 class="card-title">Voting results up to now:</h3> + <ul> + <li> + Agreed: ({{ object.voted_for.all.count }}) + {% for agreed in object.voted_for.all|sort_by:'user__last_name' %} + {{ agreed.user.last_name }}, + {% endfor %} + </li> + <li> + Disagreed: ({{ object.voted_against.all.count }}) + {% for disagreed in object.voted_against.all|sort_by:'user__last_name' %} + {{ disagreed.user.last_name }}, + {% endfor %} + </li> + <li> + Abstained: ({{ object.voted_abstain.all.count }}) + {% for abstained in object.voted_abstain.all|sort_by:'user__last_name' %} + {{ abstained.user.last_name }}, + {% endfor %} + </li> + </ul> + + {% if object.remarks.exists %} + <h3 class="card-title">Remarks:</h3> + <ul> + {% for rem in object.remarks.all %} + <li>{{ rem }}</li> + {% empty %} + <li><em>No remarks</em></li> + {% endfor %} + </ul> + {% endif %} + </div> + <div class="card-footer"> + <h3 class="card-title">Administrative actions on recommendations undergoing voting:</h3> + <ul> + <li>To send an email reminder to each Fellow with at least one voting duty: <a href="{% url 'submissions:remind_Fellows_to_vote' %}">click here</a></li> + <li>To fix the College decision and follow the Editorial Recommendation as is: <a href="{% url 'submissions:fix_College_decision' rec_id=object.id %}">click here</a></li> + <li>To request a modification of the Recommendation to request for revision: click here</li> + </ul> + </div> + </div> + +{% endblock %} diff --git a/submissions/templates/submissions/pool/assignment_request.html b/submissions/templates/submissions/pool/assignment_request.html new file mode 100644 index 0000000000000000000000000000000000000000..2f0b46cde76c735220de426c609285ce8f891ef8 --- /dev/null +++ b/submissions/templates/submissions/pool/assignment_request.html @@ -0,0 +1,20 @@ +{% extends 'submissions/pool/base.html' %} + +{% load bootstrap %} +{% load guardian_tags %} +{% load scipost_extras %} +{% load submissions_extras %} + +{% block breadcrumb_items %} + {{ block.super }} + <span class="breadcrumb-item">Assignment Request</span> +{% endblock %} + +{% block pagetitle %}: Assignment Request{% endblock pagetitle %} + +{% block content %} + <h1 class="highlight">Assignment request</h1> + <h3>Can you act as Editor-in-charge? (see below to accept/decline)</h3> + + {% include 'submissions/_submission_assignment_request.html' with assignment=assignment consider_assignment_form=form %} +{% endblock %} diff --git a/submissions/templates/submissions/pool/base.html b/submissions/templates/submissions/pool/base.html new file mode 100644 index 0000000000000000000000000000000000000000..ca638eb5ab558e81c5911ad27e2788d812086d5a --- /dev/null +++ b/submissions/templates/submissions/pool/base.html @@ -0,0 +1,13 @@ +{% extends 'scipost/base.html' %} + +{% block body_class %}{{ block.super }} pool{% endblock %} + +{% block breadcrumb %} + <nav class="breadcrumb py-md-2 px-0"> + <div class="container"> + {% block breadcrumb_items %} + <a href="{% url 'submissions:pool' %}" class="breadcrumb-item">Pool</a> + {% endblock %} + </div> + </nav> +{% endblock %} diff --git a/submissions/templates/submissions/pool/pool.html b/submissions/templates/submissions/pool/pool.html new file mode 100644 index 0000000000000000000000000000000000000000..19c631f12703eca9fef69d3178c20d06b74c0d6f --- /dev/null +++ b/submissions/templates/submissions/pool/pool.html @@ -0,0 +1,91 @@ +{% extends 'submissions/pool/base.html' %} + +{% load bootstrap %} +{% load guardian_tags %} +{% load scipost_extras %} +{% load submissions_extras %} + +{% block breadcrumb_items %} + <a href="{% url 'scipost:personal_page' %}" class="breadcrumb-item">Personal Page</a> + {% if submission %} + <a href="{% url 'submissions:pool' %}" class="breadcrumb-item">Pool</a> + <span class="breadcrumb-item">{{ submission.arxiv_identifier_w_vn_nr }}</span> + {% else %} + <span class="breadcrumb-item">Pool</span> + {% endif %} +{% endblock %} + +{% block pagetitle %}: Submissions Pool{% endblock pagetitle %} + +{% block content %} + {% with is_ECAdmin=request.user|is_in_group:'Editorial Administrators' %} + <a href="{% url 'submissions:pool' %}?test=1">See old pool layout</a> + <div class="row"> + <div class="col-md-7"> + <h1>SciPost Submissions Pool</h1> + {% if is_ECAdmin %} + <a href="{% url 'submissions:admin' %}">Go to the Editorial Administration</a> + {% endif %} + + {% if assignments_to_consider %} + <h3>Your open Assignment Requests <i class="fa fa-exclamation-circle text-warning"></i></h3> + <ul> + {% for assignment in assignments_to_consider %} + <li>On submission: {{ assignment.submission }}<br> + <a href="{% url 'submissions:assignment_request' assignment.id %}">Accept or decline here</a> + </li> + {% endfor %} + </ul> + {% endif %} + + {% if recs_to_vote_on %} + <h3>Recommendations to vote on <i class="fa fa-exclamation-circle text-warning"></i></h3> + <ul> + {% for recommendation in recs_to_vote_on %} + <li>On Editorial Recommendation of: {{ recommendation.submission }}<br> + <a href="{% url 'submissions:vote_on_rec' rec_id=recommendation.id %}">See the Editorial Recommendation</a> + </li> + {% endfor %} + </ul> + {% endif %} + + {% if assignments_to_consider or recs_to_vote_on %} + <hr> + {% endif %} + + {% if search_form %} + <h3>Filter by status</h3> + <form method="get" class="auto-submit mb-3"> + {{ search_form|bootstrap:'12,12' }} + <input type="submit" class="btn btn-secondary btn-sm" value="Filter"> + </form> + {% endif %} + + <ul class="list-unstyled" data-target="active-list"> + <!-- Submissions list --> + {% for sub in submissions_in_pool %} + <li class="p-2{% if sub == submission %} active{% endif %}"> + {% if sub == submission %} + {% include 'partials/submissions/pool/submission_li.html' with submission=sub is_current=1 %} + {% else %} + {% include 'partials/submissions/pool/submission_li.html' with submission=sub is_current=0 %} + {% endif %} + </li> + {% empty %} + <li> + <h3 class="text-center"><i class="fa fa-question fa-2x"></i><br>No Submissions found.</h3> + </li> + {% endfor %} + </ul> + </div><!-- End page content --> + + <div class="col-md-5" id="details"> + {% if submission %} + {% include 'partials/submissions/pool/submission_details.html' with submission=submission remark_form=remark_form is_ECAdmin=is_ECAdmin user=request.user %} + {% else %} + <h3><em>Click on a submission to see its summary and actions</em></h3> + {% endif %} + </div> + </div> + {% endwith %} +{% endblock %} diff --git a/submissions/templates/submissions/pool/recommendation.html b/submissions/templates/submissions/pool/recommendation.html new file mode 100644 index 0000000000000000000000000000000000000000..d2c050bbb0c1b3090e5f8c6d83a35bb2c81c6b24 --- /dev/null +++ b/submissions/templates/submissions/pool/recommendation.html @@ -0,0 +1,29 @@ +{% extends 'submissions/pool/base.html' %} + +{% load bootstrap %} + +{% block breadcrumb_items %} + {{ block.super }} + <span class="breadcrumb-item">Editorial Recommendation</span> +{% endblock %} + +{% block pagetitle %}: Editorial Recommendation{% endblock pagetitle %} + +{% block content %} + <h1>Editorial Recommendation to vote on</h1> + + {% include 'submissions/_submission_card_fellow_content.html' with submission=recommendation.submission %} + + {# <div class="card card-outline-secondary">#} + {% include 'submissions/_recommendation_fellow_content.html' with recommendation=recommendation %} + <div class="card-footer"> + <h3>Your position on this recommendation</h3> + <form action="{% url 'submissions:vote_on_rec' rec_id=recommendation.id %}" method="post"> + {% csrf_token %} + {{ form|bootstrap:'0,12' }} + <input type="submit" name="submit" value="Cast your vote" class="btn btn-primary submitButton" id="submit-id-submit"> + </form> + </div> + {# </div>#} + +{% endblock %} diff --git a/submissions/urls.py b/submissions/urls.py index 35a4f7d36c4e8d1fbe3be354b3902697349b1201..6cd83e4ec6d855ebde05931aa76a0cafb7b863b5 100644 --- a/submissions/urls.py +++ b/submissions/urls.py @@ -42,13 +42,16 @@ urlpatterns = [ views.report_pdf_compile, name='report_pdf_compile'), url(r'^admin/reports/(?P<report_id>[0-9]+)/compile$', views.report_pdf_compile, name='report_pdf_compile'), + url(r'^admin/{regex}/recommendation$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), + views.AdminRecommendationView.as_view(), name='admin_recommendation'), url(r'^submit_manuscript$', views.RequestSubmission.as_view(), name='submit_manuscript'), url(r'^submit_manuscript/prefill$', views.prefill_using_arxiv_identifier, name='prefill_using_identifier'), - url(r'^pool$', views.pool, name='pool'), + url(r'^pool/$', views.pool, name='pool'), + url(r'^pool/{regex}/$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.pool, name='pool'), url(r'^submissions_by_status/(?P<status>[a-zA-Z_]+)$', - views.submissions_by_status, name='submissions_by_status'), + views.submissions_by_status, name='submissions_by_status'), # DEPRECATED url(r'^add_remark/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.add_remark, name='add_remark'), @@ -57,8 +60,8 @@ urlpatterns = [ views.assign_submission, name='assign_submission'), url(r'^assign_submission_ack/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.assign_submission_ack, name='assign_submission_ack'), - url(r'^accept_or_decline_assignment_ack/(?P<assignment_id>[0-9]+)$', - views.accept_or_decline_assignment_ack, name='accept_or_decline_assignment_ack'), + url(r'^pool/assignment_request/(?P<assignment_id>[0-9]+)$', + views.assignment_request, name='assignment_request'), url(r'^volunteer_as_EIC/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.volunteer_as_EIC, name='volunteer_as_EIC'), url(r'^assignment_failed/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), diff --git a/submissions/views.py b/submissions/views.py index 2a0c0c65e149cb1fab4d4df257c0ccbbbd42317c..7007d5d231c2a9af3164314afbd0f38d241bee4b 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -31,13 +31,15 @@ from .forms import SubmissionIdentifierForm, RequestSubmissionForm, SubmissionSe ConsiderRefereeInvitationForm, EditorialCommunicationForm,\ EICRecommendationForm, ReportForm, VetReportForm, VotingEligibilityForm,\ SubmissionCycleChoiceForm, ReportPDFForm, SubmissionReportsForm,\ - iThenticateReportForm + iThenticateReportForm, SubmissionPoolFilterForm from .utils import SubmissionUtils from mails.views import MailEditingSubView from scipost.forms import ModifyPersonalMessageForm, RemarkForm from scipost.models import Contributor, Remark, RegistrationInvitation from scipost.utils import Utils +from scipost.permissions import is_tester + from comments.forms import CommentForm from production.models import ProductionStream @@ -94,10 +96,11 @@ class RequestSubmission(CreateView): @login_required @permission_required('scipost.can_submit_manuscript', raise_exception=True) def prefill_using_arxiv_identifier(request): - query_form = SubmissionIdentifierForm(request.POST or None, initial=request.GET or None) + query_form = SubmissionIdentifierForm(request.POST or None, initial=request.GET or None, + requested_by=request.user) if query_form.is_valid(): prefill_data = query_form.request_arxiv_preprint_form_prefill_data() - form = RequestSubmissionForm(initial=prefill_data) + form = RequestSubmissionForm(initial=prefill_data, requested_by=request.user) # Submit message to user if query_form.submission_is_resubmission(): @@ -323,7 +326,7 @@ def editorial_workflow(request): @login_required @permission_required('scipost.can_view_pool', raise_exception=True) -def pool(request): +def pool(request, arxiv_identifier_w_vn_nr=None): """ The Submissions pool contains all submissions which are undergoing the editorial process, from submission @@ -334,14 +337,13 @@ def pool(request): .prefetch_related('referee_invitations', 'remarks', 'comments')) recommendations_undergoing_voting = (EICRecommendation.objects .get_for_user_in_pool(request.user) - .filter(submission__status__in=['put_to_EC_voting'])) + .filter(submission__status='put_to_EC_voting')) recommendations_to_prepare_for_voting = (EICRecommendation.objects .get_for_user_in_pool(request.user) .filter( - submission__status__in=['voting_in_preparation'])) + submission__status='voting_in_preparation')) contributor = Contributor.objects.get(user=request.user) - assignments_to_consider = EditorialAssignment.objects.filter( - to=contributor, accepted=None, deprecated=False) + assignments_to_consider = EditorialAssignment.objects.open().filter(to=contributor) consider_assignment_form = ConsiderAssignmentForm() recs_to_vote_on = (EICRecommendation.objects.get_for_user_in_pool(request.user) .filter(eligible_to_vote=contributor) @@ -352,21 +354,53 @@ def pool(request): .exclude(submission__status__in=SUBMISSION_STATUS_VOTING_DEPRECATED)) rec_vote_form = RecommendationVoteForm() remark_form = RemarkForm() - context = {'submissions_in_pool': submissions_in_pool, - 'submission_status': SUBMISSION_STATUS, - 'recommendations_undergoing_voting': recommendations_undergoing_voting, - 'recommendations_to_prepare_for_voting': recommendations_to_prepare_for_voting, - 'assignments_to_consider': assignments_to_consider, - 'consider_assignment_form': consider_assignment_form, - 'recs_to_vote_on': recs_to_vote_on, - 'rec_vote_form': rec_vote_form, - 'remark_form': remark_form, } - return render(request, 'submissions/pool.html', context) + context = { + 'submissions_in_pool': submissions_in_pool, + 'submission_status': SUBMISSION_STATUS, + 'recommendations_undergoing_voting': recommendations_undergoing_voting, + 'recommendations_to_prepare_for_voting': recommendations_to_prepare_for_voting, + 'assignments_to_consider': assignments_to_consider, + 'consider_assignment_form': consider_assignment_form, + 'recs_to_vote_on': recs_to_vote_on, + 'rec_vote_form': rec_vote_form, + 'remark_form': remark_form, + 'submission': None + } + + # The following is in test phase. Update if test is done + # -- + + # Search + search_form = SubmissionPoolFilterForm(request.GET or None) + if search_form.is_valid(): + context['submissions_in_pool'] = search_form.search(context['submissions_in_pool'], + request.user.contributor) + context['search_form'] = search_form + + # Show specific submission in the pool + if arxiv_identifier_w_vn_nr: + try: + context['submission'] = context['submissions_in_pool'].get( + arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) + except Submission.DoesNotExist: + pass + + # Temporary test logic: only testers see the new Pool + if context['submission'] and request.GET.get('json'): + template = 'partials/submissions/pool/submission_details.html' + elif is_tester(request.user) and not request.GET.get('test'): + template = 'submissions/pool/pool.html' + else: + template = 'submissions/pool.html' + return render(request, template, context) @login_required @permission_required('scipost.can_view_pool', raise_exception=True) def submissions_by_status(request, status): + # --- + # DEPRECATED AS PER NEW POOL + # --- status_dict = dict(SUBMISSION_STATUS) if status not in status_dict.keys(): errormessage = 'Unknown status.' @@ -402,7 +436,7 @@ def add_remark(request, arxiv_identifier_w_vn_nr): messages.success(request, 'Your remark has succesfully been posted') else: messages.warning(request, 'The form was invalidly filled.') - return redirect(reverse('submissions:pool')) + return redirect(reverse('submissions:pool', args=(arxiv_identifier_w_vn_nr,))) @login_required @@ -447,56 +481,76 @@ def assign_submission_ack(request, arxiv_identifier_w_vn_nr): @login_required @permission_required('scipost.can_take_charge_of_submissions', raise_exception=True) @transaction.atomic -def accept_or_decline_assignment_ack(request, assignment_id): - contributor = Contributor.objects.get(user=request.user) - assignment = get_object_or_404(EditorialAssignment, pk=assignment_id) +def assignment_request(request, assignment_id): + """ + Process EditorialAssignment acceptance/denial form or show if not submitted. + """ + assignment = get_object_or_404(EditorialAssignment.objects.open(), + to=request.user.contributor, pk=assignment_id) + errormessage = None if assignment.submission.status == 'assignment_failed': errormessage = 'This Submission has failed pre-screening and has been rejected.' - context = {'errormessage': errormessage} - return render(request, 'submissions/accept_or_decline_assignment_ack.html', context) - if assignment.submission.editor_in_charge: + + elif assignment.submission.editor_in_charge: errormessage = (assignment.submission.editor_in_charge.get_title_display() + ' ' + assignment.submission.editor_in_charge.user.last_name + ' has already agreed to be Editor-in-charge of this Submission.') - context = {'errormessage': errormessage} - return render(request, 'submissions/accept_or_decline_assignment_ack.html', context) - if request.method == 'POST': - form = ConsiderAssignmentForm(request.POST) - if form.is_valid(): - assignment.date_answered = timezone.now() - if form.cleaned_data['accept'] == 'True': - assignment.accepted = True - assignment.to = contributor - assignment.submission.status = 'EICassigned' - assignment.submission.editor_in_charge = contributor - assignment.submission.open_for_reporting = True - deadline = timezone.now() + datetime.timedelta(days=28) # for papers - if assignment.submission.submitted_to_journal == 'SciPost Physics Lecture Notes': - deadline += datetime.timedelta(days=28) - assignment.submission.reporting_deadline = deadline - assignment.submission.open_for_commenting = True - assignment.submission.latest_activity = timezone.now() - - SubmissionUtils.load({'assignment': assignment}) - SubmissionUtils.deprecate_other_assignments() - assign_perm('can_take_editorial_actions', contributor.user, assignment.submission) - ed_admins = Group.objects.get(name='Editorial Administrators') - assign_perm('can_take_editorial_actions', ed_admins, assignment.submission) - SubmissionUtils.send_EIC_appointment_email() - SubmissionUtils.send_author_prescreening_passed_email() - - # Add SubmissionEvents - assignment.submission.add_general_event('The Editor-in-charge has been assigned.') - else: - assignment.accepted = False - assignment.refusal_reason = form.cleaned_data['refusal_reason'] - assignment.submission.status = 'unassigned' - assignment.save() - assignment.submission.save() - - context = {'assignment': assignment} - return render(request, 'submissions/accept_or_decline_assignment_ack.html', context) + + if errormessage: + # Assignments can get stuck here, + # if errormessage is given the contributor can't close the assignment!! + messages.warning(request, errormessage) + return redirect(reverse('submissions:pool')) + + form = ConsiderAssignmentForm(request.POST or None) + if form.is_valid(): + assignment.date_answered = timezone.now() + if form.cleaned_data['accept'] == 'True': + assignment.accepted = True + assignment.to = request.user.contributor + assignment.submission.status = 'EICassigned' + assignment.submission.editor_in_charge = request.user.contributor + assignment.submission.open_for_reporting = True + deadline = timezone.now() + datetime.timedelta(days=28) # for papers + if assignment.submission.submitted_to_journal == 'SciPost Physics Lecture Notes': + deadline += datetime.timedelta(days=28) + assignment.submission.reporting_deadline = deadline + assignment.submission.open_for_commenting = True + assignment.submission.latest_activity = timezone.now() + + SubmissionUtils.load({'assignment': assignment}) + SubmissionUtils.deprecate_other_assignments() + assign_perm('can_take_editorial_actions', request.user, assignment.submission) + ed_admins = Group.objects.get(name='Editorial Administrators') + assign_perm('can_take_editorial_actions', ed_admins, assignment.submission) + SubmissionUtils.send_EIC_appointment_email() + SubmissionUtils.send_author_prescreening_passed_email() + + # Add SubmissionEvents + assignment.submission.add_general_event('The Editor-in-charge has been assigned.') + msg = 'Thank you for becoming Editor-in-charge of this submission.' + url = reverse('submissions:editorial_page', + args=(assignment.submission.arxiv_identifier_w_vn_nr,)) + else: + assignment.accepted = False + assignment.refusal_reason = form.cleaned_data['refusal_reason'] + assignment.submission.status = 'unassigned' + msg = 'Thank you for considering' + url = reverse('submissions:pool') + # Save assignment and submission + assignment.save() + assignment.submission.save() + + # Form submitted, redirect user + messages.success(request, msg) + return redirect(url) + + context = { + 'assignment': assignment, + 'form': form + } + return render(request, 'submissions/pool/assignment_request.html', context) @login_required @@ -505,7 +559,7 @@ def accept_or_decline_assignment_ack(request, assignment_id): def volunteer_as_EIC(request, arxiv_identifier_w_vn_nr): """ Called when a Fellow volunteers while perusing the submissions pool. - This is an adapted version of the accept_or_decline_assignment_ack method. + This is an adapted version of the assignment_request method. """ submission = get_object_or_404(Submission.objects.get_pool(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) @@ -1373,9 +1427,14 @@ def vote_on_rec(request, rec_id): remark=form.cleaned_data['remark']) remark.save() recommendation.save() + messages.success(request, 'Thank you for your vote.') return redirect(reverse('submissions:pool')) - return redirect(reverse('submissions:pool')) + context = { + 'recommendation': recommendation, + 'form': form + } + return render(request, 'submissions/pool/recommendation.html', context) @permission_required('scipost.can_prepare_recommendations_for_voting', raise_exception=True) @@ -1497,8 +1556,21 @@ class EditorialSummaryView(SubmissionAdminViewMixin, ListView): if not context.get('submission'): context['latest_events'] = SubmissionEvent.objects.for_eic().last_hours() + + context['recommendations_undergoing_voting'] = ( + EICRecommendation.objects.get_for_user_in_pool(self.request.user) + .filter(submission__status='put_to_EC_voting')) + context['recommendations_to_prepare_for_voting'] = ( + EICRecommendation.objects.get_for_user_in_pool(self.request.user) + .filter(submission__status='voting_in_preparation')) return context + def get_template_names(self): + if self.request.GET.get('json'): + return ['partials/submissions/admin/submission_details.html'] + else: + return ['submissions/admin/editorial_admin.html'] + class PlagiarismView(SubmissionAdminViewMixin, UpdateView): permission_required = 'scipost.can_do_plagiarism_checks' @@ -1524,3 +1596,14 @@ class PlagiarismReportPDFView(SubmissionAdminViewMixin, SingleObjectMixin, Redir if not url: raise Http404 return url + + +class AdminRecommendationView(SubmissionAdminViewMixin, DetailView): + permission_required = 'scipost.can_fix_College_decision' + template_name = 'submissions/admin/recommendation.html' + editorial_page = True + + def get_object(self): + """ Get the EICRecommendation as a submission-related instance. """ + submission = super().get_object() + return submission.eicrecommendations.first()