From 148ca245739e56349e14a6f5542a3366e415a394 Mon Sep 17 00:00:00 2001 From: richard Date: Fri, 13 Sep 2002 03:31:19 +0000 Subject: [PATCH] . added generic item editing . much nicer layout of template rendering errors . added context/is_edit_ok and context/is_view_ok convenience methods and implemented use of them in the classic template git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1158 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 6 ++ doc/customizing.txt | 6 +- roundup/cgi/PageTemplates/Expressions.py | 12 ++-- roundup/cgi/PageTemplates/MultiMapping.py | 6 +- roundup/cgi/cgitb.py | 64 +++++++++++-------- roundup/cgi/templating.py | 47 ++++++++++++-- roundup/templates/classic/dbinit.py | 6 +- roundup/templates/classic/html/_generic.index | 12 +--- roundup/templates/classic/html/_generic.item | 28 ++++++-- roundup/templates/classic/html/issue.index | 6 +- roundup/templates/classic/html/issue.item | 45 +++++++++++-- roundup/templates/classic/html/query.item | 7 +- roundup/templates/classic/html/user.index | 19 ++++-- roundup/templates/classic/html/user.item | 46 ++++++------- 14 files changed, 214 insertions(+), 96 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 22da228..b6217a3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -8,6 +8,12 @@ Fixed: . switched the default issue item display to only show issue summary (add instructions to doc to make it display entire content) +Feature: + . added generic item editing + . much nicer layout of template rendering errors + . added context/is_edit_ok and context/is_view_ok convenience methods and + implemented use of them in the classic template + 2002-09-11 0.5.0 beta1 Fixed: . #576086 ] dumb copying mistake (frontends/ZRoundup.py) diff --git a/doc/customizing.txt b/doc/customizing.txt index 76a8901..614e8f6 100644 --- a/doc/customizing.txt +++ b/doc/customizing.txt @@ -2,7 +2,7 @@ Customising Roundup =================== -:Version: $Revision: 1.32 $ +:Version: $Revision: 1.33 $ .. This document borrows from the ZopeBook section on ZPT. The original is at: http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx @@ -877,6 +877,8 @@ classhelp display a link to a javascript popup containing this class' submit generate a submit button (and action hidden element) renderWith render this class with the given template. history returns 'New node - no history' :) +is_edit_ok is the user allowed to Edit the current class? +is_view_ok is the user allowed to View the current class? =========== ============================================================= Note that if you have a property of the same name as one of the above methods, @@ -910,6 +912,8 @@ renderQueryForm specific to the "query" class - render the search form for the query hasPermission specific to the "user" class - determine whether the user has a Permission +is_edit_ok is the user allowed to Edit the current item? +is_view_ok is the user allowed to View the current item? =============== ============================================================= diff --git a/roundup/cgi/PageTemplates/Expressions.py b/roundup/cgi/PageTemplates/Expressions.py index 1d253bd..054e293 100644 --- a/roundup/cgi/PageTemplates/Expressions.py +++ b/roundup/cgi/PageTemplates/Expressions.py @@ -25,7 +25,7 @@ Modified for Roundup 0.5 release: """ -__version__='$Revision: 1.5 $'[11:-2] +__version__='$Revision: 1.6 $'[11:-2] import re, sys from TALES import Engine, CompilerError, _valid_name, NAME_RE, \ @@ -121,7 +121,7 @@ class SubPathExpr: # of path names. path[i:i+1] = list(val) base = self._base - __traceback_info__ = 'sub path expression "%s"'%base + __traceback_info__ = 'path expression "%s"'%('/'.join(self._path)) if base == 'CONTEXTS': ob = econtext.contexts else: @@ -264,6 +264,10 @@ class DeferExpr: def __repr__(self): return 'defer:%s' % `self._s` +class TraversalError: + def __init__(self, path, name): + self.path = path + self.name = name def restrictedTraverse(self, path, securityManager, get=getattr, has=hasattr, N=None, M=[], @@ -281,8 +285,8 @@ def restrictedTraverse(self, path, securityManager, #print 'TRAVERSE', (object, path) done = [] while path: - __traceback_info__ = 'Traversed %r\n ... looking for %r'%(done, path) name = path.pop() + __traceback_info__ = TraversalError(done, name) if isinstance(name, TupleType): object = apply(object, name) @@ -320,7 +324,7 @@ def restrictedTraverse(self, path, securityManager, raise #print '... object is now', `o` object = o - done.append(o) + done.append((name, o)) return object diff --git a/roundup/cgi/PageTemplates/MultiMapping.py b/roundup/cgi/PageTemplates/MultiMapping.py index b528288..d4bb542 100644 --- a/roundup/cgi/PageTemplates/MultiMapping.py +++ b/roundup/cgi/PageTemplates/MultiMapping.py @@ -22,4 +22,8 @@ class MultiMapping: self.stores.append(store) def pop(self): return self.stores.pop() - + def items(self): + l = [] + for store in self.stores: + l = l + store.items() + return l diff --git a/roundup/cgi/cgitb.py b/roundup/cgi/cgitb.py index 1b13ab3..630121b 100644 --- a/roundup/cgi/cgitb.py +++ b/roundup/cgi/cgitb.py @@ -1,13 +1,13 @@ # # This module was written by Ka-Ping Yee, . # -# $Id: cgitb.py,v 1.5 2002-09-10 01:07:05 richard Exp $ +# $Id: cgitb.py,v 1.6 2002-09-13 03:31:18 richard Exp $ __doc__ = """ Extended CGI traceback handler by Ka-Ping Yee, . """ -import sys, os, types, string, keyword, linecache, tokenize, inspect +import sys, os, types, string, keyword, linecache, tokenize, inspect, cgi import pydoc, traceback from roundup.i18n import _ @@ -20,43 +20,55 @@ def breaker(): def niceDict(indent, dict): l = [] for k,v in dict.items(): - l.append('%s%s: %r'%(indent,k,v)) + l.append('%s%s'%(k, + cgi.escape(repr(v)))) return '\n'.join(l) def pt_html(context=5): - import cgi - etype, evalue = sys.exc_type, sys.exc_value - if type(etype) is types.ClassType: - etype = etype.__name__ - pyver = 'Python ' + string.split(sys.version)[0] + '
' + sys.executable - head = pydoc.html.heading( - '%s: %s'%(etype, evalue), - '#ffffff', '#777777', pyver) - - head = head + _('

A problem occurred in your template

')
-
-    l = []
+    l = ['

Templating Error

' + '

Debugging information follows

' + '
    '] + from roundup.cgi.PageTemplates.Expressions import TraversalError for frame, file, lnum, func, lines, index in inspect.trace(context): args, varargs, varkw, locals = inspect.getargvalues(frame) if locals.has_key('__traceback_info__'): ti = locals['__traceback_info__'] - l.append(str(ti)) + if isinstance(ti, TraversalError): + s = [] + for name, info in ti.path: + s.append('
  1. "%s" (%s)
  2. '%(name,cgi.escape(repr(info)))) + s = '\n'.join(s) + l.append('
  3. Looking for "%s", current path:
      %s
  4. '%( + ti.name, s)) + else: + l.append('
  5. In %s
  6. '%cgi.escape(str(ti))) if locals.has_key('__traceback_supplement__'): ts = locals['__traceback_supplement__'] if len(ts) == 2: supp, context = ts - l.append('in template %r'%context.id) + l.append('
  7. A problem occurred in your template "%s"
  8. '% + str(context.id)) elif len(ts) == 3: supp, context, info = ts - l.append('in expression %r\n current variables:\n%s\n%s\n'%(info, - niceDict(' ', context.global_vars), - niceDict(' ', context.local_vars))) - # context._scope_stack)) - - l.append('\n') - l.append(''.join(traceback.format_exception(etype, evalue, - sys.exc_traceback))) - return head + cgi.escape('\n'.join(l)) + '

 

' + l.append(''' +
  • While evaluating the %r expression on line %d + + + %s + %s +
    Current variables:
  • +'''%(info, context.position[0], niceDict(' ', context.global_vars), + niceDict(' ', context.local_vars))) + + l.append(''' + + + + +
    Full traceback:
    %s
    '''%cgi.escape(''.join(traceback.format_exception(sys.exc_type, + sys.exc_value, sys.exc_traceback)))) + l.append('

     

    ') + return '\n'.join(l) def html(context=5): etype, evalue = sys.exc_type, sys.exc_value diff --git a/roundup/cgi/templating.py b/roundup/cgi/templating.py index 8f63d3a..2425f68 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 @@ -218,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() @@ -399,7 +421,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): @@ -627,6 +649,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. @@ -638,6 +661,20 @@ 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 diff --git a/roundup/templates/classic/dbinit.py b/roundup/templates/classic/dbinit.py index 9ed49bd..778766f 100644 --- a/roundup/templates/classic/dbinit.py +++ b/roundup/templates/classic/dbinit.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: dbinit.py,v 1.28 2002-09-11 02:49:56 richard Exp $ +# $Id: dbinit.py,v 1.29 2002-09-13 03:31:18 richard Exp $ import os @@ -93,7 +93,7 @@ def open(name=None): # SECURITY SETTINGS # # new permissions for this schema - for cl in 'issue', 'file', 'msg', 'user', 'keyword': + for cl in 'issue', 'file', 'msg', 'user', 'query', 'keyword': db.security.addPermission(name="Edit", klass=cl, description="User is allowed to edit "+cl) db.security.addPermission(name="View", klass=cl, @@ -101,7 +101,7 @@ def open(name=None): # Assign the access and edit permissions for issue, file and message # to regular users now - for cl in 'issue', 'file', 'msg', 'keyword': + for cl in 'issue', 'file', 'msg', 'query', 'keyword': p = db.security.getPermission('View', cl) db.security.addPermissionToRole('User', p) p = db.security.getPermission('Edit', cl) diff --git a/roundup/templates/classic/html/_generic.index b/roundup/templates/classic/html/_generic.index index 69d3d99..16ca747 100644 --- a/roundup/templates/classic/html/_generic.index +++ b/roundup/templates/classic/html/_generic.index @@ -1,14 +1,9 @@ - - - + You are not allowed to view this page. - +

    You may edit the contents of the class using this form. Commas, newlines and double quotes (") must be @@ -35,8 +30,7 @@ You are not allowed to view this page. - + view ok - diff --git a/roundup/templates/classic/html/_generic.item b/roundup/templates/classic/html/_generic.item index d0750f5..8fcf672 100644 --- a/roundup/templates/classic/html/_generic.item +++ b/roundup/templates/classic/html/_generic.item @@ -1,5 +1,9 @@ + +You are not allowed to view this page. + +

    + enctype="multipart/form-data" tal:condition="context/is_edit_ok"> @@ -22,8 +26,24 @@ - + + + + + + + + + + + + +
      + submit button will go here +
    + + + - - diff --git a/roundup/templates/classic/html/issue.index b/roundup/templates/classic/html/issue.index index 4f69ec6..d6cce53 100644 --- a/roundup/templates/classic/html/issue.index +++ b/roundup/templates/classic/html/issue.index @@ -1,5 +1,9 @@ - + +You are not allowed to view this page. + + + diff --git a/roundup/templates/classic/html/issue.item b/roundup/templates/classic/html/issue.item index 12744a6..ddf1fb9 100644 --- a/roundup/templates/classic/html/issue.item +++ b/roundup/templates/classic/html/issue.item @@ -1,6 +1,10 @@ + +You are not allowed to view this page. + + + enctype="multipart/form-data" tal:condition="context/is_edit_ok"> @@ -65,11 +69,41 @@
    Priority
    -activity info + + + + + + + + + + + + + + + + + + + + + + +
    Titletitle
    PrioritypriorityStatusstatus
    Superseder + +
    View: +
    +
    Nosy List
    Assigned ToTopics
    + + - +

    activity info +

    @@ -102,4 +136,3 @@ changed ${context/activity}.">activity info - diff --git a/roundup/templates/classic/html/query.item b/roundup/templates/classic/html/query.item index 2b5a648..9e4f2fe 100755 --- a/roundup/templates/classic/html/query.item +++ b/roundup/templates/classic/html/query.item @@ -1,2 +1,7 @@ - + +You are not allowed to view this page. + + + diff --git a/roundup/templates/classic/html/user.index b/roundup/templates/classic/html/user.index index d553f39..0bb7d13 100644 --- a/roundup/templates/classic/html/user.index +++ b/roundup/templates/classic/html/user.index @@ -1,6 +1,11 @@ -
    Messages
    - + + +You are not allowed to view this page. + + +
    + @@ -9,13 +14,13 @@ - - - - - + + + +
    Username Real name Organisation
    + username realnameorganisationaddressphonerealnameorganisationaddressphone
    diff --git a/roundup/templates/classic/html/user.item b/roundup/templates/classic/html/user.item index 724c6aa..84e52a0 100644 --- a/roundup/templates/classic/html/user.item +++ b/roundup/templates/classic/html/user.item @@ -1,15 +1,10 @@ - - - + You are not allowed to view this page. - -
    + @@ -36,7 +31,7 @@ You are not allowed to view this page. Phone - phone + phone Organisation @@ -58,26 +53,19 @@ You are not allowed to view this page.
    - - - - - - - - -
    Queries
    NameDisplay
    - display -
    - - - - - -
    + + + + + + + +
    Queries
    NameDisplay
    + display +
    - +
    @@ -99,5 +87,7 @@ You are not allowed to view this page.
    realname
    + + -- 2.30.2