diff -r 1817f8946c22 -r faf279e33298 cubicweb/pyramid/core.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cubicweb/pyramid/core.py Mon Sep 26 14:52:12 2016 +0200 @@ -0,0 +1,400 @@ +import itertools + +from contextlib import contextmanager +from warnings import warn +from cgi import FieldStorage + +import rql + +from cubicweb.web.request import CubicWebRequestBase +from cubicweb import repoapi + +import cubicweb +import cubicweb.web +from cubicweb.server import session as cwsession + +from pyramid import httpexceptions + +from cubicweb.pyramid import tools + +import logging + +log = logging.getLogger(__name__) + + +CW_321 = cubicweb.__pkginfo__.numversion >= (3, 21, 0) + + +class Connection(cwsession.Connection): + """ A specialised Connection that access the session data through a + property. + + This behavior makes sure the actual session data is not loaded until + actually accessed. + """ + def __init__(self, session, *args, **kw): + super(Connection, self).__init__(session, *args, **kw) + self._session = session + + def _get_session_data(self): + return self._session.data + + def _set_session_data(self, data): + pass + + _session_data = property(_get_session_data, _set_session_data) + + +class Session(cwsession.Session): + """ A Session that access the session data through a property. + + Along with :class:`Connection`, it avoid any load of the pyramid session + data until it is actually accessed. + """ + def __init__(self, pyramid_request, user, repo): + super(Session, self).__init__(user, repo) + self._pyramid_request = pyramid_request + + def get_data(self): + if not getattr(self, '_protect_data_access', False): + self._data_accessed = True + return self._pyramid_request.session + + def set_data(self, data): + if getattr(self, '_data_accessed', False): + self._pyramid_request.session.clear() + self._pyramid_request.session.update(data) + + data = property(get_data, set_data) + + def new_cnx(self): + self._protect_data_access = True + try: + return Connection(self) + finally: + self._protect_data_access = False + + +def cw_headers(request): + return itertools.chain( + *[[(k, item) for item in v] + for k, v in request.cw_request.headers_out.getAllRawHeaders()]) + + +@contextmanager +def cw_to_pyramid(request): + """ Context manager to wrap a call to the cubicweb API. + + All CW exceptions will be transformed into their pyramid equivalent. + When needed, some CW reponse bits may be converted too (mainly headers)""" + try: + yield + except cubicweb.web.Redirect as ex: + assert 300 <= ex.status < 400 + raise httpexceptions.status_map[ex.status]( + ex.location, headers=cw_headers(request)) + except cubicweb.web.StatusResponse as ex: + warn('[3.16] StatusResponse is deprecated use req.status_out', + DeprecationWarning, stacklevel=2) + request.body = ex.content + request.status_int = ex.status + except cubicweb.web.Unauthorized as ex: + raise httpexceptions.HTTPForbidden( + request.cw_request._( + 'You\'re not authorized to access this page. ' + 'If you think you should, please contact the site ' + 'administrator.'), + headers=cw_headers(request)) + except cubicweb.web.Forbidden: + raise httpexceptions.HTTPForbidden( + request.cw_request._( + 'This action is forbidden. ' + 'If you think it should be allowed, please contact the site ' + 'administrator.'), + headers=cw_headers(request)) + except (rql.BadRQLQuery, cubicweb.web.RequestError) as ex: + raise + + +class CubicWebPyramidRequest(CubicWebRequestBase): + """ A CubicWeb request that only wraps a pyramid request. + + :param request: A pyramid request + + """ + def __init__(self, request): + self._request = request + + self.path = request.upath_info + + vreg = request.registry['cubicweb.registry'] + https = request.scheme == 'https' + + post = request.params.mixed() + headers_in = request.headers + + super(CubicWebPyramidRequest, self).__init__(vreg, https, post, + headers=headers_in) + + self.content = request.body_file_seekable + + def setup_params(self, params): + self.form = {} + for param, val in params.items(): + if param in self.no_script_form_params and val: + val = self.no_script_form_param(param, val) + if isinstance(val, FieldStorage) and val.file: + val = (val.filename, val.file) + if param == '_cwmsgid': + self.set_message_id(val) + elif param == '__message': + warn('[3.13] __message in request parameter is deprecated ' + '(may only be given to .build_url). Seeing this message ' + 'usualy means your application hold some