Roundup Tracker - Issues

Issue 2550663

classification
Problems with templating.py:lookupIds
Type: behavior Severity: normal
Components: Infrastructure Versions: 1.4
process
Status: closed accepted
:
: : ber, ezio.melotti, richard
Priority: high :

Created on 2010-08-10 08:14 by ezio.melotti, last changed 2011-08-22 08:19 by ber.

Messages
msg4109 Author: [hidden] (ezio.melotti) Date: 2010-08-10 08:14
While I was trying to debug
http://psf.upfronthosting.co.za/roundup/meta/issue336 I found out a few
weird things about the lookupIds function in the templating module. This
is the code of the function (without comments and docstring):
def lookupIds(db, prop, ids, fail_ok=0, num_re=num_re, do_lookup=True):
    cl = db.getclass(prop.classname)
    l = []
    for entry in ids:
        if do_lookup:
            try:
                item = cl.lookup(entry)
            except (TypeError, KeyError):
                pass
            else:
                l.append(item)
                continue
        if fail_ok or num_re.match(entry):
            l.append(entry)
    return l

First of all, if do_lookup is False the cl var is useless, so it should
be created inside the if.
Second, if do_lookup is False and fail_ok is True the function just
return a copy of ids.
Third, if both do_lookup and fail_ok are True, the function returns half
of the arguments converted and the other half as they are. This was what
caused the bug I was trying to debug (i.e., when invalid names are in
the nosy, this function returns a list of invalid names and valid ids,
and the invalid names are passed to the db when it expects numeric ids).

An example of this is in the MultilinkHTMLProperty class
(templating.py). This is apparently used for the nosy list and when it's
instantiated the following things happen:
1) MultilinkHTMLProperty.__init__ calls the __init__ of its superclass
HTMLProperty;
2) HTMLProperty.__init__ calls lookupIds passing the names in the nosy
list with do_lookup and fail_ok set to True (so only the valid names in
the nosy are converted to ids);
3) HTMLProperty.__init__ stores the resulting list (invalid names mixed
with valid ids) in self._value;
4) MultilinkHTMLProperty.__init__ calls lookupIds passing self._value
with do_lookup=False and fail_ok=True;
5) lookupIds returns a copy of the list;
6) that copy of the list is then sorted to be stored to self._value.
7) the sorting tries to get some info from the db and sends an invalid
query ("select ... from _users where id='invalidname'");
8) the db gets blocked because the query is invalid;
9) at the next (possibly valid) query the db raises a
psycopg2.InternalError exception because the db is blocked and it's not
possible to do other queries and an error page is displayed.

I'm not sure what is the best way to fix this.
One solution is to check that nodeid is numeric in
rdbms_common.py:getnode before the sql call and raise an error if it's
not numeric. This just abort the sorting and the page is rendered
properly with a message saying "xxx name is invalid" on the top in a red
box. This is probably a good idea assuming that nodeid must be numeric.
Another solution would be calling the lookupIds function with other
flags in order to avoid mixing invalid names and valid ids.
Otherwise the lookupIds can be changed to never return mixed lists, but
I don't know if other functions "need" this behavior.
The lookupIds function and some of its called (i.e. the ones with
do_lookup=False and fail_ok=True) should be refactored anyway.
msg4114 Author: [hidden] (richard) Date: 2010-08-12 05:15
That's quite the effort you've made to trace through some of the ickiest code in Roundup :-)

The data quality issue in the various *Property classes - in particular the Link and Multilink 
ones - should probably be handled at the templating level, rather than down in the database 
(potentially masking other bugs).

To that end I think it's reasonable to have make_sort_function() do the right thing. It should 
*expect* to be passed lists with mixed content (ids and labels). I think a reasonable solution 
could be:


def make_sort_function(db, classname, sort_on=None):
    """Make a sort function for a given class.
    
    The list being sorted may contain mixed ids and labels.
    """
    linkcl = db.getclass(classname)
    if sort_on is None:
        sort_on = linkcl.orderprop()
    def sortfunc(a, b):
        if num_re.match(a):
            a = linkcl.get(a, sort_on)
        if num_re.match(b):
            b = linkcl.get(b, sort_on)
        return cmp(a, b)
    return sortfunc
msg4115 Author: [hidden] (ezio.melotti) Date: 2010-08-12 07:24
So you suggest to check it in templating.py:make_sort_function rather
that in rdbms_common.py:getnode?
Fixing it there makes sense, but adding a check in getnode too might be
safer (assuming that all the nodeids are numeric (also are they always
supposed to be passed as string? I managed to pass them as ints while
working at the roundup weekly summary script and it worked fine;
checking with a regex in getnode without checking the type will break it)).

I can provide a patch to add the check (in make_sort_function or in
both) and a separate patch to refactor lookupIds and some of its calls a
little without changing its behavior (i.e. put an "if do_lookup:" before
"cl = db.getclass(prop.classname)" and replace calls that use
do_lookup=False and fail_ok=True to just use list() (I'm not sure a copy
of the list is really needed, but that's what happen now)).
msg4129 Author: [hidden] (richard) Date: 2010-09-10 06:34
I've made make_sort_function more robust as discussed. If you wish to supply a patch for 
additional changes that'd be fine.
msg4385 Author: [hidden] (ezio.melotti) Date: 2011-08-20 08:39
Your fix seems to work fine (thanks!), so I think this can be closed.
msg4389 Author: [hidden] (ber) Date: 2011-08-22 08:19
Ezio, thanks for the feedback and the confirmation on the issue!
History
Date User Action Args
2011-08-22 08:19:30bersetstatus: new -> closed
nosy: + ber
messages: + msg4389
2011-08-20 08:39:13ezio.melottisetmessages: + msg4385
2010-09-10 06:34:53richardsetmessages: + msg4129
2010-08-12 07:24:49ezio.melottisetmessages: + msg4115
2010-08-12 05:15:53richardsetpriority: high
resolution: accepted
messages: + msg4114
nosy: + richard
2010-08-10 08:14:32ezio.melotticreate