Mercurial > p > roundup > code
changeset 3126:a2889d22db4a
the cgi templating code now checks item-level
permissions (per alex's suggestion).
The templates themselves do not have row-level checks now.
Cleaned up the msg and file index templates to use batching.
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Fri, 04 Feb 2005 05:25:50 +0000 |
| parents | 5894c7bea8ce |
| children | 021b131bd816 |
| files | CHANGES.txt doc/customizing.txt roundup/cgi/templating.py templates/classic/html/file.index.html templates/classic/html/issue.index.html templates/classic/html/msg.index.html |
| diffstat | 6 files changed, 103 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES.txt Fri Jan 28 05:09:44 2005 +0000 +++ b/CHANGES.txt Fri Feb 04 05:25:50 2005 +0000 @@ -7,7 +7,8 @@ - fix initialisation of roundup-server in daemon mode so initialisation errors are visible - have Permissions only test the check function if itemid is suppled -- modify index templates to check for row-level Permission +- modify cgi templating system to check item-level permissions in listings +- enable batching in message and file listings - more documentation of security mechanisms - better unit tests for security mechanisms
--- a/doc/customizing.txt Fri Jan 28 05:09:44 2005 +0000 +++ b/doc/customizing.txt Fri Feb 04 05:25:50 2005 +0000 @@ -2,7 +2,7 @@ Customising Roundup =================== -:Version: $Revision: 1.169 $ +:Version: $Revision: 1.170 $ .. This document borrows from the ZopeBook section on ZPT. The original is at: http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx @@ -933,6 +933,8 @@ Example Scenarios ~~~~~~~~~~~~~~~~~ +See the `examples`_ section for longer examples of customisation. + **automatic registration of users in the e-mail gateway** By giving the "anonymous" user the "Email Registration" Role, any unidentified user will automatically be registered with the tracker @@ -4037,6 +4039,26 @@ new_email_user_roles = 'Provisional User' +All users may only view and edit issues, files and messages they create +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Replace the standard "classic" tracker View and Edit Permission assignments +for the "issue", "file" and "msg" classes with the following:: + + def checker(klass): + def check(db, userid, itemid, klass=klass): + return db.getclass(klass).get(itemid, 'creator') == userid + for cl in 'issue', 'file', 'msg': + p = db.security.addPermission(name='View', klass=cl, + check=checker(cl)) + db.security.addPermissionToRole('User', p) + p = db.security.addPermission(name='Edit', klass=cl, + check=checker(cl)) + db.security.addPermissionToRole('User', p) + db.security.addPermissionToRole('User', 'Create', cl) + + + Changes to the Web User Interface ---------------------------------
--- a/roundup/cgi/templating.py Fri Jan 28 05:09:44 2005 +0000 +++ b/roundup/cgi/templating.py Fri Feb 04 05:25:50 2005 +0000 @@ -558,10 +558,16 @@ ''' # get the list and sort it nicely l = self._klass.list() - sortfunc = make_sort_function(self._db, self.classname, sort_on) + sortfunc = make_sort_function(self._db, self._classname, sort_on) l.sort(sortfunc) - l = [HTMLItem(self._client, self.classname, x) for x in l] + # check perms + check = self._client.db.security.hasPermission + userid = self._client.userid + + l = [HTMLItem(self._client, self._classname, id) for id in l + if check('View', userid, self._classname, itemid=id)] + return l def csv(self): @@ -605,8 +611,13 @@ filterspec = request.filterspec sort = request.sort group = request.group + + check = self._db.security.hasPermission + userid = self._client.userid + l = [HTMLItem(self._client, self.classname, x) - for x in self._klass.filter(None, filterspec, sort, group)] + for id in self._klass.filter(None, filterspec, sort, group) + if check('View', userid, self.classname, itemid=id)] return l def classhelp(self, properties=None, label=''"(list)", width='500', @@ -1643,6 +1654,28 @@ return '\n'.join(l) # def checklist(self, ...) +class MultilinkIterator: + def __init__(self, classname, client, values): + self.classname = classname + self.client = client + self.values = values + self.id = -1 + self.cl = self.client.db.getclass(self.classname) + def next(self): + '''Return the next item, but skip inaccessible items.''' + check = self.client.db.security.hasPermission + userid = self.client.userid + while 1: + self.id += 1 + if self.id >= len(self.values): + raise StopIteration + value = self.values[self.id] + if check('View', userid, self.classname, itemid=value): + return HTMLItem(self.client, self.classname, value) + def __iter__(self): + return self + + class MultilinkHTMLProperty(HTMLProperty): ''' Multilink HTMLProperty @@ -1665,16 +1698,22 @@ ''' no extended attribute accesses make sense here ''' raise AttributeError, attr - def __getitem__(self, num): + def __iter__(self): ''' iterate and return a new HTMLItem ''' - #print 'Multi.getitem', (self, num) - value = self._value[num] - return HTMLItem(self._client, self._prop.classname, value) + return MultilinkIterator(self._prop.classname, self._client, + self._value) + + def reverse(self): + ''' return the list in reverse order + ''' + l = self._value[:] + l.reverse() + return MultilinkIterator(self._prop.classname, self._client, l) def sorted(self, property): ''' Return this multilink sorted by the given property ''' - value = list(self._value[num]) + value = list(self.__iter__()) value.sort(lambda a,b:cmp(a[property], b[property])) return value @@ -1688,14 +1727,6 @@ '''Is my _value not []?''' return self._value != [] - def reverse(self): - ''' return the list in reverse order - ''' - l = self._value[:] - l.reverse() - return [HTMLItem(self._client, self._prop.classname, value) - for value in l] - def plain(self, escape=0): ''' Render a "plain" representation of the property ''' @@ -2138,7 +2169,12 @@ re.findall(r'\b\w{2,25}\b', self.search_text), klass) else: matches = None - l = klass.filter(matches, filterspec, sort, group) + + # filter for visibility + check = self._client.db.security.hasPermission + userid = self._client.userid + l = [id for id in klass.filter(matches, filterspec, sort, group) + if check('View', userid, self.classname, itemid=id)] # return the batch object, using IDs only return Batch(self.client, l, self.pagesize, self.startwith,
--- a/templates/classic/html/file.index.html Fri Jan 28 05:09:44 2005 +0000 +++ b/templates/classic/html/file.index.html Fri Feb 04 05:25:50 2005 +0000 @@ -6,24 +6,24 @@ i18n:translate="">List of files</span> <td class="content" metal:fill-slot="content"> -<table class="otherinfo"> -<tr><th style="padding-right: 10" i18n:translate="">Download</th> - <th style="padding-right: 10" i18n:translate="">Content Type</th> - <th style="padding-right: 10" i18n:translate="">Uploaded By</th> - <th style="padding-right: 10" i18n:translate="">Date</th> -</tr> - <tal:block repeat="file context/list"> - <tr tal:condition="file/is_view_ok" - tal:attributes="class python:['normal', 'alt'][repeat['file'].index%6/3]"> - <td> - <a tal:attributes="href string:file${file/id}/${file/name}" - tal:content="file/name">dld link</a> - </td> - <td tal:content="file/type">content type</td> - <td tal:content="file/creator">creator's name</td> - <td tal:content="file/creation">creation date</td> +<table class="otherinfo" tal:define="batch request/batch"> + <tr><th style="padding-right: 10" i18n:translate="">Download</th> + <th style="padding-right: 10" i18n:translate="">Content Type</th> + <th style="padding-right: 10" i18n:translate="">Uploaded By</th> + <th style="padding-right: 10" i18n:translate="">Date</th> </tr> - </tal:block> + <tr tal:repeat="file batch" tal:attributes="class python:['normal', 'alt'][repeat['file'].index%6/3]"> + <td> + <a tal:attributes="href string:file${file/id}/${file/name}" + tal:content="file/name">dld link</a> + </td> + <td tal:content="file/type">content type</td> + <td tal:content="file/creator">creator's name</td> + <td tal:content="file/creation">creation date</td> + </tr> + + <metal:block use-macro="templates/issue.index/macros/batch-footer" /> + </table> </td>
--- a/templates/classic/html/issue.index.html Fri Jan 28 05:09:44 2005 +0000 +++ b/templates/classic/html/issue.index.html Fri Feb 04 05:25:50 2005 +0000 @@ -32,7 +32,7 @@ </th> </tr> - <tr tal:condition="i/is_view_ok"> + <tr> <td tal:condition="request/show/priority" tal:content="python:i.priority.plain() or default"> </td> <td tal:condition="request/show/id" tal:content="i/id"> </td> @@ -58,6 +58,7 @@ </tal:block> + <metal:index define-macro="batch-footer"> <tr tal:condition="batch"> <th tal:attributes="colspan python:len(request.columns)"> <table width="100%"> @@ -84,6 +85,7 @@ </table> </th> </tr> + </metal:index> </table> <a tal:attributes="href python:request.indexargs_url('issue',
--- a/templates/classic/html/msg.index.html Fri Jan 28 05:09:44 2005 +0000 +++ b/templates/classic/html/msg.index.html Fri Feb 04 05:25:50 2005 +0000 @@ -5,10 +5,9 @@ <span metal:fill-slot="body_title" tal:omit-tag="python:1" i18n:translate="">Message listing</span> <td class="content" metal:fill-slot="content"> -<table class="messages" tal:condition="request/filter"> +<table tal:define="batch request/batch" class="messages"> <tr><th colspan=2 class="header" i18n:translate="">Messages</th></tr> - <tal:block tal:repeat="msg context/list"> - <tal:block tal:condition="msg/is_view_ok"> + <tal:block tal:repeat="msg batch"> <tr> <th tal:content="string:Author: ${msg/author}">author</th> <th tal:content="string:Date: ${msg/date}">date</th> @@ -17,7 +16,9 @@ <td colspan="2"><pre tal:content="msg/content">content</pre></td> </tr> </tal:block> - </tal:block> + + <metal:block use-macro="templates/issue.index/macros/batch-footer" /> + </table> </td>
