Bug 42441 - Traceback upon changing student's class assignment in UMC module "users (schools)"
Traceback upon changing student's class assignment in UMC module "users (scho...
Status: CLOSED FIXED
Product: UCS@school
Classification: Unclassified
Component: Ucsschool-lib
UCS@school 4.1 R2
Other Linux
: P5 normal (vote)
: UCS@school 4.1 R2 vXXX
Assigned To: Florian Best
Sönke Schwardt-Krummrich
: interim-2
: 41717 42432 (view as bug list)
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2016-09-20 13:05 CEST by Sönke Schwardt-Krummrich
Modified: 2016-12-09 17:54 CET (History)
3 users (show)

See Also:
What kind of report is it?: Bug Report
What type of bug is this?: 5: Major Usability: Impairs usability in key scenarios
Who will be affected by this bug?: 3: Will affect average number of installed domains
How will those affected feel about the bug?: 4: A User would return the product
User Pain: 0.343
Enterprise Customer affected?:
School Customer affected?: Yes
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number: 2016091621000484, 2016100721000131, 2016100521000261, 2016102021000231, 2016111821000351
Bug group (optional): External feedback
Max CVSS v3 score:


Attachments
patches from previous two comments (1.76 KB, patch)
2016-10-02 20:10 CEST, Daniel Tröder
Details | Diff
patch (1.37 KB, patch)
2016-10-07 12:48 CEST, Florian Best
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sönke Schwardt-Krummrich univentionstaff 2016-09-20 13:05:51 CEST
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
Comment 1 Florian Best univentionstaff 2016-09-20 13:14:56 CEST

*** This bug has been marked as a duplicate of bug 42432 ***
Comment 2 Florian Best univentionstaff 2016-09-26 14:23:10 CEST
I will change the duplicate order.
Comment 3 Florian Best univentionstaff 2016-09-26 14:23:19 CEST
*** Bug 42432 has been marked as a duplicate of this bug. ***
Comment 4 Sönke Schwardt-Krummrich univentionstaff 2016-09-30 15:05:26 CEST
Traceback happens if the class or the password of a user is changed via the "Users (schools)" module is changed.
Comment 5 Daniel Tröder univentionstaff 2016-10-02 18:03:23 CEST
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?
Comment 6 Daniel Tröder univentionstaff 2016-10-02 19:12:59 CEST
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 = []
Comment 7 Daniel Tröder univentionstaff 2016-10-02 20:00:05 CEST
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').
Comment 8 Daniel Tröder univentionstaff 2016-10-02 20:10:21 CEST
Created attachment 8061 [details]
patches from previous two comments

patches as file for convenience
Comment 9 Daniel Tröder univentionstaff 2016-10-06 16:12:15 CEST
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
Comment 10 Florian Best univentionstaff 2016-10-07 12:48:05 CEST
Created attachment 8077 [details]
patch

The attached patch would have been the solution which resolves the cause (instead of the symptoms).
Comment 11 Florian Best univentionstaff 2016-10-07 14:14:34 CEST
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
Comment 12 Florian Best univentionstaff 2016-10-07 16:28:55 CEST
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
Comment 13 Sönke Schwardt-Krummrich univentionstaff 2016-10-07 17:17:28 CEST
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
Comment 14 Florian Best univentionstaff 2016-10-10 11:30:34 CEST
Reported again, 4.1-3 errata282 (Vahr)
Reported again, 4.1-3 errata268 (Vahr)
Comment 15 Sönke Schwardt-Krummrich univentionstaff 2016-10-10 13:39:57 CEST
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.
Comment 16 Florian Best univentionstaff 2016-10-25 15:59:55 CEST
*** Bug 41717 has been marked as a duplicate of this bug. ***
Comment 17 Florian Best univentionstaff 2016-10-25 16:00:52 CEST
Reported again, 4.1-3 errata282 (Vahr)
Comment 18 Florian Best univentionstaff 2016-12-09 17:54:24 CET
Reported again, 4.1-3 errata282 (Vahr)