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.publisher import Publisher, PublishingError
48
from ivle.webapp.routing import Router, RoutingError
49
49
from ivle.webapp import ApplicationRoot
51
51
config = ivle.config.Config()
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):
53
def generate_router(view_plugins, root):
78
55
Build a Mapper object for doing URL matching using 'routes', based on the
79
56
given plugin registry.
81
r = ObjectPermissionCheckingPublisher(root=root)
83
60
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'
95
62
for plugin in view_plugins:
96
if hasattr(plugin, forward_route_attr):
97
for fr in getattr(plugin, forward_route_attr):
63
if hasattr(plugin, 'forward_routes'):
64
for fr in plugin.forward_routes:
98
65
# An annotated function can also be passed in directly.
99
66
if hasattr(fr, '_forward_route_meta'):
100
67
r.add_forward_func(fr)
102
69
r.add_forward(*fr)
104
if hasattr(plugin, reverse_route_attr):
105
for rr in getattr(plugin, reverse_route_attr):
71
if hasattr(plugin, 'reverse_routes'):
72
for rr in plugin.reverse_routes:
106
73
# An annotated function can also be passed in directly.
107
74
if hasattr(rr, '_reverse_route_src'):
108
75
r.add_reverse_func(rr)
110
77
r.add_reverse(*rr)
112
if hasattr(plugin, view_attr):
113
for v in getattr(plugin, view_attr):
79
if hasattr(plugin, 'views'):
80
for v in plugin.views:
134
101
if user and user.valid:
137
req.publisher = generate_publisher(
138
config.plugin_index[ViewPlugin],
139
ApplicationRoot(req.config, req.store, req.user),
140
publicmode=req.publicmode)
105
raise NotImplementedError("no public mode with obtrav yet!")
107
req.router = generate_router(config.plugin_index[ViewPlugin],
108
ApplicationRoot(req.config, req.store))
143
obj, viewcls, subpath = req.publisher.resolve(req.uri.decode('utf-8'))
111
obj, viewcls, subpath = req.router.resolve(req.uri.decode('utf-8'))
145
113
# We 404 if we have a subpath but the view forbids it.
146
114
if not viewcls.subpath_allowed and subpath:
191
155
req.store.commit()
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:
157
except RoutingError, e:
201
if req.user and req.user.admin:
202
161
XHTMLErrorView(req, NotFound('Not found: ' +
203
162
str(e.args)), e[0]).render(req)
205
164
XHTMLErrorView(req, NotFound(), e[0]).render(req)
211
168
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):