From 53be57c081fd605c433a7de6d06965fca994610a Mon Sep 17 00:00:00 2001 From: Jorran de Wit <jorrandewit@outlook.com> Date: Wed, 25 Apr 2018 22:14:49 +0200 Subject: [PATCH] Add Funders list and publicly link them --- funders/managers.py | 12 +++++++ funders/migrations/0003_auto_20180425_2146.py | 20 +++++++++++ funders/migrations/0004_auto_20180425_2146.py | 20 +++++++++++ funders/migrations/0005_auto_20180425_2211.py | 36 +++++++++++++++++++ funders/migrations/0006_auto_20180425_2212.py | 25 +++++++++++++ funders/models.py | 23 ++++++++---- funders/templates/funders/base.html | 13 +++++++ funders/templates/funders/funder_details.html | 15 ++++++-- funders/templates/funders/funder_list.html | 29 +++++++++++++++ .../{funders.html => funders_dashboard.html} | 9 +++-- funders/urls.py | 4 +-- funders/views.py | 22 ++++++++---- .../templates/journals/manage_metadata.html | 2 +- .../journals/publication_detail.html | 20 +++++------ .../partials/notification_list_popover.html | 2 +- 15 files changed, 218 insertions(+), 34 deletions(-) create mode 100644 funders/managers.py create mode 100644 funders/migrations/0003_auto_20180425_2146.py create mode 100644 funders/migrations/0004_auto_20180425_2146.py create mode 100644 funders/migrations/0005_auto_20180425_2211.py create mode 100644 funders/migrations/0006_auto_20180425_2212.py create mode 100644 funders/templates/funders/base.html create mode 100644 funders/templates/funders/funder_list.html rename funders/templates/funders/{funders.html => funders_dashboard.html} (94%) diff --git a/funders/managers.py b/funders/managers.py new file mode 100644 index 000000000..12d206fbf --- /dev/null +++ b/funders/managers.py @@ -0,0 +1,12 @@ +__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.db import models + + +class FunderQuerySet(models.QuerySet): + def has_publications(self): + """Return those Funder instances related to any Publication instance.""" + return self.filter( + models.Q(publications__isnull=False) | models.Q(grants__publications__isnull=False)) diff --git a/funders/migrations/0003_auto_20180425_2146.py b/funders/migrations/0003_auto_20180425_2146.py new file mode 100644 index 000000000..b1f2aa55e --- /dev/null +++ b/funders/migrations/0003_auto_20180425_2146.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-04-25 19:46 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0002_auto_20171229_1435'), + ] + + operations = [ + migrations.AlterField( + model_name='funder', + name='acronym', + field=models.CharField(blank=True, default='', max_length=32), + ), + ] diff --git a/funders/migrations/0004_auto_20180425_2146.py b/funders/migrations/0004_auto_20180425_2146.py new file mode 100644 index 000000000..a929cb51f --- /dev/null +++ b/funders/migrations/0004_auto_20180425_2146.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-04-25 19:46 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0003_auto_20180425_2146'), + ] + + operations = [ + migrations.AlterField( + model_name='funder', + name='acronym', + field=models.CharField(blank=True, max_length=32), + ), + ] diff --git a/funders/migrations/0005_auto_20180425_2211.py b/funders/migrations/0005_auto_20180425_2211.py new file mode 100644 index 000000000..0ed563304 --- /dev/null +++ b/funders/migrations/0005_auto_20180425_2211.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-04-25 20:11 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0004_auto_20180425_2146'), + ] + + operations = [ + migrations.AlterField( + model_name='grant', + name='funder', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='grants', to='funders.Funder'), + ), + migrations.AlterField( + model_name='grant', + name='further_details', + field=models.CharField(blank=True, default='', max_length=256), + ), + migrations.AlterField( + model_name='grant', + name='recipient', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='grants', to='scipost.Contributor'), + ), + migrations.AlterField( + model_name='grant', + name='recipient_name', + field=models.CharField(blank=True, default='', max_length=64), + ), + ] diff --git a/funders/migrations/0006_auto_20180425_2212.py b/funders/migrations/0006_auto_20180425_2212.py new file mode 100644 index 000000000..bc846c396 --- /dev/null +++ b/funders/migrations/0006_auto_20180425_2212.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-04-25 20:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funders', '0005_auto_20180425_2211'), + ] + + operations = [ + migrations.AlterField( + model_name='grant', + name='further_details', + field=models.CharField(blank=True, max_length=256), + ), + migrations.AlterField( + model_name='grant', + name='recipient_name', + field=models.CharField(blank=True, max_length=64), + ), + ] diff --git a/funders/models.py b/funders/models.py index 93410a0fe..ceefe67b5 100644 --- a/funders/models.py +++ b/funders/models.py @@ -8,16 +8,21 @@ from django.urls import reverse from journals.models import Publication +from .managers import FunderQuerySet + class Funder(models.Model): - """ + """Funder is a Fundref regsitry. + Funding info metadata is linked to funders from Crossref's - Fundref registry. """ + name = models.CharField(max_length=256) - acronym = models.CharField(max_length=32, blank=True, null=True) + acronym = models.CharField(max_length=32, blank=True) identifier = models.CharField(max_length=200, unique=True) + objects = FunderQuerySet.as_manager() + class Meta: ordering = ['name', 'acronym'] @@ -28,27 +33,31 @@ class Funder(models.Model): return result def get_absolute_url(self): + """Return the Funder detail page.""" return reverse('funders:funder_publications', args=(self.id,)) def all_related_publications(self): + """Return all Publication objects linked to this Funder.""" return Publication.objects.filter( Q(funders_generic=self) | Q(grants__funder=self)).distinct() class Grant(models.Model): - """ - An instance of a grant, award or other funding. + """An instance of a grant, award or other funding. + In a Publication's metadata, all grants are listed in the Crossmark part of the metadata. """ + funder = models.ForeignKey('funders.Funder', on_delete=models.CASCADE) number = models.CharField(max_length=64) - recipient_name = models.CharField(max_length=64, blank=True, null=True) + recipient_name = models.CharField(max_length=64, blank=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) + further_details = models.CharField(max_length=256, blank=True) class Meta: + default_related_name = 'grants' ordering = ['funder', 'recipient', 'recipient_name', 'number'] unique_together = ('funder', 'number') diff --git a/funders/templates/funders/base.html b/funders/templates/funders/base.html new file mode 100644 index 000000000..45d65898c --- /dev/null +++ b/funders/templates/funders/base.html @@ -0,0 +1,13 @@ +{% extends 'scipost/base.html' %} + +{% block breadcrumb %} + <div class="container-outside breadcrumb-nav"> + <div class="container"> + <nav class="breadcrumb hidden-sm-down"> + {% block breadcrumb_items %} + <a href="{% url 'funders:funders' %}" class="breadcrumb-item">Funders</a> + {% endblock %} + </nav> + </div> + </div> +{% endblock %} diff --git a/funders/templates/funders/funder_details.html b/funders/templates/funders/funder_details.html index 382cb69bb..9fd9b51b2 100644 --- a/funders/templates/funders/funder_details.html +++ b/funders/templates/funders/funder_details.html @@ -1,16 +1,25 @@ -{% extends 'scipost/base.html' %} +{% extends 'funders/base.html' %} {% block pagetitle %}: Funder details{% endblock pagetitle %} +{% block breadcrumb_items %} + {{ block.super }} + <span class="breadcrumb-item">{{ funder.name }}</span> +{% endblock %} + {% block content %} <h1 class="highlight">Funder {{ funder.name }}</h1> -<h3>All Publications related to this Funder</h3> +<h3>All Publications related to {{ funder.name }}</h3> <ul> {% for publication in funder.all_related_publications %} - <li><a href="{{ publication.get_absolute_url }}">{{ publication }}</a></li> + <li> + <a href="{{ publication.get_absolute_url }}">{{ publication.title }}</a> + <br>by {{ publication.author_list }}, + <br>{{ publication.citation }} + </li> {% empty %} <li>No publications</li> {% endfor %} diff --git a/funders/templates/funders/funder_list.html b/funders/templates/funders/funder_list.html new file mode 100644 index 000000000..ac4b95994 --- /dev/null +++ b/funders/templates/funders/funder_list.html @@ -0,0 +1,29 @@ +{% extends 'funders/base.html' %} + +{% block pagetitle %}: Funders list{% endblock pagetitle %} + +{% block breadcrumb_items %} + <span class="breadcrumb-item">Funders</span> +{% endblock %} + +{% block content %} + +<h1 class="highlight">Funders</h1> + +{% if perms.scipost.can_view_all_funding_info %} + <a href="{% url 'funders:funders_dashboard' %}">Go to dashboard</a> + <br><br> +{% endif %} + +<h3>All Funders with a SciPost publication</h3> + +<ul> + {% for funder in funders %} + <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li> + {% empty %} + <li>No funders</li> + {% endfor %} +</ul> + + +{% endblock content %} diff --git a/funders/templates/funders/funders.html b/funders/templates/funders/funders_dashboard.html similarity index 94% rename from funders/templates/funders/funders.html rename to funders/templates/funders/funders_dashboard.html index 0ab70cf7f..16ea8e04a 100644 --- a/funders/templates/funders/funders.html +++ b/funders/templates/funders/funders_dashboard.html @@ -1,6 +1,11 @@ -{% extends 'scipost/base.html' %} +{% extends 'funders/base.html' %} -{% block pagetitle %}: Funders{% endblock pagetitle %} +{% block pagetitle %}: Funders dashboard{% endblock pagetitle %} + +{% block breadcrumb_items %} + {{ block.super }} + <span class="breadcrumb-item">Dashboard</span> +{% endblock %} {% load bootstrap %} diff --git a/funders/urls.py b/funders/urls.py index 8ec6892cd..48f99d288 100644 --- a/funders/urls.py +++ b/funders/urls.py @@ -8,10 +8,10 @@ from . import views urlpatterns = [ url(r'^$', views.funders, name='funders'), + url(r'^dashboard$', views.funders_dashboard, name='funders_dashboard'), url(r'^query_crossref_for_funder$', views.query_crossref_for_funder, name='query_crossref_for_funder'), url(r'^add$', views.add_funder, name='add_funder'), - url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications, - name='funder_publications'), + url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications, name='funder_publications'), url(r'^grants/add$', views.CreateGrantView.as_view(), name='add_grant'), ] diff --git a/funders/views.py b/funders/views.py index 5e04d384f..f6b2d5b56 100644 --- a/funders/views.py +++ b/funders/views.py @@ -20,14 +20,15 @@ from scipost.mixins import PermissionsMixin @permission_required('scipost.can_view_all_funding_info', raise_exception=True) -def funders(request): +def funders_dashboard(request): + """Administration of Funders and Grants.""" funders = Funder.objects.all() form = FunderRegistrySearchForm() grants = Grant.objects.all() grant_form = GrantForm(request=request) context = {'form': form, 'funders': funders, 'grants': grants, 'grant_form': grant_form} - return render(request, 'funders/funders.html', context) + return render(request, 'funders/funders_dashboard.html', context) @permission_required('scipost.can_view_all_funding_info', raise_exception=True) @@ -59,13 +60,20 @@ def add_funder(request): str(funder)) elif form.has_changed(): messages.warning(request, 'The form was invalidly filled.') - return redirect(reverse('funders:funders')) + return redirect(reverse('funders:funders_dashboard')) + + +def funders(request): + """List page of Funders.""" + funders = Funder.objects.has_publications().distinct() + context = { + 'funders': funders + } + return render(request, 'funders/funder_list.html', context) def funder_publications(request, funder_id): - """ - See details of specific Funder (publicly accessible). - """ + """Detail page of a specific Funder (publicly accessible).""" funder = get_object_or_404(Funder, id=funder_id) context = {'funder': funder} return render(request, 'funders/funder_details.html', context) @@ -91,4 +99,4 @@ class CreateGrantView(PermissionsMixin, HttpRefererMixin, CreateView): permission_required = 'scipost.can_create_grants' model = Grant form_class = GrantForm - success_url = reverse_lazy('funders:funders') + success_url = reverse_lazy('funders:funders_dashboard') diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html index bcaa4e0c9..0d240c96c 100644 --- a/journals/templates/journals/manage_metadata.html +++ b/journals/templates/journals/manage_metadata.html @@ -150,7 +150,7 @@ event: "focusin" <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> + <li><a href="{% url 'funders:funders_dashboard' %}" target="_blank">go to the Funders page to add a Funder and/or Grant instance</a></li> </ul> </div> </div> diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html index 67892330e..a96613517 100644 --- a/journals/templates/journals/publication_detail.html +++ b/journals/templates/journals/publication_detail.html @@ -107,24 +107,22 @@ {% endfor %} </ul> - + {% if publication.funders_generic.all %} + <h3>Funder{{ publication.funders_generic.count|pluralize }} for this publication</h3> + <ul> + {% for funder in publication.funders_generic.all %} + <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li> + {% endfor %} + </ul> + {% endif %} {% if is_edcol_admin %} {# This function is not available for public yet! #} <em>The following is not available for the public yet:</em> {% include 'partials/journals/references.html' with publication=publication %} - {% if publication.funders_generic.exists %} - <h3>Funder{{ publication.funders_generic.count|pluralize }} for this publication:</h3> - <ul> - {% for funder in publication.funders_generic.all %} - <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li> - {% endfor %} - </ul> - {% endif %} - {% if publication.institutions.exists %} - <h3>Institution{{ publication.institutions.count|pluralize }} related to this Publication:</h3> + <h3>Institution{{ publication.institutions.count|pluralize }} related to this Publication</h3> <ul> {% for institution in publication.institutions.all %} <li>{{ institution }}</li> diff --git a/notifications/templates/notifications/partials/notification_list_popover.html b/notifications/templates/notifications/partials/notification_list_popover.html index 89f08094f..3f16c4626 100644 --- a/notifications/templates/notifications/partials/notification_list_popover.html +++ b/notifications/templates/notifications/partials/notification_list_popover.html @@ -31,7 +31,7 @@ {% endif %} {% if perms.scipost.can_view_all_funding_info %} - <a class="item {% active 'funders:funders' %}" href="{% url 'funders:funders' %}">Funders</a> + <a class="item {% active 'funders:funders_dashboard' %}" href="{% url 'funders:funders_dashboard' %}">Funders</a> {% endif %} {% if perms.scipost.can_view_production %} -- GitLab