From 51a93ea4cc73c32d156716f77f754a4b2952dfb5 Mon Sep 17 00:00:00 2001 From: George Katsikas <giorgakis.katsikas@gmail.com> Date: Mon, 27 May 2024 13:34:39 +0200 Subject: [PATCH] allow affiliate journal managers to create orgs fixes #212 --- .../affiliatejournal_subsidy_list.html | 1 + scipost_django/organizations/forms.py | 2 + scipost_django/organizations/utils.py | 4 +- scipost_django/organizations/views.py | 69 ++++++++++++++----- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/scipost_django/affiliates/templates/affiliates/affiliatejournal_subsidy_list.html b/scipost_django/affiliates/templates/affiliates/affiliatejournal_subsidy_list.html index 402842d88..de543da3c 100644 --- a/scipost_django/affiliates/templates/affiliates/affiliatejournal_subsidy_list.html +++ b/scipost_django/affiliates/templates/affiliates/affiliatejournal_subsidy_list.html @@ -23,6 +23,7 @@ <div class="border border-warning mb-2 p-2"> <strong class="text-warning">Management</strong> <h4>Add a Subsidy</h4> + <p>Use the form below to add a subsidy to the journal. If you do not find the organization you are looking for, you may <a href="{% url "organizations:organization_create" %}">create it</a>.</p> <form action="{% url 'affiliates:journal_add_subsidy' slug=journal.slug %}" method="post"> {% csrf_token %} {{ add_subsidy_form.as_p }} diff --git a/scipost_django/organizations/forms.py b/scipost_django/organizations/forms.py index e1e4242b6..ea7d73d97 100644 --- a/scipost_django/organizations/forms.py +++ b/scipost_django/organizations/forms.py @@ -82,6 +82,7 @@ class OrganizationForm(forms.ModelForm): widgets = { "status": forms.RadioSelect, "address": forms.Textarea(attrs={"rows": 1}), + "ror_json": forms.HiddenInput(), } def __init__(self, *args, **kwargs): @@ -93,6 +94,7 @@ class OrganizationForm(forms.ModelForm): self.helper = FormHelper() self.helper.layout = Layout( Div( + Div(Field("ror_json")), Div(Field("ror_id"), css_class="col"), Div( Submit( diff --git a/scipost_django/organizations/utils.py b/scipost_django/organizations/utils.py index fa81b6676..67cdb77be 100644 --- a/scipost_django/organizations/utils.py +++ b/scipost_django/organizations/utils.py @@ -1,4 +1,3 @@ -import json import requests import urllib @@ -60,7 +59,6 @@ class RORAPIHandler: if k.endswith("__not"): filters.append(name[k[:-5]] != v) elif k.endswith("__in"): - print(v, name[k[:-4]]) filters.append(v in name[k[:-4]]) else: filters.append(name[k] == v) @@ -74,7 +72,7 @@ class RORAPIHandler: geonames = result.get("locations", [{}])[0].get("geonames_details", {}) organization_fields = { - "ror_json": json.dumps(result), + "ror_json": result, "name": _first_name(result, types__in="ror_display"), "name_original": _first_name(result, types__in="label", lang__not="en"), "acronym": _first_name(result, types__in="acronym"), diff --git a/scipost_django/organizations/views.py b/scipost_django/organizations/views.py index a46a39b00..8fdd1d816 100644 --- a/scipost_django/organizations/views.py +++ b/scipost_django/organizations/views.py @@ -2,10 +2,12 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" +import json from django.contrib import messages from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import UserPassesTestMixin from django.core.exceptions import PermissionDenied +from django.http import QueryDict from django.template.response import TemplateResponse from django.urls import reverse_lazy from django.db import transaction @@ -37,6 +39,7 @@ from .forms import ( ) from .models import Organization, OrganizationEvent, ContactPerson, Contact, ContactRole +from affiliates.models import AffiliateJournal from funders.models import Funder from mails.utils import DirectMailUtil from mails.views import MailEditorSubview @@ -114,30 +117,60 @@ class OrganizationCreateView(PermissionsMixin, CreateView): "organizations:organization_detail", kwargs={"pk": self.object.id} ) - def get_form(self, form_class=None): - # Handle normal form submission - if self.request.POST.get("submit", ""): - return super().get_form(form_class) + def has_permission(self): + """ + Allow those with explicit permission and any + affiliate journal managers to create organizations. + """ + is_any_affiliate_manager = any( + self.request.user.has_perm("manage_journal_content", journal) + for journal in AffiliateJournal.objects.all() + ) + self.is_any_affiliate_manager = ( + is_any_affiliate_manager and not self.request.user.is_superuser + ) - form_overrides = {} - if self.request.POST.get("fetch_ror", ""): + return super().has_permission() or is_any_affiliate_manager - # Try to fetch ROR data if ror_id is provided - ror_id = self.request.POST.get("ror_id", "") - # ror_api_handler = RORAPIHandler() - # ror_data = ror_api_handler.from_id(ror_id) - organization_fields = RORAPIHandler.organization_from_ror_id(ror_id) + def get_form_kwargs(self): + """ + Update the form kwargs to include ROR data if requested. + """ + kwargs = {} + ror_id = self.request.POST.get("ror_id", None) - # Guard against empty ror_id or no data found - if ror_id is None or organization_fields == {}: + ror_data = {} + if ror_id: + ror_data = RORAPIHandler.organization_from_ror_id(ror_id) + if ror_data == {}: messages.error(self.request, "No ROR data found for this ID.") - form_overrides |= organization_fields + ror_data["ror_id"] = ror_id + kwargs = {"initial": ror_data} - # Construct form (with ROR data) - if not form_class: - form_class = self.get_form_class() - form = form_class(self.request.POST.dict() | form_overrides or None) + # Replace POST data with the ROR data + should_replace_ror = self.request.POST.get("fetch_ror", False) + if should_replace_ror: + # JSON fields need to be serialized for the "data" key + ror_data["ror_json"] = json.dumps(ror_data["ror_json"]) + kwargs["data"] = ror_data + + return super().get_form_kwargs() | kwargs + + def get_form(self, form_class=None): + form = super().get_form(form_class) + + # Disable all fields except orgtype, status and ror_id for affiliate managers + if getattr(self, "is_any_affiliate_manager", False): + for field in form.fields: + form.fields[field].disabled = True + + form.fields["orgtype"].disabled = False + form.fields["status"].disabled = False + form.fields["ror_id"].disabled = False + + form.fields["ror_json"].required = True + form.fields["ror_id"].required = True return form -- GitLab