SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit b145f9bf authored by Jorran de Wit's avatar Jorran de Wit
Browse files

Merge branch 'development'

parents 920e4a41 a0deb877
No related branches found
No related tags found
No related merge requests found
Showing
with 279 additions and 35 deletions
...@@ -16,3 +16,7 @@ class AffiliationQuerySet(models.QuerySet): ...@@ -16,3 +16,7 @@ class AffiliationQuerySet(models.QuerySet):
Q(begin_date__isnull=True, end_date__gte=today) | Q(begin_date__isnull=True, end_date__gte=today) |
Q(begin_date__lte=today, end_date__gte=today) | Q(begin_date__lte=today, end_date__gte=today) |
Q(begin_date__isnull=True, end_date__isnull=True)) Q(begin_date__isnull=True, end_date__isnull=True))
class InstitutionQuerySet(models.QuerySet):
def has_publications(self):
return self.filter(publications__isnull=False)
...@@ -10,18 +10,19 @@ from django_countries.fields import CountryField ...@@ -10,18 +10,19 @@ from django_countries.fields import CountryField
from scipost.models import Contributor from scipost.models import Contributor
from .constants import INSTITUTION_TYPES, TYPE_UNIVERSITY from .constants import INSTITUTION_TYPES, TYPE_UNIVERSITY
from .managers import AffiliationQuerySet from .managers import AffiliationQuerySet, InstitutionQuerySet
class Institution(models.Model): class Institution(models.Model):
""" """Any (scientific) Institution with a SciPost registration."""
Any (scientific) Institution in the world should ideally have a SciPost registration.
"""
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
acronym = models.CharField(max_length=16, blank=True) acronym = models.CharField(max_length=16, blank=True)
country = CountryField() country = CountryField()
type = models.CharField(max_length=16, choices=INSTITUTION_TYPES, default=TYPE_UNIVERSITY) type = models.CharField(max_length=16, choices=INSTITUTION_TYPES, default=TYPE_UNIVERSITY)
objects = InstitutionQuerySet.as_manager()
class Meta: class Meta:
default_related_name = 'institutions' default_related_name = 'institutions'
ordering = ['country'] ordering = ['country']
...@@ -30,9 +31,11 @@ class Institution(models.Model): ...@@ -30,9 +31,11 @@ class Institution(models.Model):
return '{name} ({country})'.format(name=self.name, country=self.get_country_display()) return '{name} ({country})'.format(name=self.name, country=self.get_country_display())
def get_absolute_url(self): def get_absolute_url(self):
"""Return the Institution detail page."""
return reverse('affiliations:institution_details', args=(self.id,)) return reverse('affiliations:institution_details', args=(self.id,))
def contributors(self): def contributors(self):
"""All Contributor instances related to the Institution."""
return Contributor.objects.filter(affiliations__institution=self) return Contributor.objects.filter(affiliations__institution=self)
......
{% extends 'scipost/base.html' %}
{% block breadcrumb %}
<div class="container-outside header">
<div class="container">
<nav class="breadcrumb hidden-sm-down">
{% block breadcrumb_items %}
<a href="{% url 'affiliations:institutions' %}" class="breadcrumb-item">Institutions</a>
{% endblock %}
</nav>
</div>
</div>
{% endblock %}
{% extends 'affiliations/base.html' %}
{% load bootstrap %}
{% block pagetitle %}: Institution details{% endblock pagetitle %}
{% block breadcrumb_items %}
{{ block.super }}
<span class="breadcrumb-item">{{ institution }}</span>
{% endblock %}
{% block content %}
<h1 class="highlight">Institution {{ institution }}</h1>
<ul>
{% for publication in institution.publications.all %}
<li>
<a href="{{ publication.get_absolute_url }}">{{ publication.title }}</a>
<br>by {{ publication.author_list }},
<br>{{ publication.citation }}
</li>
{% endfor %}
</ul>
{% endblock content %}
{% extends 'scipost/_personal_page_base.html' %} {% extends 'affiliations/base.html' %}
{% load bootstrap %} {% load bootstrap %}
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
{% block breadcrumb_items %} {% block breadcrumb_items %}
{{ block.super }} {{ block.super }}
<a href="{% url 'affiliations:institutions' %}" class="breadcrumb-item">Institutions</a>
<span class="breadcrumb-item">Institution detail</span> <span class="breadcrumb-item">Institution detail</span>
{% endblock %} {% endblock %}
......
{% extends 'scipost/_personal_page_base.html' %} {% extends 'affiliations/base.html' %}
{% block pagetitle %}: Institutions{% endblock pagetitle %} {% block pagetitle %}: Institutions{% endblock pagetitle %}
{% block breadcrumb_items %} {% block breadcrumb_items %}
{{ block.super }}
<span class="breadcrumb-item">Institutions</span> <span class="breadcrumb-item">Institutions</span>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h1>All Institutions in the database</h1> <h1 class="highlight">Institutions</h1>
<h3>All Institutions with a SciPost publication</h3>
{% if is_paginated %} {% if is_paginated %}
{% include 'partials/pagination.html' with page_obj=page_obj %} {% include 'partials/pagination.html' with page_obj=page_obj %}
{% endif %} {% endif %}
<ul> <ul>
{% for institution in object_list %} {% for institution in object_list %}
<li><a href="{% url 'affiliations:institution_details' institution.id %}">{{ institution }}</a></li> <li>
<a href="{{ institution.get_absolute_url }}">{{ institution }}</a>
{% if perms.scipost.can_manage_affiliations %} &middot; <a href="{% url 'affiliations:institution_edit' institution.id %}"><i class="fa fa-pencil"></i></a>{% endif %}
</li>
{% empty %} {% empty %}
<li><em>There are no Institutions known yet.</em><li> <li><em>There are no Institutions known yet.</em><li>
{% endfor %} {% endfor %}
......
...@@ -8,8 +8,10 @@ from . import views ...@@ -8,8 +8,10 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.InstitutionListView.as_view(), name='institutions'), url(r'^$', views.InstitutionListView.as_view(), name='institutions'),
url(r'^(?P<institution_id>[0-9]+)/$', views.InstitutionUpdateView.as_view(), url(r'^(?P<institution_id>[0-9]+)/$', views.InstitutionDetailView.as_view(),
name='institution_details'), name='institution_details'),
url(r'^(?P<institution_id>[0-9]+)/edit', views.InstitutionUpdateView.as_view(),
name='institution_edit'),
url(r'^(?P<institution_id>[0-9]+)/merge$', views.merge_institutions, url(r'^(?P<institution_id>[0-9]+)/merge$', views.merge_institutions,
name='merge_institutions'), name='merge_institutions'),
] ]
...@@ -7,6 +7,7 @@ from django.contrib import messages ...@@ -7,6 +7,7 @@ from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.urls import reverse from django.urls import reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.generic.detail import DetailView
from django.views.generic.edit import UpdateView from django.views.generic.edit import UpdateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
...@@ -15,10 +16,14 @@ from .forms import InstitutionMergeForm ...@@ -15,10 +16,14 @@ from .forms import InstitutionMergeForm
from .models import Institution from .models import Institution
@method_decorator(permission_required('scipost.can_manage_affiliations'), name='dispatch')
class InstitutionListView(ListView): class InstitutionListView(ListView):
queryset = Institution.objects.has_publications()
paginate_by = 20
class InstitutionDetailView(DetailView):
model = Institution model = Institution
paginate_by = 100 pk_url_kwarg = 'institution_id'
@method_decorator(permission_required('scipost.can_manage_affiliations'), name='dispatch') @method_decorator(permission_required('scipost.can_manage_affiliations'), name='dispatch')
...@@ -53,4 +58,4 @@ def merge_institutions(request, institution_id): ...@@ -53,4 +58,4 @@ def merge_institutions(request, institution_id):
messages.success(request, 'Institution {a} merged into {b}'.format( messages.success(request, 'Institution {a} merged into {b}'.format(
a=form.cleaned_data.get('institution', '?'), b=institution)) a=form.cleaned_data.get('institution', '?'), b=institution))
return redirect(reverse('affiliations:institution_details', args=(institution.id,))) return redirect(reverse('affiliations:institution_edit', args=(institution.id,)))
__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))
# -*- 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),
),
]
# -*- 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),
),
]
# -*- 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),
),
]
# -*- 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),
),
]
...@@ -8,16 +8,21 @@ from django.urls import reverse ...@@ -8,16 +8,21 @@ from django.urls import reverse
from journals.models import Publication from journals.models import Publication
from .managers import FunderQuerySet
class Funder(models.Model): class Funder(models.Model):
""" """Funder is a Fundref regsitry.
Funding info metadata is linked to funders from Crossref's Funding info metadata is linked to funders from Crossref's
Fundref registry.
""" """
name = models.CharField(max_length=256) 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) identifier = models.CharField(max_length=200, unique=True)
objects = FunderQuerySet.as_manager()
class Meta: class Meta:
ordering = ['name', 'acronym'] ordering = ['name', 'acronym']
...@@ -28,27 +33,31 @@ class Funder(models.Model): ...@@ -28,27 +33,31 @@ class Funder(models.Model):
return result return result
def get_absolute_url(self): def get_absolute_url(self):
"""Return the Funder detail page."""
return reverse('funders:funder_publications', args=(self.id,)) return reverse('funders:funder_publications', args=(self.id,))
def all_related_publications(self): def all_related_publications(self):
"""Return all Publication objects linked to this Funder."""
return Publication.objects.filter( return Publication.objects.filter(
Q(funders_generic=self) | Q(grants__funder=self)).distinct() Q(funders_generic=self) | Q(grants__funder=self)).distinct()
class Grant(models.Model): 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 a Publication's metadata, all grants are listed
in the Crossmark part of the metadata. in the Crossmark part of the metadata.
""" """
funder = models.ForeignKey('funders.Funder', on_delete=models.CASCADE) funder = models.ForeignKey('funders.Funder', on_delete=models.CASCADE)
number = models.CharField(max_length=64) 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, recipient = models.ForeignKey('scipost.Contributor', blank=True, null=True,
on_delete=models.CASCADE) 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: class Meta:
default_related_name = 'grants'
ordering = ['funder', 'recipient', 'recipient_name', 'number'] ordering = ['funder', 'recipient', 'recipient_name', 'number']
unique_together = ('funder', 'number') unique_together = ('funder', 'number')
......
{% extends 'scipost/base.html' %}
{% block breadcrumb %}
<div class="container-outside header">
<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 %}
{% extends 'scipost/base.html' %} {% extends 'funders/base.html' %}
{% block pagetitle %}: Funder details{% endblock pagetitle %} {% block pagetitle %}: Funder details{% endblock pagetitle %}
{% block breadcrumb_items %}
{{ block.super }}
<span class="breadcrumb-item">{{ funder.name }}</span>
{% endblock %}
{% block content %} {% block content %}
<h1 class="highlight">Funder {{ funder.name }}</h1> <h1 class="highlight">Funder {{ funder.name }}</h1>
<h3>All Publications related to this Funder</h3> <h3>All Publications related to {{ funder.name }}</h3>
<ul> <ul>
{% for publication in funder.all_related_publications %} {% 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 %} {% empty %}
<li>No publications</li> <li>No publications</li>
{% endfor %} {% endfor %}
......
{% 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 %}
{% 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 %} {% load bootstrap %}
......
...@@ -8,10 +8,10 @@ from . import views ...@@ -8,10 +8,10 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.funders, name='funders'), 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, url(r'^query_crossref_for_funder$', views.query_crossref_for_funder,
name='query_crossref_for_funder'), name='query_crossref_for_funder'),
url(r'^add$', views.add_funder, name='add_funder'), url(r'^add$', views.add_funder, name='add_funder'),
url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications, url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications, name='funder_publications'),
name='funder_publications'),
url(r'^grants/add$', views.CreateGrantView.as_view(), name='add_grant'), url(r'^grants/add$', views.CreateGrantView.as_view(), name='add_grant'),
] ]
...@@ -20,14 +20,15 @@ from scipost.mixins import PermissionsMixin ...@@ -20,14 +20,15 @@ from scipost.mixins import PermissionsMixin
@permission_required('scipost.can_view_all_funding_info', raise_exception=True) @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() funders = Funder.objects.all()
form = FunderRegistrySearchForm() form = FunderRegistrySearchForm()
grants = Grant.objects.all() grants = Grant.objects.all()
grant_form = GrantForm(request=request) grant_form = GrantForm(request=request)
context = {'form': form, 'funders': funders, context = {'form': form, 'funders': funders,
'grants': grants, 'grant_form': grant_form} '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) @permission_required('scipost.can_view_all_funding_info', raise_exception=True)
...@@ -59,13 +60,20 @@ def add_funder(request): ...@@ -59,13 +60,20 @@ def add_funder(request):
str(funder)) str(funder))
elif form.has_changed(): elif form.has_changed():
messages.warning(request, 'The form was invalidly filled.') 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): def funder_publications(request, funder_id):
""" """Detail page of a specific Funder (publicly accessible)."""
See details of specific Funder (publicly accessible).
"""
funder = get_object_or_404(Funder, id=funder_id) funder = get_object_or_404(Funder, id=funder_id)
context = {'funder': funder} context = {'funder': funder}
return render(request, 'funders/funder_details.html', context) return render(request, 'funders/funder_details.html', context)
...@@ -91,4 +99,4 @@ class CreateGrantView(PermissionsMixin, HttpRefererMixin, CreateView): ...@@ -91,4 +99,4 @@ class CreateGrantView(PermissionsMixin, HttpRefererMixin, CreateView):
permission_required = 'scipost.can_create_grants' permission_required = 'scipost.can_create_grants'
model = Grant model = Grant
form_class = GrantForm form_class = GrantForm
success_url = reverse_lazy('funders:funders') success_url = reverse_lazy('funders:funders_dashboard')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment