From 76c909479c61ceccd71ba8e6cd862b6863b876aa Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Thu, 11 Nov 2021 15:32:51 +0100
Subject: [PATCH 1/9] Add the cerebrum-client to the requirments

---
 poetry.lock    | 29 +++++++++++++++++++++++++----
 pyproject.toml |  1 +
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/poetry.lock b/poetry.lock
index 84dfd0d4..2c491b9f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -119,6 +119,25 @@ jinxed = {version = ">=1.1.0", markers = "platform_system == \"Windows\""}
 six = ">=1.9.0"
 wcwidth = ">=0.1.4"
 
+[[package]]
+name = "cerebrum-client"
+version = "1.9.2"
+description = "Client for the Cerebrum REST API"
+category = "main"
+optional = false
+python-versions = "*"
+develop = false
+
+[package.dependencies]
+pydantic = "*"
+requests = "*"
+
+[package.source]
+type = "git"
+url = "https://git.app.uib.no/it-bott-integrasjoner/cerebrum-client.git"
+reference = "v1.9.2"
+resolved_reference = "95a183956ddd164f2a9fa86ed219ef640e72b7be"
+
 [[package]]
 name = "certifi"
 version = "2021.10.8"
@@ -1099,14 +1118,14 @@ test = ["fixtures", "mock", "purl", "pytest", "sphinx", "testrepository (>=0.0.1
 
 [[package]]
 name = "rope"
-version = "0.21.0"
+version = "0.21.1"
 description = "a python refactoring library..."
 category = "dev"
 optional = false
 python-versions = "*"
 
 [package.extras]
-dev = ["pytest", "pytest-timeout"]
+dev = ["build", "pytest", "pytest-timeout"]
 
 [[package]]
 name = "sentry-sdk"
@@ -1284,7 +1303,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.9"
-content-hash = "45574277e3b663b9eb9b18a24ef0996878944461d137b084199690e9683e32f7"
+content-hash = "9887d688cf3c515273b5ccbc7313ba2795d6fbf6e6828091537761c376dbee87"
 
 [metadata.files]
 ansicon = [
@@ -1327,6 +1346,7 @@ blessed = [
     {file = "blessed-1.19.0-py2.py3-none-any.whl", hash = "sha256:1f2d462631b2b6d2d4c3c65b54ef79ad87a6ca2dd55255df2f8d739fcc8a1ddb"},
     {file = "blessed-1.19.0.tar.gz", hash = "sha256:4db0f94e5761aea330b528e84a250027ffe996b5a94bf03e502600c9a5ad7a61"},
 ]
+cerebrum-client = []
 certifi = [
     {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
     {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
@@ -2012,7 +2032,8 @@ requests-mock = [
     {file = "requests_mock-1.9.3-py2.py3-none-any.whl", hash = "sha256:0a2d38a117c08bb78939ec163522976ad59a6b7fdd82b709e23bb98004a44970"},
 ]
 rope = [
-    {file = "rope-0.21.0.tar.gz", hash = "sha256:366789e069a267296889b2ee7631f9278173b5e7d468f2ea08abe26069a52aef"},
+    {file = "rope-0.21.1-py3-none-any.whl", hash = "sha256:7fa433eb946bf806a419a3da354cd9b56d565cadf7159952c8e71c72d4b1a8ec"},
+    {file = "rope-0.21.1.tar.gz", hash = "sha256:4fe61ea25ca64f1819be57fbb44ee07ca98b3dce08a0ceaaf3c6d6166b603f7f"},
 ]
 sentry-sdk = [
     {file = "sentry-sdk-1.4.3.tar.gz", hash = "sha256:b9844751e40710e84a457c5bc29b21c383ccb2b63d76eeaad72f7f1c808c8828"},
diff --git a/pyproject.toml b/pyproject.toml
index 8759d509..dd848269 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,6 +27,7 @@ django-q = "^1.3.9"
 django-structlog = "^2.1.3"
 structlog = "^21.2.0"
 phonenumbers = "^8.12.35"
+cerebrum-client = {git = "https://git.app.uib.no/it-bott-integrasjoner/cerebrum-client.git", rev = "v1.9.2"}
 
 [tool.poetry.dev-dependencies]
 Faker = "*"
-- 
GitLab


From 43cb3d8a7e981513346ca24bb6878a2930e82cc6 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Thu, 11 Nov 2021 15:33:32 +0100
Subject: [PATCH 2/9] Do not typecheck the cerebrum-client

---
 mypy.ini | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/mypy.ini b/mypy.ini
index 67b5755d..971a70a5 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -14,6 +14,9 @@ django_settings_module = gregsite.settings.dev
 # Ignore problems in auto generated modules.
 ignore_errors = True
 
+[mypy-cerebrum_client.*]
+ignore_missing_imports = True
+
 [mypy-dirtyfields]
 ignore_missing_imports = True
 
-- 
GitLab


From 299a6954194bda3ab46256ba1f5c93d1fa229e97 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Thu, 11 Nov 2021 15:34:38 +0100
Subject: [PATCH 3/9] Add a automatic flag and source to the
 SponsorOrganizationalUnit model

---
 .../0014_add_sponsor_ou_source_data.py        | 23 +++++++++++++++++++
 greg/models.py                                |  2 ++
 2 files changed, 25 insertions(+)
 create mode 100644 greg/migrations/0014_add_sponsor_ou_source_data.py

diff --git a/greg/migrations/0014_add_sponsor_ou_source_data.py b/greg/migrations/0014_add_sponsor_ou_source_data.py
new file mode 100644
index 00000000..734591e8
--- /dev/null
+++ b/greg/migrations/0014_add_sponsor_ou_source_data.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.9 on 2021-11-11 14:35
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('greg', '0013_delete_scheduletask'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='sponsororganizationalunit',
+            name='automatic',
+            field=models.BooleanField(default=False),
+        ),
+        migrations.AddField(
+            model_name='sponsororganizationalunit',
+            name='source',
+            field=models.CharField(blank=True, max_length=256),
+        ),
+    ]
diff --git a/greg/models.py b/greg/models.py
index 168c69d3..90d54ca0 100644
--- a/greg/models.py
+++ b/greg/models.py
@@ -458,6 +458,8 @@ class SponsorOrganizationalUnit(BaseModel):
         "OrganizationalUnit", on_delete=models.PROTECT, related_name="link_unit"
     )
     hierarchical_access = models.BooleanField()
+    automatic = models.BooleanField(default=False)
+    source = models.CharField(max_length=256, blank=True)
 
     class Meta:
         constraints = [
-- 
GitLab


From 2a4db6bc236b3b7da819844702d2d3b2ed894684 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Thu, 11 Nov 2021 15:43:25 +0100
Subject: [PATCH 4/9] Add example cerebrum_client config

---
 gregsite/settings/dev.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gregsite/settings/dev.py b/gregsite/settings/dev.py
index 5120e02b..cae8f715 100644
--- a/gregsite/settings/dev.py
+++ b/gregsite/settings/dev.py
@@ -17,6 +17,11 @@ ORGREG_CLIENT = {
     "headers": {"X-Gravitee-Api-Key": "bar"},
 }
 
+CEREBRUM_CLIENT = {
+    "url": "https://example.com/fake/",
+    "headers": {"X-Gravitee-Api-Key": "bar"},
+}
+
 Q_CLUSTER = {
     "name": "greg",
     "workers": 4,
-- 
GitLab


From 6995c681e2988d51330d7398fa4c267cf5372029 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Mon, 15 Nov 2021 07:59:50 +0100
Subject: [PATCH 5/9] New command for importing sponsors from Cerebrum

---
 .../commands/import_sponsors_from_cerebrum.py | 212 ++++++++++++++++++
 gregsite/settings/dev.py                      |   1 +
 2 files changed, 213 insertions(+)
 create mode 100644 greg/management/commands/import_sponsors_from_cerebrum.py

diff --git a/greg/management/commands/import_sponsors_from_cerebrum.py b/greg/management/commands/import_sponsors_from_cerebrum.py
new file mode 100644
index 00000000..338592b6
--- /dev/null
+++ b/greg/management/commands/import_sponsors_from_cerebrum.py
@@ -0,0 +1,212 @@
+"""
+Fetch all OUs from OrgReg and add the complete tree to Greg.
+
+Ignores OrganizationalUnits without identifiers with source and name matching global
+variables ORGREG_SOURCE and ORGREG_NAME
+
+Assumes that the header used for authentication is of the type
+'X-Gravitee-Api-Key': 'token'.
+
+If the path to the endpoint of the OUs is oregreg/v3/ou/ you want to give
+orgreg/v3/ as the url argument (note the trailing slash).
+"""
+from typing import Optional, Tuple
+import cerebrum_client
+
+import structlog
+
+from cerebrum_client import CerebrumClient
+from django.conf import settings
+from django.core.management.base import BaseCommand
+
+from greg.models import OrganizationalUnit, Sponsor, SponsorOrganizationalUnit
+
+logger = structlog.getLogger(__name__)
+
+
+class Command(BaseCommand):
+    help = __doc__
+
+    CEREBRUM_SOURCE = "cerebrum"
+    CEREBRUM_VALID_SOURCE_SYSTEM = ["DFO_SAP"]
+    CEREBRUM_FEIDE_INST = "uio.no"
+    CEREBRUM_NAME_SOURCE_PRIORITY = ["Cached", "Override", "DFO_SAP", "FS", "Manual"]
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.client = CerebrumClient(**settings.CEREBRUM_CLIENT)
+
+    def _has_active_dfo_aff(self, person_id: str):
+        """Check that a person has a valid employee affiliation from DFØ."""
+
+        dfo_employee_affs = [
+            x
+            for x in self.client.get_person_affiliations(person_id)
+            if x.source_system == "DFO_SAP" and x.affiliation == "ANSATT"
+        ]
+
+        return len(dfo_employee_affs) > 0
+
+    def _upsert_sponsor_unit_link(self, sponsor: Sponsor, unit: OrganizationalUnit):
+        """Ensure a link between sponsor and unit."""
+        try:
+            sunit = SponsorOrganizationalUnit.objects.get(
+                sponsor=sponsor,
+                organizational_unit=unit,
+                source=self.CEREBRUM_SOURCE,
+                automatic=True,
+            )
+            logger.info("sponsor_ou_link_found", sponsor=sponsor.id, sunit=sunit.id)
+        except SponsorOrganizationalUnit.DoesNotExist:
+            sunit = SponsorOrganizationalUnit.objects.create(
+                sponsor=sponsor,
+                organizational_unit=unit,
+                hierarchical_access=settings.CEREBRUM_HIERARCHICAL_ACCESS,
+                automatic=True,
+                source=self.CEREBRUM_SOURCE,
+            )
+            logger.info("sponsor_ou_link_create", sponsor=sponsor.id, sunit=sunit.id)
+        return SponsorOrganizationalUnit.objects.get(id=sunit.id)
+
+    def _remove_sponsor_unit_link(self, sunit: SponsorOrganizationalUnit):
+        logger.info("sponsor_ou_deleted", sunit=sunit.id)
+        sunit.delete()
+
+    def _get_person_name(
+        self, person: cerebrum_client.models.Person
+    ) -> Tuple[Optional[str], Optional[str]]:
+        """Get a persons chosen name."""
+        first_names = {x.source_system: x for x in person.names if x.variant == "FIRST"}
+        last_names = {x.source_system: x for x in person.names if x.variant == "LAST"}
+
+        for source_system in self.CEREBRUM_NAME_SOURCE_PRIORITY:
+            if source_system in first_names and source_system in last_names:
+                return first_names[source_system].name, last_names[source_system].name
+
+        return None, None
+
+    def _get_feide_id(self, person_id: str) -> Optional[str]:
+        """Infer the feide id from the primary user."""
+        primary_uname = self.client.get_person_primary_account_name(person_id)
+
+        if primary_uname:
+            return f"{primary_uname}@{self.CEREBRUM_FEIDE_INST}"
+        return None
+
+    def _upsert_sponsor_from_cerebrum(
+        self, person_id: str, unit: OrganizationalUnit
+    ) -> Optional[Sponsor]:
+        """Insert or update a sponsor from Cerebum data."""
+        # logger.bind(cerebrum_person_id=person_id)
+
+        person = self.client.get_person(person_id)
+        if not person:
+            logger.warning("cerebrum_person_missing", cerebrum_person_id=person_id)
+            return None
+
+        if not self._has_active_dfo_aff(person_id):
+            logger.warning("cerebrum_not_an_employee", cerebrum_person_id=person_id)
+            return None
+
+        feide_id = self._get_feide_id(person_id)
+        if not feide_id:
+            logger.warning("cerebrum_no_primary_account", cerebrum_person_id=person_id)
+            return None
+
+        # log = log.bind(feide_id=feide_id)
+
+        first_name, last_name = self._get_person_name(person)
+        if not first_name or not last_name:
+            logger.warning("cerebrum_no_valid_name", cerebrum_person_id=person_id)
+            return None
+
+        try:
+            sponsor = Sponsor.objects.get(feide_id=feide_id)
+            sponsor.first_name = first_name
+            sponsor.last_name = last_name
+            sponsor.save()
+            logger.info(
+                "sponsor_updated", sponsor=sponsor.id, cerebrum_person_id=person_id
+            )
+
+        except Sponsor.DoesNotExist:
+            sponsor = Sponsor.objects.create(
+                first_name=first_name,
+                last_name=last_name,
+                feide_id=feide_id,
+            )
+            logger.info(
+                "sponsor_created", sponsor=sponsor.id, cerebrum_person_id=person_id
+            )
+        return Sponsor.objects.get(id=sponsor.id)
+
+    def handle(self, *args, **options):
+        """Import of Sponsors from Cerebrum."""
+        active_units = OrganizationalUnit.objects.filter(
+            active=True,
+            deleted=False,
+        )
+
+        logger.info("import_start", nr_of_units=len(active_units))
+        for unit in active_units:
+            logger.bind(unit=unit.id)
+            sko = unit.identifiers.filter(name="legacy_stedkode").first()
+            if not sko:
+                logger.warning("orgreg_unit_missing_legacy_stedkode")
+                continue
+            logger.bind(legacy_stedkode=sko.value)
+
+            current_sponsors = unit.link_unit.filter(
+                automatic=True, source=self.CEREBRUM_SOURCE
+            ).all()
+
+            group_name = f"adm-leder-{sko.value}"
+            group = self.client.get_group(group_name)
+            if not group:
+                # No group in cererbum, remove sponsors.
+                logger.info(
+                    "cerebrum_group_not_found",
+                    unit_id=unit.id,
+                    cerebrum_group=group_name,
+                )
+                for sponsor in current_sponsors:
+                    self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+                continue
+
+            if group.expire_date:
+                # Group is expired, remove sponsors
+                logger.info(
+                    "cerebrum_group_expired",
+                    unit_id=unit.id,
+                    cerebrum_group=group_name,
+                )
+                for sponsor in current_sponsors:
+                    self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+                continue
+
+            group_members = list(self.client.list_group_members(group.id))
+            if not group_members:
+                # No members in group, remove sponsors
+                logger.info(
+                    "cerebrum_group_empty", unit_id=unit.id, cerebrum_group=group_name
+                )
+                for sponsor in current_sponsors:
+                    self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+                continue
+
+            cerebrum_sponsors = set()
+            for member in group_members:
+                if member.type == "person":
+                    sponsor = self._upsert_sponsor_from_cerebrum(member.id, unit)
+                    if sponsor:
+                        sponsor_link = self._upsert_sponsor_unit_link(
+                            sponsor=sponsor, unit=unit
+                        )
+                        cerebrum_sponsors.add(sponsor_link)
+
+            non_cerebrum_sponsors = set(current_sponsors) - cerebrum_sponsors
+
+            for non_cerebrum_sponsor in non_cerebrum_sponsors:
+                self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+
+        logger.info("import_end")
diff --git a/gregsite/settings/dev.py b/gregsite/settings/dev.py
index cae8f715..e989299f 100644
--- a/gregsite/settings/dev.py
+++ b/gregsite/settings/dev.py
@@ -21,6 +21,7 @@ CEREBRUM_CLIENT = {
     "url": "https://example.com/fake/",
     "headers": {"X-Gravitee-Api-Key": "bar"},
 }
+CEREBRUM_HIERARCHICAL_ACCESS = True
 
 Q_CLUSTER = {
     "name": "greg",
-- 
GitLab


From 3c3aa400ba7c1af11b72811b4b3cd7a534c59337 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Mon, 15 Nov 2021 08:26:16 +0100
Subject: [PATCH 6/9] Make the linter happy

---
 greg/management/commands/import_sponsors_from_cerebrum.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/greg/management/commands/import_sponsors_from_cerebrum.py b/greg/management/commands/import_sponsors_from_cerebrum.py
index 338592b6..f14455f5 100644
--- a/greg/management/commands/import_sponsors_from_cerebrum.py
+++ b/greg/management/commands/import_sponsors_from_cerebrum.py
@@ -204,9 +204,7 @@ class Command(BaseCommand):
                         )
                         cerebrum_sponsors.add(sponsor_link)
 
-            non_cerebrum_sponsors = set(current_sponsors) - cerebrum_sponsors
-
-            for non_cerebrum_sponsor in non_cerebrum_sponsors:
+            for non_cerebrum_sponsor in set(current_sponsors) - cerebrum_sponsors:
                 self._remove_sponsor_unit_link(non_cerebrum_sponsor)
 
         logger.info("import_end")
-- 
GitLab


From 8dd08ca23064e2efe5a9471cd089cb1b09fb8642 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Mon, 15 Nov 2021 08:56:24 +0100
Subject: [PATCH 7/9] Bugfix and update doc

---
 .../commands/import_sponsors_from_cerebrum.py | 27 +++++++++----------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/greg/management/commands/import_sponsors_from_cerebrum.py b/greg/management/commands/import_sponsors_from_cerebrum.py
index f14455f5..1c6e91da 100644
--- a/greg/management/commands/import_sponsors_from_cerebrum.py
+++ b/greg/management/commands/import_sponsors_from_cerebrum.py
@@ -1,15 +1,13 @@
 """
-Fetch all OUs from OrgReg and add the complete tree to Greg.
+Fetch sponsors for all units in GREG.
 
-Ignores OrganizationalUnits without identifiers with source and name matching global
-variables ORGREG_SOURCE and ORGREG_NAME
+Uses the members of the adm-leder-<legacy_stedkode> groups to
+populate Sponsors and SponsorOrganizationalUnits.
 
-Assumes that the header used for authentication is of the type
-'X-Gravitee-Api-Key': 'token'.
-
-If the path to the endpoint of the OUs is oregreg/v3/ou/ you want to give
-orgreg/v3/ as the url argument (note the trailing slash).
+This script does only remove the SponsorOrganizationalUnit.
+The Sponsor objects are kept, even with no units
 """
+
 from typing import Optional, Tuple
 import cerebrum_client
 
@@ -28,7 +26,6 @@ class Command(BaseCommand):
     help = __doc__
 
     CEREBRUM_SOURCE = "cerebrum"
-    CEREBRUM_VALID_SOURCE_SYSTEM = ["DFO_SAP"]
     CEREBRUM_FEIDE_INST = "uio.no"
     CEREBRUM_NAME_SOURCE_PRIORITY = ["Cached", "Override", "DFO_SAP", "FS", "Manual"]
 
@@ -170,7 +167,7 @@ class Command(BaseCommand):
                     cerebrum_group=group_name,
                 )
                 for sponsor in current_sponsors:
-                    self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+                    self._remove_sponsor_unit_link(sponsor)
                 continue
 
             if group.expire_date:
@@ -181,17 +178,17 @@ class Command(BaseCommand):
                     cerebrum_group=group_name,
                 )
                 for sponsor in current_sponsors:
-                    self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+                    self._remove_sponsor_unit_link(sponsor)
                 continue
 
-            group_members = list(self.client.list_group_members(group.id))
+            group_members = list(self.client.list_group_members(group_name))
             if not group_members:
                 # No members in group, remove sponsors
                 logger.info(
                     "cerebrum_group_empty", unit_id=unit.id, cerebrum_group=group_name
                 )
                 for sponsor in current_sponsors:
-                    self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+                    self._remove_sponsor_unit_link(sponsor)
                 continue
 
             cerebrum_sponsors = set()
@@ -204,7 +201,7 @@ class Command(BaseCommand):
                         )
                         cerebrum_sponsors.add(sponsor_link)
 
-            for non_cerebrum_sponsor in set(current_sponsors) - cerebrum_sponsors:
-                self._remove_sponsor_unit_link(non_cerebrum_sponsor)
+            for sponsor in set(current_sponsors) - cerebrum_sponsors:
+                self._remove_sponsor_unit_link(sponsor)
 
         logger.info("import_end")
-- 
GitLab


From 28147c7b2cc77d30c8d880a943033cc3e71958ed Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Mon, 15 Nov 2021 09:49:50 +0100
Subject: [PATCH 8/9] Remove unused code

---
 greg/management/commands/import_sponsors_from_cerebrum.py | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/greg/management/commands/import_sponsors_from_cerebrum.py b/greg/management/commands/import_sponsors_from_cerebrum.py
index 1c6e91da..be97fd72 100644
--- a/greg/management/commands/import_sponsors_from_cerebrum.py
+++ b/greg/management/commands/import_sponsors_from_cerebrum.py
@@ -94,8 +94,6 @@ class Command(BaseCommand):
         self, person_id: str, unit: OrganizationalUnit
     ) -> Optional[Sponsor]:
         """Insert or update a sponsor from Cerebum data."""
-        # logger.bind(cerebrum_person_id=person_id)
-
         person = self.client.get_person(person_id)
         if not person:
             logger.warning("cerebrum_person_missing", cerebrum_person_id=person_id)
@@ -110,8 +108,6 @@ class Command(BaseCommand):
             logger.warning("cerebrum_no_primary_account", cerebrum_person_id=person_id)
             return None
 
-        # log = log.bind(feide_id=feide_id)
-
         first_name, last_name = self._get_person_name(person)
         if not first_name or not last_name:
             logger.warning("cerebrum_no_valid_name", cerebrum_person_id=person_id)
-- 
GitLab


From 37fcabe51c168b774504a8f210b91e4f6a9ebff4 Mon Sep 17 00:00:00 2001
From: Sivert Kronen Hatteberg <skh@uio.no>
Date: Mon, 15 Nov 2021 09:58:53 +0100
Subject: [PATCH 9/9] Use get_or_create

---
 .../commands/import_sponsors_from_cerebrum.py | 28 ++++++++-----------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/greg/management/commands/import_sponsors_from_cerebrum.py b/greg/management/commands/import_sponsors_from_cerebrum.py
index be97fd72..7139e115 100644
--- a/greg/management/commands/import_sponsors_from_cerebrum.py
+++ b/greg/management/commands/import_sponsors_from_cerebrum.py
@@ -46,23 +46,19 @@ class Command(BaseCommand):
 
     def _upsert_sponsor_unit_link(self, sponsor: Sponsor, unit: OrganizationalUnit):
         """Ensure a link between sponsor and unit."""
-        try:
-            sunit = SponsorOrganizationalUnit.objects.get(
-                sponsor=sponsor,
-                organizational_unit=unit,
-                source=self.CEREBRUM_SOURCE,
-                automatic=True,
-            )
-            logger.info("sponsor_ou_link_found", sponsor=sponsor.id, sunit=sunit.id)
-        except SponsorOrganizationalUnit.DoesNotExist:
-            sunit = SponsorOrganizationalUnit.objects.create(
-                sponsor=sponsor,
-                organizational_unit=unit,
-                hierarchical_access=settings.CEREBRUM_HIERARCHICAL_ACCESS,
-                automatic=True,
-                source=self.CEREBRUM_SOURCE,
-            )
+        sunit, created = SponsorOrganizationalUnit.objects.get_or_create(
+            sponsor=sponsor,
+            organizational_unit=unit,
+            source=self.CEREBRUM_SOURCE,
+            automatic=True,
+        )
+        if created:
             logger.info("sponsor_ou_link_create", sponsor=sponsor.id, sunit=sunit.id)
+        else:
+            logger.info("sponsor_ou_link_found", sponsor=sponsor.id, sunit=sunit.id)
+            sunit.hierarchical_access = settings.CEREBRUM_HIERARCHICAL_ACCESS
+            sunit.save()
+
         return SponsorOrganizationalUnit.objects.get(id=sunit.id)
 
     def _remove_sponsor_unit_link(self, sunit: SponsorOrganizationalUnit):
-- 
GitLab