diff --git a/funders/forms.py b/funders/forms.py index ce80aab174168c89c6421f527c6f787f4e4104f9..15af6c74b76c980844435997ffb10c12441d6d7c 100644 --- a/funders/forms.py +++ b/funders/forms.py @@ -6,6 +6,8 @@ from django import forms from .models import Funder, Grant +from ajax_select.fields import AutoCompleteSelectField + from scipost.forms import HttpRefererFormMixin from scipost.models import Contributor @@ -24,6 +26,14 @@ class FunderSelectForm(forms.Form): funder = forms.ModelChoiceField(queryset=Funder.objects.all()) +class FunderOrganizationSelectForm(forms.ModelForm): + organization = AutoCompleteSelectField('organization_lookup') + + class Meta: + model = Funder + fields = [] + + class GrantForm(HttpRefererFormMixin, forms.ModelForm): class Meta: model = Grant diff --git a/funders/migrations/0007_funder_organization.py b/funders/migrations/0007_funder_organization.py new file mode 100644 index 0000000000000000000000000000000000000000..cfc8b121ec6365712a66cbdcb8764c7b8d5316a5 --- /dev/null +++ b/funders/migrations/0007_funder_organization.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-07-12 07:13 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0008_auto_20180711_0623'), + ('funders', '0006_auto_20180425_2212'), + ] + + operations = [ + migrations.AddField( + model_name='funder', + name='organization', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='partners.Organization'), + ), + ] diff --git a/funders/templates/funders/funder_link_organization.html b/funders/templates/funders/funder_link_organization.html new file mode 100644 index 0000000000000000000000000000000000000000..c52c8b7d2f6ebd4f293cee6c180ef9859fc32b7a --- /dev/null +++ b/funders/templates/funders/funder_link_organization.html @@ -0,0 +1,44 @@ +{% extends 'funders/base.html' %} + +{% block pagetitle %}: link Funder to Organization{% endblock pagetitle %} + +{% load bootstrap %} + +{% block breadcrumb_items %} +{{ block.super }} +<span class="breadcrumb-item">{{ funder.name }}</span> +{% endblock %} + +{% block content %} + +<h1>Funder: link to Organization</h1> +<div class="row"> + <div class="col-4"> + <table class="table"> + <tbody> + <tr><td>Name:</td><td>{{ funder.name }}</td></tr> + <tr><td>Acronym:</td><td>{{ funder.acronym }}</td></tr> + <tr><td>Identifier:</td><td>{{ funder.identifier }}</td></tr> + <tr><td>Organization:</td><td>{{ funder.organization }}</td></tr> + </tbody> + </table> + </div> + <div class="col-6"> + <h3>Link to:</h3> + <form action="{% url 'funders:link_to_organization' pk=funder.pk %}" method="post"> + {% csrf_token %} + {{ form|bootstrap }} + <input type="submit" value="Link" class="btn btn-primary"> + </form> + </div> + <div class="col-2"> + <p>Can't find it in the selector? <a href="{% url 'partners:organization_create' %}" target="_blank">Add a new organization to our database</a> (opens in new window)</p> + </div> +</div> + +{% endblock content %} + +{% block footer_script %} +{{ block.super }} +{{ form.media }} +{% endblock footer_script %} diff --git a/funders/templates/funders/funders_dashboard.html b/funders/templates/funders/funders_dashboard.html index 16ea8e04a2b36caa4767ce575c9196d6126a1492..78d6c232199d6722ef80e9cc9e843d61a757198d 100644 --- a/funders/templates/funders/funders_dashboard.html +++ b/funders/templates/funders/funders_dashboard.html @@ -64,7 +64,8 @@ <th>Name</th> <th>Acronym</th> <th>Identifier</th> - <th></th> + <th>Organization</th> + <th>Actions</th> </tr> </thead> <tbody id="accordion" role="tablist" aria-multiselectable="true"> @@ -73,7 +74,12 @@ <td>{{ funder.name }}</td> <td>{{ funder.acronym }}</td> <td>{{ funder.identifier }}</td> - <td><a href="{% url 'funders:funder_publications' funder.id %}">See all Publications for Funder</a></td> + <td>{{ funder.organization }}</td> + <td> + <ul> + <li><a href="{% url 'funders:link_to_organization' pk=funder.id %}">{% if not funder.organization %}Link to an{% else %}Edit the{% endif %} Organization</a></li> + <li><a href="{% url 'funders:funder_publications' funder.id %}">See all Publications for Funder</a></li> + </td> </tr> {% empty %} <tr> diff --git a/funders/urls.py b/funders/urls.py index 48f99d288374cd7faded49940a731a2604568833..df982d8cdb7491bb5c873a2a776525d2252edef0 100644 --- a/funders/urls.py +++ b/funders/urls.py @@ -14,4 +14,7 @@ urlpatterns = [ url(r'^add$', views.add_funder, name='add_funder'), url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications, name='funder_publications'), url(r'^grants/add$', views.CreateGrantView.as_view(), name='add_grant'), + url(r'^(?P<pk>[0-9]+)/link_to_organization/$', + views.LinkFunderToOrganizationView.as_view(), + name='link_to_organization'), ] diff --git a/funders/views.py b/funders/views.py index f6b2d5b56af91fda9bcfe07df1596e76cfc660cb..13de713958a442ff9709e4ef0ecd6dd2dea4f115 100644 --- a/funders/views.py +++ b/funders/views.py @@ -10,11 +10,11 @@ from django.contrib.auth.decorators import permission_required from django.core.urlresolvers import reverse, reverse_lazy from django.db import transaction from django.utils.decorators import method_decorator -from django.views.generic.edit import CreateView +from django.views.generic.edit import CreateView, UpdateView from django.shortcuts import get_object_or_404, render, redirect from .models import Funder, Grant -from .forms import FunderRegistrySearchForm, FunderForm, GrantForm +from .forms import FunderRegistrySearchForm, FunderForm, FunderOrganizationSelectForm, GrantForm from scipost.mixins import PermissionsMixin @@ -91,6 +91,21 @@ class HttpRefererMixin: return super().form_valid(form) +class LinkFunderToOrganizationView(PermissionsMixin, UpdateView): + """ + For an existing Funder instance, specify the link to an Organization. + """ + permission_required = 'scipost.can_create_grants' + model = Funder + form_class = FunderOrganizationSelectForm + template_name = 'funders/funder_link_organization.html' + success_url = reverse_lazy('funders:funders_dashboard') + + def form_valid(self, form): + form.instance.organization = form.cleaned_data['organization'] + return super().form_valid(form) + + @method_decorator(transaction.atomic, name='dispatch') class CreateGrantView(PermissionsMixin, HttpRefererMixin, CreateView): """ diff --git a/journals/views.py b/journals/views.py index f4055c6816c531c2513aaabc3c723da5a8409104..cc7a2a4d3e332c3c901acc5fe367e2f41553508a 100644 --- a/journals/views.py +++ b/journals/views.py @@ -395,14 +395,9 @@ def add_affiliation(request, doi_label, pk): return redirect(reverse('journals:author_affiliations', kwargs={'doi_label': doi_label})) context = {'table': table, 'add_affiliation_form': form} - # if table.contributor: - # context['auth'] = table.contributor - # elif table.unregistered_author: - # context['auth'] = unregistered_author - # else: - # raise return render(request, 'journals/author_affiliation_add.html', context) + @permission_required('scipost.can_draft_publication', return_403=True) @transaction.atomic def remove_affiliation(request, doi_label, pk, organization_id): diff --git a/news/templates/news/newsitem_update.html b/news/templates/news/newsitem_update.html index b9ff3e7aa8dee3025ef19dd065100d358c8a07d3..c4b6415688da9843a1bf619acb3518e8241041cd 100644 --- a/news/templates/news/newsitem_update.html +++ b/news/templates/news/newsitem_update.html @@ -32,6 +32,7 @@ {% csrf_token %} {{ form|bootstrap }} <input type="submit" value="Submit" class="btn btn-primary"> + </form> </div> </div> {% endblock content %} diff --git a/partners/forms.py b/partners/forms.py index 82958e6d33d9012a3b0ccaed96a520d0eaec431f..f4a94bd976839fbdae65a90efbb6f78401c7e3c2 100644 --- a/partners/forms.py +++ b/partners/forms.py @@ -14,8 +14,6 @@ from django_countries import countries from django_countries.widgets import CountrySelectWidget from django_countries.fields import LazyTypedChoiceField -from ajax_select.fields import AutoCompleteSelectField - from .constants import PARTNER_KINDS, PROSPECTIVE_PARTNER_PROCESSED, CONTACT_TYPES,\ PARTNER_STATUS_UPDATE, REQUEST_PROCESSED, REQUEST_DECLINED, CONTACT_GENERAL from .models import Partner, ProspectivePartner, ProspectiveContact, ProspectivePartnerEvent,\ diff --git a/partners/templates/partners/organization_list.html b/partners/templates/partners/organization_list.html index 3685c45fe26dd9b421ec574d14d1c88a6de8274c..b0ca89ff53e912c5f2a28968d119f20ddd837196 100644 --- a/partners/templates/partners/organization_list.html +++ b/partners/templates/partners/organization_list.html @@ -4,7 +4,6 @@ {% load staticfiles %} {% load partners_extras %} -{% load funders_extras %} {% block content %} <div class="row"> @@ -14,7 +13,7 @@ <h3>Management actions:</h3> <ul> <li><a href="{% url 'partners:organization_create' %}">Create a new Organization instance</a></li> - <li><a href="{% url 'funders:funders_dashboard' %}">Link Funders to Organizations</a> (nr with no linked organization (to handle): {% count_funders_wo_organization %})</li> + <li><a href="{% url 'funders:funders_dashboard' %}">Link Funders to Organizations</a> ({{ nr_funders_wo_organization }} found in need of linking)</li> </ul> {% endif %} </div> diff --git a/partners/views.py b/partners/views.py index df9733cd209873e3eeab485f16f52dd15d39ddc0..44b6998690639ad9dee0844cdaf9db20a3305fab 100644 --- a/partners/views.py +++ b/partners/views.py @@ -37,6 +37,8 @@ from .forms import ProspectivePartnerForm, ProspectiveContactForm,\ ProcessRequestContactForm, PartnersAttachmentFormSet, PartnersAttachmentForm +from funders.models import Funder + from journals.models import Publication from scipost.mixins import PermissionsMixin @@ -77,6 +79,12 @@ class OrganizationDeleteView(PermissionsMixin, DeleteView): class OrganizationListView(ListView): model = Organization + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + if self.request.user.has_perm('scipost.can_manage_organizations'): + context['nr_funders_wo_organization'] = Funder.objects.filter(organization=None).count() + return context + class OrganizationDetailView(DetailView): model = Organization