Code

Quote ampersands in URLs.
[roundup.git] / roundup / cgi / templating.py
index 106df96e2d90a6b3143eff92889e1300220415c0..61a30fecdc3e87876e0d3fd90a31c769e25a21c0 100644 (file)
@@ -535,14 +535,14 @@ class HTMLClass(HTMLInputMixin, HTMLPermissions):
                     value = lookupIds(self._db, prop,
                         handleListCGIValue(form[item]), fail_ok=1)
                 elif isinstance(prop, hyperdb.Link):
-                    value = form[item].value.strip()
+                    value = form.getfirst(item).strip()
                     if value:
                         value = lookupIds(self._db, prop, [value],
                             fail_ok=1)[0]
                     else:
                         value = None
                 else:
-                    value = form[item].value.strip() or None
+                    value = form.getfirst(item).strip() or None
             else:
                 if isinstance(prop, hyperdb.Multilink):
                     value = []
@@ -695,7 +695,7 @@ class HTMLClass(HTMLInputMixin, HTMLPermissions):
             if 'username' in properties.split( ',' ):
                 sort = 'username'
             else:
-                sort = find_sort_key(self._klass)
+                sort = self._klass.orderprop()
         sort = '&@sort=' + sort
         if property:
             property = '&property=%s'%property
@@ -1737,7 +1737,7 @@ class DateHTMLProperty(HTMLProperty):
         else :
             date = ""
         return ('<a class="classhelp" href="javascript:help_window('
-            "'%s?@template=calendar&property=%s&form=%s%s', %d, %d)"
+            "'%s?@template=calendar&amp;property=%s&amp;form=%s%s', %d, %d)"
             '">%s</a>'%(self._classname, self._name, form, date, width,
             height, label))
 
@@ -1873,8 +1873,14 @@ class LinkHTMLProperty(HTMLProperty):
         if not self.is_edit_ok():
             return self.plain(escape=1)
 
+        # Since None indicates the default, we need another way to
+        # indicate "no selection".  We use -1 for this purpose, as
+        # that is the value we use when submitting a form without the
+        # value set.
         if value is None:
             value = self._value
+        elif value == '-1':
+            value = None
 
         linkcl = self._db.getclass(self._prop.classname)
         l = ['<select name="%s">'%self._formname]
@@ -1891,7 +1897,7 @@ class LinkHTMLProperty(HTMLProperty):
                 else:
                     sort_on = ('+', sort_on)
         else:
-            sort_on = ('+', find_sort_key(linkcl))
+            sort_on = ('+', linkcl.orderprop())
 
         options = [opt
             for opt in linkcl.filter(None, conditions, sort_on, (None, None))
@@ -2077,13 +2083,24 @@ class MultilinkHTMLProperty(HTMLProperty):
                 else:
                     sort_on = ('+', sort_on)
         else:
-            sort_on = ('+', find_sort_key(linkcl))
+            sort_on = ('+', linkcl.orderprop())
 
         options = [opt
             for opt in linkcl.filter(None, conditions, sort_on)
             if self._db.security.hasPermission("View", self._client.userid,
                 linkcl.classname, itemid=opt)]
-        height = height or min(len(options), 7)
+        
+        # make sure we list the current values if they're retired
+        for val in value:
+            if val not in options:
+                options.insert(0, val)
+
+        if not height:
+            height = len(options)
+            if value:
+                # The "no selection" option.
+                height += 1
+            height = min(height, 7)
         l = ['<select multiple name="%s" size="%s">'%(self._formname, height)]
         k = linkcl.labelprop(1)
 
@@ -2139,17 +2156,11 @@ def make_sort_function(db, classname, sort_on=None):
     """
     linkcl = db.getclass(classname)
     if sort_on is None:
-        sort_on = find_sort_key(linkcl)
+        sort_on = linkcl.orderprop()
     def sortfunc(a, b):
         return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on))
     return sortfunc
 
-def find_sort_key(linkcl):
-    if linkcl.getprops().has_key('order'):
-        return 'order'
-    else:
-        return linkcl.labelprop()
-
 def handleListCGIValue(value):
     """ Value is either a single item or a list of items. Each item has a
         .value that we're actually interested in.
@@ -2231,10 +2242,10 @@ class HTMLRequest(HTMLInputMixin):
             key = '%s%s%d'%(special, name, idx)
             while key in self.form:
                 self.special_char = special
-                fields.append (self.form[key].value)
+                fields.append(self.form.getfirst(key))
                 dirkey = '%s%sdir%d'%(special, name, idx)
                 if dirkey in self.form:
-                    dirs.append(self.form[dirkey].value)
+                    dirs.append(self.form.getfirst(dirkey))
                 else:
                     dirs.append(None)
                 idx += 1
@@ -2245,7 +2256,7 @@ class HTMLRequest(HTMLInputMixin):
             if key in self.form and not fields:
                 fields = handleListCGIValue(self.form[key])
                 if dirkey in self.form:
-                    dirs.append(self.form[dirkey].value)
+                    dirs.append(self.form.getfirst(dirkey))
             if fields: # only try other special char if nothing found
                 break
         for f, d in map(None, fields, dirs):
@@ -2308,13 +2319,7 @@ class HTMLRequest(HTMLInputMixin):
         for name in ':search_text @search_text'.split():
             if self.form.has_key(name):
                 self.special_char = name[0]
-                try:
-                    self.search_text = self.form[name].value
-                except AttributeError:
-                    # http://psf.upfronthosting.co.za/roundup/meta/issue111
-                    # Multiple search_text, probably some kind of spambot.
-                    # Use first value.
-                    self.search_text = self.form[name][0].value
+                self.search_text = self.form.getfirst(name)
 
         # pagination - size and start index
         # figure batch args
@@ -2322,17 +2327,17 @@ class HTMLRequest(HTMLInputMixin):
         for name in ':pagesize @pagesize'.split():
             if self.form.has_key(name):
                 self.special_char = name[0]
-                self.pagesize = int(self.form[name].value)
+                self.pagesize = int(self.form.getfirst(name))
 
         self.startwith = 0
         for name in ':startwith @startwith'.split():
             if self.form.has_key(name):
                 self.special_char = name[0]
-                self.startwith = int(self.form[name].value)
+                self.startwith = int(self.form.getfirst(name))
 
         # dispname
         if self.form.has_key('@dispname'):
-            self.dispname = self.form['@dispname'].value
+            self.dispname = self.form.getfirst('@dispname')
         else:
             self.dispname = None
 
@@ -2424,10 +2429,10 @@ env: %(env)s
         if filter and self.filter:
             add(sc+'filter', ','.join(self.filter))
         if self.classname and filterspec:
-            props = self.client.db.getclass(self.classname).getprops()
+            cls = self.client.db.getclass(self.classname)
             for k,v in self.filterspec.items():
                 if type(v) == type([]):
-                    if isinstance(props[k], hyperdb.String):
+                    if isinstance(cls.get_transitive_prop(k), hyperdb.String):
                         add(k, ' '.join(v))
                     else:
                         add(k, ','.join(v))