Source code for tldap.modlist

# Copyright 2012-2014 Brian May
#
# This file is part of python-tldap.
#
# python-tldap is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# python-tldap is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with python-tldap  If not, see <http://www.gnu.org/licenses/>.

"""
This module contains a ``modifyModlist`` function adopted from
:py:mod:`ldap:ldap.modlist`.
"""
from typing import Dict, Iterator, List, Optional, Tuple

import ldap3
import ldap3.utils.conv

import tldap.dict


def _list_dict(line: Iterator[str], case_insensitive: bool = False):
    """
    return a dictionary with all items of l being the keys of the dictionary

    If argument case_insensitive is non-zero ldap.cidict.cidict will be
    used for case-insensitive string keys
    """
    if case_insensitive:
        raise NotImplementedError()
        d = tldap.dict.CaseInsensitiveDict()
    else:
        d = {}
    for i in line:
        d[i] = None
    return d


[docs] def escape_list(bytes_list): assert isinstance(bytes_list, list) return bytes_list
[docs] def addModlist(entry: dict, ignore_attr_types: Optional[List[str]] = None) -> Dict[str, List[bytes]]: """Build modify list for call of method LDAPObject.add()""" ignore_attr_types = _list_dict(map(str.lower, (ignore_attr_types or []))) modlist: Dict[str, List[bytes]] = {} for attrtype in entry.keys(): if attrtype.lower() in ignore_attr_types: # This attribute type is ignored continue for value in entry[attrtype]: assert value is not None if len(entry[attrtype]) > 0: modlist[attrtype] = escape_list(entry[attrtype]) return modlist # addModlist()
[docs] def modifyModlist( old_entry: dict, new_entry: dict, ignore_attr_types: Optional[List[str]] = None, ignore_oldexistent: bool = False) -> Dict[str, Tuple[str, List[bytes]]]: """ Build differential modify list for calling LDAPObject.modify()/modify_s() :param old_entry: Dictionary holding the old entry :param new_entry: Dictionary holding what the new entry should be :param ignore_attr_types: List of attribute type names to be ignored completely :param ignore_oldexistent: If true attribute type names which are in old_entry but are not found in new_entry at all are not deleted. This is handy for situations where your application sets attribute value to '' for deleting an attribute. In most cases leave zero. :return: List of tuples suitable for :py:meth:`ldap:ldap.LDAPObject.modify`. This function is the same as :py:func:`ldap:ldap.modlist.modifyModlist` except for the following changes: * MOD_DELETE/MOD_DELETE used in preference to MOD_REPLACE when updating an existing value. """ ignore_attr_types = _list_dict(map(str.lower, (ignore_attr_types or []))) modlist: Dict[str, Tuple[str, List[bytes]]] = {} attrtype_lower_map = {} for a in old_entry.keys(): attrtype_lower_map[a.lower()] = a for attrtype in new_entry.keys(): attrtype_lower = attrtype.lower() if attrtype_lower in ignore_attr_types: # This attribute type is ignored continue # Filter away null-strings new_value = list(filter(lambda x: x is not None, new_entry[attrtype])) if attrtype_lower in attrtype_lower_map: old_value = old_entry.get(attrtype_lower_map[attrtype_lower], []) old_value = list(filter(lambda x: x is not None, old_value)) del attrtype_lower_map[attrtype_lower] else: old_value = [] if not old_value and new_value: # Add a new attribute to entry modlist[attrtype] = (ldap3.MODIFY_ADD, escape_list(new_value)) elif old_value and new_value: # Replace existing attribute old_value_dict = _list_dict(old_value) new_value_dict = _list_dict(new_value) delete_values = [] for v in old_value: if v not in new_value_dict: delete_values.append(v) add_values = [] for v in new_value: if v not in old_value_dict: add_values.append(v) if len(delete_values) > 0 or len(add_values) > 0: modlist[attrtype] = ( ldap3.MODIFY_REPLACE, escape_list(new_value)) elif old_value and not new_value: # Completely delete an existing attribute modlist[attrtype] = (ldap3.MODIFY_DELETE, []) if not ignore_oldexistent: # Remove all attributes of old_entry which are not present # in new_entry at all for a in attrtype_lower_map.keys(): if a in ignore_attr_types: # This attribute type is ignored continue attrtype = attrtype_lower_map[a] modlist[attrtype] = (ldap3.MODIFY_DELETE, []) return modlist # modifyModlist()