From 54def717614ab16cb3e7a8d0ade1925e6d9507fb Mon Sep 17 00:00:00 2001
From: Trond Aasan <trond.aasan@ntnu.no>
Date: Mon, 21 Mar 2022 11:48:31 +0100
Subject: [PATCH] IGD-19 Handle persons with no primary account

---
 abstract_iga_client/iga_cerebrum_uio.py | 42 ++++++++++-------
 abstract_iga_client/iga_cerebrum_uit.py | 42 ++++++++++-------
 tests/conftest.py                       | 16 ++++++-
 tests/test_iga_cerebrum_uio.py          | 63 +++++++++++++++++++++++++
 4 files changed, 126 insertions(+), 37 deletions(-)

diff --git a/abstract_iga_client/iga_cerebrum_uio.py b/abstract_iga_client/iga_cerebrum_uio.py
index 0f4491f..ec4b9a5 100644
--- a/abstract_iga_client/iga_cerebrum_uio.py
+++ b/abstract_iga_client/iga_cerebrum_uio.py
@@ -322,19 +322,22 @@ class IgaCerebrumUio(IgaAbstract):
                 )
             )
             iga_person_dict["accounts"] = accounts
-            prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
-            # Set attributes if we already have info
-            if prim_acc_info.username == account.name:
-                if account.primary_email:
-                    iga_person_dict["primary_email"] = account.primary_email
-                iga_person_dict["feide_id"] = account.name + "@uio.no"
-            # Fetch if we didn't have it and specified it is wanted
-            else:
-                if {"primary_email", "feide_id"} & fields_to_include:
-                    primary_acc = self.client.get_account(prim_acc_info.username)
-                    if primary_acc.primary_email:
-                        iga_person_dict["primary_email"] = primary_acc.primary_email
-                    iga_person_dict["feide_id"] = primary_acc.name + "@uio.no"
+            try:
+                prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
+                # Set attributes if we already have info
+                if prim_acc_info.username == account.name:
+                    if account.primary_email:
+                        iga_person_dict["primary_email"] = account.primary_email
+                    iga_person_dict["feide_id"] = account.name + "@uio.no"
+                # Fetch if we didn't have it and specified it is wanted
+                else:
+                    if {"primary_email", "feide_id"} & fields_to_include:
+                        primary_acc = self.client.get_account(prim_acc_info.username)
+                        if primary_acc.primary_email:
+                            iga_person_dict["primary_email"] = primary_acc.primary_email
+                        iga_person_dict["feide_id"] = primary_acc.name + "@uio.no"
+            except StopIteration:
+                pass
 
         if {"sap_person_id", "fs_person_id"} & fields_to_include:
             # Both use externalids endpoint, and result is cached giving both with one
@@ -382,11 +385,14 @@ class IgaCerebrumUio(IgaAbstract):
             )
             iga_person_dict["accounts"] = accounts
             if {"primary_email", "feide_id"} & fields_to_include:
-                prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
-                primary_acc = self.client.get_account(prim_acc_info.username)
-                if primary_acc.primary_email:
-                    iga_person_dict["primary_email"] = primary_acc.primary_email
-                iga_person_dict["feide_id"] = primary_acc.name + "@uio.no"
+                try:
+                    prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
+                    primary_acc = self.client.get_account(prim_acc_info.username)
+                    if primary_acc.primary_email:
+                        iga_person_dict["primary_email"] = primary_acc.primary_email
+                    iga_person_dict["feide_id"] = primary_acc.name + "@uio.no"
+                except StopIteration:
+                    pass
 
         if {"sap_person_id", "fs_person_id"} & fields_to_include:
             # Both use externalids endpoint, and result is cached giving both with one
diff --git a/abstract_iga_client/iga_cerebrum_uit.py b/abstract_iga_client/iga_cerebrum_uit.py
index 0fbe588..897c86a 100644
--- a/abstract_iga_client/iga_cerebrum_uit.py
+++ b/abstract_iga_client/iga_cerebrum_uit.py
@@ -37,19 +37,22 @@ class IgaCerebrumUit(IgaCerebrumUio):
                 )
             )
             iga_person_dict["accounts"] = accounts
-            prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
-            # Set attributes if we already have info
-            if prim_acc_info.username == account.name:
-                if account.primary_email:
-                    iga_person_dict["primary_email"] = account.primary_email
-                iga_person_dict["feide_id"] = account.name + "@uit.no"
-            # Fetch if we didn't have it and specified it is wanted
-            else:
-                if {"primary_email", "feide_id"} & fields_to_include:
-                    primary_acc = self.client.get_account(prim_acc_info.username)
-                    if primary_acc.primary_email:
-                        iga_person_dict["primary_email"] = primary_acc.primary_email
-                    iga_person_dict["feide_id"] = primary_acc.name + "@uit.no"
+            try:
+                prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
+                # Set attributes if we already have info
+                if prim_acc_info.username == account.name:
+                    if account.primary_email:
+                        iga_person_dict["primary_email"] = account.primary_email
+                    iga_person_dict["feide_id"] = account.name + "@uit.no"
+                # Fetch if we didn't have it and specified it is wanted
+                else:
+                    if {"primary_email", "feide_id"} & fields_to_include:
+                        primary_acc = self.client.get_account(prim_acc_info.username)
+                        if primary_acc.primary_email:
+                            iga_person_dict["primary_email"] = primary_acc.primary_email
+                        iga_person_dict["feide_id"] = primary_acc.name + "@uit.no"
+            except StopIteration:
+                pass
 
         if {"sap_person_id", "fs_person_id"} & fields_to_include:
             # Both use externalids endpoint, and result is cached giving both with one
@@ -97,11 +100,14 @@ class IgaCerebrumUit(IgaCerebrumUio):
             )
             iga_person_dict["accounts"] = accounts
             if {"primary_email", "feide_id"} & fields_to_include:
-                prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
-                primary_acc = self.client.get_account(prim_acc_info.username)
-                if primary_acc.primary_email:
-                    iga_person_dict["primary_email"] = primary_acc.primary_email
-                iga_person_dict["feide_id"] = primary_acc.name + "@uit.no"
+                try:
+                    prim_acc_info = next(filter(lambda x: x.type == "primary", accounts))
+                    primary_acc = self.client.get_account(prim_acc_info.username)
+                    if primary_acc.primary_email:
+                        iga_person_dict["primary_email"] = primary_acc.primary_email
+                    iga_person_dict["feide_id"] = primary_acc.name + "@uit.no"
+                except StopIteration:
+                    pass
 
         if {"sap_person_id", "fs_person_id"} & fields_to_include:
             # Both use externalids endpoint, and result is cached giving both with one
diff --git a/tests/conftest.py b/tests/conftest.py
index 4b943bb..340afb9 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -23,7 +23,7 @@ import abstract_iga_client.iga_cerebrum_uit
 import abstract_iga_client.iga_scim_uib
 
 from abstract_iga_client.iga_abstract import IgaAbstract
-from abstract_iga_client.iga_result import IgaResult
+from abstract_iga_client.iga_result import IgaResult, IgaPerson
 
 
 def load_json_file(name):
@@ -293,6 +293,11 @@ def person_alice_accounts():
     return load_json_file("cerebrum_uio/person_alice_accounts.json")
 
 
+@pytest.fixture
+def person_alice_accounts_no_primary(person_alice_accounts):
+    return {"accounts": [x for x in person_alice_accounts["accounts"] if not x["primary"]]}
+
+
 @pytest.fixture
 def person_alice_externalids():
     return load_json_file("cerebrum_uio/person_alice_externalids.json")
@@ -313,6 +318,15 @@ def igaperson_alice():
     return load_json_file("cerebrum_uio/igaperson_alice.json")
 
 
+@pytest.fixture
+def igaperson_alice_no_primary_accounts(igaperson_alice):
+    person = IgaPerson(**igaperson_alice)
+    person.accounts = [x for x in person.accounts if x.type != "primary"]
+    person.primary_email = None
+    person.feide_id = None
+    return person
+
+
 @pytest.fixture
 def account_alice_drift():
     return load_json_file("cerebrum_uio/account_alice-drift.json")
diff --git a/tests/test_iga_cerebrum_uio.py b/tests/test_iga_cerebrum_uio.py
index 692f295..8011fe2 100644
--- a/tests/test_iga_cerebrum_uio.py
+++ b/tests/test_iga_cerebrum_uio.py
@@ -211,6 +211,38 @@ def test_get_igaperson_non_primary(
     assert actual == expected
 
 
+def test_get_igaperson_by_username_no_primary_account(
+    requests_mock,
+    account_alice,
+    person_alice_accounts_no_primary,
+    person_alice_externalids,
+    person_alice,
+    person_alice_contacts,
+    igaperson_alice_no_primary_accounts,
+):
+    client = IgaAbstract.get_iga_client(
+        "cerebrum@uio", url="https://example.com/cerebrum/"
+    )
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/accounts/alice", json=account_alice
+    )
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/persons/0/accounts",
+        json=person_alice_accounts_no_primary,
+    )
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/persons/0/external-ids",
+        json=person_alice_externalids,
+    )
+    requests_mock.get("https://example.com/cerebrum/v1/persons/0", json=person_alice)
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/persons/0/contacts", json=person_alice_contacts
+    )
+    actual = client.get_igaperson_by_username("alice", set(IgaPerson.__fields__))
+
+    assert actual == igaperson_alice_no_primary_accounts
+
+
 def test_get_igaperson_by_personid(
     requests_mock,
     igaperson_alice,
@@ -240,3 +272,34 @@ def test_get_igaperson_by_personid(
     actual = client.get_igaperson_by_personid("0", set(IgaPerson.__fields__))
 
     assert actual == expected
+
+
+def test_get_igaperson_by_personid_no_primary_accounts(
+    requests_mock,
+    igaperson_alice_no_primary_accounts,
+    person_alice,
+    person_alice_accounts_no_primary,
+    account_alice,
+    person_alice_externalids,
+    person_alice_contacts,
+):
+    client = IgaAbstract.get_iga_client(
+        "cerebrum@uio", url="https://example.com/cerebrum/"
+    )
+    requests_mock.get("https://example.com/cerebrum/v1/persons/0", json=person_alice)
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/persons/0/accounts", json=person_alice_accounts_no_primary
+    )
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/accounts/alice", json=account_alice
+    )
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/persons/0/external-ids",
+        json=person_alice_externalids,
+    )
+    requests_mock.get(
+        "https://example.com/cerebrum/v1/persons/0/contacts", json=person_alice_contacts
+    )
+    actual = client.get_igaperson_by_personid("0", set(IgaPerson.__fields__))
+
+    assert actual == igaperson_alice_no_primary_accounts
-- 
GitLab