Univention Bugzilla – Bug 42441
Traceback upon changing student's class assignment in UMC module "users (schools)"
Last modified: 2016-12-09 17:54:24 CET
The following traceback happens if the UCS@school UMC module "Benutzer (Schulen)" is used to change a class of a student from class A to class B. The traceback is shown upon saving. The first traceback has been provided by the customer, the second traceback occurred during reproduction of the error with latest SVN (upcoming 4.1R2v5). Die Ausführung des Kommandos schoolwizards/users/put schoolwizards/users ist fehlgeschlagen: Traceback (most recent call last): File "/usr/lib/pymodules/python2.7/univention/management/console/base.py", line 283, in execute function(self, request) File "/usr/lib/pymodules/python2.7/univention/management/console/modules/schoolwizards/__init__.py", line 112, in _decorated ret = func(self, request, *a, **kw) File "/usr/lib/pymodules/python2.7/ucsschool/lib/schoolldap.py", line 140, in wrapper_func return func(*args, **kwargs) File "/usr/lib/pymodules/python2.7/univention/management/console/modules/schoolwizards/__init__.py", line 204, in _modify_obj obj.modify(ldap_user_write, validate=False) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/base.py", line 471, in modify success = self.modify_without_hooks(lo, validate, move_if_necessary) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/base.py", line 494, in modify_without_hooks self.do_modify(udm_obj, lo) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/user.py", line 276, in do_modify remove = school_group.school not in self.schools TypeError: argument of type 'NoneType' is not iterable Die Ausführung des Kommandos schoolwizards/users/put schoolwizards/users ist fehlgeschlagen: Traceback (most recent call last): File "/usr/lib/pymodules/python2.7/univention/management/console/base.py", line 283, in execute function(self, request) File "/usr/lib/pymodules/python2.7/univention/management/console/modules/schoolwizards/__init__.py", line 112, in _decorated ret = func(self, request, *a, **kw) File "/usr/lib/pymodules/python2.7/ucsschool/lib/schoolldap.py", line 142, in wrapper_func return func(*args, **kwargs) File "/usr/lib/pymodules/python2.7/univention/management/console/modules/schoolwizards/__init__.py", line 204, in _modify_obj obj.modify(ldap_user_write, validate=False) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/base.py", line 471, in modify success = self.modify_without_hooks(lo, validate, move_if_necessary) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/base.py", line 494, in modify_without_hooks self.do_modify(udm_obj, lo) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/user.py", line 259, in do_modify mandatory_groups = self.groups_used(lo) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/user.py", line 458, in groups_used group_dns = self.get_specific_groups(lo) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/user.py", line 582, in get_specific_groups groups = super(Student, self).get_specific_groups(lo) File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/user.py", line 361, in get_specific_groups groups = self.get_domain_users_groups() File "/usr/lib/pymodules/python2.7/ucsschool/lib/models/user.py", line 443, in get_domain_users_groups return [self.get_group_dn('Domain Users %s' % school, school) for school in self.schools] TypeError: 'NoneType' object is not iterable
*** This bug has been marked as a duplicate of bug 42432 ***
I will change the duplicate order.
*** Bug 42432 has been marked as a duplicate of this bug. ***
Traceback happens if the class or the password of a user is changed via the "Users (schools)" module is changed.
Is it possible, that the source of this bug is the same as with the CSV-module: faulty JS code, returning 'none' instead of '{}' when no school is explicitly set?
This fixes the bug: Index: ucs-school-lib/python/models/user.py =================================================================== --- ucs-school-lib/python/models/user.py (Revision 72938) +++ ucs-school-lib/python/models/user.py (Arbeitskopie) @@ -74,6 +74,11 @@ super(User, self).__init__(*args, **kwargs) if self.school_classes is None: self.school_classes = {} + if self.schools is None: + if self.school: + self.schools = [self.school] + else: + self.schools = []
I added some debug output: Index: ucs-school-umc-wizards/umc/python/schoolwizards/__init__.py =================================================================== --- ucs-school-umc-wizards/umc/python/schoolwizards/__init__.py (Revision 72938) +++ ucs-school-umc-wizards/umc/python/schoolwizards/__init__.py (Arbeitskopie) @@ -90,6 +90,7 @@ for key, value in obj_props.iteritems(): if isinstance(value, basestring): obj_props[key] = value.strip() + MODULE.process('iter_objects_in_request() key=%r value=%r' % (key, value)) if issubclass(klass, User): klass = get_user_class(obj_props.get('type')) elif issubclass(klass, SchoolComputer): @@ -101,7 +102,9 @@ if issubclass(klass, SchoolClass): # workaround to be able to reuse this function everywhere obj_props['name'] = '%s-%s' % (obj_props['school'], obj_props['name']) + MODULE.process('iter_objects_in_request() obj_props()=%r' % obj_props) obj = klass(**obj_props) + MODULE.process('iter_objects_in_request() obj.to_dict()=%r' % obj.to_dict()) if dn: obj.old_dn = dn yield obj ------------------------------------------------------------------------------ And got this: ------------------------------------------------------------------------------ iter_objects_in_request() key='$dn$' value='uid=schueler1,cn=schueler,cn=users,ou=schulezwei,ou=sc,dc=uni,dc=dtr' iter_objects_in_request() key='name' value='schueler1' iter_objects_in_request() key='firstname' value='sch' iter_objects_in_request() key='lastname' value=u'\xfcler1' iter_objects_in_request() key='school' value='schulezwei' iter_objects_in_request() key='school_classes' value={'schulezwei': ['2b']} iter_objects_in_request() key='password' value='univention' iter_objects_in_request() key='type' value='student' iter_objects_in_request() key='email' value='' iter_objects_in_request() obj_props()={'$dn$': 'uid=schueler1,cn=schueler,cn=users,ou=schulezwei,ou=sc,dc=uni,dc=dtr', 'name': 'schueler1', 'firstname': 'sch', 'lastname': u'\xfcler1', 'school': 'schulezwei', 'school_classes': {'schulezwei': ['2b']}, 'password': 'univention', 'type': 'student', 'email': ''} iter_objects_in_request() obj.to_dict()={'$dn$': 'uid=schueler1,cn=schueler,cn=users,ou=schulezwei,ou=sc,dc=uni,dc=dtr', 'display_name': u'sch \xfcler1', 'name': 'schueler1', 'firstname': 'sch', 'lastname': u'\xfcler1', 'type_name': u'Sch\xfcler', 'school': 'schulezwei', 'school_classes': {'schulezwei': ['2b']}, 'disabled': None, 'birthday': None, 'schools': None, 'password': 'univenti on', 'type': 'student', 'email': '', 'objectType': 'users/user'} ------------------------------------------------------------------------------ So the error happens, because in schoolwizards/__init__.py → _modify_obj(): user = User(**{...}) user.modify() IMHO the step missing is to first get the existing object from LDAP/UDM, apply the changes to it and then run modify() on it. So this here fixes the Bug too, and at the right spot: Index: ucs-school-umc-wizards/umc/python/schoolwizards/__init__.py =================================================================== --- ucs-school-umc-wizards/umc/python/schoolwizards/__init__.py (Revision 72938) +++ ucs-school-umc-wizards/umc/python/schoolwizards/__init__.py (Arbeitskopie) @@ -200,8 +200,13 @@ if obj.errors: ret.append({'result' : {'message' : obj.get_error_msg()}}) continue + obj_loaded = obj.from_dn(obj.dn, obj.school, ldap_user_read) + for name, _attr in obj._attributes.iteritems(): + new_value = getattr(obj, name) + if new_value is not None: + setattr(obj_loaded, name, new_value) try: - obj.modify(ldap_user_write, validate=False) + obj_loaded.modify(ldap_user_write, validate=False) except uldapBaseException as exc: ret.append({'result' : {'message' : get_exception_msg(exc)}}) else: ------------------------------------------------------------------------------ I'm not entirely sure about excluding 'None' values - Florian can they be valid in other modules? Regardless of this, the previous patch (from Comment6) should be applied too, to make the User objects attributes always behave consistently (as was done with 'school_classes').
Created attachment 8061 [details] patches from previous two comments patches as file for convenience
72958: initialize Users schools attribute in constructor 72959: fix modifying users (change school_classes, password) 72961: add comments, remove unused variable 72962: support renaming of classes 72963: YAML package version 72964: YAML ucs-school-umc-wizards 8.0.0-9.1.144.201610061601 ucs-school-lib 9.0.23-7.262.201610061608
Created attachment 8077 [details] patch The attached patch would have been the solution which resolves the cause (instead of the symptoms).
I reverted the uneccessary python backend changes and added the javascript changes. I also made the ucs-school-lib changes more robust so that the default values are set for every attribute and wrong API usage is still detected. ucs-school-umc-wizards (8.0.0-11): r73003 | Bug #42441: fix fuzzy r72995 | Bug #42441: fix modifications of user objects r72994 | Revert "Bug #42441: fix modifying users (change school_classes, password)" r72993 | Revert "Bug #42441: add comments, remove unused variable" r72992 | Revert "Bug #42441: support renaming of classes" Package: ucs-school-lib Version: 9.0.24-1.263.201610071409 Branch: ucs_4.1-0 Scope: ucs-school-4.1r2 Package: ucs-school-umc-wizards Version: 8.0.0-11.146.201610071412 Branch: ucs_4.1-0 Scope: ucs-school-4.1r2
The change in ucsschool lib has adapted to set the default value only if attr.value_default is set. So the default value for SchoolClass.users keeps being None and modifications of a SchoolClass are still possible without sending the current users in the put/modify request. ucs-school-lib (9.0.24-2): r73014 | Bug #42441: make default value explicitly setable to allow None values
OK: code change OK: functional test OK: advisory Tests (checked all LDAP changes during tests): - user with one OU - changed password - changed class - changed mail address - user with two OUs (tested for each OU seperately) - changed password - changed class - changed mail address - create class - modify class description - create computer - modify computer - create OU - modify OU
Reported again, 4.1-3 errata282 (Vahr) Reported again, 4.1-3 errata268 (Vahr)
UCS@school 4.1 R2 v6 has been released. http://docs.software-univention.de/changelog-ucsschool-4.1R2v6-de.html If this error occurs again, please clone this bug.
*** Bug 41717 has been marked as a duplicate of this bug. ***
Reported again, 4.1-3 errata282 (Vahr)