summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 409eb83)
raw | patch | inline | side by side (parent: 409eb83)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 13 Sep 2002 03:31:19 +0000 (03:31 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 13 Sep 2002 03:31:19 +0000 (03:31 +0000) |
. 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
. 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
14 files changed:
diff --git a/CHANGES.txt b/CHANGES.txt
index 22da228994ffae80a2328ed727a49d7d9232974e..b6217a3f432db26eabfe32b773ad30de90ceecbe 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
. 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 76a890164c40e66cc9874b35ca0622c8d31a58e1..614e8f64445e5e39924a6fe9d915e5c4332a2e81 100644 (file)
--- a/doc/customizing.txt
+++ b/doc/customizing.txt
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
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,
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?
=============== =============================================================
index 1d253bd82a04fa5c5319d149d7b2124333433b9e..054e29344b2793c1c1b79997ed48aee1eb816282 100644 (file)
"""
-__version__='$Revision: 1.5 $'[11:-2]
+__version__='$Revision: 1.6 $'[11:-2]
import re, sys
from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
# 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:
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=[],
#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)
raise
#print '... object is now', `o`
object = o
- done.append(o)
+ done.append((name, o))
return object
index b528288766c99c9d6016e1f1357bdd7efa180563..d4bb542509738ab7edd0df46ab94626841a91a15 100644 (file)
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 1b13ab32bfb6fd457c33268b82a5f22401e22b71..630121b7d65c5518677782feba285c90da780503 100644 (file)
--- a/roundup/cgi/cgitb.py
+++ b/roundup/cgi/cgitb.py
#
# This module was written by Ka-Ping Yee, <ping@lfw.org>.
#
-# $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, <ping@lfw.org>.
"""
-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 _
def niceDict(indent, dict):
l = []
for k,v in dict.items():
- l.append('%s%s: %r'%(indent,k,v))
+ l.append('<tr><td><strong>%s</strong></td><td>%s</td></tr>'%(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] + '<br>' + sys.executable
- head = pydoc.html.heading(
- '<font size=+1><strong>%s</strong>: %s</font>'%(etype, evalue),
- '#ffffff', '#777777', pyver)
-
- head = head + _('<p>A problem occurred in your template</p><pre>')
-
- l = []
+ l = ['<h1>Templating Error</h1>'
+ '<p class="help">Debugging information follows</p>'
+ '<ol>']
+ 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('<li>"%s" (%s)</li>'%(name,cgi.escape(repr(info))))
+ s = '\n'.join(s)
+ l.append('<li>Looking for "%s", current path:<ol>%s</ol></li>'%(
+ ti.name, s))
+ else:
+ l.append('<li>In %s</li>'%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('<li>A problem occurred in your template "%s"</li>'%
+ 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)) + '</pre><p> </p>'
+ l.append('''
+<li>While evaluating the %r expression on line %d
+<table class="otherinfo" style="font-size: 90%%">
+ <tr><th colspan="2" class="header">Current variables:</th></tr>
+ %s
+ %s
+</table></li>
+'''%(info, context.position[0], niceDict(' ', context.global_vars),
+ niceDict(' ', context.local_vars)))
+
+ l.append('''
+</ol>
+<table style="font-size: 80%%; color: gray">
+ <tr><th class="header" align="left">Full traceback:</th></tr>
+ <tr><td><pre>%s</pre></td></tr>
+</table>'''%cgi.escape(''.join(traceback.format_exception(sys.exc_type,
+ sys.exc_value, sys.exc_traceback))))
+ l.append('<p> </p>')
+ return '\n'.join(l)
def html(context=5):
etype, evalue = sys.exc_type, sys.exc_value
index 8f63d3a8576c24897cb600d89e3cd194f82144f8..2425f6810a2125fdf526c21b482d24c33915927f 100644 (file)
}
# 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
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.<classname>*)
'''
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()
# 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):
# used for security checks
self._security = client.db.security
+
_marker = []
def hasPermission(self, role, classname=_marker):
''' Determine if the user has the Role.
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
index 9ed49bdcaf7e9214703e695ca11adcb8e2b49517..778766f9933f06e08ceb3b40db181176c3fb1126 100644 (file)
# 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
# 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,
# 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 69d3d9926f080d7a6e0380542370397816d58236..16ca747c01510a487bb3b2f8bda390a33d63e4cf 100644 (file)
<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
-<tal:block tal:define="
- editok python:request.user.hasPermission('Edit') or
- context.id == request.user.id;
- viewok python:request.user.hasPermission('View')">
-
-<span tal:condition="python:not (viewok or editok)">
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
You are not allowed to view this page.
</span>
-<tal:block tal:condition="editok">
+<tal:block tal:condition="context/is_edit_ok">
<p class="form-help">
You may edit the contents of the <span tal:replace="request/classname" />
class using this form. Commas, newlines and double quotes (") must be
</form>
</tal:block>
-<tal:block tal:condition="python:viewok and not editok">
+<tal:block tal:condition="context/is_only_view_ok">
view ok
</tal:block>
-</tal:block>
diff --git a/roundup/templates/classic/html/_generic.item b/roundup/templates/classic/html/_generic.item
index d0750f5c240e52c6d9052b3695ef4e0cff354a24..8fcf6721978f31c409725afd01cb1fb611d30051 100644 (file)
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data">
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
<input type="hidden" name=":template" value="item">
<input type="hidden" name=":required" value="title">
</table>
-<tal:block tal:condition="context/id">
+<table class="form" tal:condition="context/is_only_view_ok">
+
+<tr tal:repeat="prop python:db[context._classname].properties()">
+ <tal:block tal:condition="python:prop._name not in ('id', 'creator',
+ 'creation', 'activity')">
+ <th tal:content="prop/_name"></th>
+ <td tal:content="structure python:context[prop._name].field()"></td>
+ </tal:block>
+</tr>
+<tr>
+ <td> </td>
+ <td colspan=3 tal:content="structure context/submit">
+ submit button will go here
+ </td>
+</tr>
+</table>
+
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()">
<tal:block tal:replace="structure context/history" />
</tal:block>
-
-</form>
diff --git a/roundup/templates/classic/html/issue.index b/roundup/templates/classic/html/issue.index
index 4f69ec6d80e004edd81ae161d48de90fb627d677..d6cce5335b39410f7ea68ab68fb3abca7e09007f 100644 (file)
<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
-<tal:block tal:define="batch request/batch">
+<tal:block tal:condition="not:context/is_view_ok">
+You are not allowed to view this page.
+</tal:block>
+
+<tal:block tal:define="batch request/batch" tal:condition="context/is_view_ok">
<table class="list">
<tr>
<th tal:condition="request/show/priority">Priority</th>
index 12744a61bf21c56ae676223f84a2437681a2daee..ddf1fb917e1115581df2e192988902fd9dee723a 100644 (file)
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
<!-- dollarId: issue.item,v 1.4 2001/08/03 01:19:43 richard Exp dollar-->
<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data">
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
<input type="hidden" name=":template" value="item">
<input type="hidden" name=":required" value="title">
</tr>
</table>
-<span tal:condition="context/id" tal:content="structure string:Created on
-<b>${context/creation}</b> by <b>${context/creator}</b>, last
-changed <b>${context/activity}</b>.">activity info</span>
+</form>
+
+<table class="form" tal:condition="context/is_only_view_ok">
+<tr>
+ <th nowrap>Title</th><td colspan=3 tal:content="context/title">title</td>
+</tr>
+
+<tr>
+ <th nowrap>Priority</th><td tal:content="context/priority">priority</td>
+ <th nowrap>Status</th><td tal:content="context/status">status</td>
+</tr>
+
+<tr>
+ <th nowrap>Superseder</th>
+ <td>
+ <span tal:condition="context/superseder" tal:repeat="sup context/superseder">
+ <br>View: <a tal:attributes="href string:issue${sup/id}"
+ tal:content="sup/id"></a>
+ </span>
+ </td>
+ <th nowrap>Nosy List</th><td><span tal:replace="context/nosy" /></td>
+</tr>
+
+<tr>
+ <th nowrap>Assigned To</th><td tal:content="context/assignedto"></td>
+ <th nowrap>Topics</th><td tal:content="structure context/topic"></td>
+</tr>
+</table>
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()">
-<tal:block tal:condition="context/id">
+ <p tal:content="structure string:Created on
+ <b>${context/creation}</b> by <b>${context/creator}</b>, last
+ changed <b>${context/activity}</b>.">activity info
+ </p>
<table class="messages" tal:condition="context/messages">
<tr><th colspan=4 class="header">Messages</th></tr>
</tal:block>
-</form>
index 2b5a64842b70cbee9a514f25d1a4817ca6d4ae9e..9e4f2fed83ffd1f7de04857878d4216f74000e4d 100755 (executable)
-<span tal:content="structure context/renderQueryForm" />
+<span tal:condition="not:context/is_edit_ok">
+You are not allowed to view this page.
+</span>
+
+<span tal:condition="context/is_edit_ok"
+ tal:content="structure context/renderQueryForm" />
index d553f39d0d6a761dbe6e1c39bb85bd2c66ad0d14..0bb7d13498e38aba8f4877113c3339f5cb767d79 100644 (file)
<!-- dollarId: user.index,v 1.3 2002/07/09 05:29:51 richard Exp dollar-->
-<table width="100%" border=0 cellspacing=0 cellpadding=2 class="list">
-<tr class="list-header">
+
+<span tal:condition="not:context/is_view_ok">
+You are not allowed to view this page.
+</span>
+
+<table width="100%" tal:condition="context/is_view_ok" class="list">
+<tr>
<th>Username</th>
<th>Real name</th>
<th>Organisation</th>
</tr>
<tr tal:repeat="user context/list"
tal:attributes="class python:['row-normal', 'row-alt'][repeat['user'].even()]">
- <td valign="top">
+ <td>
<a tal:attributes="href string:user${user/id}"
tal:content="user/username">username</a>
</td>
- <td valign="top" tal:content="user/realname">realname</td>
- <td valign="top" tal:content="user/organisation">organisation</td>
- <td valign="top" tal:content="python:user.address.email()">address</td>
- <td valign="top" tal:content="user/phone">phone</td>
+ <td tal:content="user/realname">realname</td>
+ <td tal:content="user/organisation">organisation</td>
+ <td tal:content="python:user.address.email()">address</td>
+ <td tal:content="user/phone">phone</td>
</tr>
</table>
index 724c6aa3f3dc3a079011db0401fda13041493654..84e52a0022307f8b3735da6e560341a6336cbc8f 100644 (file)
<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:block tal:define="
- editok python:request.user.hasPermission('Edit') or
- context.id == request.user.id;
- viewok python:request.user.hasPermission('View')">
-
-<span tal:condition="python:not (viewok or editok)">
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
You are not allowed to view this page.
</span>
-<tal:block tal:condition="editok">
-<form method="POST" onSubmit="return submit_once()" enctype="multipart/form-data">
+<form method="POST" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
<input type="hidden" name=":required" value="username,address">
</tr>
<tr>
<th>Phone</th>
- <td tal:content="structure context/phone/field">phone</td>
+ <td tal:content="structure context/phone/field/asdfasdf">phone</td>
</tr>
<tr>
<th>Organisation</th>
</table>
</form>
-<tal:block tal:condition="context/id">
- <table class="otherinfo" tal:condition="context/queries">
- <tr><th colspan="2" class="header">Queries</th></tr>
- <tr><th>Name</th><th>Display</th></tr>
- <tr tal:repeat="query context/queries">
- <td><a tal:attributes="href string:query${query/id}"
- tal:content="query/name"></a></td>
- <td>
- <a tal:attributes="href python:'%s%s'%(query['klass'], query['url'])">display</a>
- </td>
- </tr>
- </table>
-
- <tal:block tal:replace="structure context/history" />
-
-</tal:block>
-
-</tal:block>
+<table class="otherinfo" tal:condition="context/queries">
+ <tr><th colspan="2" class="header">Queries</th></tr>
+ <tr><th>Name</th><th>Display</th></tr>
+ <tr tal:repeat="query context/queries">
+ <td><a tal:attributes="href string:query${query/id}"
+ tal:content="query/name"></a></td>
+ <td>
+ <a tal:attributes="href python:'%s%s'%(query['klass'], query['url'])">display</a>
+ </td>
+ </tr>
+</table>
-<table class="form" tal:condition="python:viewok and not editok">
+<table class="form" tal:condition="context/is_only_view_ok">
<tr>
<th colspan=2 class="header" tal:content="context/realname">realname</th>
</tr>
</tr>
</table>
+<tal:block tal:condition="python:context.id and context.is_view_ok()">
+ <tal:block tal:replace="structure context/history" />
</tal:block>