from pyramid import security
from pyramid.httpexceptions import HTTPSeeOther
from pyramid import httpexceptions
import cubicweb
import cubicweb.web
from cubicweb.web.application import CubicWebPublisher
from cubicweb.web import LogOut, cors
from pyramid_cubicweb.core import cw_to_pyramid
class PyramidSessionHandler(object):
"""A CW Session handler that rely on the pyramid API to fetch the needed
informations"""
def __init__(self, appli):
self.appli = appli
def get_session(self, req):
return req._request.cw_session
def logout(self, req, goto_url):
raise LogOut(url=goto_url)
class CubicWebPyramidHandler(object):
def __init__(self, appli):
self.appli = appli
def __call__(self, request):
"""
Handler that mimics what CubicWebPublisher.main_handle_request and
CubicWebPublisher.core_handle do
"""
# XXX The main handler of CW forbid anonymous https connections
# I guess we can drop this "feature" but in doubt I leave this comment
# so we don't forget about it. (cdevienne)
req = request.cw_request
vreg = request.registry['cubicweb.registry']
try:
try:
with cw_to_pyramid(request):
cors.process_request(req, vreg.config)
ctrlid, rset = self.appli.url_resolver.process(req, req.path)
try:
controller = vreg['controllers'].select(
ctrlid, req, appli=self.appli)
except cubicweb.NoSelectableObject:
raise httpexceptions.HTTPUnauthorized(
req._('not authorized'))
req.update_search_state()
content = controller.publish(rset=rset)
# XXX this auto-commit should be handled by the cw_request cleanup
# or the pyramid transaction manager.
# It is kept here to have the ValidationError handling bw
# compatible
if req.cnx:
txuuid = req.cnx.commit()
# commited = True
if txuuid is not None:
req.data['last_undoable_transaction'] = txuuid
except cors.CORSPreflight:
request.response.status_int = 200
except cubicweb.web.ValidationError as ex:
# XXX The validation_error_handler implementation is light, we
# should redo it better in cw_to_pyramid, so it can be properly
# handled when raised from a cubicweb view.
# BUT the real handling of validation errors should be done
# earlier in the controllers, not here. In the end, the
# ValidationError should never by handled here.
content = self.appli.validation_error_handler(req, ex)
except cubicweb.web.RemoteCallFailed as ex:
# XXX The default pyramid error handler (or one that we provide
# for this exception) should be enough
# content = self.appli.ajax_error_handler(req, ex)
raise
if content is not None:
request.response.body = content
# XXX CubicWebPyramidRequest.headers_out should
# access directly the pyramid response headers.
request.response.headers.clear()
for k, v in req.headers_out.getAllRawHeaders():
for item in v:
request.response.headers.add(k, item)
except LogOut as ex:
# The actual 'logging out' logic should be in separated function
# that is accessible by the pyramid views
headers = security.forget(request)
raise HTTPSeeOther(ex.url, headers=headers)
# except AuthenticationError:
# XXX I don't think it makes sens to catch this ex here (cdevienne)
return request.response
def includeme(config):
# Set up a defaut route to handle non-catched urls.
# This is to keep legacy compatibility for cubes that makes use of the
# cubicweb controllers.
cwconfig = config.registry['cubicweb.config']
repository = config.registry['cubicweb.repository']
cwappli = CubicWebPublisher(
repository, cwconfig,
session_handler_fact=PyramidSessionHandler)
handler = CubicWebPyramidHandler(cwappli)
config.registry['cubicweb.appli'] = cwappli
config.registry['cubicweb.handler'] = handler
config.add_route('catchall', pattern='*path')
config.add_view(handler, route_name='catchall')