diff --git a/journals/admin.py b/journals/admin.py index 48f9f4ee5a90149ca010e5fe22edf9d85e75f7c6..0626c2b11e1a6fc2828b11a359c6ac2d05033f5a 100644 --- a/journals/admin.py +++ b/journals/admin.py @@ -1,9 +1,16 @@ from django.contrib import admin, messages -from journals.models import Journal, Volume, Issue, Publication, Deposit +from journals.models import UnregisteredAuthor, Journal, Volume, Issue, Publication, Deposit +class UnregisteredAuthorAdmin(admin.ModelAdmin): + search_fields = ['last_name'] + ordering = ['last_name'] + +admin.site.register(UnregisteredAuthor, UnregisteredAuthorAdmin) + + class JournalAdmin(admin.ModelAdmin): search_fields = ['name'] list_display = ['__str__', 'doi_string', 'active'] diff --git a/journals/utils.py b/journals/utils.py index bda96d34647ef5620842afed9113749834afe348..b1e7630d7fc7656e2a559f33977dedad3b42f3ba 100644 --- a/journals/utils.py +++ b/journals/utils.py @@ -22,6 +22,8 @@ class JournalUtils(object): + cls.publication.citation() + '.' '\n\nThe publication page is located at the permanent link ' 'https://scipost.org/' + cls.publication.doi_label + '.' + '\n\nThe permanent DOI for your publication is 10.21468/' + + cls.publication.doi_label + '.' '\n\nTo facilitate dissemination of your paper, we greatly encourage ' 'you to update the arXiv Journal-ref with this information.' '\n\nWe warmly congratulate you on this achievement and thank you ' diff --git a/production/constants.py b/production/constants.py index 0a0b7ec8a445d3f04da78430cf52f28a55930147..ce9caee48c34a9a78db9235df621d04550b13e91 100644 --- a/production/constants.py +++ b/production/constants.py @@ -17,4 +17,5 @@ PRODUCTION_EVENTS = ( ('proofs_returned_by_authors', 'Proofs returned by Authors'), ('corrections_implemented', 'Corrections implemented'), ('authors_have_accepted_proofs', 'Authors have accepted proofs'), + ('paper_published', 'Paper has been published'), ) diff --git a/production/migrations/0004_auto_20170528_1526.py b/production/migrations/0004_auto_20170528_1526.py new file mode 100644 index 0000000000000000000000000000000000000000..c901494033b5772f07bfead5252165f5974d65fb --- /dev/null +++ b/production/migrations/0004_auto_20170528_1526.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-05-28 13:26 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('production', '0003_auto_20170522_1021'), + ] + + operations = [ + migrations.AlterField( + model_name='productionevent', + name='event', + field=models.CharField(choices=[('assigned_to_supervisor', 'Assigned by EdAdmin to Supervisor'), ('message_edadmin_to_supervisor', 'Message from EdAdmin to Supervisor'), ('message_supervisor_to_edadmin', 'Message from Supervisor to EdAdmin'), ('officer_tasked_with_proof_production', 'Supervisor tasked officer with proofs production'), ('message_supervisor_to_officer', 'Message from Supervisor to Officer'), ('message_officer_to_supervisor', 'Message from Officer to Supervisor'), ('proofs_produced', 'Proofs have been produced'), ('proofs_checked_by_supervisor', 'Proofs have been checked by Supervisor'), ('proofs_sent_to_authors', 'Proofs sent to Authors'), ('proofs_returned_by_authors', 'Proofs returned by Authors'), ('corrections_implemented', 'Corrections implemented'), ('authors_have_accepted_proofs', 'Authors have accepted proofs'), ('paper_published', 'Paper has been published')], max_length=64), + ), + ] diff --git a/production/migrations/0005_productionstream_status.py b/production/migrations/0005_productionstream_status.py new file mode 100644 index 0000000000000000000000000000000000000000..81236c4f5629b772eab6d7018fb29ccb699d4aca --- /dev/null +++ b/production/migrations/0005_productionstream_status.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-05-28 13:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('production', '0004_auto_20170528_1526'), + ] + + operations = [ + migrations.AddField( + model_name='productionstream', + name='status', + field=models.CharField(choices=[('ongoing', 'Ongoing'), ('completed', 'Completed')], default='ongoing', max_length=32), + ), + ] diff --git a/production/migrations/0006_productionstream_closed.py b/production/migrations/0006_productionstream_closed.py new file mode 100644 index 0000000000000000000000000000000000000000..214570de6029880b899ad87f70c15b062fab2514 --- /dev/null +++ b/production/migrations/0006_productionstream_closed.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-05-28 13:41 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('production', '0005_productionstream_status'), + ] + + operations = [ + migrations.AddField( + model_name='productionstream', + name='closed', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/production/models.py b/production/models.py index c2cb30209aa2153f2c6b3e2365ce3e1dd6fd2b95..8cd82781cdff1ae47ddb738ef3ecebe2aa3d6eef 100644 --- a/production/models.py +++ b/production/models.py @@ -1,7 +1,7 @@ from django.db import models from django.utils import timezone -from .constants import PRODUCTION_EVENTS +from .constants import PRODUCTION_STREAM_STATUS, PRODUCTION_EVENTS from scipost.models import Contributor @@ -13,6 +13,9 @@ from scipost.models import Contributor class ProductionStream(models.Model): submission = models.OneToOneField('submissions.Submission', on_delete=models.CASCADE) opened = models.DateTimeField() + closed = models.DateTimeField(default=timezone.now) + status = models.CharField(max_length=32, + choices=PRODUCTION_STREAM_STATUS, default='ongoing') def __str__(self): return str(self.submission) diff --git a/production/templates/production/_production_stream_card.html b/production/templates/production/_production_stream_card.html index fda086794d4c0faa5efcdf4bbc80d314b7dc2a26..c39436c5c30b365de02d699b205fcafdc0d38806 100644 --- a/production/templates/production/_production_stream_card.html +++ b/production/templates/production/_production_stream_card.html @@ -17,7 +17,11 @@ {% if stream.total_duration %} <h3>Total duration for this stream: {{ stream.total_duration|duration }}</h3> {% endif %} + {% if perms.scipost.can_publish_accepted_submission %} + <h3><a href="{% url 'production:mark_as_completed' stream_id=stream.id %}">Mark this stream as completed</a></h3> + {% endif %} </div> + {% if form %} <div class="col-5"> <h3>Add an event to this production stream:</h3> <form action="{% url 'production:add_event' stream_id=stream.id %}" method="post"> @@ -26,4 +30,6 @@ <input type="submit" name="submit" value="Submit"> </form> </div> + {% endif %} + </div> </div> diff --git a/production/templates/production/completed.html b/production/templates/production/completed.html new file mode 100644 index 0000000000000000000000000000000000000000..1cd7059cd206c97570a179c2e4c623619db68dd4 --- /dev/null +++ b/production/templates/production/completed.html @@ -0,0 +1,21 @@ +{% extends 'scipost/base.html' %} + +{% load bootstrap %} + +{% block content %} + +<div class="row"> + <div class="col-12"> + <h3>Completed production streams</h3> + <ul class="list-group list-group-flush"> + {% for stream in streams %} + <li class="list-group-item"> + {% include 'production/_production_stream_card.html' with stream=stream %} + </li> + <hr/> + {% endfor %} + </ul> + </div> +</div> + +{% endblock content %} diff --git a/production/urls.py b/production/urls.py index 11007074f3a47e420c14b81f62009486dab8f23c..3ff66bdb86cc57bdd8a1bf8a79cf9457a0a60f14 100644 --- a/production/urls.py +++ b/production/urls.py @@ -4,6 +4,9 @@ from production import views as production_views urlpatterns = [ url(r'^$', production_views.production, name='production'), + url(r'^completed$', production_views.completed, name='completed'), url(r'^add_event/(?P<stream_id>[0-9]+)$', production_views.add_event, name='add_event'), + url(r'^mark_as_completed/(?P<stream_id>[0-9]+)$', + production_views.mark_as_completed, name='mark_as_completed'), ] diff --git a/production/views.py b/production/views.py index 4093d7751d30398ce87f78f36b3482b1b5dae76f..52363947aa75203c2957cd7a5a1cb920553275ad 100644 --- a/production/views.py +++ b/production/views.py @@ -21,18 +21,25 @@ def production(request): Overview page for the production process. All papers with accepted but not yet published status are included here. """ - accepted_submissions = Submission.objects.filter( - status='accepted').order_by('latest_activity') - streams = ProductionStream.objects.all().order_by('opened') + streams = ProductionStream.objects.filter(status='ongoing').order_by('opened') prodevent_form = ProductionEventForm() context = { - 'accepted_submissions': accepted_submissions, 'streams': streams, 'prodevent_form': prodevent_form, } return render(request, 'production/production.html', context) +@permission_required('scipost.can_view_production', return_403=True) +def completed(request): + """ + Overview page for closed production streams. + """ + streams = ProductionStream.objects.filter(status='completed').order_by('-opened') + context = {'streams': streams,} + return render(request, 'production/completed.html', context) + + @permission_required('scipost.can_view_production', return_403=True) @transaction.atomic def add_event(request, stream_id): @@ -57,6 +64,16 @@ def add_event(request, stream_id): return render(request, 'scipost/error.html', {'errormessage': errormessage}) +@permission_required('scipost.can_view_production', return_403=True) +@transaction.atomic +def mark_as_completed(request, stream_id): + stream = get_object_or_404(ProductionStream, pk=stream_id) + stream.status = 'completed' + stream.closed = timezone.now() + stream.save() + return redirect(reverse('production:production')) + + def upload_proofs(request): """ TODO diff --git a/scipost/templates/scipost/personal_page.html b/scipost/templates/scipost/personal_page.html index 6f3c572d5f36abdf5f2296792252f41fb2af432a..04decd986cf50c0916fe695ee7a0acdcb963de38 100644 --- a/scipost/templates/scipost/personal_page.html +++ b/scipost/templates/scipost/personal_page.html @@ -34,10 +34,15 @@ <a href="#account" class="nav-link active" data-toggle="tab">Account</a> </li> {% if 'SciPost Administrators' in user_groups or 'Editorial Administrators' in user_groups or 'Editorial College' in user_groups or 'Advisory Board' in user_groups or 'Vetting Editors' in user_groups or 'Ambassadors' in user_groups or 'Junior Ambassadors' in user_groups %} - <li class="nav-item btn btn-secondary"> - <a href="#editorial-actions" class="nav-link" data-toggle="tab">Editorial Actions</a> - </li> - {% endif %} + <li class="nav-item btn btn-secondary"> + <a href="#editorial-actions" class="nav-link" data-toggle="tab">Editorial Actions</a> + </li> + {% endif %} + {% if perms.scipost.can_view_production %} + <li class="nav-item btn btn-secondary"> + <a href="#production" class="nav-link" data-toggle="tab">Production</a> + </li> + {% endif %} {% if perms.scipost.can_referee %} <li class="nav-item btn btn-secondary"> {% with pending_count=pending_ref_tasks|length %} @@ -310,6 +315,30 @@ </div><!-- End tab --> {% endif %} + {% if perms.scipost.can_view_production %} + <!-- Tab: Production --> + <div class="tab-pane" id="production" role="tabpanel"> + <div class="row"> + <div class="col-12"> + <div class="card card-grey"> + <div class="card-block"> + <h2 class="card-title mb-0">Production Tasks</h2> + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col-md-4"> + <h3>Production workflow</h3> + <ul> + <li><a href="{% url 'production:production' %}">Go to the production page</a></li> + <li><a href="{% url 'production:completed' %}">View completed streams</a></li> + </ul> + </div> + </div> + </div> + {% endif %} + {% if perms.scipost.can_referee %} <!-- Tab: Refereeing --> <div class="tab-pane" id="refereeing" role="tabpanel"> diff --git a/submissions/forms.py b/submissions/forms.py index 71632fa47b2e7cbff6d728ad29ae18fc1a242166..4b6fdcc8425010d118d279a7838a8b4a3b3c336b 100644 --- a/submissions/forms.py +++ b/submissions/forms.py @@ -56,6 +56,11 @@ class SubmissionChecks: if kwargs['initial'].get('is_resubmission', None): self.is_resubmission = kwargs['initial']['is_resubmission'] in ('True', True) + # `is_resubmission` property if data is coming from (POST) request + if kwargs.get('data', None): + if kwargs['data'].get('is_resubmission', None): + self.is_resubmission = kwargs['data']['is_resubmission'] in ('True', True) + def _submission_already_exists(self, identifier): if Submission.objects.filter(arxiv_identifier_w_vn_nr=identifier).exists(): error_message = 'This preprint version has already been submitted to SciPost.' @@ -88,7 +93,7 @@ class SubmissionChecks: identifiers = self.identifier_into_parts(identifier) submission = (Submission.objects .filter(arxiv_identifier_wo_vn_nr=identifiers['arxiv_identifier_wo_vn_nr']) - .order_by('-arxiv_vn_nr').last()) + .order_by('arxiv_vn_nr').last()) # If submissions are found; check their statuses if submission: diff --git a/submissions/models.py b/submissions/models.py index 9e697af3908fdf117f182ae6a0f26c337a9c900b..6bf5ae9c6c7b1b9378efa71e54f26a7a8074ee88 100644 --- a/submissions/models.py +++ b/submissions/models.py @@ -156,7 +156,7 @@ class Submission(ArxivCallable, models.Model): def count_obtained_reports(self): return self.reports.filter(status=1, invited__isnull=False).count() - def count_refused_resports(self): + def count_refused_reports(self): return self.reports.filter(status__lte=-1).count() def count_awaiting_vetting(self): diff --git a/submissions/templates/submissions/_submission_refereeing_status.html b/submissions/templates/submissions/_submission_refereeing_status.html index 94e9ba3cbd35ab3eccca9bcba9e3fc9c4d9585d7..50066b96f9b564b3e9d18b1dc24d191c56e922f6 100644 --- a/submissions/templates/submissions/_submission_refereeing_status.html +++ b/submissions/templates/submissions/_submission_refereeing_status.html @@ -1,6 +1,6 @@ {% if submission.refereeing_cycle != 'direct_rec' %} <div class="card-block"> <p class="card-text">Nr referees invited: {{submission.referee_invitations.count}} <span>[{{submission.count_accepted_invitations}} acccepted / {{submission.count_declined_invitations}} declined / {{submission.count_pending_invitations}} response pending]</span></p> - <p class="card-text">Nr reports obtained: {{submission.count_obtained_reports}} [{{submission.count_invited_reports}} invited / {{submission.count_contrib_reports}} contributed], nr refused: {{submission.count_refused_resports}}, nr awaiting vetting: {{submission.count_awaiting_vetting}}</p> + <p class="card-text">Nr reports obtained: {{submission.count_obtained_reports}} [{{submission.count_invited_reports}} invited / {{submission.count_contrib_reports}} contributed], nr refused: {{submission.count_refused_reports}}, nr awaiting vetting: {{submission.count_awaiting_vetting}}</p> </div> {% endif %} diff --git a/submissions/views.py b/submissions/views.py index 56fc14ca6c9a17d72555f191f449c9b4eea76942..a3764b96f5a4e937c229c7f4026b76b3739b9952 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -6,7 +6,7 @@ from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.models import Group from django.core.urlresolvers import reverse, reverse_lazy from django.db import transaction -from django.http import Http404 +from django.http import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404, render, redirect from django.template import Template, Context from django.utils import timezone @@ -75,10 +75,9 @@ class RequestSubmission(CreateView): # Send emails SubmissionUtils.load({'submission': submission}) SubmissionUtils.send_authors_submission_ack_email() - return super().form_valid(form) + return HttpResponseRedirect(self.success_url) def form_invalid(self, form): - # r = form.errors for error_messages in form.errors.values(): messages.warning(self.request, *error_messages) return super().form_invalid(form)