diff --git a/comments/models.py b/comments/models.py index 82ae4cf7bb8e43c962f9fdf99fd3ead00923e41d..b5d00c911998a27de84ae928a1ded10b955c6a77 100644 --- a/comments/models.py +++ b/comments/models.py @@ -4,6 +4,7 @@ from django.db import models from django.shortcuts import get_object_or_404 from django.utils import timezone from django.utils.functional import cached_property +from django.urls import reverse from guardian.shortcuts import assign_perm @@ -131,6 +132,9 @@ class Comment(TimeStampedModel): def get_absolute_url(self): return self.content_object.get_absolute_url().split('#')[0] + '#comment_id' + str(self.id) + def get_attachment_url(self): + return reverse('comments:attachment', args=(self.id,)) + def grant_permissions(self): # Import here due to circular import errors from submissions.models import Submission diff --git a/comments/templates/comments/_add_comment_form.html b/comments/templates/comments/_add_comment_form.html index b3a51a16b34e172a2155dfb7ff6031e318a541e1..e50ce6528019f236fa9c2e7f8a634d63d86c9ec1 100644 --- a/comments/templates/comments/_add_comment_form.html +++ b/comments/templates/comments/_add_comment_form.html @@ -17,6 +17,7 @@ <div class="row"> <div class="col-md-9"> {{form.comment_text|bootstrap:'12,12'}} + <p> In your comment, you can use LaTeX \$...\$ for in-text equations or \ [ ... \ ] for on-line equations. </p> diff --git a/comments/templates/comments/_comment_card_content.html b/comments/templates/comments/_comment_card_content.html index c6788a79a355818dc3e31f711bdda0027efcdeaf..47487bc7a6182e10fb8be44b1040aa4cddd23dd3 100644 --- a/comments/templates/comments/_comment_card_content.html +++ b/comments/templates/comments/_comment_card_content.html @@ -3,7 +3,7 @@ <p class="card-text"> <a href="{{comment.author.get_absolute_url}}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a>: - <a href="{{comment.get_absolute_url}"> + <a href="{{comment.get_absolute_url}}"> "{{comment.comment_text|slice:'30'}}{% if comment.comment_text|length > 30 %}...{% endif %}" </a> </p><p class="card-text pl-md-3"> diff --git a/comments/templates/comments/_single_comment.html b/comments/templates/comments/_single_comment.html index 0759c42ee017a67d2bbf6d345f140b5baf7b29aa..ee94826ec7b15950249cc4f51465cee07fb6b5a4 100644 --- a/comments/templates/comments/_single_comment.html +++ b/comments/templates/comments/_single_comment.html @@ -3,7 +3,6 @@ {% load file_extentions %} <div class="comment"> - {% include 'comments/_comment_identifier.html' with comment=comment %} {% include 'comments/_comment_categories.html' with comment=comment %} @@ -16,9 +15,9 @@ {% if comment.file_attachment %} <h3>Attachment:</h3> <p> - <a target="_blank" href="{{ comment.file_attachment.url }}"> + <a target="_blank" href="{{ comment.get_attachment_url }}"> {% if comment.file_attachment|is_image %} - <img class="attachment attachment-comment" src="{{ comment.file_attachment.url }}"> + <img class="attachment attachment-comment" src="{{ comment.get_attachment_url }}"> {% else %} {{ comment.file_attachment|filename }}<br><small>{{ comment.file_attachment.size|filesizeformat }}</small> {% endif %} diff --git a/comments/templates/comments/_vet_comment_form.html b/comments/templates/comments/_vet_comment_form.html index 204b12d7017b92b141c0e0aeb8c04271136f0e6b..711beb89fe8edd8c63ec00263c7f17a8a4357942 100644 --- a/comments/templates/comments/_vet_comment_form.html +++ b/comments/templates/comments/_vet_comment_form.html @@ -23,9 +23,9 @@ {% if comment.file_attachment %} <h3>Attachment:</h3> <p> - <a target="_blank" href="{{ comment.file_attachment.url }}"> + <a target="_blank" href="{{ comment.get_attachment_url }}"> {% if comment.file_attachment|is_image %} - <img class="attachment attachment-comment" src="{{ comment.file_attachment.url }}"> + <img class="attachment attachment-comment" src="{{ comment.get_attachment_url }}"> {% else %} {{ comment.file_attachment|filename }}<br><small>{{ comment.file_attachment.size|filesizeformat }}</small> {% endif %} diff --git a/comments/templates/comments/add_comment.html b/comments/templates/comments/add_comment.html new file mode 100644 index 0000000000000000000000000000000000000000..780fb54a30d4281d6c02acd41caef0272f14f03a --- /dev/null +++ b/comments/templates/comments/add_comment.html @@ -0,0 +1,22 @@ +{% extends 'scipost/base.html' %} + +{% load bootstrap %} + +{% block pagetitle %}: Add Comment{% endblock pagetitle %} + +{% block content %} + + <h1 class="highlight">Add Comment</h1> + + + {% if user.is_authenticated and perms.scipost.can_submit_comments %} + + <hr> + + <h2 class="highlight" id="contribute_comment">Contribute a Comment:</h2> + + {% include 'comments/_add_comment_form.html' with form=form url='' %} + + {% endif %} + +{% endblock content %} diff --git a/comments/urls.py b/comments/urls.py index 213fbd1ad0d6a5bcfaa152aaf878469adc2ed086..1c7f2a46e6939064148007f742a813b023078b8f 100644 --- a/comments/urls.py +++ b/comments/urls.py @@ -8,6 +8,7 @@ urlpatterns = [ url(r'^vet_submitted$', views.vet_submitted_comments_list, name='vet_submitted_comments_list'), url(r'^new/(?P<type_of_object>[a-z]+)/(?P<object_id>[0-9]+)$', views.new_comment, name='new_comment'), + url(r'^(?P<comment_id>[0-9]+)/attachment$', views.attachment, name='attachment'), url(r'^(?P<comment_id>[0-9]+)/reply$', views.reply_to_comment, name='reply_to_comment'), url(r'^(?P<comment_id>[0-9]+)/vet$', views.vet_submitted_comment, name='vet_submitted_comment'), diff --git a/comments/views.py b/comments/views.py index fba5791ba8e8a1b212eee8660dc77d77b7f32bb0..fb5199bd410e3758df115d1d6ac6486979108c4f 100644 --- a/comments/views.py +++ b/comments/views.py @@ -1,16 +1,18 @@ -from django.utils import timezone -from django.shortcuts import get_object_or_404, render, redirect from django.contrib.auth.decorators import permission_required, login_required from django.contrib import messages from django.core.urlresolvers import reverse from django.db import transaction +from django.http import HttpResponse, Http404 +from django.utils import timezone +from django.shortcuts import get_object_or_404, render, redirect from guardian.shortcuts import get_objects_for_user import strings +from .constants import EXTENTIONS_IMAGES, EXTENTIONS_PDF from .models import Comment from .forms import CommentForm, VetCommentForm -from .utils import CommentUtils +from .utils import CommentUtils, validate_file_extention from theses.models import ThesisLink from submissions.utils import SubmissionUtils @@ -20,7 +22,7 @@ from commentaries.models import Commentary @permission_required('scipost.can_submit_comments', raise_exception=True) def new_comment(request, **kwargs): - form = CommentForm(request.POST or None) + form = CommentForm(request.POST or None, request.FILES or None) if form.is_valid(): object_id = int(kwargs["object_id"]) type_of_object = kwargs["type_of_object"] @@ -41,6 +43,8 @@ def new_comment(request, **kwargs): messages.success(request, strings.acknowledge_submit_comment) return redirect(_object.get_absolute_url()) + context = {'form': form} + return(render(request, 'comments/add_comment.html', context)) @permission_required('scipost.can_vet_comments', raise_exception=True) @@ -178,3 +182,21 @@ def express_opinion(request, comment_id, opinion): comment = get_object_or_404(Comment, pk=comment_id) comment.update_opinions(request.user.contributor.id, opinion) return redirect(comment.get_absolute_url()) + + +def attachment(request, comment_id): + """ + Open/read attachment of Comment if available. + """ + comment = get_object_or_404(Comment.objects.exclude(file_attachment=''), pk=comment_id) + if validate_file_extention(comment.file_attachment, EXTENTIONS_IMAGES): + content_type = 'image/jpeg' + elif validate_file_extention(comment.file_attachment, EXTENTIONS_PDF): + content_type = 'application/pdf' + else: + raise Http404 + + response = HttpResponse(comment.file_attachment.read(), content_type=content_type) + filename = 'comment-attachment-%s' % comment.file_attachment.name + response['Content-Disposition'] = ('filename=' + filename) + return response diff --git a/funders/forms.py b/funders/forms.py index 64676af4446f442411f856981a0393bf8a512945..b7db43fcb0ecb60b2ed0e9e8ebb0e3afacc2b6fb 100644 --- a/funders/forms.py +++ b/funders/forms.py @@ -2,6 +2,9 @@ from django import forms from .models import Funder, Grant +from scipost.models import Contributor + + class FunderRegistrySearchForm(forms.Form): name = forms.CharField(max_length=128) @@ -9,13 +12,23 @@ class FunderRegistrySearchForm(forms.Form): class FunderForm(forms.ModelForm): class Meta: model = Funder - fields = ['name', 'identifier',] + fields = ['name', 'acronym', 'identifier',] + + +class FunderSelectForm(forms.Form): + funder = forms.ModelChoiceField(queryset=Funder.objects.all()) class GrantForm(forms.ModelForm): class Meta: model = Grant - fields = ['funder', 'number', 'recipient_name', 'recipient',] + fields = ['funder', 'number', 'recipient_name', 'recipient', 'further_details'] + + def __init__(self, *args, **kwargs): + super(GrantForm, self).__init__(*args, **kwargs) + self.fields['recipient'] = forms.ModelChoiceField( + queryset=Contributor.objects.all().order_by('user__last_name'), + required=False) class GrantSelectForm(forms.Form): diff --git a/funders/migrations/0004_auto_20170726_2037.py b/funders/migrations/0004_auto_20170726_2037.py new file mode 100644 index 0000000000000000000000000000000000000000..59544eb74125ea1719eaa0443a713a567ee15159 --- /dev/null +++ b/funders/migrations/0004_auto_20170726_2037.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-07-26 18:37 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0003_auto_20170726_0606'), + ] + + operations = [ + migrations.AlterModelOptions( + name='funder', + options={'ordering': ['name', 'acronym']}, + ), + migrations.AddField( + model_name='funder', + name='acronym', + field=models.CharField(blank=True, max_length=32, null=True), + ), + ] diff --git a/funders/migrations/0005_grant_further_details.py b/funders/migrations/0005_grant_further_details.py new file mode 100644 index 0000000000000000000000000000000000000000..095cd8735b666a133bce4ffde5cad79ab8202cb7 --- /dev/null +++ b/funders/migrations/0005_grant_further_details.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-07-27 04:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0004_auto_20170726_2037'), + ] + + operations = [ + migrations.AddField( + model_name='grant', + name='further_details', + field=models.CharField(blank=True, max_length=256, null=True), + ), + ] diff --git a/funders/models.py b/funders/models.py index 3957bf92f13ae9a3825a06aa780e68c6063e6b73..b0cba639a76892890c968812958aae7be5e62bd7 100644 --- a/funders/models.py +++ b/funders/models.py @@ -7,13 +7,17 @@ class Funder(models.Model): Fundref registry. """ name = models.CharField(max_length=256) + acronym = models.CharField(max_length=32, blank=True, null=True) identifier = models.CharField(max_length=200, unique=True) class Meta: - ordering = ['name'] + ordering = ['name', 'acronym'] def __str__(self): - return self.name + result = self.name + if self.acronym: + result += ' (%s)' % self.acronym + return result class Grant(models.Model): @@ -27,6 +31,7 @@ class Grant(models.Model): recipient_name = models.CharField(max_length=64, blank=True, null=True) recipient = models.ForeignKey('scipost.Contributor', blank=True, null=True, on_delete=models.CASCADE) + further_details = models.CharField(max_length=256, blank=True, null=True) class Meta: ordering = ['funder', 'recipient', 'recipient_name', 'number'] @@ -38,4 +43,6 @@ class Grant(models.Model): grantstring += ' (%s)' % str(self.recipient) elif self.recipient_name: grantstring += ' (%s)' % self.recipient_name + if self.further_details: + grantstring += ' [%s]' % self.further_details return grantstring diff --git a/funders/templates/funders/funders.html b/funders/templates/funders/funders.html index 7ae67d06b8fa03d6fb504cd5475f30f1c22120cb..cd9dfd6d4c2f7afc44d157a94a4471d7113720b0 100644 --- a/funders/templates/funders/funders.html +++ b/funders/templates/funders/funders.html @@ -57,6 +57,7 @@ <thead class="thead-default"> <tr> <th>Name</th> + <th>Acronym</th> <th>Identifier</th> </tr> </thead> @@ -64,6 +65,7 @@ {% for funder in funders %} <tr data-toggle="collapse" data-parent="#accordion" href="#collapse{{ funder.id }}" aria-expanded="true" aria-controls="collapse{{ funder.id }}" style="cursor: pointer;"> <td>{{ funder.name }}</td> + <td>{{ funder.acronym }}</td> <td>{{ funder.identifier }}</td> </tr> {% empty %} diff --git a/funders/templates/funders/query_crossref_for_funder.html b/funders/templates/funders/query_crossref_for_funder.html index b8459c8a21ff63b830f9c8919fdefb2fe28f9174..35c1b9a7ee15dbe05d6c0dabdcad77b83ce9e30e 100644 --- a/funders/templates/funders/query_crossref_for_funder.html +++ b/funders/templates/funders/query_crossref_for_funder.html @@ -29,6 +29,7 @@ <form action="{% url 'funders:add_funder' %}" method="post"> {% csrf_token %} <input name='name' style="width: 64%" value='{{ item.name }}'> + <input name='acronym' style="width: 64%" placeholder='acronym (if known)'> <input name='identifier' style="width: 64%" value='{{ item.uri }}'> <input class="btn btn-secondary" type="submit" value="Add this funder"> </form> diff --git a/journals/constants.py b/journals/constants.py index 7db8b8c2a556c43aaddb121825a6ec209746412e..7673cf16062813b0d1ceba90839c40b082fce962 100644 --- a/journals/constants.py +++ b/journals/constants.py @@ -65,3 +65,9 @@ CC_LICENSES = ( (CCBYSA4, 'CC BY-SA (4.0)'), (CCBYNC4, 'CC BY-NC (4.0)'), ) + +CC_LICENSES_URI = ( + (CCBY4, 'https://creativecommons.org/licenses/by/4.0'), + (CCBYSA4, 'https://creativecommons.org/licenses/by-sa/4.0'), + (CCBYNC4, 'https://creativecommons.org/licenses/by-nc/4.0'), + ) diff --git a/journals/helpers.py b/journals/helpers.py index d1d656c2bad92ed789800d15dbe3685f93ca4d84..6c097de27734169f18446b14b253ec9923a1059b 100644 --- a/journals/helpers.py +++ b/journals/helpers.py @@ -1,6 +1,18 @@ +import re + from .exceptions import JournalNameError, PaperNumberError +def issue_doi_label_from_doi_label(doi_label): + """ + Strip the last digits block from the label. + """ + m = re.match(r'[a-zA-Z]+.[0-9]+.[0-9]+', doi_label) + s = m.start() + e = m.end() + return doi_label[s:e] + + def journal_name_abbrev_citation(journal_name): if journal_name == 'SciPostPhys': return 'SciPost Phys.' diff --git a/journals/migrations/0041_publication_funders_generic.py b/journals/migrations/0041_publication_funders_generic.py new file mode 100644 index 0000000000000000000000000000000000000000..419bf2f1282102d83e154ff15449fabc1f687001 --- /dev/null +++ b/journals/migrations/0041_publication_funders_generic.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-07-27 04:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0005_grant_further_details'), + ('journals', '0040_merge_20170726_0945'), + ] + + operations = [ + migrations.AddField( + model_name='publication', + name='funders_generic', + field=models.ManyToManyField(blank=True, to='funders.Funder'), + ), + ] diff --git a/journals/models.py b/journals/models.py index 36e739a040f8fff042d5e5a24c7eefbd90d2e30b..f472114235bed8485792f20c0e08e290ab5ad12d 100644 --- a/journals/models.py +++ b/journals/models.py @@ -8,7 +8,7 @@ from .behaviors import doi_journal_validator, doi_volume_validator,\ doi_issue_validator, doi_publication_validator from .constants import SCIPOST_JOURNALS, SCIPOST_JOURNALS_DOMAINS,\ STATUS_DRAFT, STATUS_PUBLISHED, ISSUE_STATUSES,\ - CCBY4, CC_LICENSES + CCBY4, CC_LICENSES, CC_LICENSES_URI from .helpers import paper_nr_string, journal_name_abbrev_citation from .managers import IssueManager, PublicationManager, JournalManager @@ -145,6 +145,7 @@ class Publication(models.Model): pdf_file = models.FileField(upload_to='UPLOADS/PUBLICATIONS/%Y/%m/', max_length=200) cc_license = models.CharField(max_length=32, choices=CC_LICENSES, default=CCBY4) grants = models.ManyToManyField('funders.Grant', blank=True) + funders_generic = models.ManyToManyField('funders.Funder', blank=True) # not linked to a grant metadata = JSONField(default={}, blank=True, null=True) metadata_xml = models.TextField(blank=True, null=True) # for Crossref deposit latest_metadata_update = models.DateTimeField(blank=True, null=True) @@ -170,6 +171,12 @@ class Publication(models.Model): def get_absolute_url(self): return reverse('scipost:publication_detail', args=[self.doi_label]) + def get_cc_license_URI(self): + for (key, val) in CC_LICENSES_URI: + if key == self.cc_license: + return val + raise KeyError + @property def doi_string(self): return '10.21468/' + self.doi_label diff --git a/journals/templates/journals/_publication_details.html b/journals/templates/journals/_publication_details.html index 09460585a57824dced8a72b11653262f3c14bbc3..03e1a66d1a285e4c84b6b181a2a11cd19ed31fc0 100644 --- a/journals/templates/journals/_publication_details.html +++ b/journals/templates/journals/_publication_details.html @@ -17,7 +17,7 @@ <li> <!-- Start Crossmark Snippet v2.0 --> <script src="https://crossmark-cdn.crossref.org/widget/v2.0/widget.js"></script> - <a data-target="crossmark"><img src="https://crossmark-cdn.crossref.org/widget/v2.0/logos/CROSSMARK_Color_horizontal.svg" width="120" /></a> + <a data-target="crossmark"><img src="https://crossmark-cdn.crossref.org/widget/v2.0/logos/CROSSMARK_BW_horizontal.svg" width="120" /></a> <!-- End Crossmark Snippet --> </li> </ul> diff --git a/journals/templates/journals/create_citation_list_metadata.html b/journals/templates/journals/create_citation_list_metadata.html index f28ebffeac71f5b7286d4ac347b08008dd1b667c..292301ee572ebbf850624e07462cd3f5a4fb0d5c 100644 --- a/journals/templates/journals/create_citation_list_metadata.html +++ b/journals/templates/journals/create_citation_list_metadata.html @@ -50,7 +50,7 @@ <hr> - <h3>Once you're happy with this metadata, you can <a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a></h3> + <h3>Once you're happy with this metadata, you can <a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a> or to <a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">this publication's metadata management page</a></h3> </div> </div> diff --git a/journals/templates/journals/create_funding_info_metadata.html b/journals/templates/journals/create_funding_info_metadata.html index 8134c2f123aefa250f9ceae3fe58f2d110240116..b11cb1c864927ebdb7abe0e66168c41295a256a2 100644 --- a/journals/templates/journals/create_funding_info_metadata.html +++ b/journals/templates/journals/create_funding_info_metadata.html @@ -44,7 +44,7 @@ <hr> - <h3>Once you're happy with this metadata, you can <a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a></h3> + <h3>Once you're happy with this metadata, you can <a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a> or to <a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">this publication's metadata management page</a></h3> </div> </div> diff --git a/journals/templates/journals/create_metadata_xml.html b/journals/templates/journals/create_metadata_xml.html index 8cf13758da2c63fa2f8ab62fc1d77cc90083ec0c..f3fef831804f54439c2bc9c56553e12761afa422 100644 --- a/journals/templates/journals/create_metadata_xml.html +++ b/journals/templates/journals/create_metadata_xml.html @@ -2,6 +2,7 @@ {% block pagetitle %}: Create metadata xml{% endblock pagetitle %} +<<<<<<< HEAD {% block breadcrumb %} <nav class="breadcrumb py-md-2 px-0 hidden-sm-down"> <div class="container"> @@ -54,3 +55,36 @@ {% endblock content %} +======= +{% block bodysup %} + + +<section> + <div class="flex-greybox"> + <h1>Create metadata XML (for Crossref deposit)</h1> + </div> + + {% if errormessage %} + <h2 style="color: red;">{{ errormessage }}</h2> + {% endif %} + + <form action="{% url 'journals:create_metadata_xml' publication.doi_label %}" method="post"> + {% csrf_token %} + {{ create_metadata_xml_form.as_p }} + <input type="submit" value="Accept the metadata"> + </form> + + <hr class="hr6"/> + + <h3>Current metadata xml:</h3> + <p>{{ publication.metadata_xml|linebreaks }}</p> + + <hr class="hr6"/> + + <h3>Once you're happy with this metadata, you can <a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">general metadata management page</a> or to <a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">this publication's metadata management page</a></h3> + +</section> + + +{% endblock bodysup %} +>>>>>>> development diff --git a/journals/templates/journals/harvest_citedby_links.html b/journals/templates/journals/harvest_citedby_links.html index f39d1d0b940b81eda93d59ad4a435220c1a5e2f4..5d10c46e5af66d536f061f553a2058d49d47f7f7 100644 --- a/journals/templates/journals/harvest_citedby_links.html +++ b/journals/templates/journals/harvest_citedby_links.html @@ -52,7 +52,7 @@ {% endfor %} {{ nr }} - <h3><a href="{{publication.get_absolute_url}}">return to the publication's page</a></h3> + <h3><a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a> or to <a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">this publication's metadata management page</a></h3> </section> diff --git a/journals/templates/journals/journals.html b/journals/templates/journals/journals.html index 081c8fce2e60ae943dbfaef365b95e52b6367b0f..33940701b942ba18c7fc8f0b7c2fa3efc316ce38 100644 --- a/journals/templates/journals/journals.html +++ b/journals/templates/journals/journals.html @@ -30,7 +30,7 @@ <a href="{% url 'scipost:landing_page' 'SciPostPhys' %}">SciPost Physics</a> </h1> <div class="py-2"> - <h3 class="mb-2"><a href="{% url 'scipost:landing_page' 'SciPostPhys' %}">Go direct to SciPost Physics</a></h3> + <h3 class="mb-2"><a href="{% url 'scipost:landing_page' 'SciPostPhys' %}">Go directly to SciPost Physics</a></h3> <p>SciPost Physics publishes outstanding-quality research articles in all domains and subject areas of Physics.</p> <p>The journal accepts three types of content: Letters, Articles and Reviews.</p> <p>Letters report broad-interest, significant breakthroughs in Physics, of interest and importance to researchers in multiple subject areas.</p> @@ -44,7 +44,7 @@ <a href="{% url 'journal:about' 'SciPostPhysProc' %}">SciPost Physics Proceedings</a> </h1> <div class="py-2"> - <h3 class="d-inline-block text-danger mb-2"><b>New!</b> <a href="{% url 'journal:about' 'SciPostPhysProc' %}">Go direct to SciPost Physics Proceedings</a></h3> + <h3 class="d-inline-block text-danger mb-2"><b>New!</b> <a href="{% url 'journal:about' 'SciPostPhysProc' %}">Go directly to SciPost Physics Proceedings</a></h3> <p>SciPost Physics Proceedings is a premium-quality, two-way open access, peer-witnessed refereed Journal for the general field of Physics.</p> <p>It aims at providing a high-quality, openly accessible publishing venue for conference/workshop/school proceedings.</p> <p>SciPost Physics Proceedings publishes articles in the domains of Experimental, Theoretical and Computational physics, in all specializations.</p> diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html index 89f1796afce4c103f9dba4c3e3b991e10555f8b6..7025abe2757158aeed4e78e5dce2144ecc013401 100644 --- a/journals/templates/journals/manage_metadata.html +++ b/journals/templates/journals/manage_metadata.html @@ -23,7 +23,18 @@ event: "focusin" <div class="row"> <div class="col-12"> - <h1 class="highlight">Manage Publications Metadata</h1> + <h1 class="highlight">Manage Publications Metadata{% if issue_doi_label %} for issue {{ issue_doi_label }}{% endif %}</h1> + {% if issue_doi_label %} + <h3>Return to the <a href="{% url 'journals:manage_metadata' %}">Main manage metadata page</a></h3> + {% endif %} + <h3>Manage metadata per issue:</h3> + <ul> + {% for issue in issues %} + <li> + <a href="{% url 'journals:manage_metadata' issue_doi_label=issue.doi_label %}">{{ issue }}</a> + </li> + {% endfor %} + </ul> </div> </div> @@ -88,20 +99,21 @@ event: "focusin" <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'deposit' %}">Deposit the metadata to Crossref</a></li> <li><a href="{% url 'journals:produce_metadata_DOAJ' doi_label=publication.doi_label %}">Produce DOAJ metadata</a></li> <li><a href="{% url 'journals:metadata_DOAJ_deposit' doi_label=publication.doi_label %}">Deposit the metadata to DOAJ</a></li> + <li><a href="{% url 'journals:harvest_citedby_links' publication.doi_label %}">Update Crossref cited-by links</a></li> </ul> </div> <div class="col-md-5"> - <h2>Funding info for this publication:</h2> - {% if publication.funding_info %} - <p>{{ publication.funding_info }}</p> + <h2>Funding statement for this publication:</h2> + {% if publication.metadata.funding_statement %} + <p>{{ publication.metadata.funding_statement }}</p> {% else %} - <p>No funding info was found</p> + <p>No funding statement was found</p> {% endif %} <h2>Grants associated to this publication:</h2> <ul> {% for grant in publication.grants.all %} - <li> {{ grant }}</li> + <li>{{ grant }}</li> {% empty %} <li>no associated grants found</li> {% endfor %} @@ -113,7 +125,23 @@ event: "focusin" {{associate_grant_form|bootstrap}} <input class="btn btn-secondary" type="submit" value="Add"> </form> - <h3>Other grant-related actions:</h3> + <br/> + <h2>Generic (not via grant) funders associated to this publication:</h2> + <ul> + {% for funder in publication.funders_generic.all %} + <li>{{ funder }}</li> + {% empty %} + <li>No generic funder found</li> + {% endfor %} + </ul> + <h3>Associate a generic funder to this publication:</h3> + <form action="{% url 'journals:add_generic_funder' publication.doi_label %}" method="post"> + {% csrf_token %} + {{associate_generic_funder_form|bootstrap}} + <input class="btn btn-secondary" type="submit" value="Add"> + </form> + <br/> + <h3>Other funding-related actions:</h3> <ul> <li><a href="{% url 'funders:funders' %}" target="_blank">go to the Funders page to add a Funder and/or Grant instance</a></li> </ul> diff --git a/journals/templates/journals/metadata_xml_deposit.html b/journals/templates/journals/metadata_xml_deposit.html index 98a4d2621ca0a29529a53f4619b330f41d29cf85..5d3f4871132092d3ddce2e4bd263f27de49f76ac 100644 --- a/journals/templates/journals/metadata_xml_deposit.html +++ b/journals/templates/journals/metadata_xml_deposit.html @@ -38,7 +38,7 @@ <h3 class="mt-3">Response text:</h3> <p>{{ response_text|linebreaks }}</p> - <h3><a href="{{publication.get_absolute_url}}">return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a></h3> + <h3><a href="{{publication.get_absolute_url}}">return to the publication's page</a>, to the <a href="{% url 'journals:manage_metadata' %}">general metadata management page</a> or to <a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">this publication's metadata management page</a></h3> </div> diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html index 9181566b3c5d8b80aba8a062031cce3292b298fb..908822960bceac29efb26de3962514d67abc1508 100644 --- a/journals/templates/journals/publication_detail.html +++ b/journals/templates/journals/publication_detail.html @@ -119,6 +119,8 @@ <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'test' %}">Test metadata deposit (via Crossref test server)</a></li> <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'deposit' %}">Deposit the metadata to Crossref</a></li> <li><a href="{% url 'journals:harvest_citedby_links' publication.doi_label %}">Update Crossref cited-by links</a></li> + <li><a href="{% url 'journals:manage_metadata' %}">Metadata management page</a></li> + <li><a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">This publication's metadata management page</a></li> </ul> </div> </div> diff --git a/journals/urls/general.py b/journals/urls/general.py index 7af9d780d4c4b5db5490a33e018bd5ba924780b1..478572c2a241c0572bffea2ac26ed3b8c91fae81 100644 --- a/journals/urls/general.py +++ b/journals/urls/general.py @@ -41,6 +41,12 @@ urlpatterns = [ url(r'^add_new_unreg_author/(?P<publication_id>[0-9]+)$', journals_views.add_new_unreg_author, name='add_new_unreg_author'), + url(r'^manage_metadata/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$', + journals_views.manage_metadata, + name='manage_metadata'), + url(r'^manage_metadata/(?P<issue_doi_label>[a-zA-Z]+.[0-9]+.[0-9]+)$', + journals_views.manage_metadata, + name='manage_metadata'), url(r'^manage_metadata/$', journals_views.manage_metadata, name='manage_metadata'), @@ -53,6 +59,9 @@ urlpatterns = [ url(r'^add_associated_grant/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$', journals_views.add_associated_grant, name='add_associated_grant'), + url(r'^add_generic_funder/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$', + journals_views.add_generic_funder, + name='add_generic_funder'), url(r'^create_metadata_xml/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$', journals_views.create_metadata_xml, name='create_metadata_xml'), diff --git a/journals/views.py b/journals/views.py index 57c4b6da29a331ab8ca524c61a17ace570d3ee43..6dbf0f2d7188ecbefad6f81675997141db67bcec 100644 --- a/journals/views.py +++ b/journals/views.py @@ -16,7 +16,7 @@ from django.db import transaction from django.http import HttpResponse from .exceptions import PaperNumberingError -from .helpers import paper_nr_string +from .helpers import paper_nr_string, issue_doi_label_from_doi_label from .models import Journal, Issue, Publication, UnregisteredAuthor, Deposit, DOAJDeposit from .forms import FundingInfoForm, InitiatePublicationForm, ValidatePublicationForm,\ UnregisteredAuthorForm, CreateMetadataXMLForm, CitationListBibitemsForm @@ -26,7 +26,7 @@ from funders.models import Funder from submissions.models import Submission from scipost.models import Contributor -from funders.forms import GrantSelectForm +from funders.forms import FunderSelectForm, GrantSelectForm from guardian.decorators import permission_required @@ -277,12 +277,22 @@ def validate_publication(request): @permission_required('scipost.can_publish_accepted_submission', return_403=True) -def manage_metadata(request): - publications = Publication.objects.order_by('-publication_date', '-paper_nr') +def manage_metadata(request, issue_doi_label=None, doi_label=None): + issues = Issue.objects.all().order_by('-until_date') + publications = Publication.objects.all() + if doi_label: + issue_doi_label = issue_doi_label_from_doi_label(doi_label) + if issue_doi_label: + publications = publications.filter(in_issue__doi_label=issue_doi_label) + publications = publications.order_by('-publication_date', '-paper_nr') associate_grant_form = GrantSelectForm() + associate_generic_funder_form = FunderSelectForm() context = { + 'issues': issues, + 'issue_doi_label': issue_doi_label, 'publications': publications, 'associate_grant_form': associate_grant_form, + 'associate_generic_funder_form': associate_generic_funder_form, } return render(request, 'journals/manage_metadata.html', context) @@ -295,7 +305,8 @@ def mark_first_author(request, publication_id, contributor_id): publication.first_author = contributor publication.first_author_unregistered = None publication.save() - return redirect(publication.get_absolute_url()) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': publication.doi_label})) @permission_required('scipost.can_publish_accepted_submission', return_403=True) @@ -306,7 +317,8 @@ def mark_first_author_unregistered(request, publication_id, unregistered_author_ publication.first_author = None publication.first_author_unregistered = unregistered_author publication.save() - return redirect(publication.get_absolute_url()) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': publication.doi_label})) @permission_required('scipost.can_publish_accepted_submission', return_403=True) @@ -323,7 +335,8 @@ def add_author(request, publication_id, contributor_id=None, unregistered_author contributor = get_object_or_404(Contributor, id=contributor_id) publication.authors.add(contributor) publication.save() - return redirect(publication.get_absolute_url()) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': publication.doi_label})) if request.method == 'POST': form = UnregisteredAuthorForm(request.POST) @@ -358,7 +371,8 @@ def add_unregistered_author(request, publication_id, unregistered_author_id): unregistered_author = get_object_or_404(UnregisteredAuthor, id=unregistered_author_id) publication.unregistered_authors.add(unregistered_author) publication.save() - return redirect(publication.get_absolute_url()) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': publication.doi_label})) @permission_required('scipost.can_publish_accepted_submission', return_403=True) @@ -370,7 +384,8 @@ def add_new_unreg_author(request, publication_id): if new_unreg_author_form.is_valid(): new_unreg_author = new_unreg_author_form.save() publication.authors_unregistered.add(new_unreg_author) - return redirect(publication.get_absolute_url()) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': publication.doi_label})) raise Http404 @@ -441,7 +456,25 @@ def add_associated_grant(request, doi_label): publication.grants.add(grant_select_form.cleaned_data['grant']) publication.save() messages.success(request, 'Grant added to publication %s' % str(publication)) - return redirect(reverse('journals:manage_metadata')) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': publication.doi_label})) + + +@permission_required('scipost.can_publish_accepted_submission', return_403=True) +@transaction.atomic +def add_generic_funder(request, doi_label): + """ + Called by an Editorial Administrator. + This associates a funder (generic, not via grant) from the database to this publication. + """ + publication = get_object_or_404(Publication, doi_label=doi_label) + funder_select_form = FunderSelectForm(request.POST or None) + if funder_select_form.is_valid(): + publication.funders_generic.add(funder_select_form.cleaned_data['funder']) + publication.save() + messages.success(request, 'Generic funder added to publication %s' % str(publication)) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': doi_label})) @permission_required('scipost.can_publish_accepted_submission', return_403=True) @@ -459,7 +492,8 @@ def create_metadata_xml(request, doi_label): if create_metadata_xml_form.is_valid(): create_metadata_xml_form.save() messages.success(request, 'Metadata XML saved') - return redirect(reverse('journals:manage_metadata')) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': doi_label})) # create a doi_batch_id salt = "" @@ -477,7 +511,8 @@ def create_metadata_xml(request, doi_label): 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' 'xmlns:fr="http://www.crossref.org/fundref.xsd" ' 'xsi:schemaLocation="http://www.crossref.org/schema/4.4.0 ' - 'http://www.crossref.org/shema/deposit/crossref4.4.0.xsd">\n' + 'http://www.crossref.org/shema/deposit/crossref4.4.0.xsd" ' + 'xmlns:ai="http://www.crossref.org/AccessIndicators.xsd">\n' '<head>\n' '<doi_batch_id>' + str(doi_batch_id) + '</doi_batch_id>\n' '<timestamp>' + timezone.now().strftime('%Y%m%d%H%M%S') + '</timestamp>\n' @@ -567,10 +602,11 @@ def create_metadata_xml(request, doi_label): '<crossmark_domain><domain>scipost.org</domain></crossmark_domain>\n' '</crossmark_domains>\n' '<crossmark_domain_exclusive>false</crossmark_domain_exclusive>\n' - '<custom_metadata>\n' ) - funders = Funder.objects.filter(grant__in=publication.grants.all()).distinct() + funders = (Funder.objects.filter(grant__in=publication.grants.all()) + | publication.funders_generic.all()).distinct() nr_funders = funders.count() + initial['metadata_xml'] += '<custom_metadata>\n' if nr_funders > 0: initial['metadata_xml'] += '<fr:program name="fundref">\n' for funder in funders: @@ -589,9 +625,14 @@ def create_metadata_xml(request, doi_label): if nr_funders > 1: initial['metadata_xml'] += '</fr:assertion>\n' initial['metadata_xml'] += '</fr:program>\n' - initial['metadata_xml'] += ( - '</custom_metadata>\n' + '<ai:program name="AccessIndicators">\n' + '<ai:license_ref>' + publication.get_cc_license_URI() + + '</ai:license_ref>\n' + '</ai:program>\n' + ) + initial['metadata_xml'] += '</custom_metadata>\n' + initial['metadata_xml'] += ( '</crossmark>\n' '<archive_locations><archive name="CLOCKSS"></archive></archive_locations>\n' '<doi_data>\n' @@ -602,6 +643,10 @@ def create_metadata_xml(request, doi_label): '<resource>https://scipost.org/' + publication.doi_string + '/pdf</resource>\n' '</item></collection>\n' + '<collection property="text-mining">\n' + '<item><resource mime_type="application/pdf">' + 'https://scipost.org/' + publication.doi_string + '/pdf</resource></item>\n' + '</collection>' '</doi_data>\n' ) try: @@ -706,7 +751,8 @@ def mark_deposit_success(request, deposit_id, success): elif success == '0': deposit.deposit_successful = False deposit.save() - return redirect(reverse('journals:manage_metadata')) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': deposit.publication.doi_label})) @permission_required('scipost.can_publish_accepted_submission', return_403=True) @@ -835,7 +881,8 @@ def harvest_citedby_links(request, doi_label): if r.status_code == 401: messages.warning(request, ('<h3>Crossref credentials are invalid.</h3>' 'Please contact the SciPost Admin.')) - return redirect(reverse('journals:harvest_all_publications')) + return redirect(reverse('journals:manage_metadata', + kwargs={'doi_label': doi_label})) response_headers = r.headers response_text = r.text response_deserialized = ET.fromstring(r.text) diff --git a/scipost/admin.py b/scipost/admin.py index 21a0de1351f583a3073d8292ca7df866b37d9f01..36831284095a32ab06999a534bec999cd713bb46 100644 --- a/scipost/admin.py +++ b/scipost/admin.py @@ -183,6 +183,14 @@ def college_fellow_is_active(fellow): '''Check if fellow is currently active.''' return fellow.is_active() +class EditorialCollegeFellowshipAdminForm(forms.ModelForm): + contributor = forms.ModelChoiceField( + queryset=Contributor.objects.order_by('user__last_name')) + + class Meta: + model = EditorialCollegeFellowship + fields = '__all__' + class EditorialCollegeFellowshipAdmin(admin.ModelAdmin): list_display = ('__str__', 'college', college_fellow_is_active) @@ -192,6 +200,7 @@ class EditorialCollegeFellowshipAdmin(admin.ModelAdmin): fields = ('contributor', 'college', 'start_date', 'until_date', 'affiliation', ) college_fellow_is_active.boolean = True + form = EditorialCollegeFellowshipAdminForm admin.site.register(EditorialCollegeFellowship, EditorialCollegeFellowshipAdmin) diff --git a/scipost/static/scipost/assets/css/_form.scss b/scipost/static/scipost/assets/css/_form.scss index e1fab6c76e0359af43c085b126f7294e00013281..33a9f6b430bed5efa164b3e3a5bc0e156857c435 100644 --- a/scipost/static/scipost/assets/css/_form.scss +++ b/scipost/static/scipost/assets/css/_form.scss @@ -10,6 +10,10 @@ border-color: #d9534f; } +.has-error .help-block { + color: $brand-danger; +} + .has-error .multiple-checkbox .help-block { color: $brand-danger; font-weight: 600; diff --git a/submissions/views.py b/submissions/views.py index 61debe7ab40c73b50e08116e30397f41481f10f9..3e6d66d230c8fafb88b9fd0d3870a5482341214f 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -884,7 +884,7 @@ def decline_ref_invitation(request, invitation_key): invitation.submission.add_event_for_author('A referee has declined the' ' refereeing invitation.') invitation.submission.add_event_for_eic('Referee %s has declined the refereeing ' - 'invitation.' % invitation.referee.user.last_name) + 'invitation.' % invitation.last_name) messages.success(request, 'Thank you for informing us that you will not provide a Report.') return redirect(reverse('scipost:index'))