X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=roundup%2Fcgi%2Ftemplating.py;h=3cb9780c909f94bb833018cce663673f09ec2971;hb=e26c0e6a8f9dca8e604bae291509feec1e492354;hp=226851de94308db566d0413a7d2e2cbc7e5e56b4;hpb=6d2be114edcf3dbfa05cb94e92f97eabaf3eacb5;p=roundup.git diff --git a/roundup/cgi/templating.py b/roundup/cgi/templating.py index 226851d..3cb9780 100644 --- a/roundup/cgi/templating.py +++ b/roundup/cgi/templating.py @@ -27,6 +27,8 @@ from roundup import hyperdb, date, support from roundup import i18n from roundup.i18n import _ +from KeywordsExpr import render_keywords_expression_editor + try: import cPickle as pickle except ImportError: @@ -115,9 +117,9 @@ def find_template(dir, name, view): if os.path.exists(src): return (src, generic) - raise NoTemplate, 'No template file exists for templating "%s" '\ + raise NoTemplate('No template file exists for templating "%s" ' 'with template "%s" (neither "%s" nor "%s")'%(name, view, - filename, generic) + filename, generic)) class Templates: templates = {} @@ -565,10 +567,7 @@ class HTMLClass(HTMLInputMixin, HTMLPermissions): for klass, htmlklass in propclasses: if not isinstance(prop, klass): continue - if isinstance(prop, hyperdb.Multilink): - value = [] - else: - value = None + value = prop.get_default_value() return htmlklass(self._client, self._classname, None, prop, item, value, self._anonymous) @@ -601,13 +600,10 @@ class HTMLClass(HTMLInputMixin, HTMLPermissions): l = [] for name, prop in self._props.items(): for klass, htmlklass in propclasses: - if isinstance(prop, hyperdb.Multilink): - value = [] - else: - value = None if isinstance(prop, klass): + value = prop.get_default_value() l.append(htmlklass(self._client, self._classname, '', - prop, name, value, self._anonymous)) + prop, name, value, self._anonymous)) if sort: l.sort(lambda a,b:cmp(a._name, b._name)) return l @@ -673,13 +669,21 @@ class HTMLClass(HTMLInputMixin, HTMLPermissions): "request" takes precedence over the other three arguments. """ + security = self._db.security + userid = self._client.userid if request is not None: + # for a request we asume it has already been + # security-filtered filterspec = request.filterspec sort = request.sort group = request.group + else: + cn = self.classname + filterspec = security.filterFilterspec(userid, cn, filterspec) + sort = security.filterSortspec(userid, cn, sort) + group = security.filterSortspec(userid, cn, group) - check = self._db.security.hasPermission - userid = self._client.userid + check = security.hasPermission if not check('Web Access', userid): return [] @@ -1104,6 +1108,13 @@ class _HTMLItem(HTMLInputMixin, HTMLPermissions): cell[-1] += ' -> %s'%current[k] current[k] = val + elif isinstance(prop, hyperdb.Password) and args[k] is not None: + val = args[k].dummystr() + cell.append('%s: %s'%(self._(k), val)) + if current.has_key(k): + cell[-1] += ' -> %s'%current[k] + current[k] = val + elif not args[k]: if current.has_key(k): cell.append('%s: %s'%(self._(k), current[k])) @@ -1281,8 +1292,9 @@ class HTMLProperty(HTMLInputMixin, HTMLPermissions): HTMLInputMixin.__init__(self) def __repr__(self): - return ''%(id(self), self._formname, - self._prop, self._value) + classname = self.__class__.__name__ + return '<%s(0x%x) %s %r %r>'%(classname, id(self), self._formname, + self._prop, self._value) def __str__(self): return self.plain() def __cmp__(self, other): @@ -1343,7 +1355,42 @@ class StringHTMLProperty(HTMLProperty): )''', re.X | re.I) protocol_re = re.compile('^(ht|f)tp(s?)://', re.I) - def _hyper_repl_item(self,match,replacement): + + + def _hyper_repl(self, match): + if match.group('url'): + return self._hyper_repl_url(match, '%s%s') + elif match.group('email'): + return self._hyper_repl_email(match, '%s') + elif len(match.group('id')) < 10: + return self._hyper_repl_item(match, + '%(item)s') + else: + # just return the matched text + return match.group(0) + + def _hyper_repl_url(self, match, replacement): + u = s = match.group('url') + if not self.protocol_re.search(s): + u = 'http://' + s + end = '' + if '>' in s: + # catch an escaped ">" in the URL + pos = s.find('>') + end = s[pos:] + u = s = s[:pos] + if ')' in s and s.count('(') != s.count(')'): + # don't include extraneous ')' in the link + pos = s.rfind(')') + end = s[pos:] + end + u = s = s[:pos] + return replacement % (u, s, end) + + def _hyper_repl_email(self, match, replacement): + s = match.group('email') + return replacement % (s, s) + + def _hyper_repl_item(self, match, replacement): item = match.group('item') cls = match.group('class').lower() id = match.group('id') @@ -1356,27 +1403,6 @@ class StringHTMLProperty(HTMLProperty): except KeyError: return item - def _hyper_repl(self, match): - if match.group('url'): - u = s = match.group('url') - if not self.protocol_re.search(s): - u = 'http://' + s - # catch an escaped ">" at the end of the URL - if s.endswith('>'): - u = s = s[:-4] - e = '>' - else: - e = '' - return '%s%s'%(u, s, e) - elif match.group('email'): - s = match.group('email') - return '%s'%(s, s) - elif len(match.group('id')) < 10: - return self._hyper_repl_item(match, - '%(item)s') - else: - # just return the matched text - return match.group(0) def _hyper_repl_rst(self, match): if match.group('url'): @@ -1542,7 +1568,10 @@ class PasswordHTMLProperty(HTMLProperty): if self._value is None: return '' - return self._('*encrypted*') + value = self._value.dummystr() + if escape: + value = cgi.escape(value) + return value def field(self, size=30, **kwargs): """ Render a form edit field for the property. @@ -1944,7 +1973,7 @@ class LinkHTMLProperty(HTMLProperty): **kwargs) def menu(self, size=None, height=None, showid=0, additional=[], value=None, - sort_on=None, html_kwargs = {}, **conditions): + sort_on=None, html_kwargs={}, translate=True, **conditions): """ Render a form select list for this property "size" is used to limit the length of the list labels @@ -1957,6 +1986,11 @@ class LinkHTMLProperty(HTMLProperty): (direction, property) where direction is '+' or '-'. A single string with the direction prepended may be used. For example: ('-', 'order'), '+name'. + "html_kwargs" specified additional html args for the + generated html ') return '\n'.join(l) @@ -2154,19 +2191,23 @@ class MultilinkHTMLProperty(HTMLProperty): return self.plain(escape=1) linkcl = self._db.getclass(self._prop.classname) - value = self._value[:] - # map the id to the label property - if not linkcl.getkey(): - showid=1 - if not showid: - k = linkcl.labelprop(1) - value = lookupKeys(linkcl, k, value) - value = ','.join(value) - return self.input(name=self._formname, size=size, value=value, - **kwargs) + + if 'value' not in kwargs: + value = self._value[:] + # map the id to the label property + if not linkcl.getkey(): + showid=1 + if not showid: + k = linkcl.labelprop(1) + value = lookupKeys(linkcl, k, value) + value = ','.join(value) + kwargs["value"] = value + + return self.input(name=self._formname, size=size, **kwargs) def menu(self, size=None, height=None, showid=0, additional=[], - value=None, sort_on=None, html_kwargs = {}, **conditions): + value=None, sort_on=None, html_kwargs={}, translate=True, + **conditions): """ Render a form ') return '\n'.join(l) + # set the propclasses for HTMLItem -propclasses = ( +propclasses = [ (hyperdb.String, StringHTMLProperty), (hyperdb.Number, NumberHTMLProperty), (hyperdb.Boolean, BooleanHTMLProperty), @@ -2283,16 +2328,32 @@ propclasses = ( (hyperdb.Password, PasswordHTMLProperty), (hyperdb.Link, LinkHTMLProperty), (hyperdb.Multilink, MultilinkHTMLProperty), -) +] + +def register_propclass(prop, cls): + for index,propclass in enumerate(propclasses): + p, c = propclass + if prop == p: + propclasses[index] = (prop, cls) + break + else: + propclasses.append((prop, cls)) + def make_sort_function(db, classname, sort_on=None): - """Make a sort function for a given class + """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): - return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on)) + 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 def handleListCGIValue(value): @@ -2412,12 +2473,16 @@ class HTMLRequest(HTMLInputMixin): self.columns = handleListCGIValue(self.form[name]) break self.show = support.TruthDict(self.columns) + security = self._client.db.security + userid = self._client.userid # sorting and grouping self.sort = [] self.group = [] self._parse_sort(self.sort, 'sort') self._parse_sort(self.group, 'group') + self.sort = security.filterSortspec(userid, self.classname, self.sort) + self.group = security.filterSortspec(userid, self.classname, self.group) # filtering self.filter = [] @@ -2447,6 +2512,8 @@ class HTMLRequest(HTMLInputMixin): self.filterspec[name] = handleListCGIValue(fv) else: self.filterspec[name] = fv.value + self.filterspec = security.filterFilterspec(userid, self.classname, + self.filterspec) # full-text search argument self.search_text = None @@ -2663,7 +2730,7 @@ function help_window(helpurl, width, height) { """%self.base - def batch(self): + def batch(self, permission='View'): """ Return a batch object for results from the "current search" """ check = self._client.db.security.hasPermission @@ -2689,7 +2756,7 @@ function help_window(helpurl, width, height) { # filter for visibility l = [id for id in klass.filter(matches, filterspec, sort, group) - if check('View', userid, self.classname, itemid=id)] + if check(permission, userid, self.classname, itemid=id)] # return the batch object, using IDs only return Batch(self.client, l, self.pagesize, self.startwith, @@ -2814,6 +2881,9 @@ class TemplatingUtils: raise AttributeError, name return self.client.instance.templating_utils[name] + def keywords_expressions(self, request): + return render_keywords_expression_editor(request) + def html_calendar(self, request): """Generate a HTML calendar. @@ -2827,7 +2897,9 @@ class TemplatingUtils: html will simply be a table. """ - date_str = request.form.getfirst("date", ".") + tz = request.client.db.getUserTimezone() + current_date = date.Date(".").local(tz) + date_str = request.form.getfirst("date", current_date) display = request.form.getfirst("display", date_str) template = request.form.getfirst("@template", "calendar") form = request.form.getfirst("form")