Hi Zsolt, I like this approach, as it makes front end template development straightforward even if it doesn't represent the pinnacle of clean backend.
On 12 November 2016 at 20:13, Zsolt Ero <zsolt....@gmail.com> wrote: > OK, here is something I made, by looking at pviews util. > > def route_allowed(request, route_name): > from zope.interface import providedBy > from pyramid.interfaces import IRouteRequest > from pyramid.interfaces import IRequest > from pyramid.view import _find_views > > > reg = request.registry > request_iface = reg.queryUtility(IRouteRequest, name=route_name, > default=IRequest) > context_iface = providedBy(request.context) > views = _find_views(reg, request_iface, context_iface, '') > > > assert len(views) == 1 > > > view = views[0] > permission = view.__permission__ > > > return bool(request.has_permission(permission)) > > Can you explain why this is wrong or how can I make it better? It is > limited to the exactly one matching view case (assert len(views) == 1), > but I believe it's a fair limitation and is not a problem for a typical URL > Dispatch app, and definitely not a problem for my use case. > > Zsolt > > > > > On Saturday, 12 November 2016 18:25:45 UTC+1, Zsolt Ero wrote: >> >> Here is what I see: >> - The way Pyramid does everything super flexibly (URL structure, the view >> callables, the role concepts, and the permissions as you said it) can make >> it very complicated to do otherwise simple things, such as making a >> request.route_allowed()... >> - If request.route_url() exists and works, why can we not make >> request.route_allowed()? I understand that one route *may* point to >> multiple views, but that mechanism is implemented already, since Pyramid >> can decide what to do on every incoming request. >> - The *only* thing what I can imagine is not obvious from a request and >> a route_url is the GET/POST, etc. kind, since the user might want to change >> that between requests. (For example calling a form, etc.). >> >> So why can we not make a simple request.route_allowed(**kwargs, >> method='GET') method, where kwargs would be the same as for route_url()? >> >> Zsolt >> >> >> On Saturday, 12 November 2016 00:40:17 UTC+1, Mike Orr wrote: >>> >>> On Thu, Nov 10, 2016 at 12:48 PM, Zsolt Ero <zsol...@gmail.com> wrote: >>> > Hi, I'd like to do the simplest possible thing in Pyramid / URL >>> Dispatch, >>> > yet it seems almost impossibly hard to do it. >>> > >>> > So it's the super common case of having a menu, and I'd only like to >>> insert >>> > menu items which are available for the current user. >>> > >>> > I'm looking for a function to fit in this usage: >>> > >>> > {% macro nav_item(request, route_name, text) -%} >>> > {% if request.view_execution_permitted(route_name) %} >>> > <li> >>> > <a href="{{ request.route_url(route_name) }}">{{ text }}</a> >>> > </li> >>> > {% endif %} >>> > {%- endmacro %} >>> > >>> > >>> > My problems are the following: >>> > >>> > 1. view_execution_permitted doesn't work like this, unlike other >>> security >>> > functions, for example request.has_permission(). Why? >>> >>> There seems to be a logic problem here. Routes aren't >>> authorization-significant entities; a route is just a URL pattern. >>> Users belong in roles/groups (Pyramid calls all of these "principals" >>> -- defined by the "groupfinder" callback in the authentication >>> policy). Principles have permissions -- defined in the ACLs others >>> have talked about. A simple URL Dispatch application may have just one >>> ACL for everything: a root factory defined at startup sets all the >>> permissions that all the pages need. A more complex URL Dispatch >>> application may have different roots for different parts of the >>> application (different view configurations), and each of these can do >>> their own private traversal to sub-objects. But it's easier to start >>> with a single root for the entire application. Each request will have >>> its own instance of that root, which is the "context" available to the >>> view and the authorization system. Finally, the view configuration >>> ties all of these together: the view, the route, the root factory with >>> its ACL, and the permission required to execute the view. The reason >>> all these are separate is to keep some independence between the URL >>> structure, the view callables, the role concepts, and the permissions: >>> so you can design each one autonomously to its best structure, and you >>> can change one (within limits) without affecting the others. >>> >>> So the answer to your question is, what determines which menu items >>> should be displayed? Not the routes, the *roles* (principles). The >>> roles imply permissions, and r'equest.has_permission' tells whether >>> the user has that permission (i.e., can execute the views that require >>> that permission). However, there's no formal listing of which routes >>> go with which permissions; that's all tied up in the complex view >>> confugrations. But you should know which permission each page >>> requires. So you should do a (in Mako syntax which I'm more familiar >>> with) '% if request.has_permission("foo_permission"): <a >>> href="${request.route_url('foo_route')}">text</a> % endif'. I have one >>> application with permissions and I use 'pyramid_layout', so I define >>> several boolean attributes in the layout object ('can_do_this', >>> 'can_do_that'), and use those to decide which menu items to display in >>> the site template. For links in individual pages, the view sets >>> similar booleans. Actually, I don't always use booleans because I like >>> to generate the URLs outside the templates, so I use None to indicate >>> no URL (no link), or I give a list of permitted URLs that doesn't >>> include the unpermitted ones. >>> >>> If you need to do something dynamically (e.g., user-defined URLs and >>> permissions that the developer doesn't know about), then studying >>> Kotti might be useful, because it allows site admins to define users >>> and roles and pages and link them together. >>> >>> So I don't think you'll need to ask whether a route is permitted to a >>> user; that concept belongs in the principles and ACLs. But there may >>> be something I'm missing. As for 'view_execution_permitted', I've >>> never used that and I'm not sure it's useful for application >>> developers, especially in a URL Dispatch application. It may be >>> something Pyramid uses more internally. The fact that it requires a >>> view name is a red flag. Routes kind of replace view names in URL >>> Dispatch. Traversal uses view names extensively to choose between >>> multiple views for a resource. URL Dispatch uses mostly the route name >>> to choose a view, and specifying a view name could accidentally make >>> the view configuration not match the request. >>> >> -- > You received this message because you are subscribed to the Google Groups > "pylons-discuss" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to pylons-discuss+unsubscr...@googlegroups.com. > To post to this group, send email to pylons-discuss@googlegroups.com. > To view this discussion on the web visit https://groups.google.com/d/ > msgid/pylons-discuss/648eb04e-4036-4161-985a-c7317e8cd653% > 40googlegroups.com > <https://groups.google.com/d/msgid/pylons-discuss/648eb04e-4036-4161-985a-c7317e8cd653%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > For more options, visit https://groups.google.com/d/optout. > -- Mikko Ohtamaa http://opensourcehacker.com http://twitter.com/moo9000 -- You received this message because you are subscribed to the Google Groups "pylons-discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+unsubscr...@googlegroups.com. To post to this group, send email to pylons-discuss@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/pylons-discuss/CAK8RCUtXpLfn7ejR1yWuEubK9P5yQai8esGchXLK7RfMpBnT1w%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.