summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 44241e9)
raw | patch | inline | side by side (parent: 44241e9)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 20 Jan 2004 00:06:56 +0000 (00:06 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 20 Jan 2004 00:06:56 +0000 (00:06 +0000) |
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2051 57a73879-2fb5-44c3-a270-3262357dd7e2
roundup/cgi/templating.py | patch | blob | history |
index cbc742bb44d488411204cf57959ce8a12271508d..49242ef84b0729b2d2dac3ac5bd6683b0de33cc4 100644 (file)
class NoTemplate(Exception):
pass
+class Unauthorised(Exception):
+ def __init__(self, action, klass):
+ self.action = action
+ self.klass = klass
+ def __str__(self):
+ return 'You are not allowed to %s items of class %s'%(self.action,
+ self.klass)
+
def find_template(dir, name, extension):
''' Find a template in the nominated dir
'''
getEngine().getContext(c), output, tal=1, strictinsert=0)()
return output.getvalue()
+ def __repr__(self):
+ return '<Roundup PageTemplate %r>'%self.id
+
class HTMLDatabase:
''' Return HTMLClasses for valid class fetches
'''
'''
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()
+ def view_check(self):
+ ''' Raise the Unauthorised exception if the user's not permitted to
+ view this class.
+ '''
+ if not self.is_view_ok():
+ raise Unauthorised("view", self._classname)
+
+ def edit_check(self):
+ ''' Raise the Unauthorised exception if the user's not permitted to
+ edit this class.
+ '''
+ if not self.is_edit_ok():
+ raise Unauthorised("edit", self._classname)
+
def input_html4(**attrs):
"""Generate an 'input' (html4) element with given attributes"""
return '<input %s>'%' '.join(['%s="%s"'%item for item in attrs.items()])
l.sort(lambda a,b:cmp(a._name, b._name))
return l
- def list(self):
+ def list(self, sort_on=None):
''' List all items in this class.
'''
if self.classname == 'user':
# get the list and sort it nicely
l = self._klass.list()
- sortfunc = make_sort_function(self._db, self.classname)
+ sortfunc = make_sort_function(self._db, self.classname, sort_on)
l.sort(sortfunc)
l = [klass(self._client, self.classname, x) for x in l]
idlessprops.sort()
return ['id'] + idlessprops
- def filter(self, request=None):
+ def filter(self, request=None, filterspec={}, sort=(None,None),
+ group=(None,None)):
''' Return a list of items from this class, filtered and sorted
by the current requested filterspec/filter/sort/group args
+
+ "request" takes precedence over the other three arguments.
'''
- # XXX allow direct specification of the filterspec etc.
if request is not None:
filterspec = request.filterspec
sort = request.sort
group = request.group
- else:
- filterspec = {}
- sort = (None,None)
- group = (None,None)
if self.classname == 'user':
klass = HTMLUser
else:
def submit(self, label="Submit New Entry"):
''' Generate a submit button (and action hidden element)
'''
- return self.input(type="hidden",name="@action",value="new") + '\n' + \
- self.input(type="submit",name="submit",value=label)
+ self.view_check()
+ if self.is_edit_ok():
+ return self.input(type="hidden",name="@action",value="new") + \
+ '\n' + self.input(type="submit",name="submit",value=label)
+ return ''
def history(self):
+ self.view_check()
return 'New node - no history'
def renderWith(self, name, **kwargs):
pt = Templates(self._db.config.TEMPLATES).get(self.classname, name)
# use our fabricated request
- return pt.render(self._client, self.classname, req)
+ args = {
+ 'ok_message': self._client.ok_message,
+ 'error_message': self._client.error_message
+ }
+ return pt.render(self._client, self.classname, req, **args)
class HTMLItem(HTMLInputMixin, HTMLPermissions):
''' Accesses through an *item*
return []
def history(self, direction='descending', dre=re.compile('\d+')):
+ self.view_check()
+
l = ['<table class="history">'
'<tr><th colspan="4" class="header">',
_('History'),
self._classname) or (self._nodeid == self._client.userid and
self._db.user.get(self._client.userid, 'username') != 'anonymous')
-class HTMLProperty(HTMLInputMixin):
+class HTMLProperty(HTMLInputMixin, HTMLPermissions):
''' String, Number, Date, Interval HTMLProperty
Has useful attributes:
self._formname = name
HTMLInputMixin.__init__(self)
-
+
def __repr__(self):
return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self._formname,
self._prop, self._value)
"hyperlink" turns on/off in-text hyperlinking of URLs, email
addresses and designators
'''
+ self.view_check()
+
if self._value is None:
return ''
if escape:
This requires the StructureText module to be installed separately.
'''
+ self.view_check()
+
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
+ ''' Render the property as a field in HTML.
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
if self._value is None:
value = ''
else:
value = cgi.escape(str(self._value))
+
+ if self.is_edit_ok():
value = '"'.join(value.split('"'))
- return self.input(name=self._formname,value=value,size=size)
+ return self.input(name=self._formname,value=value,size=size)
+
+ return self.plain()
def multiline(self, escape=0, rows=5, cols=40):
- ''' Render a multiline form edit field for the property
+ ''' Render a multiline form edit field for the property.
+
+ If not editable, just display the plain() value in a <pre> tag.
'''
+ self.view_check()
+
if self._value is None:
value = ''
else:
value = cgi.escape(str(self._value))
+
+ if self.is_edit_ok():
value = '"'.join(value.split('"'))
- return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%(
- self._formname, rows, cols, value)
+ return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%(
+ self._formname, rows, cols, value)
+
+ return '<pre>%s</pre>'%self.plain()
def email(self, escape=1):
''' Render the value of the property as an obscured email address
'''
- if self._value is None: value = ''
- else: value = str(self._value)
+ self.view_check()
+
+ if self._value is None:
+ value = ''
+ else:
+ value = str(self._value)
if value.find('@') != -1:
name, domain = value.split('@')
domain = ' '.join(domain.split('.')[:-1])
def plain(self):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
if self._value is None:
return ''
return _('*encrypted*')
def field(self, size = 30):
''' Render a form edit field for the property.
+
+ If not editable, just display the value via plain().
'''
- return self.input(type="password", name=self._formname, size=size)
+ self.view_check()
+
+ if self.is_edit_ok():
+ return self.input(type="password", name=self._formname, size=size)
+
+ return self.plain()
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 "@confirm@name".
+
+ If not editable, display nothing.
'''
- return self.input(type="password", name="@confirm@%s"%self._formname,
- size=size)
+ self.view_check()
+
+ if self.is_edit_ok():
+ return self.input(type="password",
+ name="@confirm@%s"%self._formname, size=size)
+
+ return ''
class NumberHTMLProperty(HTMLProperty):
def plain(self):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
return str(self._value)
def field(self, size = 30):
- ''' Render a form edit field for the property
+ ''' Render a form edit field for the property.
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
if self._value is None:
value = ''
else:
value = cgi.escape(str(self._value))
+
+ if self.is_edit_ok():
value = '"'.join(value.split('"'))
- return self.input(name=self._formname,value=value,size=size)
+ return self.input(name=self._formname,value=value,size=size)
+
+ return self.plain()
def __int__(self):
''' Return an int of me
def plain(self):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
if self._value is None:
return ''
return self._value and "Yes" or "No"
def field(self):
''' Render a form edit field for the property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
+ if not is_edit_ok():
+ return self.plain()
+
checked = self._value and "checked" or ""
if self._value:
- s = self.input(type="radio",name=self._formname,value="yes",checked="checked")
+ s = self.input(type="radio", name=self._formname, value="yes",
+ checked="checked")
s += 'Yes'
- s +=self.input(type="radio",name=self._formname,value="no")
+ s +=self.input(type="radio", name=self._formname, value="no")
s += 'No'
else:
- s = self.input(type="radio",name=self._formname,value="yes")
+ s = self.input(type="radio", name=self._formname, value="yes")
s += 'Yes'
- s +=self.input(type="radio",name=self._formname,value="no",checked="checked")
+ s +=self.input(type="radio", name=self._formname, value="no",
+ checked="checked")
s += 'No'
return s
def plain(self):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
if self._value is None:
return ''
return str(self._value.local(self._db.getUserTimezone()))
This is useful for defaulting a new value. Returns a
DateHTMLProperty.
'''
+ self.view_check()
+
return DateHTMLProperty(self._client, self._nodeid, self._prop,
self._formname, date.Date('.'))
def field(self, size = 30):
''' Render a form edit field for the property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
if self._value is None:
value = ''
else:
- value = cgi.escape(str(self._value.local(self._db.getUserTimezone())))
+ tz = self._db.getUserTimezone()
+ value = cgi.escape(str(self._value.local(tz)))
+
+ if is_edit_ok():
value = '"'.join(value.split('"'))
- return self.input(name=self._formname,value=value,size=size)
+ return self.input(name=self._formname,value=value,size=size)
+
+ return self.plain()
def reldate(self, pretty=1):
''' Render the interval between the date and now.
If the "pretty" flag is true, then make the display pretty.
'''
+ self.view_check()
+
if not self._value:
return ''
string, then it'll be stripped from the output. This is handy
for the situatin when a date only specifies a month and a year.
'''
+ self.view_check()
+
if format is not self._marker:
return self._value.pretty(format)
else:
def local(self, offset):
''' Return the date/time as a local (timezone offset) date/time.
'''
+ self.view_check()
+
return DateHTMLProperty(self._client, self._nodeid, self._prop,
self._formname, self._value.local(offset))
def plain(self):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
if self._value is None:
return ''
return str(self._value)
def pretty(self):
''' Render the interval in a pretty format (eg. "yesterday")
'''
+ self.view_check()
+
return self._value.pretty()
def field(self, size = 30):
''' Render a form edit field for the property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
if self._value is None:
value = ''
else:
value = cgi.escape(str(self._value))
+
+ if is_edit_ok():
value = '"'.join(value.split('"'))
- return self.input(name=self._formname,value=value,size=size)
+ return self.input(name=self._formname,value=value,size=size)
+
+ return self.plain()
class LinkHTMLProperty(HTMLProperty):
''' Link HTMLProperty
def plain(self, escape=0):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
if self._value is None:
return ''
linkcl = self._db.classes[self._prop.classname]
def field(self, showid=0, size=None):
''' Render a form edit field for the property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
+ if not self.is_edit_ok():
+ return self.plain()
+
+ # edit field
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), (None, None))
- # TODO: make this a field display, not a menu one!
- l = ['<select name="%s">'%self._formname]
- k = linkcl.labelprop(1)
if self._value is None:
- s = 'selected="selected" '
+ value = ''
else:
- s = ''
- l.append(_('<option %svalue="-1">- no selection -</option>')%s)
-
- # make sure we list the current value if it's retired
- if self._value and self._value not in options:
- options.insert(0, self._value)
-
- for optionid in options:
- # get the option value, and if it's None use an empty string
- option = linkcl.get(optionid, k) or ''
-
- # figure if this option is selected
- s = ''
- if optionid == self._value:
- s = 'selected="selected" '
-
- # figure the label
- if showid:
- lab = '%s%s: %s'%(self._prop.classname, optionid, option)
+ k = linkcl.getkey()
+ if k:
+ label = linkcl.get(self._value, k)
else:
- lab = option
-
- # truncate if it's too long
- if size is not None and len(lab) > size:
- lab = lab[:size-3] + '...'
-
- # and generate
- lab = cgi.escape(lab)
- l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab))
- l.append('</select>')
- return '\n'.join(l)
+ label = self._value
+ value = cgi.escape(str(self._value))
+ value = '"'.join(value.split('"'))
+ return '<input name="%s" value="%s" size="%s">'%(self._formname,
+ label, size)
def menu(self, size=None, height=None, showid=0, additional=[],
- **conditions):
+ sort_on=None, **conditions):
''' Render a form select list for this property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
+ if not self.is_edit_ok():
+ return self.plain()
+
value = self._value
linkcl = self._db.getclass(self._prop.classname)
if linkcl.getprops().has_key('order'):
sort_on = ('+', 'order')
else:
- sort_on = ('+', linkcl.labelprop())
+ if sort_on is None:
+ sort_on = ('+', linkcl.labelprop())
+ else:
+ sort_on = ('+', sort_on)
options = linkcl.filter(None, conditions, sort_on, (None, None))
# make sure we list the current value if it's retired
def __init__(self, *args, **kwargs):
HTMLProperty.__init__(self, *args, **kwargs)
if self._value:
- self._value.sort(make_sort_function(self._db, self._prop.classname))
+ sortfun = make_sort_function(self._db, self._prop.classname)
+ self._value.sort(sortfun)
def __len__(self):
''' length of the multilink '''
def plain(self, escape=0):
''' Render a "plain" representation of the property
'''
+ self.view_check()
+
linkcl = self._db.classes[self._prop.classname]
k = linkcl.labelprop(1)
labels = []
def field(self, size=30, showid=0):
''' Render a form edit field for the property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
+ if not self.is_edit_ok():
+ return self.plain()
+
linkcl = self._db.getclass(self._prop.classname)
value = self._value[:]
# map the id to the label property
return self.input(name=self._formname,size=size,value=value)
def menu(self, size=None, height=None, showid=0, additional=[],
- **conditions):
+ sort_on=None, **conditions):
''' Render a form select list for this property
+
+ If not editable, just display the value via plain().
'''
+ self.view_check()
+
+ if not self.is_edit_ok():
+ return self.plain()
+
value = self._value
linkcl = self._db.getclass(self._prop.classname)
- sort_on = ('+', find_sort_key(linkcl))
+ if sort_on is None:
+ sort_on = ('+', find_sort_key(linkcl))
+ else:
+ sort_on = ('+', sort_on)
options = linkcl.filter(None, conditions, sort_on)
height = height or min(len(options), 7)
l = ['<select multiple name="%s" size="%s">'%(self._formname, height)]
(hyperdb.Multilink, MultilinkHTMLProperty),
)
-def make_sort_function(db, classname):
+def make_sort_function(db, classname, sort_on=None):
'''Make a sort function for a given class
'''
linkcl = db.getclass(classname)
- sort_on = find_sort_key(linkcl)
+ if sort_on is None:
+ sort_on = find_sort_key(linkcl)
def sortfunc(a, b):
return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on))
return sortfunc
function submit_once() {
if (submitted) {
alert("Your request is being processed.\\nPlease be patient.");
+ event.returnValue = 0; // work-around for IE
return 0;
}
submitted = true;