diff --git a/finances/admin.py b/finances/admin.py index effd61f1080b9a1c58cf789ad3aa77ad9c07f87a..c887dee025b18e2249c89740f90d08ad10be7f57 100644 --- a/finances/admin.py +++ b/finances/admin.py @@ -4,7 +4,9 @@ __license__ = "AGPL v3" from django.contrib import admin -from .models import WorkLog +from .models import Subsidy, WorkLog +admin.site.register(Subsidy) + admin.site.register(WorkLog) diff --git a/finances/constants.py b/finances/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..e5f21aad2669aa93f5614a6a97cd2d04fab2ddb9 --- /dev/null +++ b/finances/constants.py @@ -0,0 +1,38 @@ +__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +import datetime + + +SUBSIDY_TYPE_GRANT = 'grant' +SUBSIDY_TYPE_PARTNERAGREEMENT = 'partneragreement' +SUBSIDY_TYPE_COLLABORATION = 'collaborationagreement' + +SUBSIDY_TYPES = ( + (SUBSIDY_TYPE_GRANT, 'Grant'), + (SUBSIDY_TYPE_PARTNERAGREEMENT, 'Partner Agreement'), + (SUBSIDY_TYPE_COLLABORATION, 'Collaboration Agreement'), +) + + +SUBSIDY_PROMISED = 'promised' +SUBSIDY_INVOICED = 'invoiced' +SUBSIDY_RECEIVED = 'received' + +SUBSIDY_STATUS = ( + (SUBSIDY_PROMISED, 'promised'), + (SUBSIDY_INVOICED, 'invoiced'), + (SUBSIDY_RECEIVED, 'received'), +) + + +SUBSIDY_DURATION = ( + (datetime.timedelta(days=365), '1 year'), + (datetime.timedelta(days=730), '2 years'), + (datetime.timedelta(days=1095), '3 years'), + (datetime.timedelta(days=1460), '4 years'), + (datetime.timedelta(days=1825), '5 years'), + (datetime.timedelta(days=3650), '10 years'), + (datetime.timedelta(days=36500), 'Indefinite (100 years)'), +) diff --git a/finances/migrations/0002_subsidy.py b/finances/migrations/0002_subsidy.py new file mode 100644 index 0000000000000000000000000000000000000000..a66d36940496ab56e3d7efdb796394c9bda3afae --- /dev/null +++ b/finances/migrations/0002_subsidy.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-06 21:41 +from __future__ import unicode_literals + +import datetime +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('organizations', '0002_populate_from_partners_org'), + ('finances', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Subsidy', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('subsidy_type', models.CharField(choices=[('grant', 'Grant'), ('partneragreement', 'Partner Agreement'), ('collaborationagreement', 'Collaboration Agreement')], max_length=256)), + ('description', models.CharField(max_length=256)), + ('amount', models.PositiveSmallIntegerField()), + ('status', models.CharField(choices=[('promised', 'promised'), ('invoiced', 'invoiced'), ('received', 'received')], max_length=32)), + ('date', models.DateField()), + ('duration', models.DurationField(blank=True, choices=[(datetime.timedelta(365), '1 year'), (datetime.timedelta(730), '2 years'), (datetime.timedelta(1095), '3 years'), (datetime.timedelta(1460), '4 years'), (datetime.timedelta(1825), '5 years'), (datetime.timedelta(3650), '10 years'), (datetime.timedelta(36500), 'Indefinite (100 years)')], null=True)), + ('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='organizations.Organization')), + ], + options={ + 'verbose_name_plural': 'subsidies', + }, + ), + ] diff --git a/finances/migrations/0003_auto_20181007_1647.py b/finances/migrations/0003_auto_20181007_1647.py new file mode 100644 index 0000000000000000000000000000000000000000..6c5ec4f487af2022bef217d35bd022e415414ef2 --- /dev/null +++ b/finances/migrations/0003_auto_20181007_1647.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-07 14:47 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finances', '0002_subsidy'), + ] + + operations = [ + migrations.AlterField( + model_name='subsidy', + name='amount', + field=models.PositiveSmallIntegerField(help_text='in € (rounded)'), + ), + ] diff --git a/finances/migrations/0004_auto_20181007_2016.py b/finances/migrations/0004_auto_20181007_2016.py new file mode 100644 index 0000000000000000000000000000000000000000..625230696b9b6fabc07a4efce06b2ff769c0ed23 --- /dev/null +++ b/finances/migrations/0004_auto_20181007_2016.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-07 18:16 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finances', '0003_auto_20181007_1647'), + ] + + operations = [ + migrations.AlterField( + model_name='subsidy', + name='description', + field=models.TextField(), + ), + ] diff --git a/finances/models.py b/finances/models.py index 1343616c535be0cc03bd555f255164864a72a15b..53cf87379e6e99537d256a600f16ec4adeefe99a 100644 --- a/finances/models.py +++ b/finances/models.py @@ -6,11 +6,46 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey from django.db import models +from django.urls import reverse from django.utils import timezone +from django.utils.html import format_html +from .constants import SUBSIDY_TYPES, SUBSIDY_STATUS, SUBSIDY_DURATION from .utils import id_to_slug +class Subsidy(models.Model): + """ + A subsidy given to SciPost by an Organization. + Any fund given to SciPost, in any form, must be associated + to a corresponding Subsidy instance. + + This can for example be: + - a Partners agreement + - an incidental grant + - a development grant for a specific purpose + - a Collaboration Agreement + - a donation + """ + organization = models.ForeignKey('organizations.Organization', on_delete=models.CASCADE) + subsidy_type = models.CharField(max_length=256, choices=SUBSIDY_TYPES) + description = models.TextField() + amount = models.PositiveSmallIntegerField(help_text="in € (rounded)") + status = models.CharField(max_length=32, choices=SUBSIDY_STATUS) + date = models.DateField() + duration = models.DurationField(choices=SUBSIDY_DURATION, blank=True, null=True) + + class Meta: + verbose_name_plural = 'subsidies' + + def __str__(self): + return format_html('{}: €{} from {}, for {}', + self.date, self.amount, self.organization, self.description) + + def get_absolute_url(self): + return reverse('finances:subsidy_details', args=(self.id,)) + + class WorkLog(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL) comments = models.TextField(blank=True) diff --git a/finances/templates/finances/_subsidy_card.html b/finances/templates/finances/_subsidy_card.html new file mode 100644 index 0000000000000000000000000000000000000000..3d1ffc36a2ababf94c41a1d874c9e38c6693c6e0 --- /dev/null +++ b/finances/templates/finances/_subsidy_card.html @@ -0,0 +1,42 @@ +{% load bootstrap %} + +{% load user_groups %} + +<div class="card-body"> + <div class="row"> + <div class="col-12"> + + <h3 class="highlight">Subsidy details</h3> + {% if perms.scipost.can_manage_subsidies %} + <ul class="list-inline"><li class="list-inline-item"><strong>Admin actions:</strong></li> + <li class="list-inline-item"><a href="{% url 'finances:subsidy_update' pk=subsidy.id %}"><span class="text-warning">Update</span></a></li> + <li class="list-inline-item"><a href="{% url 'finances:subsidy_delete' pk=subsidy.id %}"><span class="text-danger">Delete</span></a></li> + </ul> + {% endif %} + + <table class="table"> + <tr> + <td>From:</td><td><a href="{{ subsidy.organization.get_absolute_url }}">{{ subsidy.organization }}</a></td> + </tr> + <tr> + <td>Type:</td><td>{{ subsidy.get_subsidy_type_display }}</td> + </tr> + <tr> + <td>Description:</td><td>{{ subsidy.description }}</td> + </tr> + <tr> + <td>Amount:</td><td>€{{ subsidy.amount }}</td> + </tr> + <tr> + <td>Date:</td><td>{{ subsidy.date }}</td> + </tr> + {% if subsidy.duration %} + <tr> + <td>Duration:</td><td>{{ subsidy.get_duration_display }}</td> + </tr> + {% endif %} + </table> + </div> + </div> + +</div> diff --git a/finances/templates/finances/base.html b/finances/templates/finances/base.html new file mode 100644 index 0000000000000000000000000000000000000000..f906eaeba8f731537620149d6f341da3a17c11ee --- /dev/null +++ b/finances/templates/finances/base.html @@ -0,0 +1,15 @@ +{% extends 'scipost/base.html' %} + +{% block body_class %}{{ block.super }} finances{% endblock %} + +{% block breadcrumb %} + <div class="container-outside header"> + <div class="container"> + <nav class="breadcrumb hidden-sm-down"> + {% block breadcrumb_items %} + <a href="{% url 'finances:finances' %}" class="breadcrumb-item">Finances</a> + {% endblock %} + </nav> + </div> + </div> +{% endblock %} diff --git a/finances/templates/finances/finances.html b/finances/templates/finances/finances.html new file mode 100644 index 0000000000000000000000000000000000000000..1a6698429d4c84ffe5c018ce71810009b4b510fb --- /dev/null +++ b/finances/templates/finances/finances.html @@ -0,0 +1,24 @@ +{% extends 'finances/base.html' %} + +{% load bootstrap %} + +{% block breadcrumb_items %} + {{ block.super }} + <span class="breadcrumb-item">Finances</span> +{% endblock %} + +{% block pagetitle %}: Finances{% endblock pagetitle %} + +{% block content %} +<div class="row"> + <div class="col-12"> + <h3 class="highlight">Finances</h3> + <ul> + <li><a href="{% url 'finances:subsidies' %}">View {% if perms.scipost.can_manage_subsidies %}(and manage) {% endif %}info on Subsidies obtained by SciPost</a></li> + {% if perms.scipost.can_view_timesheets %} + <li><a href="{% url 'finances:timesheets' %}">Manage Timesheets</a></li> + {% endif %} + </ul> + </div> +</div> +{% endblock content %} diff --git a/finances/templates/finances/subsidy_confirm_delete.html b/finances/templates/finances/subsidy_confirm_delete.html new file mode 100644 index 0000000000000000000000000000000000000000..9b7ed50ef7c2fa82de9df646b60ef386b7914bf5 --- /dev/null +++ b/finances/templates/finances/subsidy_confirm_delete.html @@ -0,0 +1,30 @@ +{% extends 'finances/base.html' %} + +{% load bootstrap %} + +{% block breadcrumb_items %} +{{ block.super }} +<span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span> +<span class="breadcrumb-item">Confirm deletetion</span> +{% endblock %} + +{% block pagetitle %}: Delete Subsidy{% endblock pagetitle %} + +{% block content %} +<div class="row"> + <div class="col-12"> + <h1 class="highlight">Delete Subsidy</h1> + {{ object }} + </div> +</div> +<div class="row"> + <div class="col-12"> + <form method="post"> + {% csrf_token %} + <h3 class="mb-2">Are you sure you want to delete this Subsidy?</h3> + <input type="submit" class="btn btn-danger" value="Yes, delete it" /> + </form> + </div> +</div> + +{% endblock content %} diff --git a/finances/templates/finances/subsidy_detail.html b/finances/templates/finances/subsidy_detail.html new file mode 100644 index 0000000000000000000000000000000000000000..ab90b4673d71649e813e958dacb25b70ad32bfee --- /dev/null +++ b/finances/templates/finances/subsidy_detail.html @@ -0,0 +1,22 @@ +{% extends 'finances/base.html' %} + +{% load bootstrap %} + +{% block pagetitle %}: Subsidy details{% endblock pagetitle %} + +{% block breadcrumb_items %} +{{ block.super }} +<span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span> +<span class="breadcrumb-item">{{ subsidy }}</span> +{% endblock %} + + +{% block content %} + +<div class="row"> + <div class="col-12"> + {% include 'finances/_subsidy_card.html' with subsidy=subsidy %} + </div> +</div> + +{% endblock content %} diff --git a/finances/templates/finances/subsidy_form.html b/finances/templates/finances/subsidy_form.html new file mode 100644 index 0000000000000000000000000000000000000000..8458a2a3904b5c8f4a0bbe4398c271d5127de6a3 --- /dev/null +++ b/finances/templates/finances/subsidy_form.html @@ -0,0 +1,23 @@ +{% extends 'finances/base.html' %} + +{% load bootstrap %} + +{% block breadcrumb_items %} +{{ block.super }} +<span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span> +<span class="breadcrumb-item">{% if form.instance.id %}Update {{ form.instance }}{% else %}Add new Subsidy{% endif %}</span> +{% endblock %} + +{% block pagetitle %}: Subsidies{% endblock pagetitle %} + + +{% block content %} +<div class="row"> + <div class="col-12"> + <form action="" method="post"> + {% csrf_token %} + {{ form|bootstrap }} + <input type="submit" value="Submit" class="btn btn-primary"> + </div> +</div> +{% endblock content %} diff --git a/finances/templates/finances/subsidy_list.html b/finances/templates/finances/subsidy_list.html new file mode 100644 index 0000000000000000000000000000000000000000..286716e4bc34b3b26142c166c5efe4c8f2b10cae --- /dev/null +++ b/finances/templates/finances/subsidy_list.html @@ -0,0 +1,68 @@ +{% extends 'finances/base.html' %} + +{% block pagetitle %}: Subsidies{% endblock pagetitle %} + +{% load staticfiles %} + + +{% block headsup %} +<script type="text/javascript"> +$(document).ready(function($) { + $(".table-row").click(function() { + window.document.location = $(this).data("href"); + }); +}); +</script> +{% endblock headsup %} + + +{% block breadcrumb_items %} +{{ block.super }} +<span class="breadcrumb-item">Subsidies</span> +{% endblock %} + +{% block content %} + +<div class="row"> + <div class="col-12"> + <h3 class="highlight">Subsidies</h3> + {% if perms.scipost.can_manage_subsidies %} + <ul> + <li><a href="{% url 'finances:subsidy_create' %}">Add a Subsidy</a></li> + </ul> + {% endif %} + </div> +</div> + +<div class="row"> + <div class="col-12"> + <h4>Subsidies obtained:</h4> + <table class="table table-hover mb-5"> + <thead class="thead-default"> + <tr> + <th>From Organization</th> + <th>Type</th> + <th>Amount</th> + <th>Date</th> + </tr> + </thead> + <tbody> + {% for subsidy in object_list %} + <tr class="table-row" data-href="{% url 'finances:subsidy_details' pk=subsidy.id %}" style="cursor: pointer;"> + <td>{{ subsidy.organization }}</td> + <td>{{ subsidy.get_subsidy_type_display }}</td> + <td>€{{ subsidy.amount }}</td> + <td>{{ subsidy.date }}</td> + </tr> + {% empty %} + <tr> + <td colspan="4">No Subsidy found</td> + </tr> + {% endfor %} + </tbody> + </table> + + </div> +</div> + +{% endblock content %} diff --git a/finances/urls.py b/finances/urls.py index 7299cbd1ee55d9619e8a4abd7df0b93cf70769bb..b7027f8c2ba86bdc363bfae3562425c4539a6468 100644 --- a/finances/urls.py +++ b/finances/urls.py @@ -3,11 +3,53 @@ __license__ = "AGPL v3" from django.conf.urls import url +from django.views.generic import TemplateView from . import views urlpatterns = [ - url(r'^$', views.timesheets, name='finance'), - url(r'^timesheets$', views.timesheets, name='timesheets'), - url(r'^logs/(?P<slug>\d+)/delete$', views.LogDeleteView.as_view(), name='log_delete'), + url( + r'^$', + TemplateView.as_view(template_name='finances/finances.html'), + name='finances' + ), + + # Subsidies + url( + r'^subsidies/$', + views.SubsidyListView.as_view(), + name='subsidies' + ), + url( + r'^subsidies/add/$', + views.SubsidyCreateView.as_view(), + name='subsidy_create' + ), + url( + r'^subsidies/(?P<pk>[0-9]+)/update/$', + views.SubsidyUpdateView.as_view(), + name='subsidy_update' + ), + url( + r'^subsidies/(?P<pk>[0-9]+)/delete/$', + views.SubsidyDeleteView.as_view(), + name='subsidy_delete' + ), + url( + r'^subsidies/(?P<pk>[0-9]+)/$', + views.SubsidyDetailView.as_view(), + name='subsidy_details' + ), + + # Timesheets + url( + r'^timesheets$', + views.timesheets, + name='timesheets' + ), + url( + r'^logs/(?P<slug>\d+)/delete$', + views.LogDeleteView.as_view(), + name='log_delete' + ), ] diff --git a/finances/views.py b/finances/views.py index 34123e7e256a0244aea236a9657143e46fc6f965..5178e84f42128483b06c3245044b2c1d5fc21429 100644 --- a/finances/views.py +++ b/finances/views.py @@ -5,14 +5,67 @@ __license__ = "AGPL v3" from django.contrib import messages from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import LoginRequiredMixin +from django.core.urlresolvers import reverse_lazy from django.http import Http404 from django.shortcuts import render -from django.views.generic.edit import DeleteView +from django.views.generic.detail import DetailView +from django.views.generic.edit import CreateView, UpdateView, DeleteView +from django.views.generic.list import ListView from .forms import LogsMonthlyActiveFilter -from .models import WorkLog +from .models import Subsidy, WorkLog from .utils import slug_to_id +from scipost.mixins import PermissionsMixin + + + +############# +# Subsidies # +############# + +class SubsidyCreateView(PermissionsMixin, CreateView): + """ + Create a new Subsidy. + """ + permission_required = 'scipost.can_manage_subsidies' + model = Subsidy + fields = '__all__' + template_name = 'finances/subsidy_form.html' + success_url = reverse_lazy('finances:subsidies') + + +class SubsidyUpdateView(PermissionsMixin, UpdateView): + """ + Update a Subsidy. + """ + permission_required = 'scipost.can_manage_subsidies' + model = Subsidy + fields = '__all__' + template_name = 'finances/subsidy_form.html' + success_url = reverse_lazy('finances:subsidies') + + +class SubsidyDeleteView(PermissionsMixin, DeleteView): + """ + Delete a Subsidy. + """ + permission_required = 'scipost.can_manage_subsidies' + model = Subsidy + success_url = reverse_lazy('finances:subsidies') + + +class SubsidyListView(ListView): + model = Subsidy + + +class SubsidyDetailView(DetailView): + model = Subsidy + + +############################ +# Timesheets and Work Logs # +############################ @permission_required('scipost.can_view_timesheets', raise_exception=True) def timesheets(request): diff --git a/journals/models.py b/journals/models.py index 2e13ad41a8761f4dff24cb2243357312fb1ee8fd..0b3785c2de4c36f79f9b9318a99efc51e4ef3051 100644 --- a/journals/models.py +++ b/journals/models.py @@ -7,7 +7,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.fields import JSONField from django.core.exceptions import ValidationError from django.db import models -from django.db.models import Avg, Sum, F +from django.db.models import Avg, Min, Sum, F from django.utils import timezone from django.urls import reverse @@ -24,6 +24,7 @@ from scipost.constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS from scipost.fields import ChoiceArrayField + ################ # Journals etc # ################ @@ -492,6 +493,15 @@ class Publication(models.Model): return val raise KeyError + def get_all_affiliations(self): + """ + Returns all author affiliations. + """ + from organizations.models import Organization + return Organization.objects.filter( + publicationauthorstable__publication=self + ).annotate(order=Min('publicationauthorstable__order')).order_by('order') + def get_all_funders(self): from funders.models import Funder return Funder.objects.filter( diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html index 0d93550d622ef38e17e3f19f7845f03c39db4116..a52c4ad13e6a3e9619424be519690c28de45bb3b 100644 --- a/journals/templates/journals/publication_detail.html +++ b/journals/templates/journals/publication_detail.html @@ -6,151 +6,187 @@ {% load scipost_extras %} {% load user_groups %} +{% is_scipost_admin request.user as is_scipost_admin %} +{% is_edcol_admin request.user as is_edcol_admin %} + {% block pagetitle %}: {{ publication.citation }} - {{ publication.title }}{% endblock pagetitle %} {% block body_class %}{{ block.super }} publication{% endblock %} {% block breadcrumb_items %} - {{block.super}} - <a href="{{ journal.get_absolute_url }}" class="breadcrumb-item">{{ journal }}</a> - {% if publication.in_issue %} - <a href="{{ publication.in_issue.get_absolute_url }}" class="breadcrumb-item">{{ publication.in_issue.short_str }}</a> - {% endif %} - <span class="breadcrumb-item active">{{publication.title}}</span> +{{block.super}} +<a href="{{ journal.get_absolute_url }}" class="breadcrumb-item">{{ journal }}</a> +{% if publication.in_issue %} +<a href="{{ publication.in_issue.get_absolute_url }}" class="breadcrumb-item">{{ publication.in_issue.short_str }}</a> +{% endif %} +<span class="breadcrumb-item active">{{publication.title}}</span> {% endblock %} {% block headsup %} - <meta name="citation_title" content="{{ publication.title }}"/> - {% for author in publication.authors.all %} - {% if author.contributor %} - <meta name="citation_author" content="{{ author.contributor.user.last_name }}, {{ author.contributor.user.first_name }}"/> - {% elif author.unregistered_author %} - <meta name="citation_author" content="{{ author.unregistered_author.last_name }}, {{ author.unregistered_author.first_name }}"/> - {% endif %} - {% endfor %} - <meta name="citation_doi" content="{{ publication.doi_string }}"/> - <meta name="citation_publication_date" content="{{ publication.publication_date|date:'Y/m/d' }}"/> - <meta name="citation_journal_title" content="{{ journal }}"/> - <meta name="citation_issn" content="{{ journal.issn }}"/> - {% if publication.in_issue %} - <meta name="citation_volume" content="{{ publication.in_issue.in_volume.number }}"/> - <meta name="citation_issue" content="{{ publication.in_issue.number }}"/> - {% endif %} - <meta name="citation_firstpage" content="{{ publication.paper_nr|paper_nr_string_filter }}"/> - <meta name="citation_pdf_url" content="https://scipost.org/{{ publication.doi_string }}/pdf"/> - <meta name="dc.identifier" content="doi:{{ publication.doi_string }}"/> - - <script> - $(document).ready(function(){ - $("#citationslist").hide(); - - $("#citationslistbutton").click(function(){ - $("#citationslist").toggle(); - }); - }); - </script> +<meta name="citation_title" content="{{ publication.title }}"/> +{% for author in publication.authors.all %} +{% if author.contributor %} +<meta name="citation_author" content="{{ author.contributor.user.last_name }}, {{ author.contributor.user.first_name }}"/> +{% elif author.unregistered_author %} +<meta name="citation_author" content="{{ author.unregistered_author.last_name }}, {{ author.unregistered_author.first_name }}"/> +{% endif %} +{% endfor %} +<meta name="citation_doi" content="{{ publication.doi_string }}"/> +<meta name="citation_publication_date" content="{{ publication.publication_date|date:'Y/m/d' }}"/> +<meta name="citation_journal_title" content="{{ journal }}"/> +<meta name="citation_issn" content="{{ journal.issn }}"/> +{% if publication.in_issue %} +<meta name="citation_volume" content="{{ publication.in_issue.in_volume.number }}"/> +<meta name="citation_issue" content="{{ publication.in_issue.number }}"/> +{% endif %} +<meta name="citation_firstpage" content="{{ publication.paper_nr|paper_nr_string_filter }}"/> +<meta name="citation_pdf_url" content="https://scipost.org/{{ publication.doi_string }}/pdf"/> +<meta name="dc.identifier" content="doi:{{ publication.doi_string }}"/> + +<script> + $(document).ready(function(){ + $("#citationslist").hide(); + + $("#citationslistbutton").click(function(){ + $("#citationslist").toggle(); + }); + }); +</script> {% endblock headsup %} {% block content %} - {% if not publication.is_published and perms.can_publish_accepted_submission %} - <div class="card bg-warning text-white"> - <div class="card-body"> - <p class="card-text text-center"> - This Publication is not published yet. - Current status: {{ publication.get_status_display }} - </p> - </div> - </div> - {% endif %} - - {% is_edcol_admin request.user as is_edcol_admin %} - - {% include 'partials/journals/publication_summary.html' with publication=publication %} - - {% if publication.commentary and publication.commentary.comments.vetted.exists %} - <h3>Post-publication commentaries</h3> - <p> - This Publication ({{ publication.commentary.comments.vetted.count }}) has been commented on, see <a href="{{ publication.commentary.get_absolute_url }}">this Publication's Commentary page</a> for details. - </p> - {% endif %} - - {% if publication.citedby|length >= 1 %} - - <div class="row"> - <div class="col-6 col-md-2"> - <h3 class="mb-2">Cited by {{ publication.citedby|length }}</h3> - <a href="javascript:;" data-toggle="toggle" data-target="#citationslist">Toggle view</a> - </div> - <div class="col-6 col-md-2"> - <img src="{% static 'scipost/images/citedby.gif' %}" alt="Crossref Cited-by" width="64" /> - </div> - </div> - <div class="row" id="citationslist" style="display: none;"> - <div class="col-12"> - {% include 'journals/_publication_citations.html' with publication=publication %} - </div> - </div> - {% endif %} - - <div class="row"> - <div class="col-12"> - <h3>Authors</h3> - <ul> - {% for author in publication.authors.all %} - {% if author.is_registered %} - <li><a href="{{ author.contributor.get_absolute_url }}">{{ author.contributor }}</a></li> - {% else %} - <li>{{ author.unregistered_author }}</li> - {% endif %} - {% endfor %} - </ul> - - {% if publication.get_all_funders %} - <h3>Funder{{ publication.get_all_funders|length|pluralize }} for this publication</h3> - <ul> - {% for funder in publication.get_all_funders %} - <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li> - {% endfor %} - </ul> - {% endif %} - - {% if publication.institutions.all %} - <h3>Institution{{ publication.institutions.all|pluralize }} related to this Publication</h3> - <ul> - {% for institution in publication.institutions.all %} - <li><a href="{{ institution.get_absolute_url }}">{{ institution }}</a></li> - {% endfor %} - </ul> - {% endif %} - </div> - </div> - - {% if request.user and request.user.contributor in publication.registered_authors.all %} - <h3>Author actions</h3> - <ul> - <li><a href="{% url 'commentaries:comment_on_publication' publication.doi_label %}">Place a comment on this publication</a></li> - </ul> - {% endif %} - - {% if publication.status == 'draft' and perms.scipost.can_draft_publication %} - <hr class="divider"> - <div class="row"> - <div class="col-12"> - {% include 'partials/journals/publication_preparation.html' with publication=publication %} - </div> - </div> - {% endif %} - - {% if is_edcol_admin %} - <hr class="divider"> - <div class="row"> - <div class="col-12"> - <h3>Editorial Administration tools</h3> - {% include 'partials/journals/admin/publication_actions.html' with publication=publication %} - </div> - </div> - {% endif %} +{% if not publication.is_published and perms.can_publish_accepted_submission %} +<div class="card bg-warning text-white"> + <div class="card-body"> + <p class="card-text text-center"> + This Publication is not published yet. + Current status: {{ publication.get_status_display }} + </p> + </div> +</div> +{% endif %} + +{% include 'partials/journals/publication_summary.html' with publication=publication %} + +{% if publication.commentary and publication.commentary.comments.vetted.exists %} +<h3>Post-publication commentaries</h3> +<p> + This Publication ({{ publication.commentary.comments.vetted.count }}) has been commented on, see <a href="{{ publication.commentary.get_absolute_url }}">this Publication's Commentary page</a> for details. +</p> +{% endif %} + +{% if publication.citedby|length >= 1 %} + +<div class="row"> + <div class="col-6 col-md-2"> + <h3 class="mb-2">Cited by {{ publication.citedby|length }}</h3> + <a href="javascript:;" data-toggle="toggle" data-target="#citationslist">Toggle view</a> + </div> + <div class="col-6 col-md-2"> + <img src="{% static 'scipost/images/citedby.gif' %}" alt="Crossref Cited-by" width="64" /> + </div> +</div> +<div class="row" id="citationslist" style="display: none;"> + <div class="col-12"> + {% include 'journals/_publication_citations.html' with publication=publication %} + </div> +</div> +{% endif %} +<hr/> + +<div class="card"> + <div class="card-header"> + Author{{ publication.authors.all|length|pluralize }}/Affiliation{{ affiliations_list|length|pluralize }}: mappings to Contributors and <a href="{% url 'organizations:organizations' %}" target="_blank">Organizations</a> + </div> + <div class="card-body"> + <ul class="list-inline m-1"> + {% for author in publication.authors.all %} + <li class="list-inline-item mr-1"> + {% for aff in affiliations_list %} + {% if aff in author.affiliations.all %} + <sup>{{ forloop.counter }} </sup> + {% endif %}{% endfor %} + {% if author.is_registered %} + <a href="{{ author.contributor.get_absolute_url }}">{{ author.contributor.user.first_name }} {{ author.contributor.user.last_name }}</a>{% else %}{{ author.unregistered_author.first_name }} {{ author.unregistered_author.last_name }}{% endif %}{% if not forloop.last %}, {% endif %} + </li> + {% endfor %} + </ul> + + <ul class="list list-unstyled m-2"> + {% for aff in affiliations_list %} + <li><sup>{{ forloop.counter }}</sup> <a href="{{ aff.get_absolute_url }}">{{ aff.name_full }}</a></li> + {% endfor %} + </ul> + </div> +</div> + +{% if publication.get_all_funders %} +<div class="card"> + <div class="card-header"> + Funder{{ publication.get_all_funders|length|pluralize }} for the research work leading to this publication + </div> + <div class="card-content"> + <ul class="m-2"> + {% for funder in publication.get_all_funders %} + {% if funder.organization %} + {% if funder.name != funder.organization.name and funder.name != funder.organization.name_original %} + <li>{{ funder }} (through Organization: <a href="{{ funder.organization.get_absolute_url }}">{{ funder.organization.name_and_acronym }}</a>)</li> + {% else %} + <li><a href="{{ funder.organization.get_absolute_url }}">{{ funder.organization.name_and_acronym }}</a></li> + {% endif %} + {% else %} + <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li> + {% endif %} + {% endfor %} + </ul> + </div> +</div> +{% endif %} + +{% if is_scipost_admin or is_edcol_admin %} +{% if publication.institutions.all %} +<div class="card"> + <div class="card-header"> + Institution{{ publication.institutions.all|pluralize }} related to this Publication (<span class="text-danger">Admin-only view, to be removed</span>) + </div> + <div class="card-content"> + <ul class="m-2"> + {% for institution in publication.institutions.all %} + <li><a href="{{ institution.get_absolute_url }}">{{ institution }}</a></li> + {% endfor %} + </ul> + </div> +</div> +{% endif %} +{% endif %} + + +{% if request.user and request.user.contributor in publication.registered_authors.all %} +<h3>Author actions</h3> +<ul> + <li><a href="{% url 'commentaries:comment_on_publication' publication.doi_label %}">Place a comment on this publication</a></li> +</ul> +{% endif %} + +{% if publication.status == 'draft' and perms.scipost.can_draft_publication %} +<hr class="divider"> +<div class="row"> + <div class="col-12"> + {% include 'partials/journals/publication_preparation.html' with publication=publication %} + </div> +</div> +{% endif %} + +{% if is_edcol_admin %} +<hr class="divider"> +<div class="row"> + <div class="col-12"> + <h3>Editorial Administration tools</h3> + {% include 'partials/journals/admin/publication_actions.html' with publication=publication %} + </div> +</div> +{% endif %} {% endblock content %} diff --git a/journals/views.py b/journals/views.py index e660f9e2830cefe73995f8c4743f84d126f49ead..46f6ca720b9223ef2bd9bdb09fb9573c55f7df35 100644 --- a/journals/views.py +++ b/journals/views.py @@ -1266,6 +1266,7 @@ def publication_detail(request, doi_label): context = { 'publication': publication, + 'affiliations_list': publication.get_all_affiliations(), 'journal': publication.get_journal(), } return render(request, 'journals/publication_detail.html', context) diff --git a/notifications/templates/notifications/partials/notification_list_popover.html b/notifications/templates/notifications/partials/notification_list_popover.html index 3f16c462650a4c636afde7c90ebd8d78bf609d74..86cb6344269f533abd00158d4f7834347225ac3b 100644 --- a/notifications/templates/notifications/partials/notification_list_popover.html +++ b/notifications/templates/notifications/partials/notification_list_popover.html @@ -1,4 +1,7 @@ {% load request_filters %} +{% load user_groups %} + +{% is_financial_admin request.user as if_financial_admin %} <div class="popover-template"> <div class="popover notifications" role="tooltip"> @@ -26,8 +29,8 @@ <a class="item {% active 'partners:dashboard' %}" href="{% url 'partners:dashboard' %}">Partner Page</a> {% endif %} - {% if perms.scipost.can_view_timesheets %} - <a class="item {% active 'finances:finance' %}" href="{% url 'finances:finance' %}">Financial Administration</a> + {% if is_financial_admin %} + <a class="item {% active 'finances:finances' %}" href="{% url 'finances:finance' %}">Financial Administration</a> {% endif %} {% if perms.scipost.can_view_all_funding_info %} diff --git a/organizations/models.py b/organizations/models.py index 60bd72d2d65230c36a32c9c734862199b48653de..5a1f335dc563b2d17a1f638eb3620f38f1bff9c7 100644 --- a/organizations/models.py +++ b/organizations/models.py @@ -12,7 +12,9 @@ from django_countries.fields import CountryField from .constants import ORGANIZATION_TYPES, ORGANIZATION_STATUSES, ORGSTATUS_ACTIVE -from journals.models import Publication, PublicationAuthorsTable, OrgPubFraction +from scipost.models import Contributor +from journals.models import Publication, OrgPubFraction, UnregisteredAuthor + class Organization(models.Model): """ @@ -65,6 +67,20 @@ class Organization(models.Model): def __str__(self): return self.name + def name_and_acronym(self): + if self.acronym: + return '%s (%s)' % (self.name, self.acronym) + return self.name + + def name_full(self): + text = '' + if self.name_original: + text += self.name_original + ' / ' + text += self.name + if self.acronym: + text += ' (' + self.acronym + ')' + return text + @property def full_name(self): full_name_str = "" @@ -81,7 +97,7 @@ class Organization(models.Model): return full_name_str + self.full_name def get_absolute_url(self): - return reverse('organizations:organization_details', args=(self.id,)) + return reverse('organizations:organization_details', kwargs = {'pk': self.id}) def get_publications(self): return Publication.objects.filter( @@ -109,12 +125,14 @@ class Organization(models.Model): ).aggregate(Sum('fraction'))['fraction__sum'] def get_contributor_authors(self): - return self.publicationauthorstable_set.select_related( - 'contributor').order_by('contributor__user__last_name') + cont_id_list = [tbl.contributor.id for tbl in self.publicationauthorstable_set.all() \ + if tbl.contributor is not None] + return Contributor.objects.filter(id__in=cont_id_list).order_by('user__last_name') def get_unregistered_authors(self): - return self.publicationauthorstable_set.select_related( - 'unregistered_author').order_by('unregistered_author__last_name') + unreg_id_list = [tbl.unregistered_author.id for tbl in self.publicationauthorstable_set.all( + ) if tbl.unregistered_author is not None] + return UnregisteredAuthor.objects.filter(id__in=unreg_id_list).order_by('last_name') @property def has_current_agreement(self): @@ -125,13 +143,19 @@ class Organization(models.Model): return False return self.partner.agreements.now_active().exists() + def get_total_subsidies_obtained(self, n_years_part=None): + """ + Computes the total amount received by SciPost, in the form + of subsidies from this Organization. + """ + return self.subsidy_set.aggregate(models.Sum('amount')).get('amount__sum', 0) + def get_total_contribution_obtained(self, n_years_past=None): """ Computes the contribution obtained from this organization, summed over all time. """ contrib = 0 - now = timezone.now().date() for agreement in self.partner.agreements.all(): - contrib += agreement.offered_yearly_contribution * int(agreement.duration.days/365) + contrib += agreement.offered_yearly_contribution * int(agreement.duration.days / 365) return contrib diff --git a/organizations/templates/organizations/_organization_card.html b/organizations/templates/organizations/_organization_card.html index 502d3455988f94e8eb11d8fbbf3dbdf2074a61cf..8635befd495d432629087319bca6eeb73a566eb4 100644 --- a/organizations/templates/organizations/_organization_card.html +++ b/organizations/templates/organizations/_organization_card.html @@ -1,28 +1,39 @@ {% load bootstrap %} +{% load user_groups %} {% load organizations_extras %} +{% block headsup %} +<script type="text/javascript"> +$(document).ready(function($) { + $(".table-row").click(function() { + window.document.location = $(this).data("href"); + }); +}); +</script> +{% endblock headsup %} + +{% is_scipost_admin request.user as is_scipost_admin %} + <div class="card-body"> <div class="row"> <div class="col-12"> <ul class="nav nav-tabs" id="organization-{{ org.id }}-tab" role="tablist"> - {% if perms.scipost.can_manage_organizations %} <li class="nav-item"> <a class="nav-link" id="details-{{ org.id }}-tab" data-toggle="tab" href="#details-{{ org.id }}" role="tab" aria-controls="details-{{ org.id }}" aria-selected="true">Details</a> </li> - {% endif %} <li class="nav-item"> - <a class="nav-link active" id="publications-{{ org.id }}-tab" data-toggle="tab" href="#publications-{{ org.id }}" role="tab" aria-controls="publications-{{ org.id }}" aria-selected="true">Publications & PubFractions</a> + <a class="nav-link active" id="publications-{{ org.id }}-tab" data-toggle="tab" href="#publications-{{ org.id }}" role="tab" aria-controls="publications-{{ org.id }}" aria-selected="true">Publications{% if is_scipost_admin %} & PubFractions{% endif %}</a> </li> <li class="nav-item"> <a class="nav-link" id="authors-{{ org.id }}-tab" data-toggle="tab" href="#authors-{{ org.id }}" role="tab" aria-controls="authors-{{ org.id }}" aria-selected="true">Associated Authors</a> </li> <li class="nav-item"> - <a class="nav-link" id="funders-{{ org.id }}-tab" data-toggle="tab" href="#funders-{{ org.id }}" role="tab" aria-controls="funders-{{ org.id }}" aria-selected="true">Funder instances</a> + <a class="nav-link" id="funders-{{ org.id }}-tab" data-toggle="tab" href="#funders-{{ org.id }}" role="tab" aria-controls="funders-{{ org.id }}" aria-selected="true">Funder Registry instances</a> </li> <li class="nav-item"> - <a class="nav-link" id="partnership-{{ org.id }}-tab" data-toggle="tab" href="#partnership-{{ org.id }}" role="tab" aria-controls="partnership-{{ org.id }}" aria-selected="true">Partnership history</a> + <a class="nav-link" id="support-{{ org.id }}-tab" data-toggle="tab" href="#support-{{ org.id }}" role="tab" aria-controls="support-{{ org.id }}" aria-selected="true">Support history</a> </li> {% if perms.scipost.can_manage_organizations %} <li class="nav-item"> @@ -33,17 +44,15 @@ <div class="tab-content" id="organization-{{ org.id }}-tab"> - {% if perms.scipost.can_manage_organizations %} <div class="tab-pane pt-4" id="details-{{ org.id }}" role="tabpanel" aria-labelledby="details-{{ org.id }}-tab"> <h3>Details:</h3> {% include 'organizations/_organization_details_contents.html' with org=org %} </div> - {% endif %} <div class="tab-pane show active pt-4" id="publications-{{ org.id }}" role="tabpanel" aria-labelledby="publications-{{ org.id }}-tab"> - <h3>Publications associated to this Organization <span class="text-muted small">(with total PubFractions <i class="fa fa-info-circle" data-toggle="tooltip" data-html="true" title="" data-original-title="Fraction of a publication's funding/institutional support associated to a given Organization"></i>)</span>:</h3> + <h3>Publications associated to this Organization{% if is_scipost_admin %} <span class="text-muted small">(with total PubFractions <i class="fa fa-info-circle" data-toggle="tooltip" data-html="true" title="" data-original-title="Fraction of a publication's funding/institutional support associated to a given Organization"></i>)</span>{% endif %}:</h3> {% for pubyear in pubyears %} - <h4>{{ pubyear }} <span class="text-muted small">(total pubfractions: {{ org|pubfractions_in_year:pubyear }})</span></h4> + <h4>{{ pubyear }}{% if is_scipost_admin %} <span class="text-muted small">(total pubfractions: {{ org|pubfractions_in_year:pubyear }})</span>{% endif %}</h4> <ul> {% for publication in org.get_publications %} {% if publication.publication_date|date:'Y'|add:"0" == pubyear %} @@ -85,18 +94,59 @@ </div> <div class="tab-pane pt-4" id="funders-{{ org.id }}" role="tabpanel" aria-labelledby="funders-{{ org.id }}-tab"> - <h3>Funder instances (from FundRef) associated to this Organization:</h3> + <h3>Funder Registry instances associated to this Organization:</h3> <ul> {% for funder in org.funder_set.all %} <li>{{ funder }}</li> {% empty %} - <li>No FundRef instance found</li> + <li>No Funder Registry instance found<br/><br/> + <strong class="text-danger">Without a Funder Registry instance, we cannot record funding acknowledgements to this Organization with Crossref.</strong> + <p>Are you a representative of this Organization? We advise you to:</p> + <ul> + <li>Make sure your Organization gets included in <a href="https://www.crossref.org/services/funder-registry/" target="_blank">Crossref's Funder Registry</a>;</li> + <li>After inclusion, <a href="mailto:admin@scipost.org?subject=Inclusion of {{ organization }} {% if organization.acronym %}({{ organization.acronym }}){% endif %} in the Funder Registry">contact our administration</a> with this information so that we can update our records.</li> + </ul> + </li> {% endfor %} </ul> </div> - <div class="tab-pane pt-4" id="partnership-{{ org.id }}" role="tabpanel" aria-labelledby="partnership-{{ org.id }}-tab"> - <h3>Partnership history:</h3> + <div class="tab-pane pt-4" id="support-{{ org.id }}" role="tabpanel" aria-labelledby="support-{{ org.id }}-tab"> + <h3>Support history</h3> + {% if org.subsidy_set.all|length > 0 %} + <p>List of the subsidies (in one form or another) which SciPost has received from this Organization. Click on a row to see more details.</p> + <table class="table table-hover mb-5"> + <thead class="thead-default"> + <tr> + <th>Type</th> + <th>Amount</th> + <th>Date</th> + <th>Duration</th> + </tr> + </thead> + <tbody> + {% for subsidy in org.subsidy_set.all %} + <tr class="table-row" data-href="{% url 'finances:subsidy_details' pk=subsidy.id %}" style="cursor: pointer;"> + <td>{{ subsidy.get_subsidy_type_display }}</td> + <td>€{{ subsidy.amount }}</td> + <td>{{ subsidy.date }}</td> + <td>{{ subsidy.get_duration_display }}</td> + </tr> + {% endfor %} + <tr style="border-top: 2px solid black"> + <td>Total support obtained:</td> + <td>€{{ org.get_total_subsidies_obtained }}</td> + <td colspan="2"> + </tr> + </tbody> + </table> + {% else %} + <p><strong>This Organization has <span class="text-danger">not yet</span> supported SciPost.</strong></p> + {% endif %} + + {% if is_scipost_admin %} + <h3 class="text-danger">To be removed (Admin view only):</h3> + <h3>Supporting Partner Agreements history:</h3> {% with agreement=org.partner.get_latest_active_agreement %} {% if agreement %} <p>This organization is currently a SciPost Supporting Partner.</p> @@ -116,7 +166,7 @@ <td>{{ agreement.get_status_display }}</td> <td>{{ agreement.get_duration_display }}</td> <td>{{ agreement.start_date }}</td> - <td>€ {{ agreement.offered_yearly_contribution }}</td> + <td>€{{ agreement.offered_yearly_contribution }}</td> </tr> {% endfor %} <tr style="border-top: 2px solid black"> @@ -127,6 +177,7 @@ <p>This organization has <span class="text-danger">not yet</span> been a SciPost Supporting Partner.</p> {% endif %} </div> + {% endif %} <div class="tab-pane pt-4" id="manage-{{ org.id }}" role="tabpanel" aria-labelledby="manage-{{ org.id }}-tab"> {% if perms.scipost.can_manage_organizations %} diff --git a/organizations/templates/organizations/_organization_details_contents.html b/organizations/templates/organizations/_organization_details_contents.html index 88fb765d1d0766da467c6591c9d01cbc6f3ced9e..3e54d17a1dd247fd91a17702f340d502ab927494 100644 --- a/organizations/templates/organizations/_organization_details_contents.html +++ b/organizations/templates/organizations/_organization_details_contents.html @@ -24,9 +24,20 @@ <tr> <td>Status</td><td>{{ org.get_status_display }}</td> </tr> + <tr> + <td>GRID id (link)</td><td>{% if org.grid_json.id %}<a href="https://grid.ac/institutes/{{ org.grid_json.id }}" target="_blank">{{ org.grid_json.id }}{% else %}No GRID id found{% endif %}</td> + </tr> + <tr> + <td>Crossref Org ID (link)</td><td>{% if org.crossref_json.org_id %}<a href="https://crossref.org" target="_blank">{{ org.crossref_json.org_id }}{% else %}No Crossref Org ID found{% endif %}</td> + </tr> + {% if org.parent %} + <tr> + <td>Parent</td><td><a href="{{ org.parent.get_absolute_url }}">{{ org.parent }}</a></td> + </tr> + {% endif %} {% if org.superseded_by %} <tr> - <td>Superseded by</td><td>{{ org.superseded_by.get_absolute_url }}</td> + <td>Superseded by</td><td><a href="{{ org.superseded_by.get_absolute_url }}">{{ org.superseded_by }}</a></td> </tr> {% endif %} </table> diff --git a/organizations/templates/organizations/organization_confirm_delete.html b/organizations/templates/organizations/organization_confirm_delete.html index 8ea21f23cfe9abbc543a21f2c0eabb1e5701e5aa..600b75bb3aeb19aac85c8686f2ed4c09bd50ff13 100644 --- a/organizations/templates/organizations/organization_confirm_delete.html +++ b/organizations/templates/organizations/organization_confirm_delete.html @@ -13,12 +13,11 @@ </div> <div class="row"> <div class="col-12"> - <form method="post"> - {% csrf_token %} - <h3 class="mb-2">Are you sure you want to delete this Organization?</h3> - <input type="submit" class="btn btn-danger" value="Yes, delete it" /> - </form> - </ul> + <form method="post"> + {% csrf_token %} + <h3 class="mb-2">Are you sure you want to delete this Organization?</h3> + <input type="submit" class="btn btn-danger" value="Yes, delete it" /> + </form> </div> </div> diff --git a/organizations/templates/organizations/organization_detail.html b/organizations/templates/organizations/organization_detail.html index 10474db59bf5f62f5599f5d362ef1866c67a4458..47455259fbce4232acd3ce9e980ffa03e449e260 100644 --- a/organizations/templates/organizations/organization_detail.html +++ b/organizations/templates/organizations/organization_detail.html @@ -11,7 +11,31 @@ {% block content %} -<h1 class="highlight">{{ organization }}</h1> + + <table class="table highlight"> + <tr> + <td><img src="{{ organization.country.flag }}" style="width:20px;" alt="{{ organization.country }} flag"/> <span class="text-muted"><small>[{{ organization.country }}]</small></span> {{ organization.get_country_display }}</td> + <td> + <h2>{{ organization.full_name }} <small>{% if organization.acronym %}[{{ organization.acronym }}]{% endif %}</small></h2> + {% if organization.parent %} + <small class="text-muted"><p>Parent: <a href="{{ organization.parent.get_absolute_url }}">{{ organization.parent }}</a></p></small> + {% endif %} + {% if organization.children.all %} + <small class="text-muted"> + <p>Parent of: + {% for child in organization.children.all %} + <a href="{{ child.get_absolute_url }}">{{ child }}</a>{% if not forloop.last %}, {% endif %} + {% endfor %} + </p> + </small> + {% endif %} + {% if organization.superseded_by %} + <small class="text-muted"><p>Superseded by {{ organization.superseded_by }}</p></small> + {% endif %} + </td> + </tr> + </table> + <div class="row"> <div class="col-12"> diff --git a/organizations/templates/organizations/organization_list.html b/organizations/templates/organizations/organization_list.html index 75503090fc39ae834cdc9895c8ceeb736b0df162..e5ea3aa4c4b1f5d61eb47d9680a9814991ae9169 100644 --- a/organizations/templates/organizations/organization_list.html +++ b/organizations/templates/organizations/organization_list.html @@ -3,8 +3,11 @@ {% block pagetitle %}: Organizations{% endblock pagetitle %} {% load staticfiles %} +{% load user_groups %} {% load organizations_extras %} +{% is_scipost_admin request.user as is_scipost_admin %} + {% block headsup %} <script type="text/javascript"> $(document).ready(function($) { @@ -22,16 +25,17 @@ $(document).ready(function($) { {% block content %} <div class="row"> - <div class="col-12"> - <h1 class="highlight">Organizations</h1> - {% if perms.scipost.can_manage_organizations %} - <h3>Management actions:</h3> - <ul> - <li><a href="{% url 'organizations:organization_create' %}">Create a new Organization instance</a></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> + <div class="col-12"> + <h1 class="highlight">Organizations</h1> + {% if perms.scipost.can_manage_organizations %} + <h3>Management actions:</h3> + <ul> + <li><a href="{% url 'organizations:organization_create' %}">Create a new Organization instance</a></li> + <li><a href="{% url 'funders:funders_dashboard' %}">Link Funders to Organizations</a> ({{ nr_funders_wo_organization }} found in need of linking)</li> + <li>Link Partners to Organizations ({{ nr_partners_wo_organization }} found in need of linking)</li> + </ul> + {% endif %} + </div> </div> @@ -52,7 +56,9 @@ $(document).ready(function($) { <p>Click on a row to see more details about the Organization, including per-year breakdowns of:</p> <ul> <li>associated publications</li> + {% if is_scipost_admin %} <li>associated support fractions</li> + {% endif %} <li>associated authors</li> <li>partnership history</li> </ul> diff --git a/organizations/views.py b/organizations/views.py index 8311375d3d3e2a4155608418b3d0b482010382a3..d11f618d346fd1f555cc14993282ae07b8c01a18 100644 --- a/organizations/views.py +++ b/organizations/views.py @@ -12,6 +12,7 @@ from django.views.generic.list import ListView from .models import Organization from funders.models import Funder +from partners.models import Partner from scipost.mixins import PermissionsMixin @@ -54,6 +55,7 @@ class OrganizationListView(ListView): 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() + context['nr_partners_wo_organization'] = Partner.objects.filter(organization=None).count() context['pubyears'] = range(int(timezone.now().strftime('%Y')), 2015, -1) return context diff --git a/partners/admin.py b/partners/admin.py index 8e0c86879af58dd987dae79e0379034f004ab618..88d5592046548dd8b5f437b6786a1a73ec0558c7 100644 --- a/partners/admin.py +++ b/partners/admin.py @@ -4,7 +4,7 @@ __license__ = "AGPL v3" from django.contrib import admin -from .models import Contact, Partner, Consortium, Institution,\ +from .models import Contact, Partner, PartnerEvent, \ ProspectivePartner, ProspectiveContact, ProspectivePartnerEvent,\ MembershipAgreement, ContactRequest, PartnersAttachment @@ -43,10 +43,16 @@ class ProspectivePartnerAdmin(admin.ModelAdmin): list_filter = ('kind', 'status') +class PartnerEventInline(admin.TabularInline): + model = PartnerEvent + extra = 0 + + class PartnerAdmin(admin.ModelAdmin): search_fields = ('institution', ) inlines = ( ContactToPartnerInline, + PartnerEventInline, ) @@ -57,9 +63,7 @@ class MembershipAgreementAdmin(admin.ModelAdmin): admin.site.register(Partner, PartnerAdmin) -admin.site.register(Consortium) admin.site.register(Contact) admin.site.register(ContactRequest) -admin.site.register(Institution) admin.site.register(ProspectivePartner, ProspectivePartnerAdmin) admin.site.register(MembershipAgreement, MembershipAgreementAdmin) diff --git a/partners/constants.py b/partners/constants.py index 02a5e5da0d48941562a34f07c819af79968cf471..31f301c3e44ea67c8bdbf68fd1e5b3dc67a7ac85 100644 --- a/partners/constants.py +++ b/partners/constants.py @@ -74,12 +74,6 @@ REQUEST_STATUSES = ( ) -CONSORTIUM_STATUS = ( - ('Prospective', 'Prospective'), - ('Active', 'Active'), - ('Inactive', 'Inactive'), -) - PARTNER_STATUS_UPDATE = 'status_update' PARTNER_EVENTS = ( ('initial', 'Contacted (initial)'), diff --git a/partners/forms.py b/partners/forms.py index f4a94bd976839fbdae65a90efbb6f78401c7e3c2..dc4fe752acdbd9860b72913388e2d90b22bba95c 100644 --- a/partners/forms.py +++ b/partners/forms.py @@ -9,6 +9,8 @@ from django.core.exceptions import ValidationError from django.db import transaction from django.db.models import Q +from ajax_select.fields import AutoCompleteSelectField + from captcha.fields import ReCaptchaField from django_countries import countries from django_countries.widgets import CountrySelectWidget @@ -17,7 +19,7 @@ from django_countries.fields import LazyTypedChoiceField 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,\ - Institution, Contact, PartnerEvent, MembershipAgreement, ContactRequest,\ + Contact, PartnerEvent, MembershipAgreement, ContactRequest,\ PartnersAttachment from .utils import PartnerUtils @@ -130,25 +132,12 @@ class PartnerEventForm(forms.ModelForm): ) -class InstitutionForm(forms.ModelForm): - class Meta: - model = Institution - fields = ( - 'kind', - 'name', - 'acronym', - 'address', - 'country', - 'logo', - 'css_class', - ) - - class PartnerForm(forms.ModelForm): + organization = AutoCompleteSelectField('organization_lookup') + class Meta: model = Partner fields = ( - 'institution', 'organization', 'status', 'main_contact' @@ -322,8 +311,7 @@ class ContactFormset(forms.BaseModelFormSet): class PromoteToPartnerForm(forms.ModelForm): - address = forms.CharField(widget=forms.Textarea(), required=False) - acronym = forms.CharField(max_length=16) + organization = AutoCompleteSelectField('organization_lookup') class Meta: model = ProspectivePartner @@ -334,17 +322,8 @@ class PromoteToPartnerForm(forms.ModelForm): ) def promote_to_partner(self, current_user): - # Create new instances - institution = Institution( - kind=self.cleaned_data['kind'], - name=self.cleaned_data['institution_name'], - acronym=self.cleaned_data['acronym'], - address=self.cleaned_data['address'], - country=self.cleaned_data['country'] - ) - institution.save() partner = Partner( - institution=institution, + organization=self.cleaned_data['organization'], main_contact=None ) partner.save() @@ -360,7 +339,7 @@ class PromoteToPartnerForm(forms.ModelForm): # Close Prospect self.instance.status = PROSPECTIVE_PARTNER_PROCESSED self.instance.save() - return (partner, institution,) + return partner class PromoteToContactForm(forms.ModelForm): diff --git a/partners/migrations/0019_auto_20181007_1647.py b/partners/migrations/0019_auto_20181007_1647.py new file mode 100644 index 0000000000000000000000000000000000000000..b3b110f7ab9ff889c6b3719866f77db8e1c78afe --- /dev/null +++ b/partners/migrations/0019_auto_20181007_1647.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-07 14:47 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0018_auto_20180922_1609'), + ] + + operations = [ + migrations.RemoveField( + model_name='contact', + name='consortia', + ), + migrations.RemoveField( + model_name='membershipagreement', + name='consortium', + ), + ] diff --git a/partners/migrations/0020_auto_20181007_1649.py b/partners/migrations/0020_auto_20181007_1649.py new file mode 100644 index 0000000000000000000000000000000000000000..540ad0e17f38e0635a3bbb2fc62ad3e858968509 --- /dev/null +++ b/partners/migrations/0020_auto_20181007_1649.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-07 14:49 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0019_auto_20181007_1647'), + ] + + operations = [ + migrations.RemoveField( + model_name='consortium', + name='partners', + ), + migrations.DeleteModel( + name='Consortium', + ), + ] diff --git a/partners/migrations/0021_auto_20181007_1746.py b/partners/migrations/0021_auto_20181007_1746.py new file mode 100644 index 0000000000000000000000000000000000000000..c29a0a5b2e6d48fae933f6586a7d58f9e8e23331 --- /dev/null +++ b/partners/migrations/0021_auto_20181007_1746.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-07 15:46 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0020_auto_20181007_1649'), + ] + + operations = [ + migrations.RemoveField( + model_name='partner', + name='institution', + ), + migrations.AlterField( + model_name='contact', + name='partners', + field=models.ManyToManyField(help_text='All Partners (+related Organizations) the Contact is related to.', to='partners.Partner'), + ), + ] diff --git a/partners/migrations/0022_delete_institution.py b/partners/migrations/0022_delete_institution.py new file mode 100644 index 0000000000000000000000000000000000000000..4a97896eb5dbc9af0d99c59306f53cf8a17b7984 --- /dev/null +++ b/partners/migrations/0022_delete_institution.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-07 15:48 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0021_auto_20181007_1746'), + ] + + operations = [ + migrations.DeleteModel( + name='Institution', + ), + ] diff --git a/partners/models.py b/partners/models.py index 7106748a976e5739aa8d1bf429b635714c8c2131..b0cdfcb548deaa4cfbe2de5ad4f87a2dd5076f20 100644 --- a/partners/models.py +++ b/partners/models.py @@ -17,7 +17,7 @@ from django.urls import reverse from django_countries.fields import CountryField from .constants import ( - PARTNER_KINDS, PARTNER_STATUS, CONSORTIUM_STATUS, MEMBERSHIP_DURATION, PARTNER_EVENTS, + PARTNER_KINDS, PARTNER_STATUS, MEMBERSHIP_DURATION, PARTNER_EVENTS, PROSPECTIVE_PARTNER_STATUS, PROSPECTIVE_PARTNER_EVENTS, MEMBERSHIP_AGREEMENT_STATUS, PROSPECTIVE_PARTNER_ADDED, PARTNER_KIND_UNI_LIBRARY) from .constants import ( @@ -118,23 +118,6 @@ class ProspectivePartnerEvent(models.Model): # Partner-related objects # ########################### -class Institution(models.Model): - """ - An Institution is any form of academic organization which SciPost interacts with. - """ - kind = models.CharField(max_length=32, choices=PARTNER_KINDS) - name = models.CharField(max_length=256) - logo = models.ImageField(upload_to='institutions/logo/%Y/', blank=True) - css_class = models.CharField(max_length=256, blank=True, - verbose_name="Additional logo CSS class") - acronym = models.CharField(max_length=16) - address = models.TextField(blank=True) - country = CountryField() - - def __str__(self): - return '%s (%s)' % (self.name, self.get_kind_display()) - - class ContactRequest(models.Model): """ A ContactRequest request for a new Contact usually made by another Contact. @@ -169,11 +152,8 @@ class Contact(models.Model): title = models.CharField(max_length=4, choices=TITLE_CHOICES) description = models.CharField(max_length=256, blank=True) partners = models.ManyToManyField('partners.Partner', - help_text=('All Partners (+related Institutions)' + help_text=('All Partners (+related Organizations)' ' the Contact is related to.')) - consortia = models.ManyToManyField('partners.Consortium', blank=True, - help_text=('All Consortia for which the Contact has' - ' explicit permission to view/edit its data.')) activation_key = models.CharField(max_length=40, blank=True) key_expires = models.DateTimeField(default=timezone.now) @@ -228,8 +208,6 @@ class Partner(models.Model): Supporting Partners. These are the official Partner objects created by SciPost Admin. """ - institution = models.ForeignKey('partners.Institution', on_delete=models.CASCADE, - blank=True, null=True) organization = models.OneToOneField('organizations.Organization', on_delete=models.CASCADE, blank=True, null=True) status = models.CharField(max_length=16, choices=PARTNER_STATUS, default=PARTNER_INITIATED) @@ -239,9 +217,7 @@ class Partner(models.Model): objects = PartnerManager() def __str__(self): - if self.institution: - return self.institution.acronym + ' (' + self.get_status_display() + ')' - return self.get_status_display() + return self.organization.__str__() + ' (' + self.get_status_display() + ')' def get_absolute_url(self): return reverse('partners:partner_view', args=(self.id,)) @@ -269,18 +245,6 @@ class PartnerEvent(models.Model): return '%s: %s' % (str(self.partner), self.get_event_display()) -class Consortium(models.Model): - """ - Collection of Partners. - """ - name = models.CharField(max_length=128) - partners = models.ManyToManyField('partners.Partner', blank=True) - status = models.CharField(max_length=16, choices=CONSORTIUM_STATUS) - - class Meta: - verbose_name_plural = 'consortia' - - class MembershipAgreement(models.Model): """ Agreement for membership of the Supporting Partners Board. @@ -288,8 +252,6 @@ class MembershipAgreement(models.Model): """ partner = models.ForeignKey('partners.Partner', on_delete=models.CASCADE, blank=True, null=True, related_name='agreements') - consortium = models.ForeignKey('partners.Consortium', on_delete=models.CASCADE, - blank=True, null=True) status = models.CharField(max_length=16, choices=MEMBERSHIP_AGREEMENT_STATUS) date_requested = models.DateField() start_date = models.DateField() diff --git a/partners/templates/partners/_agreement_card.html b/partners/templates/partners/_agreement_card.html index bb2c012a1bb3370da6a3154a358cdfbf858a0ad9..8e3fb69717f7b857e9d14a34b6d7c180a861444d 100644 --- a/partners/templates/partners/_agreement_card.html +++ b/partners/templates/partners/_agreement_card.html @@ -2,10 +2,10 @@ <div class="row"> <div class="col-md-4"> <address> - <h3>{{ agreement.partner.institution.name }}</h3> - <strong>{{ agreement.partner.institution.acronym }} ({{ agreement.partner.institution.get_kind_display }})</strong><br> - {{ agreement.partner.institution.address|linebreaks }} - {{ agreement.partner.institution.get_country_display }} + <h3>{{ agreement.partner.organization.name }}</h3> + <strong>{{ agreement.partner.organization.acronym }} ({{ agreement.partner.organization.get_kind_display }})</strong><br> + {{ agreement.partner.organization.address|linebreaks }} + {{ agreement.partner.organization.get_country_display }} </address> </div> <div class="col-md-4"> diff --git a/partners/templates/partners/_partner_card.html b/partners/templates/partners/_partner_card.html index c04961e6755bfb5dcae126347a7dba9a9d6e1008..4d97ec4274ba9782fd78d2089d80cbfb46ae921e 100644 --- a/partners/templates/partners/_partner_card.html +++ b/partners/templates/partners/_partner_card.html @@ -3,14 +3,14 @@ <div class="card-body"> <div class="row"> <div class="col-md-1"> - <p>{{ partner.institution.country }}</p> + <p>{{ partner.organization.country }}</p> </div> <div class="col-md-4"> <address> - <h3><a href="{{partner.get_absolute_url}}">{{ partner.institution.name }}</a></h3> - <strong>{{ partner.institution.acronym }} ({{ partner.institution.get_kind_display }})</strong><br> - {{ partner.institution.address|linebreaks }} - {{ partner.institution.get_country_display }}<br> + <h3><a href="{{partner.get_absolute_url}}">{{ partner.organization.name }}</a></h3> + <strong>{{ partner.organization.acronym }} ({{ partner.organization.get_orgtype_display }})</strong><br> + {{ partner.organization.address|linebreaks }} + {{ partner.organization.get_country_display }}<br> Main contact: {{ partner.main_contact|default_if_none:'<em>Unknown</em>' }} </address> </div> @@ -29,9 +29,9 @@ <li><a href="{% url 'partners:partner_edit' partner.id %}">Edit Partner</a> {% if not partner.organization %}<span class="text-danger">please specify the Organization{% endif %} </li> - <li><a href="{% url 'partners:institution_edit' partner.institution.id %}">Edit Institution</a></li> + <li><a href="{% url 'organizations:organization_update' partner.organization.id %}">Update the Organization</a></li> <li><a href="{% url 'partners:partner_add_contact' partner.id %}">Add Contact</a></li> - <li><a href="{{partner.get_absolute_url}}">View events ({{partner.events.count}})</a></li> + <li><a href="{{ partner.get_absolute_url }}">View events ({{ partner.events.count }})</a></li> </ul> </div> diff --git a/partners/templates/partners/_partners_page_base.html b/partners/templates/partners/_partners_page_base.html index 8b768d2798a691882848847cf556f8cb3914747f..62956ba3ea8e66a3a6b3ed58c41a721275efe3d5 100644 --- a/partners/templates/partners/_partners_page_base.html +++ b/partners/templates/partners/_partners_page_base.html @@ -5,7 +5,7 @@ <div class="container"> <nav class="breadcrumb hidden-sm-down"> {% block breadcrumb_items %} - <a href="{% url 'partners:dashboard' %}" class="breadcrumb-item">Partner Page</a> + <a href="{% url 'partners:dashboard' %}" class="breadcrumb-item">Partners Page</a> {% endblock %} </nav> </div> diff --git a/partners/templates/partners/dashboard.html b/partners/templates/partners/dashboard.html index 7ba9733e3ad8c27c4cb43afbdf5bd852e37aae87..ce7dc05d2b232677ad6e0f8b37524cd508633fff 100644 --- a/partners/templates/partners/dashboard.html +++ b/partners/templates/partners/dashboard.html @@ -69,11 +69,11 @@ <ul class="list-unstyled mb-5"> {% for partner in request.user.partner_contact.partners.all %} <li class="media mb-2"> - <img class="d-flex mr-3" width="64" src="{% if partner.institution.logo %}{{partner.institution.logo.url}}{% endif %}" alt="Partner Logo"> + <img class="d-flex mr-3" width="64" src="{% if partner.organization.logo %}{{partner.organization.logo.url}}{% endif %}" alt="Partner Logo"> <div class="media-body"> - <h3 class="mt-0"><strong>{{partner.institution.name}}</strong></h3> + <h3 class="mt-0"><strong>{{partner.organization.name}}</strong></h3> <p> - {{partner.institution.acronym}} ({{partner.institution.get_kind_display}})<br> + {{partner.organization.acronym}} ({{partner.organization.get_orgtype_display}})<br> <a href="{{partner.get_absolute_url}}">View/edit</a> </p> </div> diff --git a/partners/templates/partners/institution_edit.html b/partners/templates/partners/institution_edit.html deleted file mode 100644 index 46fed7ad380de950082effef4fd9a292c37b1310..0000000000000000000000000000000000000000 --- a/partners/templates/partners/institution_edit.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends 'partners/_partners_page_base.html' %} - -{% block breadcrumb_items %} - {{block.super}} - <span class="breadcrumb-item">Edit Institution</span> -{% endblock %} - -{% block pagetitle %}{{block.super}} Edit Institution{% endblock pagetitle %} - -{% load bootstrap %} - -{% block content %} - -<div class="row"> - <div class="col-12"> - <h1 class="highlight">Edit Institution {{institution}}</h1> - </div> -</div> - -<div class="row"> - <div class="col-12"> - <form method="post" enctype="multipart/form-data"> - {% csrf_token %} - <div class="mb-5"> - {{ form|bootstrap }} - </div> - - <input class="btn btn-primary" type="submit" value="Submit"/> - </form> - </div> -</div> - -{% endblock content %} diff --git a/partners/templates/partners/partner_edit.html b/partners/templates/partners/partner_edit.html index e074cb3ef9c0b7d1f709e119f424157ed6eb3109..93aa56f1fc4a890b561b715284a54ca50b0a9c04 100644 --- a/partners/templates/partners/partner_edit.html +++ b/partners/templates/partners/partner_edit.html @@ -44,6 +44,9 @@ {% endblock content %} {% block footer_script %} +{ block.super }} +{{ form.media }} + <script> function delete_hide_contact_groups(delete_input) { input_el = $(delete_input); diff --git a/partners/templates/partners/partners_detail.html b/partners/templates/partners/partners_detail.html index da9797ea4e456ea387cc74fd56825f2af7dd265e..0187e4780e2527f72b60d1eb90cdad2c6ffb5f81 100644 --- a/partners/templates/partners/partners_detail.html +++ b/partners/templates/partners/partners_detail.html @@ -23,10 +23,10 @@ <a href="{% url 'partners:partner_edit' partner.id %}">Edit partner</a> {% endif %} <address> - <h3>{{ partner.institution.name }}</h3> - <strong>{{ partner.institution.acronym }} ({{ partner.institution.get_kind_display }})</strong><br> - {{ partner.institution.address|linebreaks }} - {{ partner.institution.get_country_display }}<br> + <h3>{{ partner.organization.name }}</h3> + <strong>{{ partner.organization.acronym }} ({{ partner.organization.get_orgtype_display }})</strong><br> + {{ partner.organization.address|linebreaks }} + {{ partner.organization.get_country_display }}<br> Main contact: {{ partner.main_contact|default_if_none:'<em>Unknown</em>' }} </address> diff --git a/partners/templates/partners/promote_prospartner.html b/partners/templates/partners/promote_prospartner.html index 437ad8ca295b966aff18eb5371c9591093701287..7393a4c35fb489903b578db95af5e659475ee38f 100644 --- a/partners/templates/partners/promote_prospartner.html +++ b/partners/templates/partners/promote_prospartner.html @@ -35,3 +35,8 @@ </div> {% endblock content %} + +{% block footer_script %} +{ block.super }} +{{ form.media }} +{% endblock %} diff --git a/partners/templates/partners/supporting_partners.html b/partners/templates/partners/supporting_partners.html index eae38ebca13b0ecc76bd581390d5f23629b964f5..54bb08a50e9bfb4ab831a5ce87783f675d1e744b 100644 --- a/partners/templates/partners/supporting_partners.html +++ b/partners/templates/partners/supporting_partners.html @@ -155,11 +155,11 @@ <ul class="list-unstyled mb-5"> {% for agreement in current_agreements %} <li class="media mb-2"> - <img class="d-flex mr-3 {{ agreement.partner.institution.css_class }}" width="192" src="{% if agreement.partner.institution.logo %}{{agreement.partner.institution.logo.url}}{% endif %}" alt="Partner Logo"> + <img class="d-flex mr-3 {{ agreement.partner.organization.css_class }}" width="192" src="{% if agreement.partner.organization.logo %}{{agreement.partner.organization.logo.url}}{% endif %}" alt="Partner Logo"> <div class="media-body"> <p> - <strong>{{agreement.partner.institution.name}}</strong><br> - {{agreement.partner.institution.get_country_display}} + <strong>{{ agreement.partner.organization.name }}</strong><br> + {{ agreement.partner.organization.get_country_display }} </p> </div> </li> diff --git a/partners/urls.py b/partners/urls.py index a11e5d3d9d9f1ab4a66370bb4ca3556ddee8fb80..a514a4c665da8aa5efcd96a8e30f0073294a3ae7 100644 --- a/partners/urls.py +++ b/partners/urls.py @@ -38,10 +38,6 @@ urlpatterns = [ url(r'agreements/(?P<agreement_id>[0-9]+)/attachments/(?P<attachment_id>[0-9]+)$', views.agreement_attachments, name='agreement_attachments'), - # Institutions - url(r'institutions/(?P<institution_id>[0-9]+)/edit$', views.institution_edit, - name='institution_edit'), - # Users url(r'activate/(?P<activation_key>.+)$', views.activate_account, name='activate_account'), diff --git a/partners/views.py b/partners/views.py index 5e61a0eb143c94601672e77e94009b2ef46229ae..4f3520a7d739fd277987b0987c80059c15590609 100644 --- a/partners/views.py +++ b/partners/views.py @@ -26,13 +26,12 @@ from .constants import PROSPECTIVE_PARTNER_REQUESTED,\ PROSPECTIVE_PARTNER_EVENT_REQUESTED, PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT,\ PROSPECTIVE_PARTNER_FOLLOWED_UP from .models import Partner, ProspectivePartner, ProspectiveContact, ContactRequest,\ - ProspectivePartnerEvent, MembershipAgreement, Contact, Institution,\ - PartnersAttachment + ProspectivePartnerEvent, MembershipAgreement, Contact, PartnersAttachment from .forms import ProspectivePartnerForm, ProspectiveContactForm,\ PromoteToPartnerForm,\ ProspectivePartnerEventForm, MembershipQueryForm,\ PartnerForm, ContactForm, ContactFormset, ContactModelFormset,\ - NewContactForm, InstitutionForm, ActivationForm, PartnerEventForm,\ + NewContactForm, ActivationForm, PartnerEventForm,\ MembershipAgreementForm, RequestContactForm, RequestContactFormSet,\ ProcessRequestContactForm, PartnersAttachmentFormSet, PartnersAttachmentForm @@ -125,7 +124,7 @@ def promote_prospartner(request, prospartner_id): contact_formset = ContactModelFormset(request.POST or None, queryset=prospartner.prospective_contacts.all()) if form.is_valid() and contact_formset.is_valid(): - partner, institution = form.promote_to_partner(request.user) + partner = form.promote_to_partner(request.user) contacts = contact_formset.promote_contacts(partner, request.user) messages.success(request, ('<h3>Upgraded Partner %s</h3>' '%i contacts have received a validation mail.') % @@ -234,26 +233,11 @@ def process_contact_requests(request): return render(request, 'partners/process_contact_requests.html', context) -################### -# Institution Views -################### -@permission_required('scipost.can_manage_SPB', return_403=True) -def institution_edit(request, institution_id): - institution = get_object_or_404(Institution, id=institution_id) - form = InstitutionForm(request.POST or None, request.FILES or None, instance=institution) - if form.is_valid(): - form.save() - messages.success(request, 'Institution has been updated.') - return redirect(reverse('partners:dashboard')) - context = { - 'form': form - } - return render(request, 'partners/institution_edit.html', context) - ########################### # Prospective Partner Views ########################### + @permission_required('scipost.can_manage_SPB', return_403=True) def add_prospective_partner(request): form = ProspectivePartnerForm(request.POST or None) diff --git a/profiles/migrations/0011_auto_20181006_2341.py b/profiles/migrations/0011_auto_20181006_2341.py new file mode 100644 index 0000000000000000000000000000000000000000..af1221f59d1a8680dd162060137682a46292c50e --- /dev/null +++ b/profiles/migrations/0011_auto_20181006_2341.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-10-06 21:41 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0010_auto_20181002_1114'), + ] + + operations = [ + migrations.AlterModelOptions( + name='profileemail', + options={'ordering': ['-primary', '-still_valid', 'email']}, + ), + migrations.RemoveField( + model_name='profile', + name='email', + ), + ] diff --git a/profiles/templates/profiles/profile_confirm_delete.html b/profiles/templates/profiles/profile_confirm_delete.html index 471ec55535f3e5c98594c37352889f67c9069a97..f23f8a9e62006e8f7905fee5e4e983357903b15f 100644 --- a/profiles/templates/profiles/profile_confirm_delete.html +++ b/profiles/templates/profiles/profile_confirm_delete.html @@ -18,12 +18,11 @@ </div> <div class="row"> <div class="col-12"> - <form method="post"> - {% csrf_token %} - <h3 class="mb-2">Are you sure you want to delete this Profile?</h3> - <input type="submit" class="btn btn-danger" value="Yes, delete it" /> - </form> - </ul> + <form method="post"> + {% csrf_token %} + <h3 class="mb-2">Are you sure you want to delete this Profile?</h3> + <input type="submit" class="btn btn-danger" value="Yes, delete it" /> + </form> </div> </div> diff --git a/scipost/management/commands/add_groups_and_permissions.py b/scipost/management/commands/add_groups_and_permissions.py index 928cd548f77e93ba1c90057be7a816dc99726922..f701e296f42347dbd93874192f404088b6531354 100644 --- a/scipost/management/commands/add_groups_and_permissions.py +++ b/scipost/management/commands/add_groups_and_permissions.py @@ -291,6 +291,10 @@ class Command(BaseCommand): content_type=content_type) # Financial administration + can_manage_subsidies, created = Permission.objects.get_or_create( + codename='can_manage_subsidies', + name='Can manage subsidies', + content_type=content_type) can_view_timesheets, created = Permission.objects.get_or_create( codename='can_view_timesheets', name='Can view timesheets', @@ -346,6 +350,7 @@ class Command(BaseCommand): ]) FinancialAdmin.permissions.set([ + can_manage_subsidies, can_view_timesheets, ]) diff --git a/scipost/models.py b/scipost/models.py index d56d55feceb499621c3e60f4ee78c712362d443d..a4bec62c981e70b44de3b2c03002cb395f2345e1 100644 --- a/scipost/models.py +++ b/scipost/models.py @@ -84,16 +84,23 @@ class Contributor(models.Model): """Check if Contributor is currently not marked as unavailable.""" return not self.unavailability_periods.today().exists() - def is_EdCol_Admin(self): - """Check if Contributor is an Editorial Administrator.""" - return (self.user.groups.filter(name='Editorial Administrators').exists() - or self.user.is_superuser) - def is_SP_Admin(self): """Check if Contributor is a SciPost Administrator.""" return (self.user.groups.filter(name='SciPost Administrators').exists() or self.user.is_superuser) + def is_Fin_Admin(self): + """ + Check if Contributor is a SciPost Financial Administrator. + """ + return (self.user.groups.filter(name='Financial Administrators').exists() + or self.user.is_superuser) + + def is_EdCol_Admin(self): + """Check if Contributor is an Editorial Administrator.""" + return (self.user.groups.filter(name='Editorial Administrators').exists() + or self.user.is_superuser) + def is_MEC(self): """Check if Contributor is a member of the Editorial College.""" return self.fellowships.active().exists() or self.user.is_superuser diff --git a/scipost/templates/partials/scipost/personal_page/admin_actions.html b/scipost/templates/partials/scipost/personal_page/admin_actions.html new file mode 100644 index 0000000000000000000000000000000000000000..d0f616fdc56b2e5bf990d54f104056df9b3a3d58 --- /dev/null +++ b/scipost/templates/partials/scipost/personal_page/admin_actions.html @@ -0,0 +1,87 @@ +{% load user_groups %} +{% is_scipost_admin request.user as is_scipost_admin %} +<div class="row"> + <div class="col-12"> + <div class="card card-grey"> + <div class="card-body"> + <h2 class="card-title mb-0">Admin Actions</h2> + </div> + </div> + </div> +</div> + +<div class="row"> + {% if perms.scipost.can_vet_registration_requests or perms.scipost.can_create_registration_invitations or perms.scipost.can_resend_registration_requests %} + <div class="col-md-4"> + <h3>Registration actions</h3> + <ul> + {% if perms.scipost.can_vet_registration_requests %} + <li><a href="{% url 'scipost:vet_registration_requests' %}">Vet Registration requests</a> ({{ nr_reg_to_vet }})</li> + {% endif %} + {% if perms.scipost.can_resend_registration_requests %} + <li><a href="{% url 'scipost:registration_requests' %}">Awaiting validation</a> ({{ nr_reg_awaiting_validation }})</li> + {% endif %} + {% if perms.scipost.can_create_registration_invitations %} + <li><a href="{% url 'invitations:list' %}">Manage Registration Invitations</a></li> + {% endif %} + </ul> + + {% if perms.scipost.can_manage_registration_invitations %} + <h3>Notifications</h3> + <ul> + <li><a href="{% url 'invitations:citation_notification_list' %}">Manage citation notifications</a></li> + </ul> + {% endif %} + + {% if is_scipost_admin %} + <h3>Email communications</h3> + <ul> + {% if perms.scipost.can_email_group_members %} + <li><a href="{% url 'scipost:email_group_members' %}">Email Group Members</a></li> + {% endif %} + {% if perms.scipost.can_email_particulars %} + <li><a href="{% url 'scipost:send_precooked_email' %}">Send a precooked email</a></li> + <li><a href="{% url 'scipost:email_particular' %}">Email a particular individual/address</a></li> + {% endif %} + {% if perms.scipost.can_manage_mailchimp %} + <li><a href="{% url 'mailing_lists:overview' %}">Manage mailing lists</a></li> + {% endif %} + </ul> + + {% endif %} + + </div> + {% endif %} + + <div class="col-md-4"> + {% if perms.scipost.can_view_profiles %} + <h3>Profiles</h3> + <ul> + <li><a href="{% url 'profiles:profiles' %}">List/Manage Profiles</a></li> + </ul> + {% endif %} + + {% if perms.scipost.can_manage_organizations %} + <h3>Organizations</h3> + <ul> + <li><a href="{% url 'organizations:organizations' %}">Manage Organizations</a></li> + <li><a href="{% url 'affiliations:institutions' %}">Manage Institutions database</a></li> + </ul> + {% endif %} + + </div> + + <div class="col-md-4"> + <h3>Finances</h3> + <ul> + {% if perms.scipost.can_manage_subsidies %} + <li><a href="{% url 'finances:subsidies' %}">Manage Subsidies</a></li> + {% endif %} + {% if perms.scipost.can_view_timesheets %} + <li><a href="{% url 'finances:timesheets' %}">Production Team Timesheets</a></li> + {% endif %} + </ul> + </div> + + +</div> diff --git a/scipost/templates/partials/scipost/personal_page/editorial_actions.html b/scipost/templates/partials/scipost/personal_page/editorial_actions.html index af0fe691f063ea0f99dd1c500a33b7e2c25d2fd7..df5d934427c521ef7fbf03828e29a9bc392a4b11 100644 --- a/scipost/templates/partials/scipost/personal_page/editorial_actions.html +++ b/scipost/templates/partials/scipost/personal_page/editorial_actions.html @@ -11,58 +11,6 @@ </div> <div class="row"> - {% if perms.scipost.can_vet_registration_requests or perms.scipost.can_create_registration_invitations or perms.scipost.can_resend_registration_requests %} - <div class="col-md-4"> - <h3>Registration actions</h3> - <ul> - {% if perms.scipost.can_vet_registration_requests %} - <li><a href="{% url 'scipost:vet_registration_requests' %}">Vet Registration requests</a> ({{ nr_reg_to_vet }})</li> - {% endif %} - {% if perms.scipost.can_resend_registration_requests %} - <li><a href="{% url 'scipost:registration_requests' %}">Awaiting validation</a> ({{ nr_reg_awaiting_validation }})</li> - {% endif %} - {% if perms.scipost.can_create_registration_invitations %} - <li><a href="{% url 'invitations:list' %}">Manage Registration Invitations</a></li> - {% endif %} - </ul> - - {% if perms.scipost.can_manage_registration_invitations %} - <h3>Notifications</h3> - <ul> - <li><a href="{% url 'invitations:citation_notification_list' %}">Manage citation notifications</a></li> - </ul> - {% endif %} - - {% if is_scipost_admin %} - <h3>Email communications</h3> - <ul> - {% if perms.scipost.can_email_group_members %} - <li><a href="{% url 'scipost:email_group_members' %}">Email Group Members</a></li> - {% endif %} - {% if perms.scipost.can_email_particulars %} - <li><a href="{% url 'scipost:send_precooked_email' %}">Send a precooked email</a></li> - <li><a href="{% url 'scipost:email_particular' %}">Email a particular individual/address</a></li> - {% endif %} - {% if perms.scipost.can_manage_mailchimp %} - <li><a href="{% url 'mailing_lists:overview' %}">Manage mailing lists</a></li> - {% endif %} - </ul> - - <h3>SciPost Administation</h3> - <ul> - <li><a href="{% url 'organizations:organizations' %}">Manage Organizations</a></li> - <li><a href="{% url 'affiliations:institutions' %}">Manage Institutions database</a></li> - </ul> - {% endif %} - - {% if perms.scipost.can_view_timesheets %} - <h3>Finance</h3> - <ul> - <li><a href="{% url 'finances:timesheets' %}">Production Team Timesheets</a></li> - </ul> - {% endif %} - </div> - {% endif %} <div class="col-md-4"> {% if perms.scipost.can_vet_comments or perms.scipost.can_vet_submitted_reports %} @@ -100,27 +48,6 @@ </ul> {% endif %} - {% if perms.scipost.can_view_profiles %} - <h3>Profiles</h3> - <ul> - <li><a href="{% url 'profiles:profiles' %}">List/Manage Profiles</a></li> - </ul> - {% endif %} - - {% if perms.scipost.can_manage_college_composition %} - <h3>Colleges and Fellowships</h3> - <ul> - <li><a href="{% url 'colleges:potential_fellowships' %}">Manage Potential Fellowships</a></li> - <li><a href="{% url 'colleges:fellowships' %}">Manage Fellowships</a></li> - </ul> - {% endif %} - - {% if perms.scipost.can_attend_VGMs %} - <h3>Virtual General Meetings</h3> - <ul> - <li><a href="{% url 'virtualmeetings:VGMs' %}">List of VGMs</a></li> - </ul> - {% endif %} </div> {% if perms.scipost.can_oversee_refereeing or request.user.contributor.is_MEC %} @@ -156,6 +83,24 @@ {% endif %} </div> {% endif %} + + <div class="col-md-4"> + {% if perms.scipost.can_manage_college_composition %} + <h3>Colleges and Fellowships</h3> + <ul> + <li><a href="{% url 'colleges:potential_fellowships' %}">Manage Potential Fellowships</a></li> + <li><a href="{% url 'colleges:fellowships' %}">Manage Fellowships</a></li> + </ul> + {% endif %} + + {% if perms.scipost.can_attend_VGMs %} + <h3>Virtual General Meetings</h3> + <ul> + <li><a href="{% url 'virtualmeetings:VGMs' %}">List of VGMs</a></li> + </ul> + {% endif %} + </div> + </div> {% if active_assignments %} diff --git a/scipost/templates/scipost/index.html b/scipost/templates/scipost/index.html index 2fc8a47ebe17eae4bce6120e4e8a4c0fe07b03a7..a4717dcd58d531ec70046d5410c46ae2f393543f 100644 --- a/scipost/templates/scipost/index.html +++ b/scipost/templates/scipost/index.html @@ -201,8 +201,8 @@ <div class="supporting-partners"> <ul id="fader"> {% for agreement in current_agreements %} - {% if agreement.partner.institution.logo %} - <li class="item"><img height="100" class="rounded" src="{{ agreement.partner.institution.logo.url }}" alt="Partner Logo"></li> + {% if agreement.partner.organization.logo %} + <li class="item"><img height="100" class="rounded" src="{{ agreement.partner.organization.logo.url }}" alt="Partner Logo"></li> {% endif %} {% endfor %} </ul> diff --git a/scipost/templates/scipost/personal_page.html b/scipost/templates/scipost/personal_page.html index b48c766d67fdbe009375dcc820a291ad01bb64b3..2f35382ae66abf10bf2a6289f1c83c5a733d0f5c 100644 --- a/scipost/templates/scipost/personal_page.html +++ b/scipost/templates/scipost/personal_page.html @@ -27,16 +27,17 @@ {% else %} {# Save all Permission groups into template variables #} - {% is_edcol_admin request.user as is_edcol_admin %} - {% is_scipost_admin request.user as is_scipost_admin %} - {% is_editorial_college request.user as is_editorial_college %} - {% is_advisory_board request.user as is_advisory_board %} - {% is_vetting_editor request.user as is_vetting_editor %} - {% is_ambassador request.user as is_ambassador %} - {% is_junior_ambassador request.user as is_junior_ambassador %} - {% is_registered_contributor request.user as is_registered_contributor %} - {% is_tester request.user as is_tester %} - {% is_production_officer request.user as is_production_officer %} + {% is_edcol_admin request.user as is_edcol_admin %} + {% is_scipost_admin request.user as is_scipost_admin %} + {% is_financial_admin request.user as is_financial_admin %} + {% is_editorial_college request.user as is_editorial_college %} + {% is_advisory_board request.user as is_advisory_board %} + {% is_vetting_editor request.user as is_vetting_editor %} + {% is_ambassador request.user as is_ambassador %} + {% is_junior_ambassador request.user as is_junior_ambassador %} + {% is_registered_contributor request.user as is_registered_contributor %} + {% is_tester request.user as is_tester %} + {% is_production_officer request.user as is_production_officer %} <div class="row"> <div class="col-12"> @@ -47,6 +48,11 @@ <li class="nav-item btn btn-outline-secondary"> <a class="nav-link" {% if tab == 'account' %}sp-autoload='true'{% endif %} href="#account" sp-dynamic-load="{% url 'scipost:personal_page_account' %}" data-toggle="tab">Account</a> </li> + {% if is_scipost_admin or is_financial_admin %} + <li class="nav-item btn btn-outline-secondary"> + <a class="nav-link" {% if tab == 'admin_actions' %}sp-autoload='true'{% endif %} href="#admin-actions" sp-dynamic-load="{% url 'scipost:personal_page_admin_actions' %}" data-toggle="tab">Admin Actions</a> + </li> + {% endif %} {% if is_scipost_admin or is_edcol_admin or is_editorial_college or is_advisory_board or is_vetting_editor or is_ambassador or is_junior_ambassador %} <li class="nav-item btn btn-outline-secondary"> <a class="nav-link" {% if tab == 'editorial_actions' %}sp-autoload='true'{% endif %} href="#editorial-actions" sp-dynamic-load="{% url 'scipost:personal_page_editorial_actions' %}" data-toggle="tab">Editorial Actions</a> @@ -94,6 +100,12 @@ <div class="tab-pane active" id="account" role="tabpanel"> </div><!-- End tab --> + {% if is_scipost_admin %} + <!-- Tab: Admin Actions --> + <div class="tab-pane" id="admin-actions" role="tabpanel"> + </div> + {% endif %} + {% if is_scipost_admin or is_edcol_admin or is_editorial_college or is_advisory_board or is_vetting_editor or is_ambassador or is_junior_ambassador %} <!-- Tab: Editorial Actions --> <div class="tab-pane" id="editorial-actions" role="tabpanel"> diff --git a/scipost/templatetags/user_groups.py b/scipost/templatetags/user_groups.py index 7f58dd5944097119fdc3a4e8033b2275510aa597..21fdecf8a109e12616e830c28fe843c320dea1ec 100644 --- a/scipost/templatetags/user_groups.py +++ b/scipost/templatetags/user_groups.py @@ -25,6 +25,15 @@ def is_scipost_admin(user): return user.groups.filter(name='SciPost Administrators').exists() or user.is_superuser +@register.simple_tag +def is_financial_admin(user): + """ + Assign template variable (boolean) to check if user is Financial Administrator. + This assignment is limited to a certain context block! + """ + return user.groups.filter(name='Financial Administrators').exists() or user.is_superuser + + @register.simple_tag def is_editorial_college(user): """ diff --git a/scipost/urls.py b/scipost/urls.py index 857e7ea35b14c2d183c5460434fc9974c42991aa..cbbf0b3ccadfd6c117bcc72cf696bd79f5707799 100644 --- a/scipost/urls.py +++ b/scipost/urls.py @@ -112,6 +112,8 @@ urlpatterns = [ url(r'^personal_page/$', views.personal_page, name='personal_page'), url(r'^personal_page/account$', views.personal_page, name='personal_page_account', kwargs={'tab': 'account'}), + url(r'^personal_page/admin_actions$', views.personal_page, + name='personal_page_admin_actions', kwargs={'tab': 'admin_actions'}), url(r'^personal_page/editorial_actions$', views.personal_page, name='personal_page_editorial_actions', kwargs={'tab': 'editorial_actions'}), url(r'^personal_page/refereeing$', views.personal_page, diff --git a/scipost/views.py b/scipost/views.py index 51c421a3e51aabd0ce55519ca52d5b922b76e0d9..3ed4f3ef2eebbca601a6cd49455f243b1052e7a2 100644 --- a/scipost/views.py +++ b/scipost/views.py @@ -412,8 +412,8 @@ def delete_unavailable_period(request, period_id): @login_required @is_contributor_user() -def _personal_page_editorial_account(request): - """Personal Page tab: Account.""" +def _personal_page_account(request): + """ Personal Page tab: Account. """ contributor = request.user.contributor context = { 'contributor': contributor, @@ -423,9 +423,33 @@ def _personal_page_editorial_account(request): return render(request, 'partials/scipost/personal_page/account.html', context) +@login_required +@is_contributor_user() +def _personal_page_admin_actions(request): + """ Personal Page tab: Admin Actions. """ + permission = request.user.groups.filter(name__in=[ + 'SciPost Administrators', + 'Financial Administrators']).exists() or request.user.is_superuser + + if not permission: + raise PermissionDenied + + context = {} + contributor = request.user.contributor + + if contributor.is_SP_Admin(): + # count the number of pending registration requests + context['nr_reg_to_vet'] = Contributor.objects.awaiting_vetting().count() + context['nr_reg_awaiting_validation'] = Contributor.objects.awaiting_validation().count() + + return render(request, 'partials/scipost/personal_page/admin_actions.html', context) + + @is_contributor_user() def _personal_page_editorial_actions(request): - """Personal Page tab: Editorial Actions.""" + """ + Personal Page tab: Editorial Actions. + """ permission = request.user.groups.filter(name__in=[ 'Ambassadors', 'Advisory Board', @@ -441,9 +465,6 @@ def _personal_page_editorial_actions(request): contributor = request.user.contributor if contributor.is_SP_Admin(): - # count the number of pending registration requests - context['nr_reg_to_vet'] = Contributor.objects.awaiting_vetting().count() - context['nr_reg_awaiting_validation'] = Contributor.objects.awaiting_validation().count() context['nr_submissions_to_assign'] = Submission.objects.prescreening().count() context['nr_recommendations_to_prepare_for_voting'] = \ EICRecommendation.objects.voting_in_preparation().count() @@ -472,7 +493,9 @@ def _personal_page_editorial_actions(request): @permission_required('scipost.can_referee', return_403=True) @is_contributor_user() def _personal_page_refereeing(request): - """Personal Page tab: Refereeing.""" + """ + Personal Page tab: Refereeing. + """ context = { 'contributor': request.user.contributor } @@ -482,7 +505,9 @@ def _personal_page_refereeing(request): @login_required @is_contributor_user() def _personal_page_publications(request): - """Personal Page tab: Publications.""" + """ + Personal Page tab: Publications. + """ contributor = request.user.contributor context = { 'contributor': contributor, @@ -499,7 +524,9 @@ def _personal_page_publications(request): @login_required @is_contributor_user() def _personal_page_submissions(request): - """Personal Page tab: Submissions.""" + """ + Personal Page tab: Submissions. + """ contributor = request.user.contributor context = {'contributor': contributor} @@ -516,7 +543,9 @@ def _personal_page_submissions(request): @login_required @is_contributor_user() def _personal_page_commentaries(request): - """Personal Page tab: Commentaries.""" + """ + Personal Page tab: Commentaries. + """ contributor = request.user.contributor context = {'contributor': contributor} @@ -532,7 +561,9 @@ def _personal_page_commentaries(request): @login_required @is_contributor_user() def _personal_page_theses(request): - """Personal Page tab: Theses.""" + """ + Personal Page tab: Theses. + """ contributor = request.user.contributor context = {'contributor': contributor} @@ -548,7 +579,9 @@ def _personal_page_theses(request): @login_required @is_contributor_user() def _personal_page_comments(request): - """Personal Page tab: Comments.""" + """ + Personal Page tab: Comments. + """ contributor = request.user.contributor context = { 'contributor': contributor, @@ -561,7 +594,9 @@ def _personal_page_comments(request): @login_required @is_contributor_user() def _personal_page_author_replies(request): - """Personal Page tab: Author Replies.""" + """ + Personal Page tab: Author Replies. + """ contributor = request.user.contributor context = { 'contributor': contributor, @@ -573,10 +608,14 @@ def _personal_page_author_replies(request): @login_required def personal_page(request, tab='account'): - """Personal Page is the main view for accessing user functions.""" + """ + Personal Page is the main view for accessing user functions. + """ if request.is_ajax(): if tab == 'account': - return _personal_page_editorial_account(request) + return _personal_page_account(request) + elif tab == 'admin_actions': + return _personal_page_admin_actions(request) elif tab == 'editorial_actions': return _personal_page_editorial_actions(request) elif tab == 'refereeing': diff --git a/submissions/templates/submissions/admin/submission_reassign.html b/submissions/templates/submissions/admin/submission_reassign.html index 9a7df7e7ec835f7bc95043026cd1fa30f5cd2b63..c49cfa1d63d6184dffd4474678b98d5a00f0d362 100644 --- a/submissions/templates/submissions/admin/submission_reassign.html +++ b/submissions/templates/submissions/admin/submission_reassign.html @@ -26,7 +26,7 @@ <form method="post"> {% csrf_token %} {{ form|bootstrap }} - <input type="submit" class="btn btn-primary" onClick="confirm('Are you damn sure? There is no way back here.')" value="Confirm reassignment"> + <input type="submit" class="btn btn-primary" onClick="confirm('Are you certain? There is no way back here.')" value="Confirm reassignment"> </form> </div>