From 381c6de61d8d1795dac22aebf453d3700e8de88a Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Wed, 26 Jul 2017 09:38:47 +0200
Subject: [PATCH] Add funders app, include in Crossmark metadata

---
 SciPost_v1/settings/base.py                   |   1 +
 SciPost_v1/urls.py                            |   1 +
 funders/__init__.py                           |   0
 funders/admin.py                              |   9 ++
 funders/apps.py                               |   5 +
 funders/forms.py                              |  22 +++
 funders/migrations/0001_initial.py            |  36 +++++
 funders/migrations/0002_auto_20170725_2011.py |  23 +++
 funders/migrations/0003_auto_20170726_0606.py |  19 +++
 funders/migrations/__init__.py                |   0
 funders/models.py                             |  41 ++++++
 funders/templates/funders/funders.html        | 133 ++++++++++++++++++
 .../funders/query_crossref_for_funder.html    |  48 +++++++
 funders/tests.py                              |   3 +
 funders/urls.py                               |  18 +++
 funders/views.py                              |  65 +++++++++
 journals/admin.py                             |   1 +
 .../migrations/0036_auto_20170725_1729.py     |  40 ++++++
 .../migrations/0037_auto_20170725_1730.py     |  20 +++
 .../migrations/0038_auto_20170725_1738.py     |  33 +++++
 .../migrations/0039_publication_grants.py     |  21 +++
 journals/models.py                            |   2 +-
 .../templates/journals/manage_metadata.html   |  73 +++++++---
 journals/urls/general.py                      |   3 +
 journals/views.py                             |  49 ++++++-
 25 files changed, 642 insertions(+), 24 deletions(-)
 create mode 100644 funders/__init__.py
 create mode 100644 funders/admin.py
 create mode 100644 funders/apps.py
 create mode 100644 funders/forms.py
 create mode 100644 funders/migrations/0001_initial.py
 create mode 100644 funders/migrations/0002_auto_20170725_2011.py
 create mode 100644 funders/migrations/0003_auto_20170726_0606.py
 create mode 100644 funders/migrations/__init__.py
 create mode 100644 funders/models.py
 create mode 100644 funders/templates/funders/funders.html
 create mode 100644 funders/templates/funders/query_crossref_for_funder.html
 create mode 100644 funders/tests.py
 create mode 100644 funders/urls.py
 create mode 100644 funders/views.py
 create mode 100644 journals/migrations/0036_auto_20170725_1729.py
 create mode 100644 journals/migrations/0037_auto_20170725_1730.py
 create mode 100644 journals/migrations/0038_auto_20170725_1738.py
 create mode 100644 journals/migrations/0039_publication_grants.py

diff --git a/SciPost_v1/settings/base.py b/SciPost_v1/settings/base.py
index 861544adb..28b54d4d4 100644
--- a/SciPost_v1/settings/base.py
+++ b/SciPost_v1/settings/base.py
@@ -95,6 +95,7 @@ INSTALLED_APPS = (
     'virtualmeetings',
     'production',
     'partners',
+    'funders',
     'webpack_loader',
 )
 
diff --git a/SciPost_v1/urls.py b/SciPost_v1/urls.py
index adf26e3aa..cb5b11d4b 100644
--- a/SciPost_v1/urls.py
+++ b/SciPost_v1/urls.py
@@ -20,6 +20,7 @@ urlpatterns = [
     url(r'^commentaries/', include('commentaries.urls', namespace="commentaries")),
     url(r'^commentary/', include('commentaries.urls', namespace="commentaries")),
     url(r'^comments/', include('comments.urls', namespace="comments")),
+    url(r'^funders/', include('funders.urls', namespace="funders")),
     url(r'^journals/', include('journals.urls.general', namespace="journals")),
     url(r'^mailing_list/', include('mailing_lists.urls', namespace="mailing_lists")),
     url(r'^submissions/', include('submissions.urls', namespace="submissions")),
diff --git a/funders/__init__.py b/funders/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/funders/admin.py b/funders/admin.py
new file mode 100644
index 000000000..d049c6c0f
--- /dev/null
+++ b/funders/admin.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+
+from .models import Funder, Grant
+
+
+admin.site.register(Funder)
+
+
+admin.site.register(Grant)
diff --git a/funders/apps.py b/funders/apps.py
new file mode 100644
index 000000000..413a2e31c
--- /dev/null
+++ b/funders/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class FundersConfig(AppConfig):
+    name = 'funders'
diff --git a/funders/forms.py b/funders/forms.py
new file mode 100644
index 000000000..64676af44
--- /dev/null
+++ b/funders/forms.py
@@ -0,0 +1,22 @@
+from django import forms
+
+from .models import Funder, Grant
+
+class FunderRegistrySearchForm(forms.Form):
+    name = forms.CharField(max_length=128)
+
+
+class FunderForm(forms.ModelForm):
+    class Meta:
+        model = Funder
+        fields = ['name', 'identifier',]
+
+
+class GrantForm(forms.ModelForm):
+    class Meta:
+        model = Grant
+        fields = ['funder', 'number', 'recipient_name', 'recipient',]
+
+
+class GrantSelectForm(forms.Form):
+    grant = forms.ModelChoiceField(queryset=Grant.objects.all())
diff --git a/funders/migrations/0001_initial.py b/funders/migrations/0001_initial.py
new file mode 100644
index 000000000..bf7e7e4fb
--- /dev/null
+++ b/funders/migrations/0001_initial.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:40
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('scipost', '0059_auto_20170701_1356'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Funder',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=256)),
+                ('identifier', models.CharField(max_length=200, unique=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Grant',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('number', models.CharField(max_length=64)),
+                ('recipient_name', models.CharField(blank=True, max_length=64, null=True)),
+                ('funder', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='funders.Funder')),
+                ('recipient', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+            ],
+        ),
+    ]
diff --git a/funders/migrations/0002_auto_20170725_2011.py b/funders/migrations/0002_auto_20170725_2011.py
new file mode 100644
index 000000000..c689cf120
--- /dev/null
+++ b/funders/migrations/0002_auto_20170725_2011.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 18:11
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='funder',
+            options={'ordering': ['name']},
+        ),
+        migrations.AlterModelOptions(
+            name='grant',
+            options={'ordering': ['funder', 'recipient', 'recipient_name', 'number']},
+        ),
+    ]
diff --git a/funders/migrations/0003_auto_20170726_0606.py b/funders/migrations/0003_auto_20170726_0606.py
new file mode 100644
index 000000000..d7c8df068
--- /dev/null
+++ b/funders/migrations/0003_auto_20170726_0606.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 04:06
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0002_auto_20170725_2011'),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name='grant',
+            unique_together=set([('funder', 'number')]),
+        ),
+    ]
diff --git a/funders/migrations/__init__.py b/funders/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/funders/models.py b/funders/models.py
new file mode 100644
index 000000000..3957bf92f
--- /dev/null
+++ b/funders/models.py
@@ -0,0 +1,41 @@
+from django.db import models
+
+
+class Funder(models.Model):
+    """
+    Funding info metadata is linked to funders from Crossref's
+    Fundref registry.
+    """
+    name = models.CharField(max_length=256)
+    identifier = models.CharField(max_length=200, unique=True)
+
+    class Meta:
+        ordering = ['name']
+
+    def __str__(self):
+        return self.name
+
+
+class Grant(models.Model):
+    """
+    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(Funder, on_delete=models.CASCADE)
+    number = models.CharField(max_length=64)
+    recipient_name = models.CharField(max_length=64, blank=True, null=True)
+    recipient = models.ForeignKey('scipost.Contributor', blank=True, null=True,
+                                  on_delete=models.CASCADE)
+
+    class Meta:
+        ordering = ['funder', 'recipient', 'recipient_name', 'number']
+        unique_together = ('funder', 'number')
+
+    def __str__(self):
+        grantstring = '%s, grant number %s' % (str(self.funder), self.number)
+        if self.recipient:
+            grantstring += ' (%s)' % str(self.recipient)
+        elif self.recipient_name:
+            grantstring += ' (%s)' % self.recipient_name
+        return grantstring
diff --git a/funders/templates/funders/funders.html b/funders/templates/funders/funders.html
new file mode 100644
index 000000000..7ae67d06b
--- /dev/null
+++ b/funders/templates/funders/funders.html
@@ -0,0 +1,133 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: Funders{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+        <h1 class="highlight">Funders (and associated grants)</h1>
+  </div>
+</div>
+
+
+<div class="row">
+    <div class="col-12">
+        <div class="tab-nav-container">
+            <div class="tab-nav-inner">
+                <!-- Nav tabs -->
+                <ul class="nav btn-group personal-page-nav" role="tablist">
+                  <li class="nav-item btn btn-secondary">
+                    <a href="#funders" class="nav-link active" data-toggle="tab">Funders</a>
+                  </li>
+                  <li class="nav-item btn btn-secondary">
+                    <a href="#grants" class="nav-link" data-toggle="tab">Grants</a>
+                  </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+</div>
+
+
+
+<div class="tab-content">
+
+  <!-- Tab: Funders -->
+  <div class="tab-pane active" id="funders" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+        <h2 class="highlight">Funders</h2>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-12">
+	<h2>Find a new funder in the Fundref registry</h2>
+        <form action="{% url 'funders:query_crossref_for_funder' %}" method="post">
+          {% csrf_token %}
+          {{form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Search">
+        </form>
+	<br/>
+	<h2>Funders in the SciPost database</h2>
+	<table class="table table-hover mb-5">
+	  <thead class="thead-default">
+	    <tr>
+	      <th>Name</th>
+	      <th>Identifier</th>
+	    </tr>
+	  </thead>
+	  <tbody id="accordion" role="tablist" aria-multiselectable="true">
+	    {% 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.identifier }}</td>
+	    </tr>
+            {% empty %}
+            <tr>
+              <td colspan="3">No funders found</td>
+            </tr>
+	    {% endfor %}
+	  </tbody>
+	</table>
+      </div>
+    </div>
+  </div>
+
+
+  <!-- Tab: Grants -->
+  <div class="tab-pane" id="grants" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+        <h2 class="highlight">Grants</h2>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-12">
+	<h2>Add a grant</h2>
+        <form action="{% url 'funders:add_grant' %}" method="post">
+          {% csrf_token %}
+          {{grant_form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Add">
+        </form>
+	<br/>
+	<h2>Grants in the SciPost database</h2>
+	<table class="table table-hover mb-5">
+	  <thead class="thead-default">
+	    <tr>
+	      <th>Funder Name</th>
+	      <th>Recipient</th>
+	      <th>Number</th>
+	    </tr>
+	  </thead>
+	  <tbody id="accordion" role="tablist" aria-multiselectable="true">
+	    {% for grant in grants %}
+	    <tr data-toggle="collapse" data-parent="#accordion" href="#collapse{{ grant.id }}" aria-expanded="true" aria-controls="collapse{{ grant.id }}" style="cursor: pointer;">
+	      <td>{{ grant.funder.name }}</td>
+	      {% if grant.recipient %}
+	      <td>{{ grant.recipient }}</td>
+	      {% elif grant.recipient_name %}
+	      <td>{{ grant.recipient_name }}</td>
+	      {% else %}
+	      <td></td>
+	      {% endif %}
+	      <td>{{ grant.number }}</td>
+	    </tr>
+            {% empty %}
+            <tr>
+              <td colspan="3">No grants found</td>
+            </tr>
+	    {% endfor %}
+	  </tbody>
+	</table>
+      </div>
+    </div>
+  </div>
+</div>
+
+
+{% endblock content %}
diff --git a/funders/templates/funders/query_crossref_for_funder.html b/funders/templates/funders/query_crossref_for_funder.html
new file mode 100644
index 000000000..b8459c8a2
--- /dev/null
+++ b/funders/templates/funders/query_crossref_for_funder.html
@@ -0,0 +1,48 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block pagetitle %}: Query Crossref for funder{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+        <h1 class="highlight">Query Crossref Fundref Registry for Funders</h1>
+        <form action="{% url 'funders:query_crossref_for_funder' %}" method="post">
+          {% csrf_token %}
+          {{form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Search">
+        </form>
+	{% if response_headers %}
+	<p>{{ response_headers }}</p>
+	{% endif %}
+	{% if response_text %}
+	<p>{{ response_text }}</p>
+	{% endif %}
+	{% if response %}
+	<p>{{ response }}</p>
+	<ul>
+	  {% for item in response.message.items %}
+	  <li>
+	    {{ item.name }}, {{ item.id }}, {{ item.uri }}
+	    <form action="{% url 'funders:add_funder' %}" method="post">
+              {% csrf_token %}
+	      <input name='name' style="width: 64%" value='{{ item.name }}'>
+	      <input name='identifier' style="width: 64%" value='{{ item.uri }}'>
+              <input class="btn btn-secondary" type="submit" value="Add this funder">
+	    </form>
+	  </li>
+	  {% endfor %}
+	</ul>
+	<form action="{% url 'funders:add_funder' %}" method="post">
+          {% csrf_token %}
+          {{funder_form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Submit">
+        </form>
+	{% endif %}
+  </div>
+</div>
+
+
+{% endblock content %}
diff --git a/funders/tests.py b/funders/tests.py
new file mode 100644
index 000000000..7ce503c2d
--- /dev/null
+++ b/funders/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/funders/urls.py b/funders/urls.py
new file mode 100644
index 000000000..ec3521ede
--- /dev/null
+++ b/funders/urls.py
@@ -0,0 +1,18 @@
+from django.conf.urls import url
+from django.views.generic import TemplateView
+
+from . import views
+
+urlpatterns = [
+    url(r'^$', views.funders,
+        name='funders'),
+    url(r'^query_crossref_for_funder$',
+        views.query_crossref_for_funder,
+        name='query_crossref_for_funder'),
+    url(r'^add_funder$',
+        views.add_funder,
+        name='add_funder'),
+    url(r'^add_grant$',
+        views.add_grant,
+        name='add_grant'),
+]
diff --git a/funders/views.py b/funders/views.py
new file mode 100644
index 000000000..50f46f967
--- /dev/null
+++ b/funders/views.py
@@ -0,0 +1,65 @@
+import requests
+import json
+
+from django.contrib import messages
+from django.contrib.auth.decorators import permission_required
+from django.core.urlresolvers import reverse
+from django.shortcuts import render, redirect
+
+from .models import Funder, Grant
+from .forms import FunderRegistrySearchForm, FunderForm, GrantForm
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def funders(request):
+    funders = Funder.objects.all()
+    form = FunderRegistrySearchForm()
+    grants = Grant.objects.all()
+    grant_form = GrantForm()
+    context = {'form': form, 'funders': funders,
+               'grants': grants, 'grant_form': grant_form}
+    return render(request, 'funders/funders.html', context)
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def query_crossref_for_funder(request):
+    """
+    Checks Crossref's Fundref Registry for an entry
+    corresponding to the funder name being looked for.
+    If found, creates a funders.Funder instance.
+    """
+    form = FunderRegistrySearchForm(request.POST or None)
+    context = {'form': form}
+    if form.is_valid():
+        queryurl = 'http://api.crossref.org/funders?query=%s' % form.cleaned_data['name']
+        query = requests.get(queryurl)
+        response = json.loads(query.text)
+        context['response_headers'] = query.headers
+        context['response_text'] = query.text
+        context['response'] = response
+        context['funder_form'] = FunderForm()
+    return render(request, 'funders/query_crossref_for_funder.html', context)
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def add_funder(request):
+    form = FunderForm(request.POST or None)
+    if form.is_valid():
+        funder = form.save()
+        messages.success(request, ('<h3>Funder %s successfully created</h3>') %
+                         str(funder))
+    elif form.has_changed():
+        messages.warning(request, 'The form was invalidly filled.')
+    return redirect(reverse('funders:funders'))
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def add_grant(request):
+    grant_form = GrantForm(request.POST or None)
+    if grant_form.is_valid():
+        grant = grant_form.save()
+        messages.success(request, ('<h3>Grant %s successfully added</h3>') %
+                         str(grant))
+    elif grant_form.has_changed():
+        messages.warning(request, 'The form was invalidly filled (grant already exists?).')
+    return redirect(reverse('funders:funders'))
diff --git a/journals/admin.py b/journals/admin.py
index 6b5f4cecd..0ed07f17e 100644
--- a/journals/admin.py
+++ b/journals/admin.py
@@ -64,6 +64,7 @@ class PublicationAdmin(admin.ModelAdmin):
 admin.site.register(Publication, PublicationAdmin)
 
 
+
 class DepositAdmin(admin.ModelAdmin):
     list_display = ('publication', 'timestamp', 'doi_batch_id', 'deposition_date',)
     readonly_fields = ('publication', 'doi_batch_id', 'metadata_xml', 'deposition_date',)
diff --git a/journals/migrations/0036_auto_20170725_1729.py b/journals/migrations/0036_auto_20170725_1729.py
new file mode 100644
index 000000000..65ec9846b
--- /dev/null
+++ b/journals/migrations/0036_auto_20170725_1729.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:29
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0059_auto_20170701_1356'),
+        ('journals', '0035_auto_20170714_0609'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Funder',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=256)),
+                ('identifier', models.CharField(max_length=200, unique=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Grant',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('number', models.CharField(max_length=64)),
+                ('recipient_name', models.CharField(blank=True, max_length=64, null=True)),
+                ('funder', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='journals.Funder')),
+                ('recipient', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='publication',
+            name='grants',
+            field=models.ManyToManyField(blank=True, null=True, to='journals.Grant'),
+        ),
+    ]
diff --git a/journals/migrations/0037_auto_20170725_1730.py b/journals/migrations/0037_auto_20170725_1730.py
new file mode 100644
index 000000000..db456745e
--- /dev/null
+++ b/journals/migrations/0037_auto_20170725_1730.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:30
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0036_auto_20170725_1729'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='publication',
+            name='grants',
+            field=models.ManyToManyField(blank=True, to='journals.Grant'),
+        ),
+    ]
diff --git a/journals/migrations/0038_auto_20170725_1738.py b/journals/migrations/0038_auto_20170725_1738.py
new file mode 100644
index 000000000..0d32403d1
--- /dev/null
+++ b/journals/migrations/0038_auto_20170725_1738.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:38
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0037_auto_20170725_1730'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='grant',
+            name='funder',
+        ),
+        migrations.RemoveField(
+            model_name='grant',
+            name='recipient',
+        ),
+        migrations.RemoveField(
+            model_name='publication',
+            name='grants',
+        ),
+        migrations.DeleteModel(
+            name='Funder',
+        ),
+        migrations.DeleteModel(
+            name='Grant',
+        ),
+    ]
diff --git a/journals/migrations/0039_publication_grants.py b/journals/migrations/0039_publication_grants.py
new file mode 100644
index 000000000..8b2f9b1c3
--- /dev/null
+++ b/journals/migrations/0039_publication_grants.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:40
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0001_initial'),
+        ('journals', '0038_auto_20170725_1738'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='publication',
+            name='grants',
+            field=models.ManyToManyField(blank=True, to='funders.Grant'),
+        ),
+    ]
diff --git a/journals/models.py b/journals/models.py
index 722fdccdf..fb741cbbc 100644
--- a/journals/models.py
+++ b/journals/models.py
@@ -142,6 +142,7 @@ class Publication(models.Model):
     abstract = models.TextField()
     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)
     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)
@@ -216,7 +217,6 @@ class Publication(models.Model):
         return template.render(context)
 
 
-
 class Deposit(models.Model):
     """
     Each time a Crossref deposit is made for a Publication,
diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html
index b9ca627d8..89f1796af 100644
--- a/journals/templates/journals/manage_metadata.html
+++ b/journals/templates/journals/manage_metadata.html
@@ -56,11 +56,12 @@ event: "focusin"
     </tr>
     <tr id="collapse{{ publication.id }}" class="collapse" role="tabpanel" aria-labelledby="heading{{ publication.id }}" style="background-color: #fff;">
       <td colspan="5">
-	<h3 class="ml-3">Actions</h3>
-        <ul>
-          <li>Mark the first author (currently: {% if publication.first_author %}{{ publication.first_author }} {% elif publication.first_author_unregistered %}{{ publication.first_author_unregistered }} (unregistered){% endif %})
-	    <div class="row">
-              <div class="col-md-5">
+
+	<h2 class="ml-3">Actions</h2>
+	<div class="row">
+          <div class="col-md-5">
+            <ul>
+              <li>Mark the first author (currently: {% if publication.first_author %}{{ publication.first_author }} {% elif publication.first_author_unregistered %}{{ publication.first_author_unregistered }} (unregistered){% endif %})
                 <p>registered authors:</p>
                 <ul>
                   {% for author in publication.authors.all %}
@@ -69,8 +70,6 @@ event: "focusin"
                   </li>
                   {% endfor %}
                 </ul>
-              </div>
-              <div class="col-md-5">
                 <p>unregistered authors:</p>
                 <ul>
                   {% for author_unreg in publication.authors_unregistered.all %}
@@ -79,20 +78,50 @@ event: "focusin"
                   </li>
                   {% endfor %}
                 </ul>
-              </div>
-	    </div>
-          </li>
-          <li><a href="{% url 'journals:add_author' publication.id %}">Add a missing author</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 %}">(re)create metadata</a></li>
-          <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: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>
-        </ul>
-	<h3 class="ml-3">Crossref Deposits</h3>
+	      </li>
+              <li><a href="{% url 'journals:add_author' publication.id %}">Add a missing author</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 %}">(re)create metadata</a></li>
+              <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: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>
+            </ul>
+          </div>
+
+          <div class="col-md-5">
+	    <h2>Funding info for this publication:</h2>
+	    {% if publication.funding_info %}
+	    <p>{{ publication.funding_info }}</p>
+	    {% else %}
+	    <p>No funding info was found</p>
+	    {% endif %}
+	    <h2>Grants associated to this publication:</h2>
+	    <ul>
+	      {% for grant in publication.grants.all %}
+	      <li> {{ grant }}</li>
+	      {% empty %}
+	      <li>no associated grants found</li>
+	      {% endfor %}
+	    </ul>
+	    <br/>
+	    <h3>Associate a grant to this publication:</h3>
+	    <form action="{% url 'journals:add_associated_grant' publication.doi_label %}" method="post">
+	      {% csrf_token %}
+	      {{associate_grant_form|bootstrap}}
+	      <input class="btn btn-secondary" type="submit" value="Add">
+	    </form>
+	    <h3>Other grant-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>
+	  </div>
+	</div>
+
+
+	<h2 class="ml-3">Crossref Deposits</h2>
 	<table class="ml-5">
 	  <thead class="thead-default">
 	    <th>Timestamp</th>
@@ -123,7 +152,7 @@ event: "focusin"
 	  </tbody>
 	</table>
 
-	<h3 class="ml-3">DOAJ Deposits</h3>
+	<h2 class="ml-3">DOAJ Deposits</h2>
 	<table class="ml-5">
 	  <thead class="thead-default">
 	    <th>Timestamp</th>
diff --git a/journals/urls/general.py b/journals/urls/general.py
index c785ce47b..b1ba8d539 100644
--- a/journals/urls/general.py
+++ b/journals/urls/general.py
@@ -50,6 +50,9 @@ urlpatterns = [
     url(r'^create_funding_info_metadata/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$',
         journals_views.create_funding_info_metadata,
         name='create_funding_info_metadata'),
+    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'^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 bcfa7155d..f6c21da83 100644
--- a/journals/views.py
+++ b/journals/views.py
@@ -23,9 +23,12 @@ from .forms import FundingInfoForm, InitiatePublicationForm, ValidatePublication
                    UnregisteredAuthorForm, CreateMetadataXMLForm, CitationListBibitemsForm
 from .utils import JournalUtils
 
+from funders.models import Funder
 from submissions.models import Submission
 from scipost.models import Contributor
 
+from funders.forms import GrantSelectForm
+
 from guardian.decorators import permission_required
 
 
@@ -274,8 +277,10 @@ 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')
+    associate_grant_form = GrantSelectForm()
     context = {
-        'publications': publications
+        'publications': publications,
+        'associate_grant_form': associate_grant_form,
     }
     return render(request, 'journals/manage_metadata.html', context)
 
@@ -425,6 +430,22 @@ def create_funding_info_metadata(request, doi_label):
     return render(request, 'journals/create_funding_info_metadata.html', context)
 
 
+@permission_required('scipost.can_publish_accepted_submission', return_403=True)
+@transaction.atomic
+def add_associated_grant(request, doi_label):
+    """
+    Called by an Editorial Administrator.
+    This associates a grant from the database to this publication.
+    """
+    publication = get_object_or_404(Publication, doi_label=doi_label)
+    grant_select_form = GrantSelectForm(request.POST or None)
+    if grant_select_form.is_valid():
+        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'))
+
+
 @permission_required('scipost.can_publish_accepted_submission', return_403=True)
 @transaction.atomic
 def create_metadata_xml(request, doi_label):
@@ -457,6 +478,7 @@ def create_metadata_xml(request, doi_label):
         '<?xml version="1.0" encoding="UTF-8"?>\n'
         '<doi_batch version="4.4.0" xmlns="http://www.crossref.org/schema/4.4.0" '
         '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'
         '<head>\n'
@@ -547,6 +569,31 @@ 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()
+    nr_funders = funders.count()
+    if nr_funders > 0:
+        initial['metadata_xml'] += '<fr:program name="fundref">\n'
+        for funder in funders:
+            if nr_funders > 1:
+                initial['metadata_xml'] += '<fr:assertion name="fundgroup">\n'
+            initial['metadata_xml'] += (
+                '<fr:assertion name="funder_name">' + funder.name + '\n'
+                '<fr:assertion name="funder_identifier">'
+                + funder.identifier + '</fr:assertion>\n'
+                '</fr:assertion>\n')
+            for grant in publication.grants.all():
+                if grant.funder == funder:
+                    initial['metadata_xml'] += (
+                        '<fr:assertion name="award_number">'
+                        + grant.number + '</fr:assertion>\n')
+            if nr_funders > 1:
+                initial['metadata_xml'] += '</fr:assertion>\n'
+        initial['metadata_xml'] += '</fr:program>\n'
+
+    initial['metadata_xml'] += (
+        '</custom_metadata>\n'
         '</crossmark>\n'
         '<archive_locations><archive name="CLOCKSS"></archive></archive_locations>\n'
         '<doi_data>\n'
-- 
GitLab