On Nov 25, 2005, at 4:58 PM, Michael Watkins wrote: > * mario ruggier wrote [2005-11-25 15:43:56 +0100]: >> Ah, so you put the access control processing behind the get_exports() >> method. Yes, this seems a cleaner way to do it, helping also to keep >> the more upfront UI code untangled from access control complications. > > I'm following, the Dulcinea (and now QP) pattern - access control is > managed within a directory object's get_exports() method. Within UI > methods I > merely have to make a call to ensure_signed_in() if that method should > be > executable by a particular known user (possessing, or not, > permissions). > > > def SomeObjectDirectory(Directory): > > def get_exports(self): > if get_user().is_admin(): > yield('someadminthing', 'someadminthing', 'Process Foo', > None) > if get_user().is_granted('moderate', self.someobject): > yield('moderate', 'moderate', 'Moderate the thing', None) > if get_user(): # logged in users only > yield('dothis', 'dothat', 'Do This Crumb', 'Do This Title') > # etc... > if not get_user(): # not signed in > # perhaps might need to yield up something appropriate > yield('register', 'not_yet_a_user', None, None) > > # stuff everyone gets > yield('thing1', 'thing1', None, None) > # ... > > def someadminthing(self): > ensure_signed_in() > # ... > > def moderate(self): > ensure_signed_in() > # ... > > def not_yet_a_user(self): > # here we don't want to ensure they are signed in! > return registration_form() > > # etc... > > Where possible I try to avoid sprinkling user tests in the UI methods > themselves but its not completely avoidable as there clearly are many > times > when you want to show some additional capability to some users > (user.is_admin() for example) in the same stream of code dished up to > other > users. The permissions system certainly helps in keeping that clean. Thanks for this example, it illustrates quite well the situation. It seems straightforward enough, for most situations, to specify the conditions with such a combination of if statements in get_exports(). I think what I have in mind is to centralize all these if statements... and just "declare" them. Now, given it seems not so complicated anyway, it may not be worthwhile to do so, although I am not yet convinced. Anyhow, for the sake of the exercise, let me take your export examples and have a method, let's call it get_raw_exports(), yield them all with some additional info (i.e. these would be a simple version of ExportInfo objects mentioned previously). And just to be easily compatible with current 4-tuple, I am just adding a dict object at the end of the 4-tuple. So, on each directory we define in our site, we do something like: def get_raw_exports(self): yield ('someadminthing', 'someadminthing', 'Process Foo', None, dict(allowed=('admin',)) ) yield('moderate', 'moderate', 'Moderate the thing', None, dict(permission=('moderate',)) ) # Note: here only on self, i.e. not self.someobject yield('dothis', 'dothat', 'Do This Crumb', 'Do This Title', dict(allowed=('login',)) ) yield('register', 'not_yet_a_user', None, None, dict(allowed=('anon',)) ) # stuff everyone gets yield('thing1', 'thing1', None, None) # ... We can then have a generic method, probably on SiteDirectory or so, to process these raw exports: class SiteDirectory(Directory): def process_raw_exports(self): for export in self.get_raw_exports(): if len(export)>4: xinfo = export[4] if xinfo.get('allowed') in ('admin',login') or xinfo.get('permission'): if (): self.ensure_signed_in() yield export[:4] elif xinfo.get('anon'): if ( ): yield export[:4] else: continue elif xinfo.get('whatever'): .... else: yield export[:4] The get_exports() on this directory can then be as simple as just calling the generic process_raw_exports() method (but may have other tasks to do...): def get_exports(self): self.process_raw_exports() Finally, all the exported methods themselves are unburdened of all access checks, and may therefore proceed knowing that all user/access/permissions conditions are met, and just deal with building the response. Note that the conditions used as examples here are only a few, and process_raw_exports() will probably have to evolve into something quite hefty. But, the more "complicated" the single and generic process_raw_exports() gets, then the more simplifications are to be had by the many and custom get_exports() methods, as well as the even more numerous exported methods themselves. mario