diff --git a/scipost/management/commands/add_groups_and_permissions.py b/scipost/management/commands/add_groups_and_permissions.py index e1dca4d858c04a4571b4e48d59cf18e0b3488a3d..188cfc787e2c90035a8c035f2b58116452227c70 100644 --- a/scipost/management/commands/add_groups_and_permissions.py +++ b/scipost/management/commands/add_groups_and_permissions.py @@ -38,7 +38,6 @@ class Command(BaseCommand): content_type = ContentType.objects.get_for_model(Contributor) content_type_contact = ContentType.objects.get_for_model(Contact) content_type_draft_invitation = ContentType.objects.get_for_model(DraftInvitation) - content_type_report = ContentType.objects.get_for_model(Report) # Supporting Partners can_manage_SPB, created = Permission.objects.get_or_create( @@ -157,7 +156,7 @@ class Command(BaseCommand): can_vet_submitted_reports, created = Permission.objects.get_or_create( codename='can_vet_submitted_reports', name='Can vet submitted Reports', - content_type=content_type_report) + content_type=content_type) # Submissions can_submit_manuscript, created = Permission.objects.get_or_create( diff --git a/scipost/static/scipost/assets/css/_list_group.scss b/scipost/static/scipost/assets/css/_list_group.scss index 7387c9c85f91dd41b8e5ec56003f3fc6bcb80099..84f3c2448fb7905c4e6ec0afd46ab05340b3c82e 100644 --- a/scipost/static/scipost/assets/css/_list_group.scss +++ b/scipost/static/scipost/assets/css/_list_group.scss @@ -26,6 +26,22 @@ ul.events-list { ul[data-target="active-list"] { li.active { - background-color: $gray-100; + // background-color: $gray-100; } } + +.pool-list { + > .submission { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin-bottom: -1px; + + &.active { + border: 1px solid #000; + margin-bottom: 0; + } + } + // > .submission:first-child { + // border-top: 0; + // } +} diff --git a/scipost/templates/scipost/personal_page.html b/scipost/templates/scipost/personal_page.html index c7c3bcce94a4f8c5df0fa76b7673a60b7464d404..b5b567f3afe94eb0a76a3955190d5be7725e460f 100644 --- a/scipost/templates/scipost/personal_page.html +++ b/scipost/templates/scipost/personal_page.html @@ -110,13 +110,13 @@ </div> <div class="col-md-6"> {% if contributor %} - {# Scientist fields #} - {% if not contributor.is_currently_available %} - <h3 class="text-warning">You are currently unavailable</h3> - <p>Check your availability underneath if this should not be the case.</p> - <hr> - {% endif %} - {# END: Scientist fields #} + {# Scientist fields #} + {% if not contributor.is_currently_available %} + <h3 class="text-warning">You are currently unavailable</h3> + <p>Check your availability underneath if this should not be the case.</p> + <hr> + {% endif %} + {# END: Scientist fields #} {% endif %} {% if not request.user.contributor.petition_signatories.exists %} @@ -124,8 +124,8 @@ <h3 class="text-danger">Scientists, please help us out!</h3> <p class="mb-1">If it is not listed on our Partners page, please encourage your institution (through a librarian, director, ...) to join by <a class="h3 text-blue" href="{% url 'petitions:petition' slug='join-SPB' %}">signing our petition</a>.</p> </div> + <hr> {% endif %} - <hr> {% if 'SciPost Administrators' in user_groups %} <h3>You are a SciPost Administrator.</h3> @@ -158,6 +158,41 @@ <h3>You are a SciPost Production Officer.</h3> {% endif %} + {% if contributor.fellowships.exists %} + <h3>Your Fellowships:</h3> + <ul class="mb-2"> + {% for fellowship in contributor.fellowships.all %} + <li class="pt-1"> + {{ fellowship.contributor.get_discipline_display }} + + {% if fellowship.guest %} + (Guest Fellowship) + {% else %} + (Regular Fellowship) + {% endif %} + + {% if not fellowship.is_active %} + <span class="label label-outline-warning label-sm">Inactive</span> + {% endif %} + + {% if fellowship.start_date or fellowship.until_date %} + <div class="text-muted"> + {% if fellowship.start_date %} + from {{ fellowship.start_date }} + {% endif %} + + {% if fellowship.until_date %} + until {{ fellowship.until_date }} + {% endif %} + </div> + {% endif %} + </li> + + {% endfor %} + </ul> + <a href="{% url 'submissions:pool' %}" class="h3 text-primary ml-4 px-3 d-block-inline">Go to the Submissions Pool</a> + {% endif %} + <h3 class="mt-3">Update your personal data or password</h3> <ul> diff --git a/scipost/templatetags/user_groups.py b/scipost/templatetags/user_groups.py index 408837b3610ed36499ad4a021c0c8124ccecf6c2..8cd171deae8df806f99faa01f15ed397457ab72e 100644 --- a/scipost/templatetags/user_groups.py +++ b/scipost/templatetags/user_groups.py @@ -10,3 +10,18 @@ def is_edcol_admin(user): This assignment is limited to a certain context block! """ return user.groups.filter(name='Editorial Administrators').exists() or user.is_superuser + + +@register.simple_tag +def is_editor_in_charge(user, submission): + """ + Assign template variable (boolean) to check if user is Editorial Administator. + This assignment is limited to a certain context block! + """ + if user.is_superuser: + return True + + if not hasattr(user, 'contributor'): + return False + + return submission.editor_in_charge == user.contributor diff --git a/submissions/forms.py b/submissions/forms.py index 0b68bba379bfd52d474b055b033909bcaa8799b8..3563a83070ea5bb6d6d5f3bf810784ab4efaa72f 100644 --- a/submissions/forms.py +++ b/submissions/forms.py @@ -352,11 +352,6 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm): @transaction.atomic def reassign_eic_and_admins(self, submission): - # Assign permissions - assign_perm('can_take_editorial_actions', submission.editor_in_charge.user, submission) - ed_admins = Group.objects.get(name='Editorial Administrators') - assign_perm('can_take_editorial_actions', ed_admins, submission) - # Assign editor assignment = EditorialAssignment( submission=submission, @@ -472,21 +467,37 @@ class SetRefereeingDeadlineForm(forms.Form): return self.cleaned_data.get('deadline') -class VotingEligibilityForm(forms.Form): +class VotingEligibilityForm(forms.ModelForm): + eligible_Fellows = forms.ModelMultipleChoiceField( + queryset=Contributor.objects.none(), + widget=forms.CheckboxSelectMultiple({'checked': 'checked'}), + required=True, label='Eligible for voting') + + class Meta: + model = EICRecommendation + fields = () def __init__(self, *args, **kwargs): - discipline = kwargs.pop('discipline') - subject_area = kwargs.pop('subject_area') - super(VotingEligibilityForm, self).__init__(*args, **kwargs) - self.fields['eligible_Fellows'] = forms.ModelMultipleChoiceField( - queryset=Contributor.objects.filter( - user__groups__name__in=['Editorial College'], - user__contributor__discipline=discipline, - user__contributor__expertises__contains=[subject_area] - ).order_by('user__last_name'), - widget=forms.CheckboxSelectMultiple({'checked': 'checked'}), - required=True, label='Eligible for voting', - ) + super().__init__(*args, **kwargs) + # Do we need this discipline filter still with the new Pool construction??? + # -- JdW; Oct 20th, 2017 + self.fields['eligible_Fellows'].queryset = Contributor.objects.filter( + fellowships__pool=self.instance.submission, + discipline=self.instance.submission.discipline, + expertises__contains=self.instance.submission.subject_area + ).order_by('user__last_name') + + def save(self, commit=True): + recommendation = self.instance + recommendation.eligible_to_vote = self.cleaned_data['eligible_Fellows'] + submission = self.instance.submission + submission.status = 'put_to_EC_voting' + + if commit: + recommendation.save() + submission.save() + recommendation.voted_for.add(recommendation.submission.editor_in_charge) + return recommendation ############ diff --git a/submissions/managers.py b/submissions/managers.py index a8aa583f2e1a5db478c34376b7064defe11a47dc..73d324515000b1fdd5eacf6f1b40c32c5a9c92b8 100644 --- a/submissions/managers.py +++ b/submissions/managers.py @@ -27,7 +27,7 @@ class SubmissionQuerySet(models.QuerySet): """ # This method used a double query, which is a consequence of the complex distinct() # filter combined with the PostGresQL engine. Without the double query, ordering - # on a specific field after filtering would be impossible. + # on a specific field after filtering seems impossible. ids = (queryset .order_by('arxiv_identifier_wo_vn_nr', '-arxiv_vn_nr') .distinct('arxiv_identifier_wo_vn_nr') @@ -99,30 +99,16 @@ class SubmissionQuerySet(models.QuerySet): qs = self._pool(user) return qs - def get_pool(self, user): + def filter_for_eic(self, user): """ - -- DEPRECATED -- - - Return subset of active and newest 'alive' submissions. + Return the set of Submissions the user is Editor-in-charge for or return the pool if + User is Editorial Administrator. """ - return (self.user_filter(user) - .exclude(is_current=False) - .exclude(status__in=SUBMISSION_STATUS_OUT_OF_POOL) - .order_by('-submission_date')) - - def filter_editorial_page(self, user): - """ - -- DEPRECATED -- - - Return Submissions currently 'alive' (being refereed, not published). + qs = self._pool(user) - It is meant to allow opening and editing certain submissions that are officially - out of the submission cycle i.e. due to resubmission, but should still have the - possibility to be opened by the EIC. - """ - return (self.user_filter(user) - .exclude(status__in=SUBMISSION_HTTP404_ON_EDITORIAL_PAGE) - .order_by('-submission_date')) + if not user.has_perm('scipost.can_oversee_refereeing') and hasattr(user, 'contributor'): + qs = qs.filter(editor_in_charge=user.contributor) + return qs def prescreening(self): """ diff --git a/submissions/mixins.py b/submissions/mixins.py index e1a09834fcadb060d26bd739c63b4f4ff276b079..467ceab478632e655f21000bbd08b7499f0f099d 100644 --- a/submissions/mixins.py +++ b/submissions/mixins.py @@ -70,7 +70,7 @@ class SubmissionAdminViewMixin(FriendlyPermissionMixin, SubmissionFormViewMixin) qs = super().get_queryset() if self.pool: return qs.pool(self.request.user) - return qs.overcomplete_pool(self.request.user) + return qs.filter_for_eic(self.request.user) def get_object(self): """ diff --git a/submissions/models.py b/submissions/models.py index 69ebaf33e30b1b693093f3a81b95e6495aa717ee..a81fdd7889e718a1582e670de7741c868bda2a31 100644 --- a/submissions/models.py +++ b/submissions/models.py @@ -107,11 +107,6 @@ class Submission(models.Model): objects = SubmissionQuerySet.as_manager() - class Meta: - permissions = ( - ('can_take_editorial_actions', 'Can take editorial actions'), - ) - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._update_cycle() @@ -412,9 +407,6 @@ class Report(SubmissionRelatedObjectMixin, models.Model): unique_together = ('submission', 'report_nr') default_related_name = 'reports' ordering = ['-date_submitted'] - permissions = ( - ('can_vet_submitted_reports', 'Can vet submitted Reports'), - ) def __str__(self): return (self.author.user.first_name + ' ' + self.author.user.last_name + ' on ' + diff --git a/submissions/templates/partials/submissions/pool/submission_details.html b/submissions/templates/partials/submissions/pool/submission_details.html index 18750041686733b9a1146a443d4f756b136595c1..8d09053919376de748140b33c14e6b60ab271eb4 100644 --- a/submissions/templates/partials/submissions/pool/submission_details.html +++ b/submissions/templates/partials/submissions/pool/submission_details.html @@ -1,16 +1,17 @@ -{% load guardian_tags %} {% load scipost_extras %} {% load submissions_extras %} {% load user_groups %} -{% get_obj_perms request.user for submission as "sub_perms" %} -{% is_edcol_admin request.user as is_ECAdmin %} +{% is_editor_in_charge request.user submission as is_editor_in_charge %} +{% is_edcol_admin request.user as is_editorial_admin %} -<div class="card submission-detail"> - <div class="scroll"> - {% include 'submissions/_submission_card_fellow_content.html' with submission=submission %} - <div class="card-body"> +<hr> +<div class="bg-white submission-detail mt-1"> + {# <div class="scroll">#} + {% include 'submissions/_submission_card_fellow_content.html' with submission=submission hide_title=1 cardblock_class='px-0 pt-0' %} + + <div> <h3>Remarks on this submission:</h3> {% if remark_form %} {% include 'submissions/_remark_add_form.html' with submission=submission form=remark_form auto_show=1 %} @@ -24,14 +25,15 @@ {% endfor %} </ul> - {% if "can_take_editorial_actions" in sub_perms or is_ECAdmin %} + {% if is_editor_in_charge or is_editorial_admin %} + <br> {% 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 is_ECAdmin %} + {% if is_editorial_admin %} <h3>Editorial Administration</h3> <ul class="pl-4 mb-3"> {# EIC Assignments #} @@ -87,5 +89,5 @@ </div> {% endif %} </div> - </div> + {# </div>#} </div> diff --git a/submissions/templates/partials/submissions/pool/submission_li.html b/submissions/templates/partials/submissions/pool/submission_li.html index 969abe2ca373b6d72a94604271e702810d91d41c..46b7c5ad2a0393ae6be2723581626fa141327750 100644 --- a/submissions/templates/partials/submissions/pool/submission_li.html +++ b/submissions/templates/partials/submissions/pool/submission_li.html @@ -1,4 +1,4 @@ -<div class="row pool-item mb-0"> +<div class="row pool-item mb-0 px-3"> <div class="icons{% if is_current %} text-info{% endif %}"> {% include 'partials/submissions/pool/submission_tooltip.html' with submission=submission %} @@ -19,27 +19,25 @@ {% elif submission.editor_in_charge == request.user.contributor %} <strong>You are Editor-in-charge</strong> {% else %} - {{ submission.editor_in_charge }} + <span class="text-muted">Editor-in-charge:</span> {{ submission.editor_in_charge }} {% endif %} - <br> - <small class="text-muted">Editor-in-charge</small> </div> <div class="col-7"> - {{ submission.get_status_display }} - <br> - <small class="text-muted">Status</small> + <span class="label label-sm label-secondary">{{ submission.get_status_display }}</span> </div> </div> -{% comment %} - <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> + + <div class="card-text"> + <a href="{% url 'submissions:pool' submission.arxiv_identifier_w_vn_nr %}" data-toggle="dynamic" data-target="#container_{{ submission.id }}">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> -{% endcomment %} + </div> + {% 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> + <div class="card-text bg-danger text-white mt-1 py-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="#container_{{ submission.id }}">click to see details.</a> {% include 'partials/submissions/pool/required_actions_tooltip.html' with submission=submission classes='text-white' %} + </div> {% endif %} </div> diff --git a/submissions/templates/submissions/_submission_card_base.html b/submissions/templates/submissions/_submission_card_base.html index fa4d0d8c90afdca722169f35e2d1865095471efc..3b5b104b008afad6af8d7d6f39f12806e70b6e59 100644 --- a/submissions/templates/submissions/_submission_card_base.html +++ b/submissions/templates/submissions/_submission_card_base.html @@ -1,8 +1,11 @@ -<div class="card-body {% block cardblock_class_block %}{% endblock %}"> - <h5 class="pb-0">{{submission.get_subject_area_display}}</h5> - <h3 class="card-title {% block title_class_block %}{% endblock %}"> - <a href="{{submission.get_absolute_url}}">{{submission.title}}</a> - </h3> +<div class="card-body {% block cardblock_class_block %}{% endblock %} {{ cardblock_class }}"> + + {% if not hide_title %} + <h5 class="pb-0">{{submission.get_subject_area_display}}</h5> + <h3 class="card-title {% block title_class_block %}{% endblock %}"> + <a href="{{submission.get_absolute_url}}">{{submission.title}}</a> + </h3> + {% endif %} {% block card_block_footer %}{% endblock %} </div> diff --git a/submissions/templates/submissions/_submission_card_fellow_content.html b/submissions/templates/submissions/_submission_card_fellow_content.html index ffd22007ffe7915188b0ab4136088cd902c62258..326c2f85fc73876bd2bb2bc4e505cb397b9d5e0d 100644 --- a/submissions/templates/submissions/_submission_card_fellow_content.html +++ b/submissions/templates/submissions/_submission_card_fellow_content.html @@ -1,7 +1,9 @@ {% extends 'submissions/_submission_card_base.html' %} {% block card_block_footer %} - <p class="card-text mb-3">by {{submission.author_list}}</p> + {% if not hide_title %} + <p class="card-text mb-3">by {{submission.author_list}}</p> + {% endif %} <table class="text-muted w-100 mb-1"> <tr> <td style="min-width: 40%;">Version</td> diff --git a/submissions/templates/submissions/_submission_card_in_pool.html b/submissions/templates/submissions/_submission_card_in_pool.html index ad484a07864a5b1a45ee339273c28547a87e8cb3..d75435ceac00ea15807a6e43641fbe1e402986e8 100644 --- a/submissions/templates/submissions/_submission_card_in_pool.html +++ b/submissions/templates/submissions/_submission_card_in_pool.html @@ -1,9 +1,12 @@ {% load guardian_tags %} {% load scipost_extras %} {% load submissions_extras %} +{% load user_groups %} +{% is_editor_in_charge request.user submission as is_editor_in_charge %} +{% is_edcol_admin request.user as is_editorial_admin %} -{% include 'submissions/_submission_card_fellow_content.html' with submission=submission %} +{% include 'submissions/_submission_card_fellow_content.html' with submission=submission hide_title=1 %} <div class="card-body"> {% if submission.remarks.all %} @@ -19,8 +22,7 @@ {% include 'submissions/_remark_add_form.html' with submission=submission form=remark_form %} {% endif %} - {% get_obj_perms request.user for submission as "sub_perms" %} - {% if "can_take_editorial_actions" in sub_perms or is_ECAdmin %} + {% if is_editor_in_charge or is_editorial_admin %} {% 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> @@ -45,7 +47,7 @@ {% endif %} {% endif %} - {% if is_ECAdmin %} + {% if is_editorial_admin %} <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> diff --git a/submissions/templates/submissions/pool/pool.html b/submissions/templates/submissions/pool/pool.html index 482098314a5bcb48a8b7958ea9a623538cc6dce7..47d824adffb7de7309feb90b7450699d756e6aef 100644 --- a/submissions/templates/submissions/pool/pool.html +++ b/submissions/templates/submissions/pool/pool.html @@ -23,7 +23,7 @@ <a href="{% url 'submissions:pool' %}?test=1">See old pool layout</a> <div class="row"> - <div class="col-md-7"> + <div class="col-12"> <h1>SciPost Submissions Pool</h1> {% if is_ECAdmin %} @@ -89,15 +89,21 @@ </form> {% endif %} - <ul class="list-group" data-target="active-list"> + <ul class="list-unstyled pool-list" data-target="active-list"> <!-- Submissions list --> {% for sub in submissions %} - <li class="list-group-item p-2{% if sub == submission %} active{% endif %}"> + <li class="submission py-2 px-3{% if sub == submission %} active{% endif %}" id="submission_{{ submission.id }}"> {% 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 %} + + <div class="loading-container px-3" id="container_{{ sub.id }}"> + {% if submission and submission == sub %} + {% include 'partials/submissions/pool/submission_details.html' with submission=submission remark_form=remark_form is_ECAdmin=is_ECAdmin user=request.user %} + {% endif %} + </div> </li> {% empty %} <li> @@ -106,20 +112,17 @@ {% endfor %} </ul> </div><!-- End page content --> + </div> +{% endblock %} - <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> +{% comment %} + <h3><em>Click on a submission to see its summary and actions</em></h3> - {% if is_ECAdmin %} - <h2>All events in the last 24 hours</h2> - <div id="eventslist"> - {% include 'submissions/submission_event_list_general.html' with events=latest_events %} - </div> - {% endif %} - {% endif %} + {% if is_ECAdmin %} + <h2>All events in the last 24 hours</h2> + <div id="eventslist"> + {% include 'submissions/submission_event_list_general.html' with events=latest_events %} </div> - </div> -{% endblock %} + {% endif %} + + {% endcomment %} diff --git a/submissions/templatetags/submissions_extras.py b/submissions/templatetags/submissions_extras.py index de71caafbddb5aae5dc1edbe542a717123796841..c9b1abc8ec9d50d005a60829a77a0e271edcaafe 100644 --- a/submissions/templatetags/submissions_extras.py +++ b/submissions/templatetags/submissions_extras.py @@ -1,8 +1,5 @@ -import datetime - from django import template -from submissions.constants import SUBMISSION_STATUS_OUT_OF_POOL from submissions.models import Submission register = template.Library() diff --git a/submissions/views.py b/submissions/views.py index 6bd6fa2f0e8e9b5c026abfbff4ada537b95a3234..4ccb279388cd3b8b5b31ded77df7f135d97f0085 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -7,7 +7,7 @@ from django.contrib.auth.models import Group from django.core.urlresolvers import reverse, reverse_lazy from django.db import transaction, IntegrityError from django.http import Http404, HttpResponse, HttpResponseRedirect -from django.shortcuts import get_object_or_404, render, redirect +from django.shortcuts import get_object_or_404, get_list_or_404, render, redirect from django.template import Template, Context from django.utils import timezone from django.utils.decorators import method_decorator @@ -16,10 +16,9 @@ from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.edit import CreateView, UpdateView from django.views.generic.list import ListView -from guardian.decorators import permission_required_or_403 -from guardian.shortcuts import assign_perm, get_objects_for_user +from guardian.shortcuts import assign_perm -from .constants import SUBMISSION_STATUS_VOTING_DEPRECATED, STATUS_VETTED, STATUS_EIC_ASSIGNED,\ +from .constants import STATUS_VETTED, STATUS_EIC_ASSIGNED,\ SUBMISSION_STATUS_PUBLICLY_INVISIBLE, SUBMISSION_STATUS, ED_COMM_CHOICES,\ STATUS_DRAFT, CYCLE_DIRECT_REC from .models import Submission, EICRecommendation, EditorialAssignment,\ @@ -363,6 +362,7 @@ def pool(request, arxiv_identifier_w_vn_nr=None): context = { 'submissions': submissions, + 'search_form': search_form, 'submission_status': SUBMISSION_STATUS, 'recommendations': recommendations, 'assignments_to_consider': assignments_to_consider, @@ -374,7 +374,6 @@ def pool(request, arxiv_identifier_w_vn_nr=None): # The following is in test phase. Update if test is done # -- - context['search_form'] = search_form # Show specific submission in the pool context['submission'] = None @@ -409,7 +408,7 @@ def submissions_by_status(request, status): if status not in status_dict.keys(): errormessage = 'Unknown status.' return render(request, 'scipost/error.html', {'errormessage': errormessage}) - submissions_of_status = (Submission.objects.get_pool(request.user) + submissions_of_status = (Submission.objects.pool_full(request.user) .filter(status=status).order_by('-submission_date')) context = { @@ -421,13 +420,13 @@ def submissions_by_status(request, status): @login_required -@permission_required('scipost.can_view_pool', raise_exception=True) +# @permission_required('scipost.can_view_pool', raise_exception=True) def add_remark(request, arxiv_identifier_w_vn_nr): """ With this method, an Editorial Fellow or Board Member is adding a remark on a Submission. """ - submission = get_object_or_404(Submission.objects.get_pool(request.user), + submission = get_object_or_404(Submission.objects.pool_editable(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) remark_form = RemarkForm(request.POST or None) @@ -446,7 +445,11 @@ def add_remark(request, arxiv_identifier_w_vn_nr): @login_required @permission_required('scipost.can_assign_submissions', raise_exception=True) def assign_submission(request, arxiv_identifier_w_vn_nr): - submission_to_assign = get_object_or_404(Submission.objects.get_pool(request.user), + """ + Assign Editor-in-charge to Submission. + Action done by SciPost Administration or Editorial College Administration. + """ + submission_to_assign = get_object_or_404(Submission.objects.pool_editable(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) form = AssignSubmissionForm(discipline=submission_to_assign.discipline) context = {'submission_to_assign': submission_to_assign, @@ -457,7 +460,11 @@ def assign_submission(request, arxiv_identifier_w_vn_nr): @login_required @permission_required('scipost.can_assign_submissions', raise_exception=True) def assign_submission_ack(request, arxiv_identifier_w_vn_nr): - submission = get_object_or_404(Submission.objects.get_pool(request.user), + """ + Assign Editor-in-charge to Submission. + Action done by SciPost Administration or Editorial College Administration. + """ + submission = get_object_or_404(Submission.objects.pool_editable(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) if request.method == 'POST': form = AssignSubmissionForm(request.POST, discipline=submission.discipline) @@ -525,9 +532,6 @@ def assignment_request(request, assignment_id): 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() @@ -565,7 +569,7 @@ 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 assignment_request method. """ - submission = get_object_or_404(Submission.objects.get_pool(request.user), + submission = get_object_or_404(Submission.objects.pool(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) errormessage = None if submission.status == 'assignment_failed': @@ -600,9 +604,6 @@ def volunteer_as_EIC(request, arxiv_identifier_w_vn_nr): SubmissionUtils.load({'assignment': assignment}) SubmissionUtils.deprecate_other_assignments() - assign_perm('can_take_editorial_actions', contributor.user, submission) - ed_admins = Group.objects.get(name='Editorial Administrators') - assign_perm('can_take_editorial_actions', ed_admins, submission) SubmissionUtils.send_EIC_appointment_email() SubmissionUtils.send_author_prescreening_passed_email() @@ -623,7 +624,7 @@ def assignment_failed(request, arxiv_identifier_w_vn_nr): The submission is rejected. This method is called from pool.html by an Editorial Administrator. """ - submission = get_object_or_404(Submission.objects.get_pool(request.user), + submission = get_object_or_404(Submission.objects.pool(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) if request.method == 'POST': form = ModifyPersonalMessageForm(request.POST) @@ -673,10 +674,13 @@ def assignments(request): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def editorial_page(request, arxiv_identifier_w_vn_nr): - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + """ + The central page for the EIC to manage all its Editorial duties. + + Accessible for: Editor-in-charge and Editorial Administration + """ + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) context = { @@ -688,10 +692,14 @@ def editorial_page(request, arxiv_identifier_w_vn_nr): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def cycle_form_submit(request, arxiv_identifier_w_vn_nr): - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + """ + If Submission is `resubmission_incoming` the EIC should first choose what refereeing + cycle to choose. + + Accessible for: Editor-in-charge and Editorial Administration + """ + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) form = SubmissionCycleChoiceForm(request.POST or None, instance=submission) @@ -711,12 +719,14 @@ def cycle_form_submit(request, arxiv_identifier_w_vn_nr): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def select_referee(request, arxiv_identifier_w_vn_nr): - submission = get_object_or_404(Submission.objects.pool_editable(request.user), - arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) + """ + Select/Invite referees by first listing them here. + Accessible for: Editor-in-charge and Editorial Administration + """ + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), + arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) context = {} queryresults = '' @@ -753,8 +763,6 @@ def select_referee(request, arxiv_identifier_w_vn_nr): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) @transaction.atomic def recruit_referee(request, arxiv_identifier_w_vn_nr): """ @@ -764,9 +772,12 @@ def recruit_referee(request, arxiv_identifier_w_vn_nr): This function emails a registration invitation to this person. The pending refereeing invitation is then recognized upon registration, using the invitation token. + + Accessible for: Editor-in-charge and Editorial Administration """ - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) + if request.method == 'POST': ref_recruit_form = RefereeRecruitmentForm(request.POST) if ref_recruit_form.is_valid(): @@ -815,8 +826,6 @@ def recruit_referee(request, arxiv_identifier_w_vn_nr): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) @transaction.atomic def send_refereeing_invitation(request, arxiv_identifier_w_vn_nr, contributor_id): """ @@ -824,10 +833,13 @@ def send_refereeing_invitation(request, arxiv_identifier_w_vn_nr, contributor_id in the case where the referee is an identified Contributor. For a referee who isn't a Contributor yet, the method recruit_referee above is called instead. + + Accessible for: Editor-in-charge and Editorial Administration """ - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) contributor = get_object_or_404(Contributor, pk=contributor_id) + if not contributor.is_currently_available: errormessage = ('This Contributor is marked as currently unavailable. ' 'Please go back and select another referee.') @@ -860,15 +872,15 @@ def send_refereeing_invitation(request, arxiv_identifier_w_vn_nr, contributor_id @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def ref_invitation_reminder(request, arxiv_identifier_w_vn_nr, invitation_id): """ This method is used by the Editor-in-charge from the editorial_page when a referee has been invited but hasn't answered yet. It can be used for registered as well as unregistered referees. + + Accessible for: Editor-in-charge and Editorial Administration """ - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) invitation = get_object_or_404(submission.referee_invitations.all(), pk=invitation_id) invitation.nr_reminders += 1 @@ -891,9 +903,9 @@ def accept_or_decline_ref_invitations(request): RefereeInvitations need to be either accepted or declined by the invited user using this view. The decision will be taken one invitation at a time. """ - invitation = RefereeInvitation.objects.filter(referee__user=request.user, - accepted=None, - cancelled=False).first() + invitation = RefereeInvitation.objects.filter( + referee__user=request.user, accepted=None, cancelled=False).first() + if not invitation: messages.success(request, 'There are no Refereeing Invitations for you to consider.') return redirect(reverse('scipost:personal_page')) @@ -905,7 +917,9 @@ def accept_or_decline_ref_invitations(request): @login_required @permission_required('scipost.can_referee', raise_exception=True) def accept_or_decline_ref_invitation_ack(request, invitation_id): - invitation = get_object_or_404(RefereeInvitation, pk=invitation_id) + invitation = get_object_or_404(RefereeInvitation.objects.filter( + referee__user=request.user, accepted=None, cancelled=False), pk=invitation_id) + form = ConsiderRefereeInvitationForm(request.POST or None) if form.is_valid(): invitation.date_responded = timezone.now() @@ -963,15 +977,20 @@ def decline_ref_invitation(request, invitation_key): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def cancel_ref_invitation(request, arxiv_identifier_w_vn_nr, invitation_id): """ This method is used by the Editor-in-charge from the editorial_page to remove a referee for the list of invited ones. It can be used for registered as well as unregistered referees. + + Accessible for: Editor-in-charge and Editorial Administration """ - invitation = get_object_or_404(RefereeInvitation, pk=invitation_id) + try: + submissions = Submission.objects.filter_for_eic(request.user) + invitation = submissions.referee_invitations.get(pk=invitation_id) + except RefereeInvitation.DoesNotExist: + raise Http404 + invitation.cancelled = True invitation.save() SubmissionUtils.load({'invitation': invitation}) @@ -987,11 +1006,15 @@ def cancel_ref_invitation(request, arxiv_identifier_w_vn_nr, invitation_id): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def extend_refereeing_deadline(request, arxiv_identifier_w_vn_nr, days): - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + """ + Extend Refereeing deadline for Submission and open reporting and commenting. + + Accessible for: Editor-in-charge and Editorial Administration + """ + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) + submission.reporting_deadline += datetime.timedelta(days=int(days)) submission.open_for_reporting = True submission.open_for_commenting = True @@ -1005,10 +1028,14 @@ def extend_refereeing_deadline(request, arxiv_identifier_w_vn_nr, days): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def set_refereeing_deadline(request, arxiv_identifier_w_vn_nr): - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + """ + Set Refereeing deadline for Submission and open reporting and commenting if + the new date is in the future. + + Accessible for: Editor-in-charge and Editorial Administration + """ + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) form = SetRefereeingDeadlineForm(request.POST or None) @@ -1035,8 +1062,6 @@ def set_refereeing_deadline(request, arxiv_identifier_w_vn_nr): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) def close_refereeing_round(request, arxiv_identifier_w_vn_nr): """ Called by the Editor-in-charge when a satisfactory number of @@ -1044,9 +1069,12 @@ def close_refereeing_round(request, arxiv_identifier_w_vn_nr): Automatically emails the authors to ask them if they want to round off any replies to reports or comments before the editorial recommendation is formulated. + + Accessible for: Editor-in-charge and Editorial Administration """ - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) + submission.open_for_reporting = False submission.open_for_commenting = False if submission.status == 'EICassigned': # only close if currently undergoing refereeing @@ -1076,14 +1104,14 @@ def communication(request, arxiv_identifier_w_vn_nr, comtype, referee_id=None): Communication between editor-in-charge, author or referee occurring during the submission refereeing. """ - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + submission = get_object_or_404(Submission.objects.pool_full(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) errormessage = None if comtype not in dict(ED_COMM_CHOICES).keys(): errormessage = 'Unknown type of cummunication.' # TODO: Verify that this is requested by an authorized contributor (eic, ref, author) elif (comtype in ['EtoA', 'EtoR', 'EtoS'] and - not request.user.has_perm('can_take_editorial_actions', submission)): + submission.editor_in_charge != request.user.contributor): errormessage = 'Only the Editor-in-charge can perform this action.' elif (comtype in ['AtoE'] and not (request.user.contributor == submission.submitted_by)): @@ -1123,12 +1151,16 @@ def communication(request, arxiv_identifier_w_vn_nr, comtype, referee_id=None): @login_required -@permission_required_or_403('can_take_editorial_actions', - (Submission, 'arxiv_identifier_w_vn_nr', 'arxiv_identifier_w_vn_nr')) @transaction.atomic def eic_recommendation(request, arxiv_identifier_w_vn_nr): - submission = get_object_or_404(Submission.objects.pool_editable(request.user), + """ + Write EIC Recommendation. + + Accessible for: Editor-in-charge and Editorial Administration + """ + submission = get_object_or_404(Submission.objects.filter_for_eic(request.user), arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr) + if submission.eic_recommendation_required(): messages.warning(request, ('<h3>An Editorial Recommendation is not required</h3>' 'This submission\'s current status is: <em>%s</em>' @@ -1265,10 +1297,6 @@ def submit_report(request, arxiv_identifier_w_vn_nr): SubmissionUtils.email_EIC_report_delivered() SubmissionUtils.email_referee_report_delivered() - # Assign explicit permission to EIC to vet this report - assign_perm('submissions.can_vet_submitted_reports', submission.editor_in_charge.user, - newreport) - # Add SubmissionEvents for the EIC only, as it can also be rejected still submission.add_event_for_eic('%s has submitted a new Report.' % request.user.last_name) @@ -1281,12 +1309,13 @@ def submit_report(request, arxiv_identifier_w_vn_nr): @login_required -@permission_required('submissions.can_vet_submitted_reports', raise_exception=True) def vet_submitted_reports_list(request): """ Reports with status `unvetted` will be shown (oldest first). """ - reports_to_vet = Report.objects.awaiting_vetting().order_by('date_submitted') + submissions = get_list_or_404(Submission.objects.filter_for_eic(request.user)) + reports_to_vet = Report.objects.filter( + submission__in=submissions).awaiting_vetting().order_by('date_submitted') context = {'reports_to_vet': reports_to_vet} return render(request, 'submissions/vet_submitted_reports_list.html', context) @@ -1301,11 +1330,9 @@ def vet_submitted_report(request, report_id): After vetting an email is sent to the report author, bcc EIC. If report has not been refused, the submission author is also mailed. """ - # Method `get_objects_for_user` gets all Reports that are assigned to the user - # or *all* Reports if user is SciPost Admin or Vetting Editor. - report = get_object_or_404((get_objects_for_user(request.user, - 'submissions.can_vet_submitted_reports') - .awaiting_vetting()), id=report_id) + submissions = Submission.objects.filter_for_eic(request.user) + report = get_object_or_404(Report.objects.filter( + submission__in=submissions).awaiting_vetting(), id=report_id) form = VetReportForm(request.POST or None, initial={'report': report}) if form.is_valid(): @@ -1340,61 +1367,48 @@ def vet_submitted_report(request, report_id): return render(request, 'submissions/vet_submitted_report.html', context) +@login_required @permission_required('scipost.can_prepare_recommendations_for_voting', raise_exception=True) @transaction.atomic def prepare_for_voting(request, rec_id): submissions = Submission.objects.pool_editable(request.user) - recommendation = get_object_or_404(EICRecommendation.objects.filter(submission__in=submissions), - id=rec_id) - - # Fellows_with_expertise = Contributor.objects.filter( - # user__groups__name__in=['Editorial College'], - # expertises__contains=[recommendation.submission.subject_area]) - fellows_with_expertise = (recommendation.submission.fellows - .filter(expertises__contains=recommendation.submission.subject_area)) + recommendation = get_object_or_404( + EICRecommendation.objects.filter(submission__in=submissions), id=rec_id) + + fellows_with_expertise = recommendation.submission.fellows.filter( + expertises__contains=recommendation.submission.subject_area) + coauthorships = {} - if request.method == 'POST': - eligibility_form = VotingEligibilityForm( - request.POST, - discipline=recommendation.submission.discipline, - subject_area=recommendation.submission.subject_area - ) - if eligibility_form.is_valid(): - recommendation.eligible_to_vote = eligibility_form.cleaned_data['eligible_Fellows'] - recommendation.voted_for.add(recommendation.submission.editor_in_charge) - recommendation.save() - recommendation.submission.status = 'put_to_EC_voting' - recommendation.submission.save() - messages.success(request, 'We have registered your selection.') - # Add SubmissionEvents - recommendation.submission.add_event_for_eic('The Editorial Recommendation has been ' - 'put forward to the College for voting.') + eligibility_form = VotingEligibilityForm(request.POST or None, instance=recommendation) + if eligibility_form.is_valid(): + eligibility_form.save() + messages.success(request, 'We have registered your selection.') - return redirect(reverse('submissions:editorial_page', - args=[recommendation.submission.arxiv_identifier_w_vn_nr])) + # Add SubmissionEvents + recommendation.submission.add_event_for_eic('The Editorial Recommendation has been ' + 'put forward to the College for voting.') + + return redirect(reverse('submissions:editorial_page', + args=[recommendation.submission.arxiv_identifier_w_vn_nr])) else: # Identify possible co-authorships in last 3 years, disqualifying Fellow from voting: if recommendation.submission.metadata is not None: - for Fellow in fellows_with_expertise: + for fellow in fellows_with_expertise: sub_auth_boolean_str = '((' + (recommendation.submission .metadata['entries'][0]['authors'][0]['name'] .split()[-1]) for author in recommendation.submission.metadata['entries'][0]['authors'][1:]: sub_auth_boolean_str += '+OR+' + author['name'].split()[-1] sub_auth_boolean_str += ')+AND+' - search_str = sub_auth_boolean_str + Fellow.user.last_name + ')' + search_str = sub_auth_boolean_str + fellow.user.last_name + ')' queryurl = ('http://export.arxiv.org/api/query?search_query=au:%s' % search_str + '&sortBy=submittedDate&sortOrder=descending' '&max_results=5') arxivquery = feedparser.parse(queryurl) queryresults = arxivquery if queryresults.entries: - coauthorships[Fellow.user.last_name] = queryresults - - eligibility_form = VotingEligibilityForm( - discipline=recommendation.submission.discipline, - subject_area=recommendation.submission.subject_area) + coauthorships[fellow.user.last_name] = queryresults context = { 'recommendation': recommendation, @@ -1405,12 +1419,12 @@ def prepare_for_voting(request, rec_id): return render(request, 'submissions/prepare_for_voting.html', context) -@permission_required('scipost.can_take_charge_of_submissions', raise_exception=True) +@login_required @transaction.atomic def vote_on_rec(request, rec_id): submissions = Submission.objects.pool_editable(request.user) - recommendation = get_object_or_404(EICRecommendation.objects.filter(submission__in=submissions), - id=rec_id) + recommendation = get_object_or_404( + EICRecommendation.objects.filter(submission__in=submissions), id=rec_id) form = RecommendationVoteForm(request.POST or None) if form.is_valid(): @@ -1501,9 +1515,9 @@ def fix_College_decision(request, rec_id): TO FIX: If multiple recommendations are submitted; decisions may be overruled unexpectedly. TO FIX: A college decision can be fixed multiple times, there is no already-fixed mechanism!!! """ - submissions = Submission.objects.pool_editable(request.user) - recommendation = get_object_or_404(EICRecommendation.objects.filter(submission__in=submissions), - id=rec_id) + submissions = Submission.objects.pool_full(request.user) + recommendation = get_object_or_404(EICRecommendation.objects.filter( + submission__in=submissions), id=rec_id) submission = recommendation.submission if recommendation.recommendation in [1, 2, 3]: