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