import datetime
import hashlib
import logging
+import os
import re
import traceback
+
import werkzeug
import werkzeug.routing
+import werkzeug.utils
import openerp
from openerp.addons.base import ir
from openerp.addons.base.ir import ir_qweb
from openerp.addons.website.models.website import slug, url_for, _UNSLUG_RE
from openerp.http import request
+from openerp.tools import config
from openerp.osv import orm
logger = logging.getLogger(__name__)
request.website_multilang = request.website_enabled and func and func.routing.get('multilang', True)
- if not request.session.has_key('geoip'):
+ if 'geoip' not in request.session:
record = {}
if self.geo_ip_resolver is None:
try:
import GeoIP
- self.geo_ip_resolver = GeoIP.open('/usr/share/GeoIP/GeoIP.dat', GeoIP.GEOIP_STANDARD)
+ # updated database can be downloaded on MaxMind website
+ # http://dev.maxmind.com/geoip/legacy/install/city/
+ geofile = config.get('geoip_database')
+ if os.path.exists(geofile):
+ self.geo_ip_resolver = GeoIP.open(geofile, GeoIP.GEOIP_STANDARD)
+ else:
+ self.geo_ip_resolver = False
+ logger.warning('GeoIP database file %r does not exists', geofile)
except ImportError:
self.geo_ip_resolver = False
- if self.geo_ip_resolver:
+ if self.geo_ip_resolver and request.httprequest.remote_addr:
record = self.geo_ip_resolver.record_by_addr(request.httprequest.remote_addr) or {}
request.session['geoip'] = record
-
+
if request.website_enabled:
- if func:
- self._authenticate(func.routing['auth'])
- else:
- self._auth_method_public()
- request.redirect = lambda url: werkzeug.utils.redirect(url_for(url))
+ try:
+ if func:
+ self._authenticate(func.routing['auth'])
+ else:
+ self._auth_method_public()
+ except Exception as e:
+ return self._handle_exception(e)
+
+ request.redirect = lambda url, code=302: werkzeug.utils.redirect(url_for(url), code)
request.website = request.registry['website'].get_current_website(request.cr, request.uid, context=request.context)
+ request.context['website_id'] = request.website.id
+ langs = [lg[0] for lg in request.website.get_languages()]
+ path = request.httprequest.path.split('/')
if first_pass:
- request.lang = request.website.default_lang_code
+ if request.website_multilang:
+ # If the url doesn't contains the lang and that it's the first connection, we to retreive the user preference if it exists.
+ if not path[1] in langs and not request.httprequest.cookies.get('session_id'):
+ if request.lang not in langs:
+ # Try to find a similar lang. Eg: fr_BE and fr_FR
+ short = request.lang.split('_')[0]
+ langs_withshort = [lg[0] for lg in request.website.get_languages() if lg[0].startswith(short)]
+ if len(langs_withshort):
+ request.lang = langs_withshort[0]
+ else:
+ request.lang = request.website.default_lang_code
+ # We redirect with the right language in url
+ if request.lang != request.website.default_lang_code:
+ path.insert(1, request.lang)
+ path = '/'.join(path) or '/'
+ return request.redirect(path + '?' + request.httprequest.query_string)
+ else:
+ request.lang = request.website.default_lang_code
+
request.context['lang'] = request.lang
+ if not request.context.get('tz'):
+ request.context['tz'] = request.session['geoip'].get('time_zone')
if not func:
- path = request.httprequest.path.split('/')
- langs = [lg[0] for lg in request.website.get_languages()]
if path[1] in langs:
request.lang = request.context['lang'] = path.pop(1)
path = '/'.join(path) or '/'
if request.lang == request.website.default_lang_code:
# If language is in the url and it is the default language, redirect
# to url without language so google doesn't see duplicate content
- return request.redirect(path + '?' + request.httprequest.query_string)
+ return request.redirect(path + '?' + request.httprequest.query_string, code=301)
return self.reroute(path)
+ # bind modified context
+ request.website = request.website.with_context(request.context)
return super(ir_http, self)._dispatch()
def reroute(self, path):
def _postprocess_args(self, arguments, rule):
super(ir_http, self)._postprocess_args(arguments, rule)
- for arg, val in arguments.items():
+ for key, 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
+ if isinstance(val, orm.BaseModel) and isinstance(val._uid, RequestUID):
+ arguments[key] = val.sudo(request.uid)
+
try:
_, path = rule.build(arguments)
assert path is not None
path = '/' + request.lang + path
if request.httprequest.query_string:
path += '?' + request.httprequest.query_string
- return werkzeug.utils.redirect(path)
+ return werkzeug.utils.redirect(path, code=301)
def _serve_attachment(self):
domain = [('type', '=', 'binary'), ('url', '=', request.httprequest.path)]
exception=exception,
traceback=traceback.format_exc(exception),
)
- code = getattr(exception, 'code', code)
+
+ if isinstance(exception, werkzeug.exceptions.HTTPException):
+ if exception.code is None:
+ # Hand-crafted HTTPException likely coming from abort(),
+ # usually for a redirect response -> return it directly
+ return exception
+ else:
+ code = exception.code
if isinstance(exception, openerp.exceptions.AccessError):
code = 403
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]
+ to_reset = [v for v in views if v.model_data_id.noupdate is True and not v.page]
values['views'] = to_reset
elif code == 403:
logger.warn("403 Forbidden:\n\n%s", values['traceback'])
def to_python(self, value):
m = re.match(self.regex, value)
_uid = RequestUID(value=value, match=m, converter=self)
+ record_id = int(m.group(2))
+ if record_id < 0:
+ # limited support for negative IDs due to our slug pattern, assume abs() if not found
+ if not request.registry[self.model].exists(request.cr, _uid, [record_id]):
+ record_id = abs(record_id)
return request.registry[self.model].browse(
- request.cr, _uid, int(m.group(2)), context=request.context)
+ request.cr, _uid, record_id, context=request.context)
def generate(self, cr, uid, query=None, args=None, context=None):
obj = request.registry[self.model]