From f90827d1f5d7c39d71bf9205367b222d9d8f06ce Mon Sep 17 00:00:00 2001 From: Dominik George <dominik.george@teckids.org> Date: Fri, 7 Jan 2022 16:07:52 +0100 Subject: [PATCH] Allow combining matching fields for OR --- CHANGELOG.rst | 5 +++++ README.rst | 2 +- aleksis/apps/ldap/apps.py | 2 +- aleksis/apps/ldap/preferences.py | 10 ++++++++++ aleksis/apps/ldap/util/ldap_sync.py | 23 ++++++++++++++++++----- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 246e3c0..6a90877 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_. Unreleased ---------- +Added +~~~~~ + +* Person field matching can now be matched disjunctive + Fixed ~~~~~ diff --git a/README.rst b/README.rst index bc30e34..8cf24a8 100644 --- a/README.rst +++ b/README.rst @@ -19,7 +19,7 @@ Licence :: - Copyright © 2020, 2021 Dominik George <dominik.george@teckids.org> + Copyright © 2020, 2021, 2022 Dominik George <dominik.george@teckids.org> Copyright © 2020 Tom Teichler <tom.teichler@teckids.org> Licenced under the EUPL, version 1.2 or later, by Teckids e.V. (Bonn, Germany). diff --git a/aleksis/apps/ldap/apps.py b/aleksis/apps/ldap/apps.py index 8b73e09..dd195b2 100644 --- a/aleksis/apps/ldap/apps.py +++ b/aleksis/apps/ldap/apps.py @@ -15,7 +15,7 @@ class LDAPConfig(AppConfig): } licence = "EUPL-1.2+" copyright_info = ( - ([2020, 2021], "Dominik George", "dominik.george@teckids.org"), + ([2020, 2021, 2022], "Dominik George", "dominik.george@teckids.org"), ([2020], "Tom Teichler", "tom.teichler@teckids.org"), ) diff --git a/aleksis/apps/ldap/preferences.py b/aleksis/apps/ldap/preferences.py index 53f852f..fa695e8 100644 --- a/aleksis/apps/ldap/preferences.py +++ b/aleksis/apps/ldap/preferences.py @@ -150,6 +150,16 @@ class LDAPGroupSyncOwnerAttrType(ChoicePreference): row = "ldap_group_sync_owner_attr" +@site_preferences_registry.register +class LDAPMatchingMode(ChoicePreference): + section = ldap + name = "matching_mode" + default = "AND" + required = True + verbose_name = _("LDAP sync matching mode") + choices = [("AND", _("All fields must match"), "OR", _("Any one field must match"))] + + @site_preferences_registry.register class EnableLDAPPasswordChange(BooleanPreference): section = ldap diff --git a/aleksis/apps/ldap/util/ldap_sync.py b/aleksis/apps/ldap/util/ldap_sync.py index 4547211..3f7b5d7 100644 --- a/aleksis/apps/ldap/util/ldap_sync.py +++ b/aleksis/apps/ldap/util/ldap_sync.py @@ -7,7 +7,7 @@ from django.apps import apps from django.conf import settings from django.core.files import File from django.db import DataError, IntegrityError, transaction -from django.db.models import fields +from django.db.models import Q, fields from django.db.models.fields.files import FileField from django.utils.text import slugify from django.utils.translation import gettext as _ @@ -270,11 +270,24 @@ def ldap_sync_from_user(user, dn, attrs): if missing_key not in matches: defaults[missing_key] = getattr(user, missing_key) - if get_site_preferences()["ldap__create_missing_persons"]: - person, created = Person.objects.get_or_create(**matches, defaults=defaults) - else: - person = Person.objects.get(**matches) + q = Q() + matching_mode = get_site_preferences()["ldap__matching_mode"] + for field, value in matches.items(): + add_q = Q(**{field: value}) + if matching_mode == "AND": + q = q & add_q + elif matching_mode == "OR": + q = q | add_q + else: + raise ValueError(f"Invalid setting for matching mode: {matching_mode}") + + try: + person = Person.objects.get(q) created = False + except Person.DoesNotExist: + if get_site_preferences()["ldap__create_missing_persons"]: + person = Person.objects.create(**matches, **defaults) + created = True user.save() person.user = user -- GitLab