45
45
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
46
46
from ivle.webapp.base.xhtml import XHTMLView, XHTMLErrorView
47
47
from ivle.webapp.errors import HTTPError, Unauthorized, NotFound
48
from ivle.webapp.routing import Router, RoutingError
48
from ivle.webapp.publisher import Publisher, PublishingError
49
49
from ivle.webapp import ApplicationRoot
51
51
config = ivle.config.Config()
53
def generate_router(view_plugins, root):
53
class ObjectPermissionCheckingPublisher(Publisher):
54
"""A specialised publisher that checks object permissions.
56
This publisher verifies that the user holds any permission at all
57
on the model objects through which the resolution path passes. If
58
no permission is held, resolution is aborted with an Unauthorized
61
IMPORTANT: This does NOT check view permissions. It only checks
62
the objects in between the root and the view, exclusive!
65
def traversed_to_object(self, obj):
66
"""Check that the user has any permission at all over the object."""
67
if (hasattr(obj, 'get_permissions') and
68
len(obj.get_permissions(self.root.user, config)) == 0):
69
# Indicate the forbidden object if this is an admin.
70
if self.root.user and self.root.user.admin:
71
raise Unauthorized('Unauthorized: %s' % obj)
76
def generate_publisher(view_plugins, root, publicmode=False):
55
78
Build a Mapper object for doing URL matching using 'routes', based on the
56
79
given plugin registry.
81
r = ObjectPermissionCheckingPublisher(root=root)
60
83
r.add_set_switch('api', 'api')
86
view_attr = 'public_views'
87
forward_route_attr = 'public_forward_routes'
88
reverse_route_attr = 'public_reverse_routes'
91
forward_route_attr = 'forward_routes'
92
reverse_route_attr = 'reverse_routes'
62
95
for plugin in view_plugins:
63
if hasattr(plugin, 'forward_routes'):
64
for fr in plugin.forward_routes:
96
if hasattr(plugin, forward_route_attr):
97
for fr in getattr(plugin, forward_route_attr):
65
98
# An annotated function can also be passed in directly.
66
99
if hasattr(fr, '_forward_route_meta'):
67
100
r.add_forward_func(fr)
69
102
r.add_forward(*fr)
71
if hasattr(plugin, 'reverse_routes'):
72
for rr in plugin.reverse_routes:
104
if hasattr(plugin, reverse_route_attr):
105
for rr in getattr(plugin, reverse_route_attr):
73
106
# An annotated function can also be passed in directly.
74
107
if hasattr(rr, '_reverse_route_src'):
75
108
r.add_reverse_func(rr)
77
110
r.add_reverse(*rr)
79
if hasattr(plugin, 'views'):
80
for v in plugin.views:
112
if hasattr(plugin, view_attr):
113
for v in getattr(plugin, view_attr):
101
134
if user and user.valid:
105
raise NotImplementedError("no public mode with obtrav yet!")
107
req.router = generate_router(config.plugin_index[ViewPlugin],
108
ApplicationRoot(req.config, req.store))
137
req.publisher = generate_publisher(
138
config.plugin_index[ViewPlugin],
139
ApplicationRoot(req.config, req.store, req.user),
140
publicmode=req.publicmode)
111
obj, viewcls, subpath = req.router.resolve(req.uri.decode('utf-8'))
143
obj, viewcls, subpath = req.publisher.resolve(req.uri.decode('utf-8'))
113
145
# We 404 if we have a subpath but the view forbids it.
114
146
if not viewcls.subpath_allowed and subpath:
155
191
req.store.commit()
157
except RoutingError, e:
193
except Unauthorized, e:
194
# Resolution failed due to a permission check. Display a pretty
195
# error, or maybe a login page.
196
XHTMLView.get_error_view(e)(req, e, req.publisher.root).render(req)
198
except PublishingError, e:
201
if req.user and req.user.admin:
159
202
XHTMLErrorView(req, NotFound('Not found: ' +
160
str(e.args))).render(req)
203
str(e.args)), e[0]).render(req)
162
XHTMLErrorView(req, NotFound()).render(req)
205
XHTMLErrorView(req, NotFound(), e[0]).render(req)