[MERGE] Forward-port of saas-3 up to 141e1b2
authorOlivier Dony <odo@openerp.com>
Wed, 25 Jun 2014 16:34:03 +0000 (18:34 +0200)
committerOlivier Dony <odo@openerp.com>
Wed, 25 Jun 2014 16:34:03 +0000 (18:34 +0200)
1  2 
addons/website/models/ir_http.py
openerp/http.py

@@@ -79,102 -77,83 +78,117 @@@ class ir_http(orm.AbstractModel)
  
          return self._dispatch()
  
 -    def _postprocess_args(self, arguments):
 -        if hasattr(request, 'rerouting'):
 -            url = request.rerouting[0]
 -        else:
 -            url = request.httprequest.url
 -        original_url = url
 -        for arg in arguments.itervalues():
 -            if isinstance(arg, orm.browse_record) and isinstance(arg._uid, RequestUID):
 -                placeholder = arg._uid
 -                arg._uid = request.uid
 -                try:
 -                    good_slug = slug(arg)
 -                    if str(arg.id) != placeholder.value and placeholder.value != good_slug:
 -                        # TODO: properly recompose the url instead of using replace()
 -                        url = url.replace(placeholder.value, good_slug)
 -                except KeyError, e:
 -                    return self._handle_exception(e, code=404)
 -        if url != original_url:
 -            werkzeug.exceptions.abort(werkzeug.utils.redirect(url))
 +    def _postprocess_args(self, arguments, rule):
 +        if not getattr(request, 'website_enabled', False):
 +            return super(ir_http, self)._postprocess_args(arguments, rule)
 +
 +        for arg, val in arguments.items():
 +            # Replace uid placeholder by the current request.uid
 +            if isinstance(val, orm.browse_record) and isinstance(val._uid, RequestUID):
 +                val._uid = request.uid
 +        try:
 +            _, path = rule.build(arguments)
 +            assert path is not None
-         except Exception:
-             return self._handle_exception(werkzeug.exceptions.NotFound())
++        except Exception, e:
++            return self._handle_exception(e, code=404)
 +
 +        if request.httprequest.method in ('GET', 'HEAD'):
 +            generated_path = werkzeug.url_unquote_plus(path)
 +            current_path = werkzeug.url_unquote_plus(request.httprequest.path)
 +            if generated_path != current_path:
 +                if request.lang != request.website.default_lang_code:
 +                    path = '/' + request.lang + path
 +                return werkzeug.utils.redirect(path)
 +
 +    def _serve_attachment(self):
 +        domain = [('type', '=', 'binary'), ('url', '=', request.httprequest.path)]
 +        attach = self.pool['ir.attachment'].search_read(request.cr, openerp.SUPERUSER_ID, domain, ['__last_update', 'datas', 'mimetype'], context=request.context)
 +        if attach:
 +            wdate = attach[0]['__last_update']
 +            datas = attach[0]['datas']
 +            response = werkzeug.wrappers.Response()
 +            server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
 +            try:
 +                response.last_modified = datetime.datetime.strptime(wdate, server_format + '.%f')
 +            except ValueError:
 +                # just in case we have a timestamp without microseconds
 +                response.last_modified = datetime.datetime.strptime(wdate, server_format)
 +
 +            response.set_etag(hashlib.sha1(datas).hexdigest())
 +            response.make_conditional(request.httprequest)
 +
 +            if response.status_code == 304:
 +                return response
 +
 +            response.mimetype = attach[0]['mimetype']
 +            response.data = datas.decode('base64')
 +            return response
  
-     def _handle_exception(self, exception=None, code=500):
-         try:
+     def _handle_exception(self, exception, code=500):
++        # This is done first as the attachment path may
++        # not match any HTTP controller, so the request
++        # may not be website-enabled.
++        attach = self._serve_attachment()
++        if attach:
++            return attach
++
+         is_website_request = bool(getattr(request, 'website_enabled', False) and request.website)
+         if not is_website_request:
+             # Don't touch non website requests exception handling
              return super(ir_http, self)._handle_exception(exception)
-         except Exception:
-             attach = self._serve_attachment()
-             if attach:
-                 return attach
-             if getattr(request, 'website_enabled', False) and request.website:
-                 values = dict(
-                     exception=exception,
-                     traceback=traceback.format_exc(exception),
-                 )
-                 if exception:
-                     code = getattr(exception, 'code', code)
-                     if isinstance(exception, ir_qweb.QWebException):
-                         values.update(qweb_exception=exception)
-                         if isinstance(exception.qweb.get('cause'), openerp.exceptions.AccessError):
-                             code = 403
-                 if code == 500:
-                     logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
-                     if 'qweb_exception' in values:
-                         view = request.registry.get("ir.ui.view")
-                         views = view._views_get(request.cr, request.uid, exception.qweb['template'], request.context)
-                         to_reset = [v for v in views if v.model_data_id.noupdate is True]
-                         values['views'] = to_reset
-                 elif code == 403:
-                     logger.warn("403 Forbidden:\n\n%s", values['traceback'])
-                 values.update(
-                     status_message=werkzeug.http.HTTP_STATUS_CODES[code],
-                     status_code=code,
-                 )
-                 if not request.uid:
-                     self._auth_method_public()
-                 try:
-                     html = request.website._render('website.%s' % code, values)
-                 except Exception:
-                     html = request.website._render('website.http_error', values)
-                 return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
-             raise
+         else:
+             try:
+                 response = super(ir_http, self)._handle_exception(exception)
+                 if isinstance(response, Exception):
+                     exception = response
+                 else:
+                     # if parent excplicitely returns a plain response, then we don't touch it
+                     return response
+             except Exception, e:
+                 exception = e
+             values = dict(
+                 exception=exception,
+                 traceback=traceback.format_exc(exception),
+             )
+             code = getattr(exception, 'code', code)
+             if isinstance(exception, openerp.exceptions.AccessError):
+                 code = 403
+             if isinstance(exception, ir_qweb.QWebException):
+                 values.update(qweb_exception=exception)
+                 if isinstance(exception.qweb.get('cause'), openerp.exceptions.AccessError):
+                     code = 403
+             if code == 500:
+                 logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
+                 if 'qweb_exception' in values:
+                     view = request.registry.get("ir.ui.view")
+                     views = view._views_get(request.cr, request.uid, exception.qweb['template'], request.context)
+                     to_reset = [v for v in views if v.model_data_id.noupdate is True]
+                     values['views'] = to_reset
+             elif code == 403:
+                 logger.warn("403 Forbidden:\n\n%s", values['traceback'])
+             values.update(
+                 status_message=werkzeug.http.HTTP_STATUS_CODES[code],
+                 status_code=code,
+             )
+             if not request.uid:
+                 self._auth_method_public()
+             try:
+                 html = request.website._render('website.%s' % code, values)
+             except Exception:
+                 html = request.website._render('website.http_error', values)
+             return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
  
  class ModelConverter(ir.ir_http.ModelConverter):
 -    def __init__(self, url_map, model=False):
 +    def __init__(self, url_map, model=False, domain='[]'):
          super(ModelConverter, self).__init__(url_map, model)
 +        self.domain = domain
          self.regex = r'(?:[A-Za-z0-9-_]+?-)?(\d+)(?=$|/)'
  
      def to_url(self, value):
diff --cc openerp/http.py
Simple merge