commit d28a80b6463a37ccf803866f5e4ec9e268e4edcc Author: Florian Best Date: Wed Mar 30 06:17:33 2022 +0200 WIP: old sketch TODO: consider replace/(revert some of) the manual adjustments done in groups/group.py (Bug #43247) test setup: LB="$(ucr get ldap/base)" udm dns/forward_zone create --set zone=bug53165.qa --set nameserver="$(hostname -f)" udm dns/reverse_zone create --set subnet=2001:0001:0002 --set nameserver="$(hostname -f)" udm computers/ipmanagedclient create --set name=bug53165 \ --append ip=2001:1:2::f \ --append dnsEntryZoneForward="\"zoneName=bug53165.qa,$LB\" \"2001:1:2::f\"" \ --append dnsEntryZoneReverse="\"zoneName=2.0.0.0.1.0.0.0.1.0.0.2.ip6.arpa,$LB\" \"2001:1:2::f\"" udm computers/ipmanagedclient modify --dn cn=bug53165,$LB --remove ip=2001:1:2::f diff --git management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py index f36716c9da..e3fa3fd582 100644 --- management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py +++ management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py @@ -975,6 +975,57 @@ class simpleLdap(object): """Hook which is called after the object removal.""" self._release_locks() + def remove_value(self, key, value=None): + """Removes a specific value from the specified property. + If this value is currently not set univention.admin.uexceptions.valueNotSet is raised. + if value is None the whole values of this property gets removed. + """ + if not self.has_property(key): + raise univention.admin.uexceptions.noProperty(key) + + if value is None: + # remove all currently set values + self[key] = [] if self.descriptions[key].multivalue else None + return + + if not self.contains_value(key, value): + raise univention.admin.uexceptions.valueNotSet(key, value) + + if not self.descriptions[key].multivalue: + self[key] = value + return + + current_values = list(self[key]) + for val in current_values[:]: + if self.compare_value(key, value, val): + current_values.remove(val) + self[key] = current_values + + def contains_value(self, key, value): + if self.descriptions[key].multivalue and any(self.compare_value(key, value, val) for val in self[key]): + return True + if not self.descriptions[key].multivalue and self.compare_value(key, value, self[key]): + return True + return False + + def compare_value(self, key, a, b): + return self.descriptions[key].syntax.normalize(a) == self.descriptions[key].syntax.normalize(b) + + def append_value(self, key, value): + if not self.has_property(key): + raise univention.admin.uexceptions.noProperty(key) + + if self.contains_value(key, value): + raise univention.admin.uexceptions.valueAlreadySet(key, value) + + if not self.descriptions[key].multivalue: + self[key] = value + return + + current_values = self[key] + current_values.append(value) + self[key] = current_values + def _safe_cancel(self): # type: () -> None try: self.cancel() diff --git management/univention-directory-manager-modules/modules/univention/admin/syntax.py management/univention-directory-manager-modules/modules/univention/admin/syntax.py index c7897951b5..4e636a7671 100644 --- management/univention-directory-manager-modules/modules/univention/admin/syntax.py +++ management/univention-directory-manager-modules/modules/univention/admin/syntax.py @@ -257,6 +257,10 @@ class ISyntax(object): """ return text + @classmethod + def normalize(cls, value): + return cls.parse(value) + def parse_command_line(self, value): return value @@ -774,6 +778,12 @@ class UDM_Objects(ISyntax, _UDMObjectOrAttribute): return univention.admin.types.DistinguishedNameType return univention.admin.types.StringType + @classmethod + def normalize(cls, value): + if cls.key == 'dn': + return univention.admin.uldap.DN(value) + return super(UDM_Objects, cls).normalize(value) + @classmethod def parse(self, text): if not self.empty_value and not text: @@ -3414,6 +3424,10 @@ class ldapDn(simple): type_class = univention.admin.types.DistinguishedNameType + @classmethod + def normalize(cls, value): + return univention.admin.uldap.DN(value) + @classmethod def get_widget(cls, prop): if cls is ldapDn: diff --git management/univention-directory-manager-modules/modules/univention/admin/uexceptions.py management/univention-directory-manager-modules/modules/univention/admin/uexceptions.py index 2b7f168642..245acb4099 100644 --- management/univention-directory-manager-modules/modules/univention/admin/uexceptions.py +++ management/univention-directory-manager-modules/modules/univention/admin/uexceptions.py @@ -105,6 +105,14 @@ class valueMismatch(valueError): message = _('Values do not match.') +class valueNotSet(valueError): + message = _('The value is not set.') + + +class valueAlreadySet(valueError): + message = _('The value is already set.') + + class noLock(base): message = _('Could not acquire lock.') diff --git management/univention-directory-manager-modules/modules/univention/admincli/admin.py management/univention-directory-manager-modules/modules/univention/admincli/admin.py index 3305f3051d..100a596447 100755 --- management/univention-directory-manager-modules/modules/univention/admincli/admin.py +++ management/univention-directory-manager-modules/modules/univention/admincli/admin.py @@ -263,54 +263,33 @@ def object_input(module, object, input, append=None, remove=None): out.append('WARNING: file not found: %s' % values) else: values = [module.property_descriptions[key].syntax.parse_command_line(x) for x in values] - current_values = list(object[key] or []) - if current_values == ['']: - current_values = [] - - for val in values: - if val in current_values: - out.append('WARNING: cannot append %s to %s, value exists' % (val, key)) - else: - current_values.append(val) - - if not module.property_descriptions[key].multivalue: + for value in values: try: - current_values = current_values[-1] - except IndexError: - current_values = None - - try: - object[key] = current_values - except univention.admin.uexceptions.valueInvalidSyntax as errmsg: - raise OperationFailed(out, 'E: Invalid Syntax: %s' % (errmsg,)) + object.append_value(key, value) + except univention.admin.uexceptions.noProperty: + raise OperationFailed(out, "WARNING: No attribute with name %s in this module, value not appended." % (key,)) + except univention.admin.uexceptions.valueNotSet as exc: + raise OperationFailed(out, "WARNING: cannot append %s to %s: %s" % (value, key, exc)) + except univention.admin.uexceptions.valueInvalidSyntax as errmsg: + raise OperationFailed(out, 'E: Invalid Syntax: %s' % (errmsg,)) if remove: for key, values in remove.items(): - current_values = [object[key]] if not module.property_descriptions[key].multivalue else list(object[key]) - if values is None: - current_values = [] - else: - vallist = [values] if isinstance(values, six.string_types) else values - vallist = [module.property_descriptions[key].syntax.parse_command_line(x) for x in vallist] - - for val in vallist: - try: - normalized_val = module.property_descriptions[key].syntax.parse(val) - except (univention.admin.uexceptions.valueInvalidSyntax, univention.admin.uexceptions.valueError): - normalized_val = None - - if val in current_values: - current_values.remove(val) - elif normalized_val is not None and normalized_val in current_values: - current_values.remove(normalized_val) - else: - out.append("WARNING: cannot remove %s from %s, value does not exist" % (val, key)) - if not module.property_descriptions[key].multivalue: - try: - current_values = current_values[0] - except IndexError: - current_values = None - object[key] = current_values + try: + if values is None: + object.remove_value(key, values) + continue + for value in values: + value = module.property_descriptions[key].syntax.parse_command_line(value) + #try: # TODO: remove?! move into normalize() + # value = module.property_descriptions[key].syntax.parse(value) + #except (univention.admin.uexceptions.valueInvalidSyntax, univention.admin.uexceptions.valueError): + # pass + object.remove_value(key, value) + except univention.admin.uexceptions.noProperty: + out.append("WARNING: No attribute with name %s in this module, value not removed." % (key,)) + except univention.admin.uexceptions.valueNotSet as exc: + out.append("WARNING: cannot remove %s from %s: %s" % (value, key, exc)) if input: for key, value in input.items():