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