diff --git a/aleksis/apps/ldap/util/ldap_sync.py b/aleksis/apps/ldap/util/ldap_sync.py index 6d484dba92f24175799d0a58b752e3e4f5700c37..c6631a38042c8d5e685052d7445a9e9da482c8b4 100644 --- a/aleksis/apps/ldap/util/ldap_sync.py +++ b/aleksis/apps/ldap/util/ldap_sync.py @@ -1,9 +1,12 @@ +import io import re from django.apps import apps from django.conf import settings from django.contrib.auth import get_user_model from django.db.models import fields +from django.db.models.fields.files import FieldFile, FileField +from django.utils.text import slugify from django.utils.translation import gettext as _ from constance import config @@ -22,7 +25,13 @@ def syncable_fields(model): field.editable and not field.auto_created and not field.is_relation)] -def from_ldap(value, field): +def ldap_field_to_filename(dn, fieldname): + """ Generate a reproducible filename from a DN and a field name """ + + return "%s__%s" % (slugify(dn), slugify(fieldname)) + + +def from_ldap(value, instance, field, dn, ldap_field): """ Convert an LDAP value to the Python type of the target field This conversion is prone to error because LDAP deliberately breaks @@ -35,6 +44,15 @@ def from_ldap(value, field): if type(field) in (fields.DateField, fields.DateTimeField): # Be opportunistic, but keep old value if conversion fails value = datetime_from_ldap(value) or value + elif isinstance(field, FileField): + name = ldap_field_to_filename(dn, ldap_field) + content = File(io.BytesIO(value)) + + # Pre-save field file instance + fieldfile = getattr(instance, field.attname) + fieldfile.save(name, content) + + return fieldfile # Finally, use field's conversion method as default return field.to_python(value) @@ -129,7 +147,7 @@ def ldap_sync_from_user(sender, instance, created, raw, using, update_fields, ** value = apply_templates(value, patterns, templates) # Opportunistically convert LDAP string value to Python object - value = from_ldap(value, field) + value = from_ldap(value, person, field, dn, ldap_field) setattr(person, field.name, value)