Skip to content
Snippets Groups Projects
Commit 6995c681 authored by Sivert Kronen Hatteberg's avatar Sivert Kronen Hatteberg
Browse files

New command for importing sponsors from Cerebrum

parent 2a4db6bc
No related branches found
No related tags found
1 merge request!149Greg 95 cerebrum sponsor import
Pipeline #100413 failed
"""
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")
......@@ -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",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment