diff --git a/aleksis/apps/ldap/util/ldap_sync.py b/aleksis/apps/ldap/util/ldap_sync.py index 3a7d76d326aece8d011085c448d1c5ba7f33280d..c1046cbea3f26e8bc09f2362f6179965510837b7 100644 --- a/aleksis/apps/ldap/util/ldap_sync.py +++ b/aleksis/apps/ldap/util/ldap_sync.py @@ -4,6 +4,7 @@ import re from django.apps import apps from django.conf import settings from django.contrib.auth import get_user_model +from django.db import IntegrityError, transaction from django.db.models import fields from django.utils.translation import gettext as _ @@ -86,6 +87,7 @@ def apply_templates(value, patterns, templates, separator="|"): return value +@transaction.atomic def ldap_sync_from_user(sender, instance, created, **kwargs): """ Synchronise Person meta-data and groups from ldap_user on User update. """ @@ -112,14 +114,19 @@ def ldap_sync_from_user(sender, instance, created, **kwargs): matches["last_name"] = instance.last_name try: - person = Person.objects.get(**matches) + with transaction.atomic(): + person = Person.objects.get(**matches) except Person.DoesNotExist: # Bail out of further processing - logger.info("No matching person for user %s" % instance.username) + logger.warn("No matching person for user %s" % instance.username) return - - person.user = instance - logger.info("Matching person %s linked to user %s" % (str(person), instance.username)) + except Person.MultipleObjectsReturned: + # Bail out of further processing + logger.error("More than one matching person for user %s" % instance.username) + return + else: + person.user = instance + logger.info("Matching person %s linked to user %s" % (str(person), instance.username)) # Synchronise additional fields if enabled for field in syncable_fields(Person): @@ -177,18 +184,24 @@ def ldap_sync_from_user(sender, instance, created, **kwargs): short_name = short_name[:Group._meta.get_field("short_name").max_length] name = name[:Group._meta.get_field("name").max_length] - group, created = Group.objects.update_or_create( - import_ref = ldap_group[0], - defaults = { - "short_name": short_name, - "name": name - } - ) - logger.info("%s LDAP group %s for Django group %s" % ( - ("Created" if created else "Updated"), - ldap_group[1][config.LDAP_GROUP_SYNC_FIELD_NAME][0], - name - )) + try: + with transaction.atomic(): + group, created = Group.objects.update_or_create( + import_ref = ldap_group[0], + defaults = { + "short_name": short_name, + "name": name + } + ) + except IntegrityError: + logger.error("Integrity error while trying to import LDAP group %s" % ldap_group[0]) + continue + else: + logger.info("%s LDAP group %s for Django group %s" % ( + ("Created" if created else "Updated"), + ldap_group[1][config.LDAP_GROUP_SYNC_FIELD_NAME][0], + name + )) group_objects.append(group) @@ -207,6 +220,7 @@ def ldap_sync_from_user(sender, instance, created, **kwargs): del instance._skip_signal +@transaction.atomic def mass_ldap_import(): """ Utility code for mass import from ldap """