1414# used by a couple of routines
1515chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
1616
17- class Action :
17+ class Action :
1818 def __init__ (self , client ):
1919 self .client = client
2020 self .form = client .form
@@ -26,16 +26,34 @@ def __init__(self, client):
2626 self .base = client .base
2727 self .user = client .user
2828
29- def handle (self ):
29+ def execute (self ):
3030 """Execute the action specified by this object."""
31- raise NotImplementedError
31+ self .permission ()
32+ self .handle ()
3233
34+ name = ''
35+ permissionType = None
3336 def permission (self ):
3437 """Check whether the user has permission to execute this action.
3538
36- True by default.
39+ True by default. If the permissionType attribute is a string containing
40+ a simple permission, check whether the user has that permission.
41+ Subclasses must also define the name attribute if they define
42+ permissionType.
43+
44+ Despite having this permission, users may still be unauthorised to
45+ perform parts of actions. It is up to the subclasses to detect this.
3746 """
38- return 1
47+ if (self .permissionType and
48+ not self .hasPermission (self .permissionType )):
49+
50+ raise Unauthorised , _ ('You do not have permission to %s the %s class.' %
51+ (self .name , self .classname ))
52+
53+ def hasPermission (self , permission ):
54+ """Check whether the user has 'permission' on the current class."""
55+ return self .db .security .hasPermission (permission , self .client .userid ,
56+ self .client .classname )
3957
4058class ShowAction (Action ):
4159 def handle (self , typere = re .compile ('[@:]type' ),
@@ -53,19 +71,17 @@ def handle(self, typere=re.compile('[@:]type'),
5371 raise Redirect , url
5472
5573class RetireAction (Action ):
74+ name = 'retire'
75+ permissionType = 'Edit'
76+
5677 def handle (self ):
57- """Retire the context item."""
78+ """Retire the context item."""
5879 # if we want to view the index template now, then unset the nodeid
5980 # context info (a special-case for retire actions on the index page)
6081 nodeid = self .nodeid
6182 if self .template == 'index' :
6283 self .client .nodeid = None
6384
64- # generic edit is per-class only
65- if not self .permission ():
66- raise Unauthorised , _ ('You do not have permission to retire %s' %
67- self .classname )
68-
6985 # make sure we don't try to retire admin or anonymous
7086 if self .classname == 'user' and \
7187 self .db .user .get (nodeid , 'username' ) in ('admin' , 'anonymous' ):
@@ -79,15 +95,10 @@ def handle(self):
7995 _ ('%(classname)s %(itemid)s has been retired' )% {
8096 'classname' : self .classname .capitalize (), 'itemid' : nodeid })
8197
82- def permission (self ):
83- """Determine whether the user has permission to retire this class.
84-
85- Base behaviour is to check the user can edit this class.
86- """
87- return self .db .security .hasPermission ('Edit' , self .client .userid ,
88- self .client .classname )
89-
9098class SearchAction (Action ):
99+ name = 'search'
100+ permissionType = 'View'
101+
91102 def handle (self , wcre = re .compile (r'[\s,]+' )):
92103 """Mangle some of the form variables.
93104
@@ -101,11 +112,6 @@ def handle(self, wcre=re.compile(r'[\s,]+')):
101112 Split any String query values on whitespace and comma.
102113
103114 """
104- # generic edit is per-class only
105- if not self .permission ():
106- raise Unauthorised , _ ('You do not have permission to search %s' %
107- self .classname )
108-
109115 self .fakeFilterVars ()
110116 queryname = self .getQueryName ()
111117
@@ -168,12 +174,11 @@ def getQueryName(self):
168174 if self .FV_QUERYNAME .match (key ):
169175 return self .form [key ].value .strip ()
170176 return ''
171-
172- def permission (self ):
173- return self .db .security .hasPermission ('View' , self .client .userid ,
174- self .client .classname )
175177
176178class EditCSVAction (Action ):
179+ name = 'edit'
180+ permissionType = 'Edit'
181+
177182 def handle (self ):
178183 """Performs an edit of all of a class' items in one go.
179184
@@ -182,12 +187,6 @@ def handle(self):
182187 removed lines are retired.
183188
184189 """
185- # this is per-class only
186- if not self .permission ():
187- self .client .error_message .append (
188- _ ('You do not have permission to edit %s' % self .classname ))
189- return
190-
191190 # get the CSV module
192191 if rcsv .error :
193192 self .client .error_message .append (_ (rcsv .error ))
@@ -271,34 +270,27 @@ def handle(self):
271270 self .db .commit ()
272271
273272 self .client .ok_message .append (_ ('Items edited OK' ))
274-
275- def permission (self ):
276- return self .db .security .hasPermission ('Edit' , self .client .userid ,
277- self .client .classname )
278-
273+
279274class _EditAction (Action ):
275+ def isEditingSelf (self ):
276+ """Check whether a user is editing his/her own details."""
277+ return (self .nodeid == self .userid
278+ and self .db .user .get (self .nodeid , 'username' ) != 'anonymous' )
279+
280280 def editItemPermission (self , props ):
281281 """Determine whether the user has permission to edit this item.
282282
283283 Base behaviour is to check the user can edit this class. If we're
284- editing the"user" class, users are allowed to edit their own details.
284+ editing the "user" class, users are allowed to edit their own details.
285285 Unless it's the "roles" property, which requires the special Permission
286286 "Web Roles".
287287 """
288- # if this is a user node and the user is editing their own node, then
289- # we're OK
290- has = self .db .security .hasPermission
291288 if self .classname == 'user' :
292- # reject if someone's trying to edit "roles" and doesn't have the
293- # right permission.
294- if props .has_key ('roles' ) and not has ('Web Roles' , self .userid ,
295- 'user' ):
296- return 0
297- # if the item being edited is the current user, we're ok
298- if (self .nodeid == self .userid
299- and self .db .user .get (self .nodeid , 'username' ) != 'anonymous' ):
289+ if props .has_key ('roles' ) and not self .hasPermission ('Web Roles' ):
290+ raise Unauthorised , _ ("You do not have permission to edit user roles" )
291+ if self .isEditingSelf ():
300292 return 1
301- if self .db . security . hasPermission ('Edit' , self . userid , self . classname ):
293+ if self .hasPermission ('Edit' ):
302294 return 1
303295 return 0
304296
@@ -310,11 +302,8 @@ def newItemPermission(self, props):
310302 if the user has the "Web Registration" Permission.
311303
312304 """
313- has = self .db .security .hasPermission
314- if self .classname == 'user' and has ('Web Registration' , self .userid ,
315- 'user' ):
316- return 1
317- if has ('Edit' , self .userid , self .classname ):
305+ if (self .classname == 'user' and self .hasPermission ('Web Registration' )
306+ or self .hasPermission ('Edit' )):
318307 return 1
319308 return 0
320309
@@ -503,7 +492,7 @@ def handle(self):
503492 try :
504493 props , links = self .client .parsePropsFromForm (create = True )
505494 except (ValueError , KeyError ), message :
506- self .error_message .append (_ ('Error: ' ) + str (message ))
495+ self .client . error_message .append (_ ('Error: ' ) + str (message ))
507496 return
508497
509498 # handle the props - edit or create
@@ -513,7 +502,7 @@ def handle(self):
513502
514503 except (ValueError , KeyError , IndexError ), message :
515504 # these errors might just be indicative of user dumbness
516- self .error_message .append (_ ('Error: ' ) + str (message ))
505+ self .client . error_message .append (_ ('Error: ' ) + str (message ))
517506 return
518507
519508 # commit now that all the tricky stuff is done
@@ -656,17 +645,20 @@ def handle(self):
656645 self .userid , urllib .quote (message ))
657646
658647class RegisterAction (Action ):
648+ name = 'register'
649+ permissionType = 'Web Registration'
650+
659651 def handle (self ):
660652 """Attempt to create a new user based on the contents of the form
661653 and then set the cookie.
662654
663655 Return 1 on successful login.
664- """
656+ """
665657 props = self .client .parsePropsFromForm ()[0 ][('user' , None )]
666658
667- # make sure we're allowed to register
668- if not self . permission ( props ):
669- raise Unauthorised , _ ("You do not have permission to register" )
659+ # registration isn't allowed to supply roles
660+ if props . has_key ( 'roles' ):
661+ raise Unauthorised , _ ("It is not permitted to supply roles at registration." )
670662
671663 try :
672664 self .db .user .lookup (props ['username' ])
@@ -717,19 +709,6 @@ def handle(self):
717709 # redirect to the "you're almost there" page
718710 raise Redirect , '%suser?@template=rego_progress' % self .base
719711
720- def permission (self , props ):
721- """Determine whether the user has permission to register
722-
723- Base behaviour is to check the user has "Web Registration".
724-
725- """
726- # registration isn't allowed to supply roles
727- if props .has_key ('roles' ):
728- return 0
729- if self .db .security .hasPermission ('Web Registration' , self .userid ):
730- return 1
731- return 0
732-
733712class LogoutAction (Action ):
734713 def handle (self ):
735714 """Make us really anonymous - nuke the cookie too."""
@@ -779,8 +758,9 @@ def handle(self):
779758 self .client .error_message .append (_ ('Incorrect password' ))
780759 return
781760
782- # make sure we're allowed to be here
783- if not self .permission ():
761+ # Determine whether the user has permission to log in.
762+ # Base behaviour is to check the user has "Web Access".
763+ if not self .hasPermission ("Web Access" ):
784764 self .client .make_user_anonymous ()
785765 self .client .error_message .append (_ ("You do not have permission to login" ))
786766 return
@@ -800,13 +780,3 @@ def verifyPassword(self, userid, password):
800780 if not password and not stored :
801781 return 1
802782 return 0
803-
804- def permission (self ):
805- """Determine whether the user has permission to log in.
806-
807- Base behaviour is to check the user has "Web Access".
808-
809- """
810- if not self .db .security .hasPermission ('Web Access' , self .client .userid ):
811- return 0
812- return 1
0 commit comments