X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=roundup%2Fcgi%2Ftemplating.py;h=2f2a478f14e570dbe49dc0cae1c0b21f67dfb6a5;hb=3d106aaea151d4ee72945a7c8f26a8deb8f482a6;hp=11e49835391bcf53c7444251e55978b92ce58acf;hpb=c64e9460d9b73a28504402dc68d92f297f64cba6;p=roundup.git diff --git a/roundup/cgi/templating.py b/roundup/cgi/templating.py index 11e4983..2f2a478 100644 --- a/roundup/cgi/templating.py +++ b/roundup/cgi/templating.py @@ -155,7 +155,10 @@ class RoundupPageTemplate(PageTemplate.PageTemplate): } # add in the item if there is one if client.nodeid: - c['context'] = HTMLItem(client, classname, client.nodeid) + if classname == 'user': + c['context'] = HTMLUser(client, classname, client.nodeid) + else: + c['context'] = HTMLItem(client, classname, client.nodeid) else: c['context'] = HTMLClass(client, classname) return c @@ -170,7 +173,7 @@ class RoundupPageTemplate(PageTemplate.PageTemplate): if self._v_errors: raise PageTemplate.PTRuntimeError, \ - 'Page Template %s has errors.' % self.id + 'Page Template %s has errors.'%self.id # figure the context classname = classname or client.classname @@ -193,12 +196,16 @@ class HTMLDatabase: # we want config to be exposed self.config = client.db.config + def __getitem__(self, item): + self._client.db.getclass(item) + return HTMLClass(self._client, item) + def __getattr__(self, attr): try: - self._client.db.getclass(attr) + return self[attr] except KeyError: raise AttributeError, attr - return HTMLClass(self._client, attr) + def classes(self): l = self._client.db.classes.keys() l.sort() @@ -214,15 +221,34 @@ def lookupIds(db, prop, ids, num_re=re.compile('-?\d+')): l.append(cl.lookup(entry)) return l -class HTMLClass: +class HTMLPermissions: + ''' Helpers that provide answers to commonly asked Permission questions. + ''' + def is_edit_ok(self): + ''' Is the user allowed to Edit the current class? + ''' + return self._db.security.hasPermission('Edit', self._client.userid, + self._classname) + def is_view_ok(self): + ''' Is the user allowed to View the current class? + ''' + return self._db.security.hasPermission('View', self._client.userid, + self._classname) + def is_only_view_ok(self): + ''' Is the user only allowed to View (ie. not Edit) the current class? + ''' + return self.is_view_ok() and not self.is_edit_ok() + +class HTMLClass(HTMLPermissions): ''' Accesses through a class (either through *class* or *db.*) ''' def __init__(self, client, classname): self._client = client self._db = client.db - # we want classname to be exposed - self.classname = classname + # we want classname to be exposed, but _classname gives a + # consistent API for extending Class/Item + self._classname = self.classname = classname if classname is not None: self._klass = self._db.getclass(self.classname) self._props = self._klass.getprops() @@ -277,7 +303,7 @@ class HTMLClass: raise AttributeError, attr def properties(self): - ''' Return HTMLProperty for all props + ''' Return HTMLProperty for all of this class' properties. ''' l = [] for name, prop in self._props.items(): @@ -291,11 +317,19 @@ class HTMLClass: return l def list(self): + ''' List all items in this class. + ''' if self.classname == 'user': klass = HTMLUser else: klass = HTMLItem - l = [klass(self._client, self.classname, x) for x in self._klass.list()] + + # get the list and sort it nicely + l = self._klass.list() + sortfunc = make_sort_function(self._db, self._prop.classname) + l.sort(sortfunc) + + l = [klass(self._client, self.classname, x) for x in l] return l def csv(self): @@ -393,7 +427,7 @@ class HTMLClass: # use our fabricated request return pt.render(self._client, self.classname, req) -class HTMLItem: +class HTMLItem(HTMLPermissions): ''' Accesses through an *item* ''' def __init__(self, client, classname, nodeid): @@ -621,6 +655,7 @@ class HTMLUser(HTMLItem): # used for security checks self._security = client.db.security + _marker = [] def hasPermission(self, role, classname=_marker): ''' Determine if the user has the Role. @@ -632,10 +667,24 @@ class HTMLUser(HTMLItem): classname = self._default_classname return self._security.hasPermission(role, self._nodeid, classname) + def is_edit_ok(self): + ''' Is the user allowed to Edit the current class? + Also check whether this is the current user's info. + ''' + return self._db.security.hasPermission('Edit', self._client.userid, + self._classname) or self._nodeid == self._client.userid + + def is_view_ok(self): + ''' Is the user allowed to View the current class? + Also check whether this is the current user's info. + ''' + return self._db.security.hasPermission('Edit', self._client.userid, + self._classname) or self._nodeid == self._client.userid + class HTMLProperty: ''' String, Number, Date, Interval HTMLProperty - Hase useful attributes: + Has useful attributes: _name the name of the property _value the value of the property if any @@ -660,6 +709,8 @@ class HTMLProperty: class StringHTMLProperty(HTMLProperty): def plain(self, escape=0): + ''' Render a "plain" representation of the property + ''' if self._value is None: return '' if escape: @@ -667,12 +718,18 @@ class StringHTMLProperty(HTMLProperty): return str(self._value) def stext(self, escape=0): + ''' Render the value of the property as StructuredText. + + This requires the StructureText module to be installed separately. + ''' s = self.plain(escape=escape) if not StructuredText: return s return StructuredText(s,level=1,header=0) def field(self, size = 30): + ''' Render a form edit field for the property + ''' if self._value is None: value = '' else: @@ -681,6 +738,8 @@ class StringHTMLProperty(HTMLProperty): return ''%(self._name, value, size) def multiline(self, escape=0, rows=5, cols=40): + ''' Render a multiline form edit field for the property + ''' if self._value is None: value = '' else: @@ -690,29 +749,51 @@ class StringHTMLProperty(HTMLProperty): self._name, rows, cols, value) def email(self, escape=1): - ''' fudge email ''' + ''' Render the value of the property as an obscured email address + ''' if self._value is None: value = '' else: value = str(self._value) - value = value.replace('@', ' at ') - value = value.replace('.', ' ') + if value.find('@') != -1: + name, domain = value.split('@') + domain = ' '.join(domain.split('.')[:-1]) + name = name.replace('.', ' ') + value = '%s at %s ...'%(name, domain) + else: + value = value.replace('.', ' ') if escape: value = cgi.escape(value) return value class PasswordHTMLProperty(HTMLProperty): def plain(self): + ''' Render a "plain" representation of the property + ''' if self._value is None: return '' return _('*encrypted*') def field(self, size = 30): + ''' Render a form edit field for the property. + ''' return ''%(self._name, size) + def confirm(self, size = 30): + ''' Render a second form edit field for the property, used for + confirmation that the user typed the password correctly. Generates + a field with name "name:confirm". + ''' + return ''%( + self._name, size) + class NumberHTMLProperty(HTMLProperty): def plain(self): + ''' Render a "plain" representation of the property + ''' return str(self._value) def field(self, size = 30): + ''' Render a form edit field for the property + ''' if self._value is None: value = '' else: @@ -722,11 +803,15 @@ class NumberHTMLProperty(HTMLProperty): class BooleanHTMLProperty(HTMLProperty): def plain(self): + ''' Render a "plain" representation of the property + ''' if self.value is None: return '' return self._value and "Yes" or "No" def field(self): + ''' Render a form edit field for the property + ''' checked = self._value and "checked" or "" s = 'Yes'%(self._name, checked) @@ -740,11 +825,15 @@ class BooleanHTMLProperty(HTMLProperty): class DateHTMLProperty(HTMLProperty): def plain(self): + ''' Render a "plain" representation of the property + ''' if self._value is None: return '' return str(self._value) def field(self, size = 30): + ''' Render a form edit field for the property + ''' if self._value is None: value = '' else: @@ -753,6 +842,10 @@ class DateHTMLProperty(HTMLProperty): return ''%(self._name, value, size) def reldate(self, pretty=1): + ''' Render the interval between the date and now. + + If the "pretty" flag is true, then make the display pretty. + ''' if not self._value: return '' @@ -764,14 +857,20 @@ class DateHTMLProperty(HTMLProperty): class IntervalHTMLProperty(HTMLProperty): def plain(self): + ''' Render a "plain" representation of the property + ''' if self._value is None: return '' return str(self._value) def pretty(self): + ''' Render the interval in a pretty format (eg. "yesterday") + ''' return self._value.pretty() def field(self, size = 30): + ''' Render a form edit field for the property + ''' if self._value is None: value = '' else: @@ -802,6 +901,8 @@ class LinkHTMLProperty(HTMLProperty): return getattr(i, attr) def plain(self, escape=0): + ''' Render a "plain" representation of the property + ''' if self._value is None: return '' linkcl = self._db.classes[self._prop.classname] @@ -811,17 +912,19 @@ class LinkHTMLProperty(HTMLProperty): value = cgi.escape(value) return value - def field(self): + def field(self, showid=0, size=None): + ''' Render a form edit field for the property + ''' linkcl = self._db.getclass(self._prop.classname) if linkcl.getprops().has_key('order'): sort_on = 'order' else: sort_on = linkcl.labelprop() - options = linkcl.filter(None, {}, [sort_on], []) + options = linkcl.filter(None, {}, ('+', sort_on), (None, None)) # TODO: make this a field display, not a menu one! - l = [''%self._name] k = linkcl.labelprop(1) - if value is None: + if self._value is None: s = 'selected ' else: s = '' @@ -829,7 +932,7 @@ class LinkHTMLProperty(HTMLProperty): for optionid in options: option = linkcl.get(optionid, k) s = '' - if optionid == value: + if optionid == self._value: s = 'selected ' if showid: lab = '%s%s: %s'%(self._prop.classname, optionid, option) @@ -844,14 +947,13 @@ class LinkHTMLProperty(HTMLProperty): def menu(self, size=None, height=None, showid=0, additional=[], **conditions): + ''' Render a form select list for this property + ''' value = self._value # sort function sortfunc = make_sort_function(self._db, self._prop.classname) - # force the value to be a single choice - if isinstance(value, type('')): - value = value[0] linkcl = self._db.getclass(self._prop.classname) l = ['