diff --git a/SciPost_v1/settings/base.py b/SciPost_v1/settings/base.py index f3a4ed8e5a68b10a591d4081d9ea2e8ec02948fa..e8f29b0f4209cc0214a02086a00521e75bf228e0 100644 --- a/SciPost_v1/settings/base.py +++ b/SciPost_v1/settings/base.py @@ -97,6 +97,7 @@ INSTALLED_APPS = ( 'production', 'partners', 'funders', + 'stats', 'webpack_loader', ) diff --git a/SciPost_v1/urls.py b/SciPost_v1/urls.py index fc2b471e09c717922963e7287c2600c115d356a1..9b7e8331c703ed4a7cd925041ca042770c50d5c4 100644 --- a/SciPost_v1/urls.py +++ b/SciPost_v1/urls.py @@ -43,7 +43,7 @@ urlpatterns = [ url(r'^news/', include('news.urls', namespace="news")), url(r'^production/', include('production.urls', namespace="production")), url(r'^partners/', include('partners.urls', namespace="partners")), - + url(r'^stats/', include('stats.urls', namespace="stats")), # Keep temporarily for historical reasons url(r'^supporting_partners/', include('partners.urls', namespace="_partners")), ] diff --git a/scipost/templates/scipost/personal_page.html b/scipost/templates/scipost/personal_page.html index ae21f523980dc7ef829eae44ee1a17b7aac1599b..0ff78b8eeff9914108b8d946cbc9e338cc1e7c15 100644 --- a/scipost/templates/scipost/personal_page.html +++ b/scipost/templates/scipost/personal_page.html @@ -322,7 +322,7 @@ <h3>Refereeing overview</h3> <ul> <li>View (and act on) outstanding refereeing invitations in the <a href="{% url 'submissions:refereeing_overview' %}">refereeing overview</a></li> - <li><a href="{% url 'submissions:statistics' %}">View statistics</a> for submissions, refereeing, publishing</li> + <li><a href="{% url 'stats:statistics' %}">View statistics</a> for submissions, refereeing, publishing</li> </ul> <h3>Voting</h3> <ul> diff --git a/stats/__init__.py b/stats/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/stats/admin.py b/stats/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e --- /dev/null +++ b/stats/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/stats/apps.py b/stats/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..2d09b92ca1ba59e93693ada2c0c0dd7340a9df15 --- /dev/null +++ b/stats/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class StatsConfig(AppConfig): + name = 'stats' diff --git a/stats/migrations/__init__.py b/stats/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/stats/models.py b/stats/models.py new file mode 100644 index 0000000000000000000000000000000000000000..71a836239075aa6e6e4ecb700e9c42c95c022d91 --- /dev/null +++ b/stats/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/stats/templates/stats/statistics.html b/stats/templates/stats/statistics.html new file mode 100644 index 0000000000000000000000000000000000000000..afe2e43169338f2304e354f5c728868913baa7e2 --- /dev/null +++ b/stats/templates/stats/statistics.html @@ -0,0 +1,114 @@ +{% extends 'submissions/_pool_base.html' %} + +{% block pagetitle %}: statistics for submisisons{% endblock pagetitle %} + +{% load scipost_extras %} +{% load stats_extras %} + +{% load bootstrap %} + +{% block breadcrumb_items %} + {{block.super}} + <span class="breadcrumb-item">Statistics</span> +{% endblock %} + +{% block content %} + +<h1 class="highlight">Statistics</h1> + +<h2>Aggregate statistics</h2> +<p>For each Journal, clicking on a year gives aggregate statistics for Submissions (so including rejections and withdrawals) which were first submitted in that year.</p> +<p>Clicking on a Journal/Volume/Issue gives aggregates for all publications in that object.</p> +<ul> + {% for journal in journals|dictsort:"doi_label" %} + <li><a href="{% url 'stats:statistics' journal_doi_label=journal.doi_label %}">{{ journal }}</a></li> + <ul> + {% for year in journal|journal_publication_years %} + <li><a href="{% url 'stats:statistics' journal_doi_label=journal.doi_label year=year %}">{{ year }}</a></li> + {% endfor %} + </ul> + <ul> +{% for volume in journal.volume_set.all|dictsort:"number" %} +<li><a href="{% url 'stats:statistics' journal_doi_label=journal.doi_label volume_nr=volume.number %}">{{ volume }}</a></li> +<ul> + {% for issue in volume.issue_set.all|dictsort:"number" %} + <li><a href="{% url 'stats:statistics' journal_doi_label=journal.doi_label volume_nr=volume.number issue_nr=issue.number %}">{{ issue }}</a></li> + {% endfor %} +</ul> +{% endfor %} + </ul> + {% endfor %} +</ul> + +{% if journal %} + <h2>Results:</h2> + <table class="table"> + <tr> + <th>DOI label</th> + {% if year %} + <th>Year</th> + <th>Nr submissions<br/>(distinct)</th> + <th>Nr submissions<br/>(including resubmissions)</th> + <th>Nr assignment failed</th> + <th>Nr accepted/<br/>published</th> + <th>Nr rejected</th> + <th>Nr withdrawn</th> + {% else %} + <th>Nr publications</th> + <th>Duration average</th> + {% endif %} + </tr> + <tr> + {% if issue %} + <td>{{ issue.doi_label }}</td> + <td>{{ issue|issue_nr_publications }}</td> + <td>{{ issue|issue_avg_processing_duration|floatformat:2 }} days</td> + {% elif volume %} + <td>{{ volume.doi_label }}</td> + <td>{{ volume|volume_nr_publications }}</td> + <td>{{ volume|volume_avg_processing_duration|floatformat:2 }} days</td> + {% else %} + <td>{{ journal.doi_label }}</td> + {% if year %} + <td>{{ year }}</td> + <td>{{ submissions|submissions_count_distinct }}</td> + <td>{{ submissions|length }}</td> + <td>{{ submissions.assignment_failed.count }}</td> + <td>{{ submissions.accepted.count|add:submissions.published.count }}</td> + <td>{{ submissions.rejected.count }}</td> + <td>{{ submissions.withdrawn.count }}</td> + {% else %} + <td>{{ journal|journal_nr_publications }}</td> + <td>{{ journal|journal_avg_processing_duration|floatformat:2 }} days</td> + {% endif %} + {% endif %} + </tr> + </table> + {% endif %} + + {% if year %} + <h2>Refereeing stats for {{ year }}</h2> + <table class="table"> + <tr> + <th>Nr refereeing<br/>invitations</th> + <th>Nr accepted</th> + <th>Nr declined</th> + <th>Nr pending</th> + <th>Nr reports<br/>obtained</th> + <th>Nr obtained<br/>(invited)</th> + <th>Nr obtained<br/>(contributed)</th> + </tr> + <tr> + <td>{{ nr_ref_inv }}</td> + <td>{{ nr_acc }} ({% widthratio nr_acc nr_ref_inv 100 %}%)</td> + <td>{{ nr_dec }} ({% widthratio nr_dec nr_ref_inv 100 %}%)</td> + <td>{{ nr_pen }} ({% widthratio nr_pen nr_ref_inv 100 %}%)</td> + <td>{{ nr_rep_obt }}</td> + <td>{{ nr_rep_obt_inv }} ({% widthratio nr_rep_obt_inv nr_rep_obt 100 %}%)</td> + <td>{{ nr_rep_obt_con }} ({% widthratio nr_rep_obt_con nr_rep_obt 100 %}%)</td> + </tr> + </table> + {% endif %} + + +{% endblock content %} diff --git a/stats/templatetags/stats_extras.py b/stats/templatetags/stats_extras.py new file mode 100644 index 0000000000000000000000000000000000000000..9c5c6e636f86716021b322f4c66afe2090b2a294 --- /dev/null +++ b/stats/templatetags/stats_extras.py @@ -0,0 +1,69 @@ +from django import template +from django.db.models import Avg, F + +from journals.models import Publication +from submissions.constants import SUBMISSION_STATUS_OUT_OF_POOL +from submissions.models import Submission + +register = template.Library() + + + +@register.filter(name='submissions_count_distinct') +def submissions_count_distinct(submissions): + identifiers_wo_vn_nr = [] + for submission in submissions: + if submission.arxiv_identifier_wo_vn_nr not in identifiers_wo_vn_nr: + identifiers_wo_vn_nr.append(submission.arxiv_identifier_wo_vn_nr) + return len(identifiers_wo_vn_nr) + + +@register.filter(name='journal_publication_years') +def journal_publication_years(journal): + years = [] + for volume in journal.volume_set.all(): + if volume.until_date.year not in years: + years.append(volume.until_date.year) + return sorted(years) + + +@register.filter(name='journal_nr_publications') +def journal_nr_publications(journal): + return Publication.objects.filter(in_issue__in_volume__in_journal=journal).count() + + +@register.filter(name='journal_avg_processing_duration') +def journal_avg_processing_duration(journal): + duration = Publication.objects.filter( + in_issue__in_volume__in_journal=journal).aggregate( + avg=Avg(F('publication_date') - F('submission_date')))['avg'] + if not duration: return 0 + return duration.days + duration.seconds/86400 + + +@register.filter(name='volume_nr_publications') +def volume_nr_publications(volume): + return Publication.objects.filter(in_issue__in_volume=volume).count() + + +@register.filter(name='volume_avg_processing_duration') +def volume_avg_processing_duration(volume): + duration = Publication.objects.filter( + in_issue__in_volume=volume).aggregate( + avg=Avg(F('publication_date') - F('submission_date')))['avg'] + if not duration: return 0 + return duration.days + duration.seconds/86400 + + +@register.filter(name='issue_nr_publications') +def issue_nr_publications(issue): + return Publication.objects.filter(in_issue=issue).count() + + +@register.filter(name='issue_avg_processing_duration') +def issue_avg_processing_duration(issue): + duration = Publication.objects.filter( + in_issue=issue).aggregate( + avg=Avg(F('publication_date') - F('submission_date')))['avg'] + if not duration: return 0 + return duration.days + duration.seconds/86400 diff --git a/stats/tests.py b/stats/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6 --- /dev/null +++ b/stats/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/stats/urls.py b/stats/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..cddb6d0f7376ab3143acf99f2937b93c09dd8282 --- /dev/null +++ b/stats/urls.py @@ -0,0 +1,14 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)/(?P<volume_nr>[0-9]+)/(?P<issue_nr>[0-9]+)$', + views.statistics, name='statistics'), + url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)/(?P<volume_nr>[0-9]+)$', + views.statistics, name='statistics'), + url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)$', views.statistics, name='statistics'), + url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)/year/(?P<year>[0-9]{4,})$', + views.statistics, name='statistics'), + url(r'^statistics$', views.statistics, name='statistics'), +] diff --git a/stats/views.py b/stats/views.py new file mode 100644 index 0000000000000000000000000000000000000000..3b3ac22ac7d4c29fcb6271d184c53ddc905e1210 --- /dev/null +++ b/stats/views.py @@ -0,0 +1,57 @@ +import datetime + +from django.contrib.auth.decorators import login_required, permission_required +from django.shortcuts import get_object_or_404, render + +from journals.constants import SCIPOST_JOURNALS_SUBMIT +from journals.models import Journal, Volume, Issue, Publication +from submissions.models import Submission + + +@permission_required('scipost.can_oversee_refereeing', raise_exception=True) +def statistics(request, journal_doi_label=None, volume_nr=None, issue_nr=None, year=None): + journals = Journal.objects.all() + context = { + 'journals': journals, + } + if journal_doi_label: + journal = get_object_or_404(Journal, doi_label=journal_doi_label) + context['journal'] = journal + if year: + context['year'] = year + submissions = Submission.objects.filter(submitted_to_journal=journal_doi_label + ).originally_submitted(datetime.date(int(year), 1, 1), datetime.date(int(year), 12, 31)) + context['submissions'] = submissions + nr_ref_inv = 0 + nr_acc = 0 + nr_dec = 0 + nr_pen = 0 + nr_rep_obt = 0 + nr_rep_obt_inv = 0 + nr_rep_obt_con = 0 + nr_rep_ref = 0 + nr_aw_vet = 0 + for submission in submissions: + nr_ref_inv += submission.referee_invitations.count() + nr_acc += submission.count_accepted_invitations() + nr_dec += submission.count_declined_invitations() + nr_pen += submission.count_pending_invitations() + nr_rep_obt += submission.count_obtained_reports() + nr_rep_obt_inv += submission.count_invited_reports() + nr_rep_obt_con += submission.count_contrib_reports() + context['nr_ref_inv'] = nr_ref_inv + context['nr_acc'] = nr_acc + context['nr_dec'] = nr_dec + context['nr_pen'] = nr_pen + context['nr_rep_obt'] = nr_rep_obt + context['nr_rep_obt_inv'] = nr_rep_obt_inv + context['nr_rep_obt_con'] = nr_rep_obt_con + if volume_nr: + volume = get_object_or_404(Volume, in_journal=journal, + number=volume_nr) + context['volume'] = volume + if issue_nr: + issue = get_object_or_404(Issue, in_volume=volume, + number=issue_nr) + context['issue'] = issue + return render(request, 'stats/statistics.html', context) diff --git a/submissions/constants.py b/submissions/constants.py index 943de541f9e517ddce9b8ceb90bbaebda95e9cf5..5252e752e27ddad562a456d07f9893ef681cef8f 100644 --- a/submissions/constants.py +++ b/submissions/constants.py @@ -2,6 +2,7 @@ from journals.constants import SCIPOST_JOURNAL_PHYSICS STATUS_UNASSIGNED = 'unassigned' +STATUS_ASSIGNMENT_FAILED = 'assignment_failed' STATUS_RESUBMISSION_INCOMING = 'resubmitted_incoming' STATUS_REVISION_REQUESTED = 'revision_requested' STATUS_EIC_ASSIGNED = 'EICassigned' @@ -14,10 +15,15 @@ STATUS_REJECTED_VISIBLE = 'rejected_visible' STATUS_RESUBMITTED = 'resubmitted' STATUS_RESUBMITTED_REJECTED = 'resubmitted_and_rejected' STATUS_RESUBMITTED_REJECTED_VISIBLE = 'resubmitted_and_rejected_visible' +STATUS_VOTING_IN_PREPARATION = 'voting_in_preparation' +STATUS_PUT_TO_EC_VOTING = 'put_to_EC_voting' +STATUS_EC_VOTE_COMPLETED = 'EC_vote_completed' +STATUS_WITHDRAWN = 'withdrawn' + SUBMISSION_STATUS = ( (STATUS_UNASSIGNED, 'Unassigned, undergoing pre-screening'), (STATUS_RESUBMISSION_INCOMING, 'Resubmission incoming'), - ('assignment_failed', 'Failed to assign Editor-in-charge; manuscript rejected'), + (STATUS_ASSIGNMENT_FAILED, 'Failed to assign Editor-in-charge; manuscript rejected'), (STATUS_EIC_ASSIGNED, 'Editor-in-charge assigned, manuscript under review'), (STATUS_REVIEW_CLOSED, 'Review period closed, editorial recommendation pending'), # If revisions required: resubmission creates a new Submission object @@ -27,22 +33,22 @@ SUBMISSION_STATUS = ( (STATUS_RESUBMITTED_REJECTED_VISIBLE, 'Has been resubmitted and subsequently rejected (still publicly visible)'), # If acceptance/rejection: - ('voting_in_preparation', 'Voting in preparation (eligible Fellows being selected)'), - ('put_to_EC_voting', 'Undergoing voting at the Editorial College'), + (STATUS_VOTING_IN_PREPARATION, 'Voting in preparation (eligible Fellows being selected)'), + (STATUS_PUT_TO_EC_VOTING, 'Undergoing voting at the Editorial College'), (STATUS_AWAITING_ED_REC, 'Awaiting Editorial Recommendation'), - ('EC_vote_completed', 'Editorial College voting rounded up'), + (STATUS_EC_VOTE_COMPLETED, 'Editorial College voting rounded up'), (STATUS_ACCEPTED, 'Publication decision taken: accept'), (STATUS_REJECTED, 'Publication decision taken: reject'), (STATUS_REJECTED_VISIBLE, 'Publication decision taken: reject (still publicly visible)'), (STATUS_PUBLISHED, 'Published'), # If withdrawn: - ('withdrawn', 'Withdrawn by the Authors'), + (STATUS_WITHDRAWN, 'Withdrawn by the Authors'), ) SUBMISSION_HTTP404_ON_EDITORIAL_PAGE = [ - 'assignment_failed', + STATUS_ASSIGNMENT_FAILED, STATUS_PUBLISHED, - 'withdrawn', + STATUS_WITHDRAWN, STATUS_REJECTED, STATUS_REJECTED_VISIBLE, ] @@ -55,9 +61,9 @@ SUBMISSION_EXCLUDE_FROM_REPORTING = SUBMISSION_HTTP404_ON_EDITORIAL_PAGE + [ STATUS_AWAITING_ED_REC, STATUS_REVIEW_CLOSED, STATUS_ACCEPTED, - 'voting_in_preparation', - 'put_to_EC_voting', - 'withdrawn', + STATUS_VOTING_IN_PREPARATION, + STATUS_PUT_TO_EC_VOTING, + STATUS_WITHDRAWN, ] # Submissions which are allowed/required to submit a EIC Recommendation @@ -71,10 +77,10 @@ SUBMISSION_EIC_RECOMMENDATION_REQUIRED = [ SUBMISSION_STATUS_PUBLICLY_INVISIBLE = [ STATUS_UNASSIGNED, STATUS_RESUBMISSION_INCOMING, - 'assignment_failed', + STATUS_ASSIGNMENT_FAILED, STATUS_RESUBMITTED_REJECTED, STATUS_REJECTED, - 'withdrawn', + STATUS_WITHDRAWN, ] # Submissions which should not appear in search lists @@ -88,7 +94,7 @@ SUBMISSION_STATUS_PUBLICLY_UNLISTED = SUBMISSION_STATUS_PUBLICLY_INVISIBLE + [ SUBMISSION_STATUS_VOTING_DEPRECATED = [ STATUS_REJECTED, STATUS_PUBLISHED, - 'withdrawn', + STATUS_WITHDRAWN, ] SUBMISSION_TYPE = ( diff --git a/submissions/managers.py b/submissions/managers.py index e4b5b5f2a6ee91e784ba9b0d144543c2fe02f373..ca6bf98c7215811cffda6278abe18d7aa54fb85b 100644 --- a/submissions/managers.py +++ b/submissions/managers.py @@ -8,9 +8,11 @@ from .constants import SUBMISSION_STATUS_OUT_OF_POOL, SUBMISSION_STATUS_PUBLICLY SUBMISSION_STATUS_PUBLICLY_INVISIBLE, STATUS_UNVETTED, STATUS_VETTED,\ STATUS_UNCLEAR, STATUS_INCORRECT, STATUS_NOT_USEFUL, STATUS_NOT_ACADEMIC,\ SUBMISSION_HTTP404_ON_EDITORIAL_PAGE, STATUS_DRAFT, STATUS_PUBLISHED,\ - SUBMISSION_EXCLUDE_FROM_REPORTING, STATUS_REJECTED_VISIBLE,\ + SUBMISSION_EXCLUDE_FROM_REPORTING,\ + STATUS_REJECTED, STATUS_REJECTED_VISIBLE,\ STATUS_ACCEPTED, STATUS_RESUBMITTED, STATUS_RESUBMITTED_REJECTED_VISIBLE,\ - EVENT_FOR_EIC, EVENT_GENERAL, EVENT_FOR_AUTHOR, STATUS_UNASSIGNED + EVENT_FOR_EIC, EVENT_GENERAL, EVENT_FOR_AUTHOR,\ + STATUS_UNASSIGNED, STATUS_ASSIGNMENT_FAILED, STATUS_WITHDRAWN class SubmissionQuerySet(models.QuerySet): @@ -108,9 +110,38 @@ class SubmissionQuerySet(models.QuerySet): return self.filter(status__in=[STATUS_ACCEPTED, STATUS_REJECTED_VISIBLE, STATUS_PUBLISHED, STATUS_RESUBMITTED, STATUS_RESUBMITTED_REJECTED_VISIBLE]) + def originally_submitted(self, from_date, until_date): + """ + Returns the submissions originally received between from_date and until_date + (including subsequent resubmissions, even if those came in later). + """ + identifiers = [] + for sub in self.filter(is_resubmission=False, + submission_date__range=(from_date, until_date)): + identifiers.append(sub.arxiv_identifier_wo_vn_nr) + return self.filter(arxiv_identifier_wo_vn_nr__in=identifiers) + + def accepted(self): return self.filter(status=STATUS_ACCEPTED) + + def published(self): + return self.filter(status=STATUS_PUBLISHED) + + + def assignment_failed(self): + return self.filter(status=STATUS_ASSIGNMENT_FAILED) + + + def rejected(self): + return self._newest_version_only(self.filter(status__in=[STATUS_REJECTED, + STATUS_REJECTED_VISIBLE])) + + def withdrawn(self): + return self._newest_version_only(self.filter(status=STATUS_WITHDRAWN)) + + def open_for_reporting(self): """ Return Submissions that have appriopriate status for reporting. diff --git a/submissions/templates/submissions/statistics.html b/submissions/templates/submissions/statistics.html deleted file mode 100644 index 99e80d53cddea710c37307b015b248414c94ee5f..0000000000000000000000000000000000000000 --- a/submissions/templates/submissions/statistics.html +++ /dev/null @@ -1,78 +0,0 @@ -{% extends 'submissions/_pool_base.html' %} - -{% block pagetitle %}: statistics for submisisons{% endblock pagetitle %} - -{% load scipost_extras %} -{% load submissions_extras %} - -{% load bootstrap %} - -{% block breadcrumb_items %} - {{block.super}} - <span class="breadcrumb-item">Statistics</span> -{% endblock %} - -{% block content %} - -<h1 class="highlight">Statistics</h1> - -<h2>Aggregate statistics</h2> -<p>For each Journal, clicking on a year gives aggregate statistics for submissions (so including rejections). Clicking on a Journal/Volume/Issue gives aggregates for publications in this object.</p> -<ul> - {% for journal in journals %} - <li><a href="{% url 'submissions:statistics' journal_doi_label=journal.doi_label %}">{{ journal }}</a></li> - <ul> - {% for year in journal|journal_publication_years %} - <li><a href="{% url 'submissions:statistics' journal_doi_label=journal.doi_label year=year %}">{{ year }}</a></li> - {% endfor %} - </ul> - <ul> -{% for volume in journal.volume_set.all %} -<li><a href="{% url 'submissions:statistics' journal_doi_label=journal.doi_label volume_nr=volume.number %}">{{ volume }}</a></li> -<ul> - {% for issue in volume.issue_set.all %} - <li><a href="{% url 'submissions:statistics' journal_doi_label=journal.doi_label volume_nr=volume.number issue_nr=issue.number %}">{{ issue }}</a></li> - {% endfor %} -</ul> -{% endfor %} - </ul> - {% endfor %} -</ul> - -{% if journal %} - <h2>Results:</h2> - <table class="table"> - <tr> - <th>DOI label</th> - {% if year %} - <th>Year</th> - <th>Nr submissions</th> - <th>Nr distinct submissions</th> - {% endif %} - <th>Nr publications</th> - <th>Duration average</th> - </tr> - <tr> - {% if issue %} - <td>{{ issue.doi_label }}</td> - <td>{{ issue|issue_nr_publications }}</td> - <td>{{ issue|issue_avg_processing_duration|floatformat:2 }} days</td> - {% elif volume %} - <td>{{ volume.doi_label }}</td> - <td>{{ volume|volume_nr_publications }}</td> - <td>{{ volume|volume_avg_processing_duration|floatformat:2 }} days</td> - {% else %} - <td>{{ journal.doi_label }}</td> - {% if year %} - <td>{{ year }}</td> - <td>{{ submissions|length }}</td> - <td>{{ submissions|submissions_count_distinct }}</td> - {% endif %} - <td>{{ journal|journal_nr_publications }}</td> - <td>{{ journal|journal_avg_processing_duration|floatformat:2 }} days</td> - {% endif %} - </tr> - </table> -{% endif %} - -{% endblock content %} diff --git a/submissions/templatetags/submissions_extras.py b/submissions/templatetags/submissions_extras.py index 07250669e53f9a63f5c79394ec557b05b20d9e35..de71caafbddb5aae5dc1edbe542a717123796841 100644 --- a/submissions/templatetags/submissions_extras.py +++ b/submissions/templatetags/submissions_extras.py @@ -1,10 +1,7 @@ import datetime from django import template -from django.db.models import Avg, F -from django.utils import timezone -from journals.models import Publication from submissions.constants import SUBMISSION_STATUS_OUT_OF_POOL from submissions.models import Submission @@ -26,55 +23,3 @@ def is_viewable_by_authors(recommendation): return recommendation.submission.status in ['revision_requested', 'resubmitted', 'accepted', 'rejected', 'published', 'withdrawn'] - -@register.filter(name='submissions_count_distinct') -def submissions_count_distinct(submissions): - identifiers_wo_vn_nr = [] - for submission in submissions: - identifiers_wo_vn_nr.append(submission.arxiv_identifier_wo_vn_nr) - return len(identifiers_wo_vn_nr) - - -@register.filter(name='journal_publication_years') -def journal_publication_years(journal): - years = [] - for volume in journal.volume_set.all(): - if volume.until_date.year not in years: - years.append(volume.until_date.year) - return years - -@register.filter(name='journal_nr_publications') -def journal_nr_publications(journal): - return Publication.objects.filter(in_issue__in_volume__in_journal=journal).count() - -@register.filter(name='journal_avg_processing_duration') -def journal_avg_processing_duration(journal): - duration = Publication.objects.filter( - in_issue__in_volume__in_journal=journal).aggregate( - avg=Avg(F('publication_date') - F('submission_date')))['avg'] - if not duration: return 0 - return duration.days + duration.seconds/86400 - -@register.filter(name='volume_nr_publications') -def volume_nr_publications(volume): - return Publication.objects.filter(in_issue__in_volume=volume).count() - -@register.filter(name='volume_avg_processing_duration') -def volume_avg_processing_duration(volume): - duration = Publication.objects.filter( - in_issue__in_volume=volume).aggregate( - avg=Avg(F('publication_date') - F('submission_date')))['avg'] - if not duration: return 0 - return duration.days + duration.seconds/86400 - -@register.filter(name='issue_nr_publications') -def issue_nr_publications(issue): - return Publication.objects.filter(in_issue=issue).count() - -@register.filter(name='issue_avg_processing_duration') -def issue_avg_processing_duration(issue): - duration = Publication.objects.filter( - in_issue=issue).aggregate( - avg=Avg(F('publication_date') - F('submission_date')))['avg'] - if not duration: return 0 - return duration.days + duration.seconds/86400 diff --git a/submissions/urls.py b/submissions/urls.py index 20de6bfc112ed883f622939ee418f4252e7baa05..c1f46c9ab3839e1758c764de519a0ae91a24eecf 100644 --- a/submissions/urls.py +++ b/submissions/urls.py @@ -89,14 +89,6 @@ urlpatterns = [ url(r'^close_refereeing_round/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.close_refereeing_round, name='close_refereeing_round'), url(r'^refereeing_overview$', views.refereeing_overview, name='refereeing_overview'), - url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)/(?P<volume_nr>[0-9]+)/(?P<issue_nr>[0-9]+)$', - views.statistics, name='statistics'), - url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)/(?P<volume_nr>[0-9]+)$', - views.statistics, name='statistics'), - url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)$', views.statistics, name='statistics'), - url(r'^statistics/(?P<journal_doi_label>[a-zA-Z]+)/year/(?P<year>[0-9]{4,})$', - views.statistics, name='statistics'), - url(r'^statistics$', views.statistics, name='statistics'), url(r'^communication/{regex}/(?P<comtype>[a-zA-Z]{{4,}})$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.communication, name='communication'), url(r'^communication/{regex}/(?P<comtype>[a-zA-Z]{{4,}})/(?P<referee_id>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), diff --git a/submissions/views.py b/submissions/views.py index 82ccebd9df44674a64fac21aff58d9f1b3b57bb2..7f53451343204d046ff2f976e5e9fb5a96faee4f 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -35,7 +35,6 @@ from .forms import SubmissionIdentifierForm, RequestSubmissionForm, SubmissionSe from .utils import SubmissionUtils from mails.views import MailEditingSubView -from journals.models import Journal, Volume, Issue, Publication from scipost.forms import ModifyPersonalMessageForm, RemarkForm from scipost.models import Contributor, Remark, RegistrationInvitation from scipost.utils import Utils @@ -1003,32 +1002,6 @@ def refereeing_overview(request): return render(request, 'submissions/refereeing_overview.html', context) -@permission_required('scipost.can_oversee_refereeing', raise_exception=True) -def statistics(request, journal_doi_label=None, volume_nr=None, issue_nr=None, year=None): - journals = Journal.objects.all() - context = { - 'journals': journals, - } - if journal_doi_label: - journal = get_object_or_404(Journal, doi_label=journal_doi_label) - context['journal'] = journal - if year: - context['year'] = year - submissions = Submission.objects.filter( - submitted_to_journal=journal, - submission_date__year=year, - ) - context['submissions'] = submissions - if volume_nr: - volume = get_object_or_404(Volume, in_journal=journal, - number=volume_nr) - context['volume'] = volume - if issue_nr: - issue = get_object_or_404(Issue, in_volume=volume, - number=issue_nr) - context['issue'] = issue - return render(request, 'submissions/statistics.html', context) - @login_required def communication(request, arxiv_identifier_w_vn_nr, comtype, referee_id=None): """