Skip to content

Commit 62db8b1

Browse files
author
Richard Jones
committed
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.
1 parent e4b939c commit 62db8b1

File tree

6 files changed

+103
-41
lines changed

6 files changed

+103
-41
lines changed

CHANGES.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ Fixed:
77
- fix initialisation of roundup-server in daemon mode so initialisation
88
errors are visible
99
- have Permissions only test the check function if itemid is suppled
10-
- modify index templates to check for row-level Permission
10+
- modify cgi templating system to check item-level permissions in listings
11+
- enable batching in message and file listings
1112
- more documentation of security mechanisms
1213
- better unit tests for security mechanisms
1314

doc/customizing.txt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Customising Roundup
33
===================
44

5-
:Version: $Revision: 1.169 $
5+
:Version: $Revision: 1.170 $
66

77
.. This document borrows from the ZopeBook section on ZPT. The original is at:
88
http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
@@ -933,6 +933,8 @@ The ``addPermission`` method takes a couple of optional parameters:
933933
Example Scenarios
934934
~~~~~~~~~~~~~~~~~
935935

936+
See the `examples`_ section for longer examples of customisation.
937+
936938
**automatic registration of users in the e-mail gateway**
937939
By giving the "anonymous" user the "Email Registration" Role, any
938940
unidentified user will automatically be registered with the tracker
@@ -4037,6 +4039,26 @@ users, replacing the existing ``'User'`` values::
40374039
new_email_user_roles = 'Provisional User'
40384040

40394041

4042+
All users may only view and edit issues, files and messages they create
4043+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4044+
4045+
Replace the standard "classic" tracker View and Edit Permission assignments
4046+
for the "issue", "file" and "msg" classes with the following::
4047+
4048+
def checker(klass):
4049+
def check(db, userid, itemid, klass=klass):
4050+
return db.getclass(klass).get(itemid, 'creator') == userid
4051+
for cl in 'issue', 'file', 'msg':
4052+
p = db.security.addPermission(name='View', klass=cl,
4053+
check=checker(cl))
4054+
db.security.addPermissionToRole('User', p)
4055+
p = db.security.addPermission(name='Edit', klass=cl,
4056+
check=checker(cl))
4057+
db.security.addPermissionToRole('User', p)
4058+
db.security.addPermissionToRole('User', 'Create', cl)
4059+
4060+
4061+
40404062
Changes to the Web User Interface
40414063
---------------------------------
40424064

roundup/cgi/templating.py

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,16 @@ def list(self, sort_on=None):
558558
'''
559559
# get the list and sort it nicely
560560
l = self._klass.list()
561-
sortfunc = make_sort_function(self._db, self.classname, sort_on)
561+
sortfunc = make_sort_function(self._db, self._classname, sort_on)
562562
l.sort(sortfunc)
563563

564-
l = [HTMLItem(self._client, self.classname, x) for x in l]
564+
# check perms
565+
check = self._client.db.security.hasPermission
566+
userid = self._client.userid
567+
568+
l = [HTMLItem(self._client, self._classname, id) for id in l
569+
if check('View', userid, self._classname, itemid=id)]
570+
565571
return l
566572

567573
def csv(self):
@@ -605,8 +611,13 @@ def filter(self, request=None, filterspec={}, sort=(None,None),
605611
filterspec = request.filterspec
606612
sort = request.sort
607613
group = request.group
614+
615+
check = self._db.security.hasPermission
616+
userid = self._client.userid
617+
608618
l = [HTMLItem(self._client, self.classname, x)
609-
for x in self._klass.filter(None, filterspec, sort, group)]
619+
for id in self._klass.filter(None, filterspec, sort, group)
620+
if check('View', userid, self.classname, itemid=id)]
610621
return l
611622

612623
def classhelp(self, properties=None, label=''"(list)", width='500',
@@ -1643,6 +1654,28 @@ def menu(self, size=None, height=None, showid=0, additional=[],
16431654
return '\n'.join(l)
16441655
# def checklist(self, ...)
16451656

1657+
class MultilinkIterator:
1658+
def __init__(self, classname, client, values):
1659+
self.classname = classname
1660+
self.client = client
1661+
self.values = values
1662+
self.id = -1
1663+
self.cl = self.client.db.getclass(self.classname)
1664+
def next(self):
1665+
'''Return the next item, but skip inaccessible items.'''
1666+
check = self.client.db.security.hasPermission
1667+
userid = self.client.userid
1668+
while 1:
1669+
self.id += 1
1670+
if self.id >= len(self.values):
1671+
raise StopIteration
1672+
value = self.values[self.id]
1673+
if check('View', userid, self.classname, itemid=value):
1674+
return HTMLItem(self.client, self.classname, value)
1675+
def __iter__(self):
1676+
return self
1677+
1678+
16461679
class MultilinkHTMLProperty(HTMLProperty):
16471680
''' Multilink HTMLProperty
16481681
@@ -1665,16 +1698,22 @@ def __getattr__(self, attr):
16651698
''' no extended attribute accesses make sense here '''
16661699
raise AttributeError, attr
16671700

1668-
def __getitem__(self, num):
1701+
def __iter__(self):
16691702
''' iterate and return a new HTMLItem
16701703
'''
1671-
#print 'Multi.getitem', (self, num)
1672-
value = self._value[num]
1673-
return HTMLItem(self._client, self._prop.classname, value)
1704+
return MultilinkIterator(self._prop.classname, self._client,
1705+
self._value)
1706+
1707+
def reverse(self):
1708+
''' return the list in reverse order
1709+
'''
1710+
l = self._value[:]
1711+
l.reverse()
1712+
return MultilinkIterator(self._prop.classname, self._client, l)
16741713

16751714
def sorted(self, property):
16761715
''' Return this multilink sorted by the given property '''
1677-
value = list(self._value[num])
1716+
value = list(self.__iter__())
16781717
value.sort(lambda a,b:cmp(a[property], b[property]))
16791718
return value
16801719

@@ -1688,14 +1727,6 @@ def isset(self):
16881727
'''Is my _value not []?'''
16891728
return self._value != []
16901729

1691-
def reverse(self):
1692-
''' return the list in reverse order
1693-
'''
1694-
l = self._value[:]
1695-
l.reverse()
1696-
return [HTMLItem(self._client, self._prop.classname, value)
1697-
for value in l]
1698-
16991730
def plain(self, escape=0):
17001731
''' Render a "plain" representation of the property
17011732
'''
@@ -2138,7 +2169,12 @@ def batch(self):
21382169
re.findall(r'\b\w{2,25}\b', self.search_text), klass)
21392170
else:
21402171
matches = None
2141-
l = klass.filter(matches, filterspec, sort, group)
2172+
2173+
# filter for visibility
2174+
check = self._client.db.security.hasPermission
2175+
userid = self._client.userid
2176+
l = [id for id in klass.filter(matches, filterspec, sort, group)
2177+
if check('View', userid, self.classname, itemid=id)]
21422178

21432179
# return the batch object, using IDs only
21442180
return Batch(self.client, l, self.pagesize, self.startwith,

templates/classic/html/file.index.html

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@
66
i18n:translate="">List of files</span>
77
<td class="content" metal:fill-slot="content">
88

9-
<table class="otherinfo">
10-
<tr><th style="padding-right: 10" i18n:translate="">Download</th>
11-
<th style="padding-right: 10" i18n:translate="">Content Type</th>
12-
<th style="padding-right: 10" i18n:translate="">Uploaded By</th>
13-
<th style="padding-right: 10" i18n:translate="">Date</th>
14-
</tr>
15-
<tal:block repeat="file context/list">
16-
<tr tal:condition="file/is_view_ok"
17-
tal:attributes="class python:['normal', 'alt'][repeat['file'].index%6/3]">
18-
<td>
19-
<a tal:attributes="href string:file${file/id}/${file/name}"
20-
tal:content="file/name">dld link</a>
21-
</td>
22-
<td tal:content="file/type">content type</td>
23-
<td tal:content="file/creator">creator's name</td>
24-
<td tal:content="file/creation">creation date</td>
9+
<table class="otherinfo" tal:define="batch request/batch">
10+
<tr><th style="padding-right: 10" i18n:translate="">Download</th>
11+
<th style="padding-right: 10" i18n:translate="">Content Type</th>
12+
<th style="padding-right: 10" i18n:translate="">Uploaded By</th>
13+
<th style="padding-right: 10" i18n:translate="">Date</th>
2514
</tr>
26-
</tal:block>
15+
<tr tal:repeat="file batch" tal:attributes="class python:['normal', 'alt'][repeat['file'].index%6/3]">
16+
<td>
17+
<a tal:attributes="href string:file${file/id}/${file/name}"
18+
tal:content="file/name">dld link</a>
19+
</td>
20+
<td tal:content="file/type">content type</td>
21+
<td tal:content="file/creator">creator's name</td>
22+
<td tal:content="file/creation">creation date</td>
23+
</tr>
24+
25+
<metal:block use-macro="templates/issue.index/macros/batch-footer" />
26+
2727
</table>
2828

2929
</td>

templates/classic/html/issue.index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
</th>
3333
</tr>
3434

35-
<tr tal:condition="i/is_view_ok">
35+
<tr>
3636
<td tal:condition="request/show/priority"
3737
tal:content="python:i.priority.plain() or default">&nbsp;</td>
3838
<td tal:condition="request/show/id" tal:content="i/id">&nbsp;</td>
@@ -58,6 +58,7 @@
5858

5959
</tal:block>
6060

61+
<metal:index define-macro="batch-footer">
6162
<tr tal:condition="batch">
6263
<th tal:attributes="colspan python:len(request.columns)">
6364
<table width="100%">
@@ -84,6 +85,7 @@
8485
</table>
8586
</th>
8687
</tr>
88+
</metal:index>
8789
</table>
8890

8991
<a tal:attributes="href python:request.indexargs_url('issue',

templates/classic/html/msg.index.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
<span metal:fill-slot="body_title" tal:omit-tag="python:1"
66
i18n:translate="">Message listing</span>
77
<td class="content" metal:fill-slot="content">
8-
<table class="messages" tal:condition="request/filter">
8+
<table tal:define="batch request/batch" class="messages">
99
<tr><th colspan=2 class="header" i18n:translate="">Messages</th></tr>
10-
<tal:block tal:repeat="msg context/list">
11-
<tal:block tal:condition="msg/is_view_ok">
10+
<tal:block tal:repeat="msg batch">
1211
<tr>
1312
<th tal:content="string:Author: ${msg/author}">author</th>
1413
<th tal:content="string:Date: ${msg/date}">date</th>
@@ -17,7 +16,9 @@
1716
<td colspan="2"><pre tal:content="msg/content">content</pre></td>
1817
</tr>
1918
</tal:block>
20-
</tal:block>
19+
20+
<metal:block use-macro="templates/issue.index/macros/batch-footer" />
21+
2122
</table>
2223
</td>
2324

0 commit comments

Comments
 (0)