diff --git a/scipost_django/submissions/forms.py b/scipost_django/submissions/forms.py index 0dd9a33dc81efd2118d846fd8e46642fbc0f6012..70df4c571b8bb985da8ea0368fd372f26e9f5632 100644 --- a/scipost_django/submissions/forms.py +++ b/scipost_django/submissions/forms.py @@ -345,9 +345,9 @@ class SubmissionPoolSearchForm(forms.Form): if self.cleaned_data.get("search_set") == "eic": submissions = Submission.objects.filter_for_eic(user) elif self.cleaned_data.get("search_set") == "current": - submissions = Submission.objects.pool_for_user(user) + submissions = Submission.objects.in_pool(user) else: # include historical items - submissions = Submission.objects.pool_for_user(user, historical=True) + submissions = Submission.objects.in_pool(user, historical=True) if self.cleaned_data.get("specialties"): submissions = submissions.filter( specialties__in=self.cleaned_data.get("specialties") diff --git a/scipost_django/submissions/managers/assignment.py b/scipost_django/submissions/managers/assignment.py index 213108e6f892250666bdeb5fe07b45f72d7cb8a3..7913241097950da9c7eb04851785ead46fb8a2e1 100644 --- a/scipost_django/submissions/managers/assignment.py +++ b/scipost_django/submissions/managers/assignment.py @@ -10,11 +10,6 @@ from .. import constants class EditorialAssignmentQuerySet(models.QuerySet): - def get_for_user_in_pool(self, user): - return self.exclude(submission__authors=user.contributor).exclude( - models.Q(submission__author_list__icontains=user.last_name), - ~models.Q(submission__authors_false_claims=user.contributor), - ) def last_year(self): return self.filter( diff --git a/scipost_django/submissions/managers/submission.py b/scipost_django/submissions/managers/submission.py index 16086616a5fbdc6211fbc151daf98df971cfb619..87dfc470c36010a5cd36eed6cc3d1b4d937b3cf5 100644 --- a/scipost_django/submissions/managers/submission.py +++ b/scipost_django/submissions/managers/submission.py @@ -12,15 +12,15 @@ from .. import constants class SubmissionQuerySet(models.QuerySet): - def latest(self, queryset): - return queryset.exclude(status=self.model.RESUBMITTED) + def latest(self): + return self.exclude(status=self.model.RESUBMITTED) def remove_COI(self, user): """ Filter on basic conflicts of interest. - Prevent conflicts of interest by filtering submissions possibly related to user. - This filter should be inherited by other filters. + Prevent conflicts of interest by filtering out submissions + which are possibly related to user. """ try: return self.exclude(authors=user.contributor).exclude( @@ -30,74 +30,39 @@ class SubmissionQuerySet(models.QuerySet): except AttributeError: return self.none() - def _pool(self, user): - """Return the user-dependent pool of Submissions. - - This filter creates 'the complete pool' for a user. This new-style pool does - explicitly not have the author filter anymore, but registered pools for every Submission. - - !!! IMPORTANT SECURITY NOTICE !!! - All permissions regarding Editorial College actions are implicitly taken care - of in this filter method! ALWAYS use this filter method in your Editorial College - related view/action. - """ - if not hasattr(user, "contributor"): - return self.none() - - if user.has_perm("scipost.can_oversee_refereeing"): - # Editorial Administators do have permission to see all submissions - # without being one of the College Fellows. Therefore, use the 'old' author - # filter to still filter out their conflicts of interests. - return self.remove_COI(user) - else: - qs = user.contributor.fellowships.active() - return self.filter(fellows__in=qs) - - def pool_for_user(self, user, historical: bool=False): + def in_pool(self, user, historical: bool=False): """ - Return the pool of Submissions (current or historical), filtered for the user. + Filter for Submissions (current or historical) in user's pool. - * if user is EdAdmin: + If `historical==False`: only submissions UNDER_CONSIDERATION, + otherwise show full history. - * `historical==False`: Submission status in UNDER_CONSIDERATION - * `historical==True`: all + For non-EdAdmin: user must have active Fellowship and + be listed in Submission's Fellowship. - * if user is currently active Fellow: + For Senior Fellows, exclude INCOMING status; + for other Fellows, also exclude PRESCREENING. - * Fellow in Submission's fellowship and - * Submission status in UNDER_CONSIDERATION but not INCOMING or PRESCREENING - - * `historical==False`: - * `historical=True`: - - and then filter for COI. + Finally, filter out the COI. """ - # allowed_statuses = [ - # self.model.UNASSIGNED, - # self.model.EIC_ASSIGNED, - # self.model.ACCEPTED, - # self.model.ACCEPTED_AWAITING_PUBOFFER_ACCEPTANCE, - # ] - # if ( - # user.has_perm("scipost.can_oversee_refereeing") - # or user.contributor.is_active_senior_fellow - # ): - # allowed_statuses.append(self.model.INCOMING) - # return self._pool(user).filter( - # is_current=True, status__in=allowed_statuses - # ) - if not hasattr(user, "contributor"): + if not (hasattr(user, "contributor") and + user.has_perm("scipost.can_view_pool")): return self.none() - qs = self.none() - if user.contributor.is_ed_admin: - qs = self.filter(status__in=self.model.UNDER_CONSIDERATION) - else: + qs = self + if not historical: + qs = qs.latest().filter(status__in=self.model.UNDER_CONSIDERATION) + + # for non-EdAdmin, filter: in Submission's Fellowship + if not user.contributor.is_ed_admin: f_ids = user.contributor.fellowships.active() qs = self.filter(fellows__in=f_ids) - if not historical: - qs = qs.latest() + # Fellows can't see incoming and (non-Senior) prescreening + if user.contributor.is_active_senior_fellow: + qs = qs.exclude(status__in=[self.model.INCOMING,]) + elif user.contributor.is_active_fellow: + qs = qs.exclude(status__in=[self.model.INCOMING, self.model.PRESCREENING]) return qs.remove_COI(user) @@ -107,8 +72,8 @@ class SubmissionQuerySet(models.QuerySet): If user is an Editorial Administrator: return the full pool. """ - qs = self._pool(user) - if user.is_authenticated and not user.has_perm("scipost.can_oversee_refereeing"): + qs = self.in_pool(user) + if user.is_authenticated and not user.contributor.is_ed_admin: qs = qs.filter(editor_in_charge__user=user) return qs @@ -167,7 +132,7 @@ class SubmissionQuerySet(models.QuerySet): This query contains set of public() submissions, filtered to only the latest available version. """ - return self.latest(self.public()) + return self.latest().public() def treated(self): """This query returns all Submissions that are presumed to be 'done'.""" @@ -227,11 +192,11 @@ class SubmissionQuerySet(models.QuerySet): def rejected(self): """Return rejected Submissions.""" - return self.latest(self.filter(status=self.model.REJECTED)) + return self.latest().filter(status=self.model.REJECTED) def withdrawn(self): """Return withdrawn Submissions.""" - return self.latest(self.filter(status=self.model.WITHDRAWN)) + return self.latest().filter(status=self.model.WITHDRAWN) def open_for_reporting(self): """Return Submissions open for reporting.""" diff --git a/scipost_django/submissions/migrations/0120_alter_submission_status.py b/scipost_django/submissions/migrations/0120_alter_submission_status.py new file mode 100644 index 0000000000000000000000000000000000000000..e3f78bb18d7d88e26f248f1e5e33f1ae45402acb --- /dev/null +++ b/scipost_django/submissions/migrations/0120_alter_submission_status.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.16 on 2022-11-26 08:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('submissions', '0119_auto_20221126_0742'), + ] + + operations = [ + migrations.AlterField( + model_name='submission', + name='status', + field=models.CharField(choices=[('incoming', 'Submission incoming, awaiting EdAdmin'), ('admission_failed', 'Admission failed'), ('prescreening', 'In pre-screening'), ('failed_pre', 'Failed pre-screening'), ('prescreening_failed', 'Pre-screening failed'), ('unassigned', 'Unassigned, awaiting editor assignment'), ('screening', 'In screening'), ('screening_failed', 'Screening failed'), ('assigned', 'Editor-in-charge assigned'), ('assignment_failed', 'Failed to assign Editor-in-charge; manuscript rejected'), ('refereeing_in_preparation', 'Refereeing in preparation'), ('in_refereeing', 'In refereeing'), ('refereeing_closed', 'Refereeing closed (awaiting author replies and EdRec)'), ('awaiting_resubmission', 'Awaiting resubmission'), ('resubmitted', 'Has been resubmitted'), ('voting_in_preparation', 'Voting in preparation'), ('in_voting', 'In voting'), ('awaiting_decision', 'Awaiting decision'), ('accepted', 'Publication decision taken: accept'), ('accepted_in_target', 'Accepted in target Journal'), ('puboffer_waiting', 'Accepted in other journal; awaiting puboffer acceptance'), ('accepted_alt_puboffer_waiting', 'Accepted in alternative Journal; awaiting puboffer acceptance'), ('accepted_alt', 'Accepted in alternative Journal'), ('rejected', 'Publication decision taken: reject'), ('withdrawn', 'Withdrawn by the Authors'), ('published', 'Published')], default='incoming', max_length=30), + ), + ] diff --git a/scipost_django/submissions/models/submission.py b/scipost_django/submissions/models/submission.py index da4eb8375ac3d228924ed240d7eed7b38024d5be..7c258dd76e937f1820291a9dd9df63c5af13c39e 100644 --- a/scipost_django/submissions/models/submission.py +++ b/scipost_django/submissions/models/submission.py @@ -77,11 +77,11 @@ class Submission(models.Model): SUBMISSION_STATUSES = ( (INCOMING, "Submission incoming, awaiting EdAdmin"), ## descriptor rephrased (ADMISSION_FAILED, "Admission failed"), ## new - (PRESCREENING, "Undergoing pre-screening"), ## new + (PRESCREENING, "In pre-screening"), ## new (FAILED_PRESCREENING, "Failed pre-screening"), ## rename: PRESCREENING_FAILED (PRESCREENING_FAILED, "Pre-screening failed"), ## new (UNASSIGNED, "Unassigned, awaiting editor assignment"), ## rename: SCREENING - (SCREENING, "Undergoing screening"), ## new, replacement for UNASSIGNED + (SCREENING, "In screening"), ## new, replacement for UNASSIGNED (SCREENING_FAILED, "Screening failed"), ## new (EIC_ASSIGNED, "Editor-in-charge assigned"), ## rename: IN_REFEREEING or others ( @@ -376,22 +376,6 @@ class Submission(models.Model): """Return string representation of this Submission as shown in Notifications.""" return self.preprint.identifier_w_vn_nr - ###################### - # Deal with statuses # - ###################### - - @property - def pool_statuses_list_Senior_Fellows(self): - statuses = list(self.UNDER_CONSIDERATION) - statuses.remove(self.INCOMING) - return statuses - - @property - def pool_statuses_list(self): - statuses = list(self.UNDER_CONSIDERATION) - statuses.remove(self.INCOMING, self.PRESCREENING) - return statuses - @property def eic_recommendation_required(self): """Return if Submission requires a EICRecommendation to be formulated.""" diff --git a/scipost_django/submissions/templates/submissions/pool/hx_submissions_list.html b/scipost_django/submissions/templates/submissions/pool/hx_submissions_list.html index 72741e68b3b4901254a6978e77a9cf841f6d3c69..7eb1a20d9d1ce7ec57293b487c6da3dcc036d8aa 100644 --- a/scipost_django/submissions/templates/submissions/pool/hx_submissions_list.html +++ b/scipost_django/submissions/templates/submissions/pool/hx_submissions_list.html @@ -1,4 +1,5 @@ {% for submission in page_obj %} + <li{% if not forloop.first %} class="mt-4"{% endif %}><strong>{{ forloop.counter0|add:start_index }} of {{ count }}</strong></li> <li class="submission p-2 mb-2" id="submission_{{ submission.id }}"> {% include 'submissions/pool/_hx_submission_li.html' with submission=submission %} </li> diff --git a/scipost_django/submissions/views.py b/scipost_django/submissions/views.py index 7bb49b9c8ac7c1298ec4dc316419cf856ca2316d..d686a368c95b787a0fcf95086e6bd2de8f9f9e63 100644 --- a/scipost_django/submissions/views.py +++ b/scipost_django/submissions/views.py @@ -886,11 +886,14 @@ def pool_hx_submissions_list(request): if form.is_valid(): submissions = form.search_results(request.user) else: - submissions = Submission.objects.pool(request.user)[:16] + submissions = Submission.objects.in_pool(request.user)[:16] paginator = Paginator(submissions, 16) page_nr = request.GET.get("page") page_obj = paginator.get_page(page_nr) - context = {"page_obj": page_obj} + count = paginator.count + start_index = page_obj.start_index + end_index = page_obj.end_index + context = {"count": count, "page_obj": page_obj, "start_index": start_index, "end_index": end_index,} return render(request, "submissions/pool/hx_submissions_list.html", context) @@ -898,7 +901,7 @@ def pool_hx_submissions_list(request): @fellowship_or_admin_required() def pool_hx_submission_details(request, identifier_w_vn_nr): submission = get_object_or_404( - Submission.objects.pool_for_user(request.user, historical=True), + Submission.objects.in_pool(request.user, historical=True), preprint__identifier_w_vn_nr=identifier_w_vn_nr, ) context = {"remark_form": RemarkForm(), "submission": submission} @@ -914,7 +917,7 @@ def add_remark(request, identifier_w_vn_nr): is adding a remark on a Submission. """ submission = get_object_or_404( - Submission.objects.pool_for_user(request.user), + Submission.objects.in_pool(request.user), preprint__identifier_w_vn_nr=identifier_w_vn_nr, ) @@ -988,7 +991,7 @@ def submission_remove_topic(request, identifier_w_vn_nr, slug): def editorial_assignment(request, identifier_w_vn_nr, assignment_id=None): """Editorial Assignment form view.""" submission = get_object_or_404( - Submission.objects.unassigned().pool_for_user(request.user), + Submission.objects.unassigned().in_pool(request.user), preprint__identifier_w_vn_nr=identifier_w_vn_nr, ) @@ -1107,7 +1110,7 @@ def update_authors_screening(request, identifier_w_vn_nr, nrweeks): Send an email to the authors, informing them that screening is still ongoing after one week. """ submission = get_object_or_404( - Submission.objects.pool(request.user).unassigned(), + Submission.objects.in_pool(request.user).unassigned(), preprint__identifier_w_vn_nr=identifier_w_vn_nr, ) if nrweeks == 1: @@ -1142,7 +1145,7 @@ def assignment_failed(request, identifier_w_vn_nr): Submission is rejected. An Editorial Administrator can access this view from the Pool. """ submission = get_object_or_404( - Submission.objects.pool(request.user).unassigned(), + Submission.objects.in_pool(request.user).unassigned(), preprint__identifier_w_vn_nr=identifier_w_vn_nr, ) @@ -1206,7 +1209,7 @@ def editorial_page(request, identifier_w_vn_nr): for both the Editor-in-charge of the Submission and the Editorial Administration. """ submission = get_object_or_404( - Submission.objects.pool_for_user(request.user, historical=True), + Submission.objects.in_pool(request.user, historical=True), preprint__identifier_w_vn_nr=identifier_w_vn_nr, ) @@ -1819,7 +1822,7 @@ def close_refereeing_round(request, identifier_w_vn_nr): def refereeing_overview(request): """List all Submissions undergoing active Refereeing.""" submissions_under_refereeing = ( - Submission.objects.pool_for_user(request.user) + Submission.objects.in_pool(request.user) .actively_refereeing() .order_by("submission_date") ) @@ -1855,7 +1858,7 @@ def communication(request, identifier_w_vn_nr, comtype, referee_id=None): # Editorial Administration to Editor if not request.user.has_perm("scipost.can_oversee_refereeing"): raise PermissionDenied - submissions_qs = Submission.objects.pool_for_user(request.user) + submissions_qs = Submission.objects.in_pool(request.user) referee = request.user.contributor else: # Invalid commtype in the url! @@ -2231,7 +2234,7 @@ def vet_submitted_report(request, report_id): @transaction.atomic def prepare_for_voting(request, rec_id): """Form view to prepare a EICRecommendation for voting.""" - submissions = Submission.objects.pool_for_user(request.user) + submissions = Submission.objects.in_pool(request.user) recommendation = get_object_or_404( EICRecommendation.objects.voting_in_preparation().filter( submission__in=submissions @@ -2306,7 +2309,7 @@ def claim_voting_right(request, rec_id): @transaction.atomic def vote_on_rec(request, rec_id): """Form view for Fellows to cast their vote on EICRecommendation.""" - submissions = Submission.objects.pool_for_user(request.user) + submissions = Submission.objects.in_pool(request.user) previous_vote = None try: recommendation = EICRecommendation.objects.user_must_vote_on(request.user).get(