diff --git a/journals/forms.py b/journals/forms.py index 4464d567a65e5ad49d7d0870b78f1f807c35e853..27d4869c028a629a6a9f15f72f510975657434ab 100644 --- a/journals/forms.py +++ b/journals/forms.py @@ -83,6 +83,20 @@ class FundingInfoForm(forms.ModelForm): return super().save(*args, **kwargs) +class BasePublicationAuthorsTableFormSet(BaseModelFormSet): + def save(self, *args, **kwargs): + objects = super().save(*args, **kwargs) + for form in self.ordered_forms: + form.instance.order = form.cleaned_data['ORDER'] + form.instance.save() + return objects + + +PublicationAuthorOrderingFormSet = modelformset_factory( + PublicationAuthorsTable, fields=(), can_order=True, extra=0, + formset=BasePublicationAuthorsTableFormSet) + + class CreateMetadataXMLForm(forms.ModelForm): class Meta: model = Publication diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html index 08ae88c8079ddfdbc104961abab2b010b75adc7d..8b0554e06f17e37f8d007205bf55727f44c11bc2 100644 --- a/journals/templates/journals/manage_metadata.html +++ b/journals/templates/journals/manage_metadata.html @@ -103,16 +103,8 @@ event: "focusin" <div class="col-md-6"> <h2 class="ml-3">Actions</h2> <ul> - <li>Mark the first author - <ul class="list-unstyled pl-4"> - {% for author in publication.authors.all %} - <li> - {{ author.order }}. <a href="{% url 'journals:mark_first_author' doi_label=publication.doi_label author_object_id=author.id %}">{{ author }}</a> - </li> - {% endfor %} - </ul> - </li> <li><a href="{% url 'journals:add_author' doi_label=publication.doi_label %}">Add a missing author</a></li> + <li><a href="{% url 'journals:update_author_ordering' doi_label=publication.doi_label %}">Update Author ordering</a></li> <li><a href="{% url 'journals:create_citation_list_metadata' publication.doi_label %}">Create/update citation list metadata</a></li> <li><a href="{% url 'journals:create_funding_info_metadata' publication.doi_label %}">Create/update funding info metadata</a></li> diff --git a/journals/templates/journals/publication_authors_form.html b/journals/templates/journals/publication_authors_form.html new file mode 100644 index 0000000000000000000000000000000000000000..861f712b9e0e4a275ba9b436757658c8352346ac --- /dev/null +++ b/journals/templates/journals/publication_authors_form.html @@ -0,0 +1,47 @@ +{% extends 'scipost/base.html' %} + +{% load bootstrap %} + +{% block pagetitle %}: Publication Authors{% endblock pagetitle %} + +{% block breadcrumb %} + <div class="container-outside header"> + <div class="container"> + <nav class="breadcrumb hidden-sm-down"> + <a href="{% url 'journals:journals' %}" class="breadcrumb-item">Journals</a> + <a href="{{publication.get_absolute_url}}" class="breadcrumb-item">{{publication.citation}}</a> + <span class="breadcrumb-item active">Author ordering</span> + + </nav> + </div> + </div> +{% endblock %} + +{% block content %} + + +<h1 class="highlight">Author Ordering</h1> + +<div class="mb-4"> + {% include 'partials/journals/publication_li_content.html' with publication=publication %} +</div> +<a href="{% url 'journals:add_author' publication.doi_label %}">Add missing author</a> +<h3 class="highlight">Ordering</h3> + +<form method="post" enctype="multipart/form-data"> + {% csrf_token %} + {{ formset.management_form }} + <ul class="fa-ul sortable-list d-inline-block"> + {% for form in formset %} + <li> + <i class="fa fa-sort"></i> + {{ form.instance.first_name }} {{ form.instance.last_name }} + <div class="d-none">{{ form }}</div> + </li> + {% endfor %} + </ul> + <br> + <input type="submit" class="btn btn-primary" value="Save ordering"> +</form> + +{% endblock %} diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html index 20f08ba694ec77c6fc6d9d491eaf3333a274596e..c2f1e27c069cdc2a85fc35af99714f296fe7b0d3 100644 --- a/journals/templates/journals/publication_detail.html +++ b/journals/templates/journals/publication_detail.html @@ -172,17 +172,8 @@ <div class="col-12"> <h3>Editorial Administration tools</h3> <ul class="mb-0"> - <li> - Mark the first author - <ul class="list-unstyled pl-4"> - {% for author in publication.authors.all %} - <li> - {{ author.order }}. <a href="{% url 'journals:mark_first_author' doi_label=publication.doi_label author_object_id=author.id %}">{{ author }}</a> - </li> - {% endfor %} - </ul> - </li> <li><a href="{% url 'journals:add_author' doi_label=publication.doi_label %}">Add a missing author</a></li> + <li><a href="{% url 'journals:update_author_ordering' doi_label=publication.doi_label %}">Update Author ordering</a></li> <li><a href="{% url 'journals:create_citation_list_metadata' publication.doi_label %}">Create/update citation list metadata</a></li> <li><a href="{% url 'journals:create_funding_info_metadata' publication.doi_label %}">Create/update funding info metadata</a></li> <li><a href="{% url 'journals:create_metadata_xml' publication.doi_label %}">Create/update the XML metadata</a></li> diff --git a/journals/urls/general.py b/journals/urls/general.py index bf2d672b48b39132d3487756e08b41323de97649..9c60a093c4d11af6d241d44fac09f36d95945a82 100644 --- a/journals/urls/general.py +++ b/journals/urls/general.py @@ -31,6 +31,10 @@ urlpatterns = [ regex=PUBLICATION_DOI_REGEX), journals_views.DraftPublicationApprovalView.as_view(), name='send_publication_for_approval'), + url(r'^admin/publications/(?P<doi_label>{regex})/authors$'.format(regex=PUBLICATION_DOI_REGEX), + # journals_views.PublicationAuthorOrderingView.as_view(), + journals_views.publication_authors_ordering, + name='update_author_ordering'), url(r'^admin/publications/(?P<doi_label>{regex})/grants$'.format(regex=PUBLICATION_DOI_REGEX), journals_views.PublicationGrantsView.as_view(), name='update_grants'), @@ -47,10 +51,6 @@ urlpatterns = [ url(r'^admin/(?P<doi_label>{regex})/authors/add$'.format(regex=PUBLICATION_DOI_REGEX), journals_views.add_author, name='add_author'), - url(r'^admin/(?P<doi_label>{regex})/authors/mark_first/(?P<author_object_id>[0-9]+)$'.format( - regex=PUBLICATION_DOI_REGEX), - journals_views.mark_first_author, - name='mark_first_author'), url(r'^admin/(?P<doi_label>{regex})/manage_metadata$'.format(regex=PUBLICATION_DOI_REGEX), journals_views.manage_metadata, name='manage_metadata'), diff --git a/journals/views.py b/journals/views.py index 6f490b5a35f72c9c2503271fc236ff9544fdf605..746b1cf2bb13e1056e418447b31c6778a43082c7 100644 --- a/journals/views.py +++ b/journals/views.py @@ -24,13 +24,13 @@ from django.views.generic.edit import UpdateView from django.shortcuts import get_object_or_404, get_list_or_404, render, redirect from .constants import STATUS_DRAFT -from .helpers import issue_doi_label_from_doi_label from .models import Journal, Issue, Publication, Deposit, DOAJDeposit,\ GenericDOIDeposit, PublicationAuthorsTable from .forms import FundingInfoForm,\ UnregisteredAuthorForm, CreateMetadataXMLForm, CitationListBibitemsForm,\ ReferenceFormSet, CreateMetadataDOAJForm, DraftPublicationForm,\ - PublicationGrantsForm, DraftPublicationApprovalForm, PublicationPublishForm + PublicationGrantsForm, DraftPublicationApprovalForm, PublicationPublishForm,\ + PublicationAuthorOrderingFormSet from .mixins import PublicationMixin, ProdSupervisorPublicationPermissionMixin from .utils import JournalUtils @@ -189,6 +189,22 @@ class PublicationGrantsRemovalView(PermissionsMixin, DetailView): return redirect(reverse('journals:update_grants', args=(self.object.doi_label,))) +@permission_required('scipost.can_publish_accepted_submission', raise_exception=True) +def publication_authors_ordering(request, doi_label): + publication = get_object_or_404(Publication, doi_label=doi_label) + formset = PublicationAuthorOrderingFormSet( + request.POST or None, queryset=publication.authors.order_by('order')) + if formset.is_valid(): + formset.save() + messages.success(request, 'Author ordering updated') + return redirect(publication.get_absolute_url()) + context = { + 'formset': formset, + 'publication': publication, + } + return render(request, 'journals/publication_authors_form.html', context) + + class DraftPublicationUpdateView(PermissionsMixin, UpdateView): """ Any Production Officer or Administrator can draft a new publication without publishing here. @@ -283,25 +299,6 @@ def manage_metadata(request, doi_label=None, issue_doi_label=None, journal_doi_l return render(request, 'journals/manage_metadata.html', context) -@permission_required('scipost.can_publish_accepted_submission', return_403=True) -def mark_first_author(request, publication_id, author_object_id): - publication = get_object_or_404(Publication, id=publication_id) - author_object = get_object_or_404(publication.authors, id=author_object_id) - - # Redo ordering - author_object.order = 1 - author_object.save() - author_objects = publication.authors.exclude(id=author_object.id) - count = 2 - for author in author_objects: - author.order = count - author.save() - count += 1 - messages.success(request, 'Marked {} first author'.format(author_object)) - return redirect(reverse('journals:manage_metadata', - kwargs={'doi_label': publication.doi_label})) - - @permission_required('scipost.can_draft_publication', return_403=True) @transaction.atomic def add_author(request, doi_label, contributor_id=None, unregistered_author_id=None): diff --git a/package.json b/package.json index 9e3d508dcb107b4bbfa981744c683f1089a08a11..37b40615f359601885e9a941ce88f79c1691d868 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "extract-text-webpack-plugin": "^3.0.0", "file-loader": "^0.11.2", "imports-loader": "^0.7.1", - "jquery": "^2.2.0", + "jquery": "^3.3.1", + "jquery-ui": "^1.12.1", "node-loader": "^0.6.0", "node-sass": "^4.4.0", "popper.js": "^1.11.1", diff --git a/scipost/static/scipost/assets/css/_list_group.scss b/scipost/static/scipost/assets/css/_list_group.scss index c2313938bd328c3d3fa2c09ed704792f1f706da6..f05cfb69b638eafa14698f47a4edcb7f312d6e80 100644 --- a/scipost/static/scipost/assets/css/_list_group.scss +++ b/scipost/static/scipost/assets/css/_list_group.scss @@ -49,3 +49,12 @@ ul.references { ul.links > li.active a { font-weight: 700; } + +ul.sortable-list { + li { + background-color: $white; + border: 1px solid $scipost-darkblue; + padding: 0.5rem; + margin-bottom: -1px; + } +} diff --git a/scipost/static/scipost/assets/js/scripts.js b/scipost/static/scipost/assets/js/scripts.js index 6a451fe5e5b1bed6004c85e7da4fb15275f42a5f..8adbae645179b5aea816d04c6e9f86a7f06e52b5 100644 --- a/scipost/static/scipost/assets/js/scripts.js +++ b/scipost/static/scipost/assets/js/scripts.js @@ -1,3 +1,6 @@ +require('jquery-ui/ui/widgets/sortable'); +require('jquery-ui/ui/disable-selection'); + import notifications from './notifications.js'; function hide_all_alerts() { @@ -12,6 +15,19 @@ var activate_tooltip = function() { }); } + +var sort_form_list = function(list_el) { + $(list_el).sortable({ + update: function(event, ui) { + $.each($(list_el + ' li'), function(index, el) { + $(el).find('input[name$=ORDER]').val(index + 1); + }); + } + }); +}; + + + var getUrlParameter = function getUrlParameter(sParam) { var sPageURL = decodeURIComponent(window.location.search.substring(1)), sURLVariables = sPageURL.split('&'), @@ -53,6 +69,7 @@ function init_page() { }); activate_tooltip(); + sort_form_list('form ul.sortable-list'); } $(function(){