diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py index 3d1a6b53af3..724cd978bc3 100644 --- a/addons/auth_oauth/controllers/main.py +++ b/addons/auth_oauth/controllers/main.py @@ -88,7 +88,7 @@ class OAuthLogin(Home): ensure_db() if request.httprequest.method == 'GET' and request.session.uid and request.params.get('redirect'): # Redirect if already logged in and redirect param is present - return http.redirect_with_hash(request.params.get('redirect')) + return request.redirect(request.params.get('redirect')) providers = self.list_providers() response = super(OAuthLogin, self).web_login(*args, **kw) @@ -155,7 +155,7 @@ class OAuthController(http.Controller): # oauth credentials not valid, user could be on a temporary session _logger.info('OAuth2: access denied, redirect to main page in case a valid session exists, without setting cookies') url = "/web/login?oauth_error=3" - redirect = werkzeug.utils.redirect(url, 303) + redirect = request.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py index 9bca10e9da1..2dad902398f 100644 --- a/addons/auth_signup/controllers/main.py +++ b/addons/auth_signup/controllers/main.py @@ -22,7 +22,7 @@ class AuthSignupHome(Home): response.qcontext.update(self.get_auth_signup_config()) if request.httprequest.method == 'GET' and request.session.uid and request.params.get('redirect'): # Redirect if already logged in and redirect param is present - return http.redirect_with_hash(request.params.get('redirect')) + return request.redirect(request.params.get('redirect')) return response @http.route('/web/signup', type='http', auth='public', website=True, sitemap=False) diff --git a/addons/auth_totp/controllers/home.py b/addons/auth_totp/controllers/home.py index 10c2461ebf6..19d678f47a1 100644 --- a/addons/auth_totp/controllers/home.py +++ b/addons/auth_totp/controllers/home.py @@ -15,10 +15,10 @@ class Home(odoo.addons.web.controllers.main.Home): ) def web_totp(self, redirect=None, **kwargs): if request.session.uid: - return http.redirect_with_hash(self._login_redirect(request.session.uid, redirect=redirect)) + return request.redirect(self._login_redirect(request.session.uid, redirect=redirect)) if not request.session.pre_uid: - return http.redirect_with_hash('/web/login') + return request.redirect('/web/login') error = None if request.httprequest.method == 'POST': @@ -32,7 +32,7 @@ class Home(odoo.addons.web.controllers.main.Home): error = _("Invalid authentication code format.") else: request.session.finalize() - return http.redirect_with_hash(self._login_redirect(request.session.uid, redirect=redirect)) + return request.redirect(self._login_redirect(request.session.uid, redirect=redirect)) return request.render('auth_totp.auth_totp_form', { 'error': error, diff --git a/addons/calendar/controllers/main.py b/addons/calendar/controllers/main.py index 24779a2946a..418cecaf5f5 100644 --- a/addons/calendar/controllers/main.py +++ b/addons/calendar/controllers/main.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import werkzeug - import odoo.http as http from odoo.http import request @@ -70,7 +68,7 @@ class CalendarController(http.Controller): # If user is internal and logged, redirect to form view of event # otherwise, display the simplifyed web page with event informations if request.session.uid and request.env['res.users'].browse(request.session.uid).user_has_groups('base.group_user'): - return werkzeug.utils.redirect('/web?db=%s#id=%s&view_type=form&model=calendar.event' % (request.env.cr.dbname, id)) + return request.redirect('/web?db=%s#id=%s&view_type=form&model=calendar.event' % (request.env.cr.dbname, id)) # NOTE : we don't use request.render() since: # - we need a template rendering which is not lazy, to render before cursor closing diff --git a/addons/crm_mail_plugin/controllers/crm_client.py b/addons/crm_mail_plugin/controllers/crm_client.py index 72c5bc1dc36..c83199019db 100644 --- a/addons/crm_mail_plugin/controllers/crm_client.py +++ b/addons/crm_mail_plugin/controllers/crm_client.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import werkzeug - from odoo import http from odoo.http import request from odoo.tools import html2plaintext @@ -36,7 +34,7 @@ class CrmClient(http.Controller): for supporting older versions """ server_action = http.request.env.ref("crm_mail_plugin.lead_creation_prefilled_action") - return werkzeug.utils.redirect( + return request.redirect( '/web#action=%s&model=crm.lead&partner_id=%s' % (server_action.id, int(partner_id))) @http.route('/mail_plugin/lead/create', type='json', auth='outlook', cors="*") @@ -61,4 +59,4 @@ class CrmClient(http.Controller): """ action = http.request.env.ref("crm.crm_lead_view_form") url = '/web#id=%s&action=%s&model=crm.lead&edit=1&model=crm.lead' % (lead_id, action.id) - return werkzeug.utils.redirect(url) + return request.redirect(url) diff --git a/addons/google_account/controllers/main.py b/addons/google_account/controllers/main.py index 94aeacd2c1f..3483a9f7832 100644 --- a/addons/google_account/controllers/main.py +++ b/addons/google_account/controllers/main.py @@ -2,9 +2,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import json -from werkzeug.utils import redirect -from odoo import http, registry +from odoo import http from odoo.http import request @@ -18,13 +17,12 @@ class GoogleAuth(http.Controller): service = state.get('s') url_return = state.get('f') - with registry(dbname).cursor() as cr: - if kw.get('code'): - access_token, refresh_token, ttl = request.env['google.service']._get_google_tokens(kw['code'], service) - # LUL TODO only defined in google_calendar - request.env.user._set_auth_tokens(access_token, refresh_token, ttl) - return redirect(url_return) - elif kw.get('error'): - return redirect("%s%s%s" % (url_return, "?error=", kw['error'])) - else: - return redirect("%s%s" % (url_return, "?error=Unknown_error")) + if kw.get('code'): + access_token, refresh_token, ttl = request.env['google.service']._get_google_tokens(kw['code'], service) + # LUL TODO only defined in google_calendar + request.env.user._set_auth_tokens(access_token, refresh_token, ttl) + return request.redirect(url_return) + elif kw.get('error'): + return request.redirect("%s%s%s" % (url_return, "?error=", kw['error'])) + else: + return request.redirect("%s%s" % (url_return, "?error=Unknown_error")) diff --git a/addons/http_routing/models/ir_http.py b/addons/http_routing/models/ir_http.py index a64e3639565..b6fc8a7880f 100644 --- a/addons/http_routing/models/ir_http.py +++ b/addons/http_routing/models/ir_http.py @@ -423,7 +423,7 @@ class IrHttp(models.AbstractModel): # handle // in url if request.httprequest.method == 'GET' and '//' in request.httprequest.path: new_url = request.httprequest.path.replace('//', '/') + '?' + request.httprequest.query_string.decode('utf-8') - return werkzeug.utils.redirect(new_url, 301) + return request.redirect(new_url, code=301) # locate the controller method try: @@ -456,8 +456,6 @@ class IrHttp(models.AbstractModel): # For website routes (only), add website params on `request` if request.is_frontend: - request.redirect = lambda url, code=302: werkzeug.utils.redirect(url_for(url), code) - cls._add_dispatch_parameters(func) path = request.httprequest.path.split('/') @@ -493,7 +491,7 @@ class IrHttp(models.AbstractModel): path = request.httprequest.path[:-1] if request.httprequest.query_string: path += '?' + request.httprequest.query_string.decode('utf-8') - return werkzeug.utils.redirect(path, code=301) + return request.redirect(path, code=301) path.pop(1) routing_error = None return cls.reroute('/'.join(path) or '/') @@ -521,6 +519,12 @@ class IrHttp(models.AbstractModel): return result + @classmethod + def _redirect(cls, location, code=303): + if request and request.db and request.is_frontend: + location = url_for(location) + return super()._redirect(location, code) + @classmethod def reroute(cls, path): if not hasattr(request, 'rerouting'): @@ -557,7 +561,7 @@ class IrHttp(models.AbstractModel): path = '/' + request.lang.url_code + path if request.httprequest.query_string: path += '?' + request.httprequest.query_string.decode('utf-8') - return werkzeug.utils.redirect(path, code=301) + return request.redirect(path, code=301) @classmethod def _get_exception_code_values(cls, exception): diff --git a/addons/link_tracker/controller/main.py b/addons/link_tracker/controller/main.py index b2fb720fa1e..ccc86de3298 100644 --- a/addons/link_tracker/controller/main.py +++ b/addons/link_tracker/controller/main.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import werkzeug - from odoo import http from odoo.http import request @@ -18,4 +16,4 @@ class LinkTracker(http.Controller): country_code=country_code ) redirect_url = request.env['link.tracker'].get_url_from_code(code) - return werkzeug.utils.redirect(redirect_url or '', 301) + return request.redirect(redirect_url or '', code=301, local=False) diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py index 74fbda0dace..a330f02a738 100644 --- a/addons/mail/controllers/main.py +++ b/addons/mail/controllers/main.py @@ -23,7 +23,7 @@ class MailController(http.Controller): @classmethod def _redirect_to_messaging(cls): url = '/web#%s' % url_encode({'action': 'mail.action_discuss'}) - return werkzeug.utils.redirect(url) + return request.redirect(url) @classmethod def _check_token(cls, token): @@ -106,7 +106,7 @@ class MailController(http.Controller): record_action.pop('target_type', None) # the record has an URL redirection: use it directly if record_action['type'] == 'ir.actions.act_url': - return werkzeug.utils.redirect(record_action['url']) + return request.redirect(record_action['url']) # other choice: act_window (no support of anything else currently) elif not record_action['type'] == 'ir.actions.act_window': return cls._redirect_to_messaging() @@ -124,7 +124,7 @@ class MailController(http.Controller): if cids: url_params['cids'] = ','.join([str(cid) for cid in cids]) url = '/web?#%s' % url_encode(url_params) - return werkzeug.utils.redirect(url) + return request.redirect(url) @http.route('/mail/read_followers', type='json', auth='user') def read_followers(self, res_model, res_id): diff --git a/addons/mail_plugin/controllers/authenticate.py b/addons/mail_plugin/controllers/authenticate.py index 72523d78592..fd18b2d444b 100644 --- a/addons/mail_plugin/controllers/authenticate.py +++ b/addons/mail_plugin/controllers/authenticate.py @@ -50,7 +50,7 @@ class Authenticate(http.Controller): else: params.update({'success': 0, 'state': kw.get('state', '')}) updated_redirect = parsed_redirect.replace(query=werkzeug.urls.url_encode(params)) - return werkzeug.utils.redirect(updated_redirect.to_url()) + return request.redirect(updated_redirect.to_url()) # In this case, an exception will be thrown in case of preflight request if only POST is allowed. @http.route(['/mail_client_extension/auth/access_token', '/mail_plugin/auth/access_token'], type='json', auth="none", cors="*", diff --git a/addons/mass_mailing/controllers/main.py b/addons/mass_mailing/controllers/main.py index 4bc51f82234..f92a0003e00 100644 --- a/addons/mass_mailing/controllers/main.py +++ b/addons/mass_mailing/controllers/main.py @@ -146,7 +146,7 @@ class MassMailController(http.Controller): country_code=country_code, mailing_trace_id=mailing_trace_id ) - return werkzeug.utils.redirect(request.env['link.tracker'].get_url_from_code(code), 301) + return request.redirect(request.env['link.tracker'].get_url_from_code(code), code=301, local=False) @http.route('/mailing/blacklist/check', type='json', auth='public') def blacklist_check(self, mailing_id, res_id, email, token): diff --git a/addons/mass_mailing_sms/controllers/main.py b/addons/mass_mailing_sms/controllers/main.py index 7111e8627dc..52f41b460ec 100644 --- a/addons/mass_mailing_sms/controllers/main.py +++ b/addons/mass_mailing_sms/controllers/main.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import werkzeug - from odoo import http, _ from odoo.addons.phone_validation.tools import phone_validation from odoo.http import request @@ -30,7 +28,7 @@ class MailingSMSController(http.Controller): def blacklist_page(self, mailing_id, trace_code, **post): check_res = self._check_trace(mailing_id, trace_code) if not check_res.get('trace'): - return werkzeug.utils.redirect('/web') + return request.redirect('/web') return request.render('mass_mailing_sms.blacklist_main', { 'mailing_id': mailing_id, 'trace_code': trace_code, @@ -40,7 +38,7 @@ class MailingSMSController(http.Controller): def blacklist_number(self, mailing_id, trace_code, **post): check_res = self._check_trace(mailing_id, trace_code) if not check_res.get('trace'): - return werkzeug.utils.redirect('/web') + return request.redirect('/web') country_code = request.session.get('geoip', False) and request.session.geoip.get('country_code', False) if request.session.get('geoip') else None # parse and validate number sms_number = post.get('sms_number', '').strip(' ') @@ -102,4 +100,4 @@ class MailingSMSController(http.Controller): country_code=country_code, mailing_trace_id=trace_id ) - return werkzeug.utils.redirect(request.env['link.tracker'].get_url_from_code(code), 301) + return request.redirect(request.env['link.tracker'].get_url_from_code(code), code=301, local=False) diff --git a/addons/microsoft_account/controllers/main.py b/addons/microsoft_account/controllers/main.py index 5256f82dca7..63aa82bf937 100644 --- a/addons/microsoft_account/controllers/main.py +++ b/addons/microsoft_account/controllers/main.py @@ -2,9 +2,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import json -from werkzeug.utils import redirect -from odoo import http, registry +from odoo import http from odoo.http import request @@ -18,12 +17,11 @@ class MicrosoftAuth(http.Controller): service = state.get('s') url_return = state.get('f') - with registry(dbname).cursor() as cr: - if kw.get('code'): - access_token, refresh_token, ttl = request.env['microsoft.service']._get_microsoft_tokens(kw['code'], service) - request.env.user._set_microsoft_auth_tokens(access_token, refresh_token, ttl) - return redirect(url_return) - elif kw.get('error'): - return redirect("%s%s%s" % (url_return, "?error=", kw['error'])) - else: - return redirect("%s%s" % (url_return, "?error=Unknown_error")) + if kw.get('code'): + access_token, refresh_token, ttl = request.env['microsoft.service']._get_microsoft_tokens(kw['code'], service) + request.env.user._set_microsoft_auth_tokens(access_token, refresh_token, ttl) + return request.redirect(url_return) + elif kw.get('error'): + return request.redirect("%s%s%s" % (url_return, "?error=", kw['error'])) + else: + return request.redirect("%s%s" % (url_return, "?error=Unknown_error")) diff --git a/addons/payment_adyen/controllers/main.py b/addons/payment_adyen/controllers/main.py index 99202d0e795..205a58cf25f 100644 --- a/addons/payment_adyen/controllers/main.py +++ b/addons/payment_adyen/controllers/main.py @@ -234,7 +234,7 @@ class AdyenController(http.Controller): ) # Redirect the user to the status page - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route('/payment/adyen/notification', type='json', auth='public') def adyen_notification(self): diff --git a/addons/payment_alipay/controllers/main.py b/addons/payment_alipay/controllers/main.py index bac1c3c7422..8bf61970783 100644 --- a/addons/payment_alipay/controllers/main.py +++ b/addons/payment_alipay/controllers/main.py @@ -4,7 +4,6 @@ import logging import pprint import requests -import werkzeug from odoo import _, http from odoo.exceptions import ValidationError @@ -22,7 +21,7 @@ class AlipayController(http.Controller): """ Alipay return """ _logger.info("received Alipay return data:\n%s", pprint.pformat(data)) request.env['payment.transaction'].sudo()._handle_feedback_data('alipay', data) - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route(_notify_url, type='http', auth='public', methods=['POST'], csrf=False) def alipay_notify(self, **post): diff --git a/addons/payment_buckaroo/controllers/main.py b/addons/payment_buckaroo/controllers/main.py index 4c845fdc607..e7074267b59 100644 --- a/addons/payment_buckaroo/controllers/main.py +++ b/addons/payment_buckaroo/controllers/main.py @@ -3,8 +3,6 @@ import logging import pprint -import werkzeug - from odoo import http from odoo.http import request @@ -22,4 +20,4 @@ class BuckarooController(http.Controller): """ _logger.info("received notification data:\n%s", pprint.pformat(data)) request.env['payment.transaction'].sudo()._handle_feedback_data('buckaroo', data) - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') diff --git a/addons/payment_ogone/controllers/main.py b/addons/payment_ogone/controllers/main.py index 1b5986a7fca..11cc2a60a0c 100644 --- a/addons/payment_ogone/controllers/main.py +++ b/addons/payment_ogone/controllers/main.py @@ -95,7 +95,7 @@ class OgoneController(http.Controller): else: if tx_sudo.state in ('cancel', 'error'): tx_sudo.token_id.active = False # The initial payment failed, archive the token - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route( [_directlink_return_url] + _backward_compatibility_urls, type='http', auth='public', @@ -124,7 +124,7 @@ class OgoneController(http.Controller): tx_sudo = request.env['payment.transaction'].sudo()._handle_feedback_data('ogone', data) if tx_sudo.state in ('cancel', 'error'): tx_sudo.token_id.active = False # The initial payment failed, archive the token - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') def _homogenize_data(self, data): """ Format keys to follow an homogenized convention inspired by Ogone Directlink API. diff --git a/addons/payment_paypal/controllers/main.py b/addons/payment_paypal/controllers/main.py index a9b6a86d51b..3da8c937e58 100644 --- a/addons/payment_paypal/controllers/main.py +++ b/addons/payment_paypal/controllers/main.py @@ -4,7 +4,6 @@ import logging import pprint import requests -import werkzeug from odoo import _, http from odoo.exceptions import ValidationError @@ -34,7 +33,7 @@ class PaypalController(http.Controller): request.env['payment.transaction'].sudo()._handle_feedback_data('paypal', data) else: pass # The customer has cancelled the payment, don't do anything - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route(_notify_url, type='http', auth='public', methods=['GET', 'POST'], csrf=False) def paypal_ipn(self, **data): diff --git a/addons/payment_payulatam/controllers/main.py b/addons/payment_payulatam/controllers/main.py index 4e2dff4c0be..97dd63a35fd 100644 --- a/addons/payment_payulatam/controllers/main.py +++ b/addons/payment_payulatam/controllers/main.py @@ -3,8 +3,6 @@ import logging import pprint -import werkzeug - from odoo import http from odoo.http import request @@ -18,4 +16,4 @@ class PayuLatamController(http.Controller): def payulatam_return(self, **data): _logger.info("entering _handle_feedback_data with data:\n%s", pprint.pformat(data)) request.env['payment.transaction'].sudo()._handle_feedback_data('payulatam', data) - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') diff --git a/addons/payment_payumoney/controllers/main.py b/addons/payment_payumoney/controllers/main.py index 7d7d8ec6c8c..021948c6f9c 100644 --- a/addons/payment_payumoney/controllers/main.py +++ b/addons/payment_payumoney/controllers/main.py @@ -3,8 +3,6 @@ import logging import pprint -import werkzeug - from odoo import http from odoo.http import request @@ -18,4 +16,4 @@ class PayUMoneyController(http.Controller): def payumoney_return(self, **data): _logger.info("entering handle_feedback_data with data:\n%s", pprint.pformat(data)) request.env['payment.transaction'].sudo()._handle_feedback_data('payumoney', data) - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') diff --git a/addons/payment_sips/controllers/main.py b/addons/payment_sips/controllers/main.py index 4784717b5ae..a54ee56bf47 100644 --- a/addons/payment_sips/controllers/main.py +++ b/addons/payment_sips/controllers/main.py @@ -4,8 +4,6 @@ import logging import pprint -import werkzeug - from odoo import http from odoo.exceptions import ValidationError from odoo.http import request @@ -32,7 +30,7 @@ class SipsController(http.Controller): request.env['payment.transaction'].sudo()._handle_feedback_data('sips', post) except ValidationError: pass - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route(_notify_url, type='http', auth='public', methods=['POST'], csrf=False) def sips_ipn(self, **post): diff --git a/addons/payment_stripe/controllers/main.py b/addons/payment_stripe/controllers/main.py index 6c1b404b91f..8afed1e19bc 100644 --- a/addons/payment_stripe/controllers/main.py +++ b/addons/payment_stripe/controllers/main.py @@ -45,7 +45,7 @@ class StripeController(http.Controller): request.env['payment.transaction'].sudo()._handle_feedback_data('stripe', data) # Redirect the user to the status page - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route(_validation_return_url, type='http', auth='public', csrf=False) def stripe_return_from_validation(self, **data): @@ -71,7 +71,7 @@ class StripeController(http.Controller): request.env['payment.transaction'].sudo()._handle_feedback_data('stripe', data) # Redirect the user to the status page - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') @http.route('/payment/stripe/webhook', type='json', auth='public') def stripe_webhook(self): diff --git a/addons/payment_transfer/controllers/main.py b/addons/payment_transfer/controllers/main.py index 175d24793ab..01c4c5d270d 100644 --- a/addons/payment_transfer/controllers/main.py +++ b/addons/payment_transfer/controllers/main.py @@ -3,8 +3,6 @@ import logging import pprint -import werkzeug - from odoo import http from odoo.http import request @@ -18,4 +16,4 @@ class TransferController(http.Controller): def transfer_form_feedback(self, **post): _logger.info("beginning _handle_feedback_data with post data %s", pprint.pformat(post)) request.env['payment.transaction'].sudo()._handle_feedback_data('transfer', post) - return werkzeug.utils.redirect('/payment/status') + return request.redirect('/payment/status') diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py index 2a4716096db..7d8d692a792 100644 --- a/addons/point_of_sale/controllers/main.py +++ b/addons/point_of_sale/controllers/main.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import json import logging -import werkzeug.utils from odoo import http from odoo.http import request @@ -49,7 +48,7 @@ class PosController(http.Controller): pos_session = request.env['pos.session'].sudo().search(domain, limit=1) if not pos_session: - return werkzeug.utils.redirect('/web#action=point_of_sale.action_client_pos_menu') + return request.redirect('/web#action=point_of_sale.action_client_pos_menu') # The POS only work in one company, so we enforce the one of the session in the context session_info = request.env['ir.http'].session_info() session_info['user_context']['allowed_company_ids'] = pos_session.company_id.ids diff --git a/addons/portal/controllers/mail.py b/addons/portal/controllers/mail.py index 619f75723cf..347d761a08a 100644 --- a/addons/portal/controllers/mail.py +++ b/addons/portal/controllers/mail.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import werkzeug from werkzeug import urls from werkzeug.exceptions import NotFound, Forbidden @@ -241,5 +240,5 @@ class MailController(main.MailController): url_params = url.decode_query() url_params.update([("pid", pid), ("hash", hash)]) url = url.replace(query=urls.url_encode(url_params)).to_url() - return werkzeug.utils.redirect(url) + return request.redirect(url) return super(MailController, cls)._redirect_to_record(model, res_id, access_token=access_token) diff --git a/addons/portal/controllers/web.py b/addons/portal/controllers/web.py index a0b61f11b7f..147992685b6 100644 --- a/addons/portal/controllers/web.py +++ b/addons/portal/controllers/web.py @@ -11,7 +11,7 @@ class Home(main.Home): @http.route() def index(self, *args, **kw): if request.session.uid and not request.env['res.users'].sudo().browse(request.session.uid).has_group('base.group_user'): - return http.local_redirect('/my', query=request.params, keep_hash=True) + return request.redirect_query('/my', query=request.params) return super(Home, self).index(*args, **kw) def _login_redirect(self, uid, redirect=None): @@ -22,5 +22,5 @@ class Home(main.Home): @http.route('/web', type='http', auth="none") def web_client(self, s_action=None, **kw): if request.session.uid and not request.env['res.users'].sudo().browse(request.session.uid).has_group('base.group_user'): - return http.local_redirect('/my', query=request.params, keep_hash=True) + return request.redirect_query('/my', query=request.params) return super(Home, self).web_client(s_action, **kw) diff --git a/addons/sale/tests/test_access_rights.py b/addons/sale/tests/test_access_rights.py index c6e52970086..13d6b4aee84 100644 --- a/addons/sale/tests/test_access_rights.py +++ b/addons/sale/tests/test_access_rights.py @@ -141,7 +141,7 @@ class TestAccessRightsControllers(HttpCase): url='/my/orders/%s?report_type=pdf' % portal_so.id, allow_redirects=False, ) - self.assertEqual(req.status_code, 302) + self.assertEqual(req.status_code, 303) # or with a random token req = self.url_open( @@ -151,7 +151,7 @@ class TestAccessRightsControllers(HttpCase): ), allow_redirects=False, ) - self.assertEqual(req.status_code, 302) + self.assertEqual(req.status_code, 303) # but works fine with the right token req = self.url_open( @@ -177,4 +177,4 @@ class TestAccessRightsControllers(HttpCase): url='/my/orders/%s?report_type=pdf' % private_so.id, allow_redirects=False, ) - self.assertEqual(req.status_code, 302) + self.assertEqual(req.status_code, 303) diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 442d6275079..21ca100b7d4 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -141,7 +141,7 @@ class Survey(http.Controller): elif error_key == 'answer_deadline' and answer_sudo.access_token: return request.render("survey.survey_closed_expired", {'survey': survey_sudo}) - return werkzeug.utils.redirect("/") + return request.redirect("/") # ------------------------------------------------------------ # TEST / RETRY SURVEY ROUTES @@ -155,7 +155,7 @@ class Survey(http.Controller): try: answer_sudo = survey_sudo._create_answer(user=request.env.user, test_entry=True) except: - return werkzeug.utils.redirect('/') + return request.redirect('/') return request.redirect('/survey/start/%s?%s' % (survey_sudo.access_token, keep_query('*', answer_token=answer_sudo.access_token))) @http.route('/survey/retry//', type='http', auth='public', website=True) @@ -169,7 +169,7 @@ class Survey(http.Controller): survey_sudo, answer_sudo = access_data['survey_sudo'], access_data['answer_sudo'] if not answer_sudo: # attempts to 'retry' without having tried first - return werkzeug.utils.redirect("/") + return request.redirect("/") try: retry_answer_sudo = survey_sudo._create_answer( @@ -181,7 +181,7 @@ class Survey(http.Controller): **self._prepare_retry_additional_values(answer_sudo) ) except: - return werkzeug.utils.redirect("/") + return request.redirect("/") return request.redirect('/survey/start/%s?%s' % (survey_sudo.access_token, keep_query('*', answer_token=retry_answer_sudo.access_token))) def _prepare_retry_additional_values(self, answer): @@ -227,7 +227,7 @@ class Survey(http.Controller): survey_sudo.with_user(request.env.user).check_access_rights('read') survey_sudo.with_user(request.env.user).check_access_rule('read') except: - return werkzeug.utils.redirect("/") + return request.redirect("/") else: return request.render("survey.survey_403_page", {'survey': survey_sudo}) @@ -598,7 +598,7 @@ class Survey(http.Controller): if not survey: # no certification found - return werkzeug.utils.redirect("/") + return request.redirect("/") succeeded_attempt = request.env['survey.user_input'].sudo().search([ ('partner_id', '=', request.env.user.partner_id.id), diff --git a/addons/survey/controllers/survey_session_manage.py b/addons/survey/controllers/survey_session_manage.py index b058662dd5f..c3fa1facbf3 100644 --- a/addons/survey/controllers/survey_session_manage.py +++ b/addons/survey/controllers/survey_session_manage.py @@ -3,7 +3,6 @@ import datetime import json -import werkzeug from dateutil.relativedelta import relativedelta from werkzeug.exceptions import NotFound @@ -177,9 +176,9 @@ class UserInputSession(http.Controller): survey = self._fetch_from_session_code(session_code) if survey and survey.session_state in ['ready', 'in_progress']: - return werkzeug.utils.redirect("/survey/start/%s" % survey.access_token) + return request.redirect("/survey/start/%s" % survey.access_token) - return werkzeug.utils.redirect("/s") + return request.redirect("/s") @http.route('/survey/check_session_code/', type='json', auth='public', website=True) def survey_check_session_code(self, session_code): diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index bbc19b7b226..8c153e2f50d 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -118,17 +118,9 @@ def serialize_exception(f): return werkzeug.exceptions.InternalServerError(json.dumps(error)) return wrap -def redirect_with_hash(*args, **kw): - """ - .. deprecated:: 8.0 - - Use the ``http.redirect_with_hash()`` function instead. - """ - return http.redirect_with_hash(*args, **kw) - def abort_and_redirect(url): r = request.httprequest - response = werkzeug.utils.redirect(url, 302) + response = request.redirect(url, 302) response = r.app.get_response(r, response, explicit_session=False) werkzeug.exceptions.abort(response) @@ -173,7 +165,7 @@ def ensure_db(redirect='/web/database/selector'): # if no db can be found til here, send to the database selector # the database selector will redirect to database manager if needed if not db: - werkzeug.exceptions.abort(werkzeug.utils.redirect(redirect, 303)) + werkzeug.exceptions.abort(request.redirect(redirect, 303)) # always switch the session to the computed db if db != request.session.db: @@ -245,7 +237,7 @@ def login_and_redirect(db, login, key, redirect_url='/web'): return set_cookie_and_redirect(redirect_url) def set_cookie_and_redirect(redirect_url): - redirect = werkzeug.utils.redirect(redirect_url, 303) + redirect = request.redirect(redirect_url, 303) redirect.autocorrect_location_header = False return redirect @@ -818,16 +810,16 @@ class Home(http.Controller): @http.route('/', type='http', auth="none") def index(self, s_action=None, db=None, **kw): - return http.local_redirect('/web', query=request.params, keep_hash=True) + return request.redirect_query('/web', query=request.params) # ideally, this route should be `auth="user"` but that don't work in non-monodb mode. @http.route('/web', type='http', auth="none") def web_client(self, s_action=None, **kw): ensure_db() if not request.session.uid: - return werkzeug.utils.redirect('/web/login', 303) + return request.redirect('/web/login', 303) if kw.get('redirect'): - return werkzeug.utils.redirect(kw.get('redirect'), 303) + return request.redirect(kw.get('redirect'), 303) request.uid = request.session.uid try: @@ -836,7 +828,7 @@ class Home(http.Controller): response.headers['X-Frame-Options'] = 'DENY' return response except AccessError: - return werkzeug.utils.redirect('/web/login?error=access') + return request.redirect('/web/login?error=access') @http.route('/web/webclient/load_menus/', type='http', auth='user', methods=['GET']) def web_load_menus(self, unique): @@ -863,7 +855,7 @@ class Home(http.Controller): ensure_db() request.params['login_success'] = False if request.httprequest.method == 'GET' and redirect and request.session.uid: - return http.redirect_with_hash(redirect) + return request.redirect(redirect) if not request.uid: request.uid = odoo.SUPERUSER_ID @@ -879,7 +871,7 @@ class Home(http.Controller): try: uid = request.session.authenticate(request.session.db, request.params['login'], request.params['password']) request.params['login_success'] = True - return http.redirect_with_hash(self._login_redirect(uid, redirect=redirect)) + return request.redirect(self._login_redirect(uid, redirect=redirect)) except odoo.exceptions.AccessDenied as e: request.uid = old_uid if e.args == odoo.exceptions.AccessDenied().args: @@ -909,7 +901,7 @@ class Home(http.Controller): request.env['res.users'].clear_caches() request.session.session_token = security.compute_session_token(request.session, request.env) - return http.local_redirect(self._login_redirect(uid), keep_hash=True) + return request.redirect(self._login_redirect(uid)) class WebClient(http.Controller): @@ -1088,7 +1080,7 @@ class Database(http.Controller): country_code = post.get('country_code') or False dispatch_rpc('db', 'create_database', [master_pwd, name, bool(post.get('demo')), lang, password, post['login'], country_code, post['phone']]) request.session.authenticate(name, post['login'], password) - return http.local_redirect('/web/') + return request.redirect('/web') except Exception as e: error = "Database creation error: %s" % (str(e) or repr(e)) return self._render_template(error=error) @@ -1103,7 +1095,7 @@ class Database(http.Controller): raise Exception(_('Invalid database name. Only alphanumerical characters, underscore, hyphen and dot are allowed.')) dispatch_rpc('db', 'duplicate_database', [master_pwd, name, new_name]) request._cr = None # duplicating a database leads to an unusable cursor - return http.local_redirect('/web/database/manager') + return request.redirect('/web/database/manager') except Exception as e: error = "Database duplication error: %s" % (str(e) or repr(e)) return self._render_template(error=error) @@ -1116,7 +1108,7 @@ class Database(http.Controller): try: dispatch_rpc('db','drop', [master_pwd, name]) request._cr = None # dropping a database leads to an unusable cursor - return http.local_redirect('/web/database/manager') + return request.redirect('/web/database/manager') except Exception as e: error = "Database deletion error: %s" % (str(e) or repr(e)) return self._render_template(error=error) @@ -1153,7 +1145,7 @@ class Database(http.Controller): with tempfile.NamedTemporaryFile(delete=False) as data_file: backup_file.save(data_file) db.restore_db(name, data_file.name, str2bool(copy)) - return http.local_redirect('/web/database/manager') + return request.redirect('/web/database/manager') except Exception as e: error = "Database restore error: %s" % (str(e) or repr(e)) return self._render_template(error=error) @@ -1165,7 +1157,7 @@ class Database(http.Controller): def change_password(self, master_pwd, master_pwd_new): try: dispatch_rpc('db', 'change_admin_password', [master_pwd, master_pwd_new]) - return http.local_redirect('/web/database/manager') + return request.redirect('/web/database/manager') except Exception as e: error = "Master password update error: %s" % (str(e) or repr(e)) return self._render_template(error=error) @@ -1276,7 +1268,7 @@ class Session(http.Controller): @http.route('/web/session/logout', type='http', auth="none") def logout(self, redirect='/web'): request.session.logout(keep_db=True) - return werkzeug.utils.redirect(redirect, 303) + return request.redirect(redirect, 303) class DataSet(http.Controller): diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 453ee936b84..1607253d126 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -91,9 +91,6 @@ class Website(Home): session, AFTER landing on that website domain (if set) as this will be a different session. """ - parse = werkzeug.urls.url_parse - safe_path = parse(path).path - if not (request.env.user.has_group('website.group_multi_website') and request.env.user.has_group('website.group_website_publisher')): # The user might not be logged in on the forced website, so he won't @@ -103,19 +100,19 @@ class Website(Home): # Website 1 : 127.0.0.1 (admin) # Website 2 : 127.0.0.2 (not logged in) # Click on "Website 2" from Website 1 - return request.redirect(safe_path) + return request.redirect(path) website = request.env['website'].browse(website_id) if not isredir and website.domain: domain_from = request.httprequest.environ.get('HTTP_HOST', '') - domain_to = parse(website._get_http_domain()).netloc + domain_to = werkzeug.urls.url_parse(website._get_http_domain()).netloc if domain_from != domain_to: # redirect to correct domain for a correct routing map - url_to = werkzeug.urls.url_join(website._get_http_domain(), '/website/force/%s?isredir=1&path=%s' % (website.id, safe_path)) + url_to = werkzeug.urls.url_join(website._get_http_domain(), '/website/force/%s?isredir=1&path=%s' % (website.id, path)) return request.redirect(url_to) website._force() - return request.redirect(safe_path) + return request.redirect(path) # ------------------------------------------------------ # Login - overwrite of the web login so that regular users are redirected to the backend @@ -265,7 +262,7 @@ class Website(Home): url = getattr(request.website, 'social_%s' % social, False) if not url: raise werkzeug.exceptions.NotFound() - return request.redirect(url) + return request.redirect(url, local=False) @http.route('/website/get_suggested_links', type='json', auth="user", website=True) def get_suggested_link(self, needle, limit=10): diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py index 5e426fc7bcf..89f5288f42f 100644 --- a/addons/website/models/ir_http.py +++ b/addons/website/models/ir_http.py @@ -145,12 +145,12 @@ class Http(models.AbstractModel): return False template = False - if hasattr(response, 'qcontext'): # classic response + if hasattr(response, '_cached_page'): + website_page, template = response._cached_page, response._cached_template + elif hasattr(response, 'qcontext'): # classic response main_object = response.qcontext.get('main_object') website_page = getattr(main_object, '_name', False) == 'website.page' and main_object template = response.qcontext.get('response_template') - elif hasattr(response, '_cached_page'): - website_page, template = response._cached_page, response._cached_template view = template and request.env['website'].get_template(template) if view and view.track: @@ -276,7 +276,7 @@ class Http(models.AbstractModel): path = '/' + request.lang.url_code + path if request.httprequest.query_string: path += '?' + request.httprequest.query_string.decode('utf-8') - return werkzeug.utils.redirect(path, code=301) + return request.redirect(path, code=301) if page: # prefetch all menus (it will prefetch website.page too) @@ -297,7 +297,7 @@ class Http(models.AbstractModel): try: r = page._get_cache_response(cache_key) if r['time'] + page.cache_time > time.time(): - response = werkzeug.Response(r['content'], mimetype=r['contenttype']) + response = odoo.http.Response(r['content'], mimetype=r['contenttype']) response._cached_template = r['template'] response._cached_page = page return response diff --git a/addons/website/tests/test_crawl.py b/addons/website/tests/test_crawl.py index d210fd9b8f3..6ade1e761e3 100644 --- a/addons/website/tests/test_crawl.py +++ b/addons/website/tests/test_crawl.py @@ -54,7 +54,7 @@ class Crawler(HttpCaseWithUserDemo): _logger.info("%s %s", msg, url) r = self.url_open(url, allow_redirects=False) - if r.status_code in (301, 302): + if r.status_code in (301, 302, 303): # check local redirect to avoid fetch externals pages new_url = r.headers.get('Location') current_url = r.url diff --git a/addons/website/tools.py b/addons/website/tools.py index 6930f8a5e68..924df41d2e0 100644 --- a/addons/website/tools.py +++ b/addons/website/tools.py @@ -97,7 +97,7 @@ def MockRequest( referrer='', ), lang=env['res.lang']._lang_get(lang_code), - redirect=werkzeug.utils.redirect, + redirect=env['ir.http']._redirect, session=DotDict( geoip={'country_code': country_code}, debug=False, diff --git a/addons/website_blog/controllers/main.py b/addons/website_blog/controllers/main.py index 52cddb8b0ad..c2ff466f45f 100644 --- a/addons/website_blog/controllers/main.py +++ b/addons/website_blog/controllers/main.py @@ -161,7 +161,7 @@ class WebsiteBlog(http.Controller): blogs = Blog.search(request.website.website_domain(), order="create_date asc, id asc") if not blog and len(blogs) == 1: - return werkzeug.utils.redirect('/blog/%s' % slug(blogs[0]), code=302) + return request.redirect('/blog/%s' % slug(blogs[0]), code=302) date_begin, date_end, state = opt.get('date_begin'), opt.get('date_end'), opt.get('state') @@ -289,7 +289,7 @@ class WebsiteBlog(http.Controller): 'blog_id': blog_id, 'is_published': False, }) - return werkzeug.utils.redirect("/blog/%s/%s?enable_editor=1" % (slug(new_blog_post.blog_id), slug(new_blog_post))) + return request.redirect("/blog/%s/%s?enable_editor=1" % (slug(new_blog_post.blog_id), slug(new_blog_post))) @http.route('/blog/post_duplicate', type='http', auth="user", website=True, methods=['POST']) def blog_post_copy(self, blog_post_id, **post): @@ -300,4 +300,4 @@ class WebsiteBlog(http.Controller): :return redirect to the new blog created """ new_blog_post = request.env['blog.post'].with_context(mail_create_nosubscribe=True).browse(int(blog_post_id)).copy() - return werkzeug.utils.redirect("/blog/%s/%s?enable_editor=1" % (slug(new_blog_post.blog_id), slug(new_blog_post))) + return request.redirect("/blog/%s/%s?enable_editor=1" % (slug(new_blog_post.blog_id), slug(new_blog_post))) diff --git a/addons/website_event_meet/controllers/community.py b/addons/website_event_meet/controllers/community.py index e3796bdabb8..b194f1dda3b 100644 --- a/addons/website_event_meet/controllers/community.py +++ b/addons/website_event_meet/controllers/community.py @@ -3,7 +3,6 @@ import logging from werkzeug.exceptions import Forbidden, NotFound -from werkzeug.utils import redirect from odoo import exceptions, http from odoo.http import request @@ -103,7 +102,7 @@ class WebsiteEventMeetController(EventCommunityController): }) _logger.info("New meeting room (%s) created by %s (uid %s)" % (name, request.httprequest.remote_addr, request.env.uid)) - return redirect(f"/event/{slug(event)}/meeting_room/{slug(meeting_room)}") + return request.redirect(f"/event/{slug(event)}/meeting_room/{slug(meeting_room)}") @http.route(["/event/active_langs"], type="json", auth="public") def active_langs(self): diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index 27dc9956e0d..ef9ea47f611 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -46,7 +46,7 @@ class WebsiteForum(WebsiteProfile): domain = request.website.website_domain() forums = request.env['forum.forum'].search(domain) if len(forums) == 1: - return werkzeug.utils.redirect('/forum/%s' % slug(forums[0]), code=302) + return request.redirect('/forum/%s' % slug(forums[0]), code=302) return request.render("website_forum.forum_all", { 'forums': forums @@ -245,7 +245,7 @@ class WebsiteForum(WebsiteProfile): if question.parent_id: redirect_url = "/forum/%s/%s" % (slug(forum), slug(question.parent_id)) - return werkzeug.utils.redirect(redirect_url, 301) + return request.redirect(redirect_url, 301) filters = 'question' values = self._prepare_user_values(forum=forum, searches=post) values.update({ @@ -295,27 +295,27 @@ class WebsiteForum(WebsiteProfile): if record.create_uid.id == request.uid: answer = record break - return werkzeug.utils.redirect("/forum/%s/post/%s/edit" % (slug(forum), slug(answer))) + return request.redirect("/forum/%s/post/%s/edit" % (slug(forum), slug(answer))) @http.route('/forum//question//close', type='http', auth="user", methods=['POST'], website=True) def question_close(self, forum, question, **post): question.close(reason_id=int(post.get('reason_id', False))) - return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/question/%s" % (slug(forum), slug(question))) @http.route('/forum//question//reopen', type='http', auth="user", methods=['POST'], website=True) def question_reopen(self, forum, question, **kwarg): question.reopen() - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) @http.route('/forum//question//delete', type='http', auth="user", methods=['POST'], website=True) def question_delete(self, forum, question, **kwarg): question.active = False - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) @http.route('/forum//question//undelete', type='http', auth="user", methods=['POST'], website=True) def question_undelete(self, forum, question, **kwarg): question.active = True - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) # Post # -------------------------------------------------- @@ -323,7 +323,7 @@ class WebsiteForum(WebsiteProfile): def forum_post(self, forum, **post): user = request.env.user if not user.email or not tools.single_email_re.match(user.email): - return werkzeug.utils.redirect("/forum/%s/user/%s/edit?email_required=1" % (slug(forum), request.session.uid)) + return request.redirect("/forum/%s/user/%s/edit?email_required=1" % (slug(forum), request.session.uid)) values = self._prepare_user_values(forum=forum, searches={}, header={'ask_hide': True}, new_question=True) return request.render("website_forum.new_question", values) @@ -340,7 +340,7 @@ class WebsiteForum(WebsiteProfile): post_tag_ids = forum._tag_to_write_vals(post.get('post_tags', '')) if request.env.user.forum_waiting_posts_count: - return werkzeug.utils.redirect("/forum/%s/ask" % slug(forum)) + return request.redirect("/forum/%s/ask" % slug(forum)) new_question = request.env['forum.post'].create({ 'forum_id': forum.id, @@ -349,7 +349,7 @@ class WebsiteForum(WebsiteProfile): 'parent_id': post_parent and post_parent.id or False, 'tag_ids': post_tag_ids }) - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), post_parent and slug(post_parent) or new_question.id)) + return request.redirect("/forum/%s/%s" % (slug(forum), post_parent and slug(post_parent) or new_question.id)) @http.route('/forum//post//comment', type='http', auth="user", methods=['POST'], website=True) def post_comment(self, forum, post, **kwargs): @@ -361,7 +361,7 @@ class WebsiteForum(WebsiteProfile): body=body, message_type='comment', subtype_xmlid='mail.mt_comment') - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) @http.route('/forum//post//toggle_correct', type='json', auth="public", website=True) def post_toggle_correct(self, forum, post, **kwargs): @@ -380,8 +380,8 @@ class WebsiteForum(WebsiteProfile): question = post.parent_id post.unlink() if question: - werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) - return werkzeug.utils.redirect("/forum/%s" % slug(forum)) + request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s" % slug(forum)) @http.route('/forum//post//edit', type='http', auth="user", website=True) def post_edit(self, forum, post, **kwargs): @@ -415,7 +415,7 @@ class WebsiteForum(WebsiteProfile): vals['tag_ids'] = forum._tag_to_write_vals(kwargs.get('post_tags', '')) post.write(vals) question = post.parent_id if post.parent_id else post - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) # JSON utilities # -------------------------------------------------- @@ -513,7 +513,7 @@ class WebsiteForum(WebsiteProfile): elif post.state == 'offensive': url = "/forum/%s/offensive_posts" % (slug(forum)) post.validate() - return werkzeug.utils.redirect(url) + return request.redirect(url) @http.route('/forum//post//refuse', type='http', auth="user", website=True) def post_refuse(self, forum, post, **kwargs): @@ -547,7 +547,7 @@ class WebsiteForum(WebsiteProfile): url = "/forum/%s/%s/#answer-%s" % (slug(forum), post.parent_id.id, post.id) else: url = "/forum/%s/%s" % (slug(forum), slug(post)) - return werkzeug.utils.redirect(url) + return request.redirect(url) # User # -------------------------------------------------- @@ -556,15 +556,15 @@ class WebsiteForum(WebsiteProfile): if partner_id: partner = request.env['res.partner'].sudo().search([('id', '=', partner_id)]) if partner and partner.user_ids: - return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), partner.user_ids[0].id)) - return werkzeug.utils.redirect("/forum/%s" % slug(forum)) + return request.redirect("/forum/%s/user/%d" % (slug(forum), partner.user_ids[0].id)) + return request.redirect("/forum/%s" % slug(forum)) # Profile # ----------------------------------- @http.route(['/forum//user/'], type='http', auth="public", website=True) def view_user_forum_profile(self, forum, user_id, forum_origin, **post): - return werkzeug.utils.redirect('/profile/user/' + str(user_id) + '?forum_id=' + str(forum.id) + '&forum_origin=' + str(forum_origin)) + return request.redirect('/profile/user/' + str(user_id) + '?forum_id=' + str(forum.id) + '&forum_origin=' + str(forum_origin)) def _prepare_user_profile_values(self, user, **post): values = super(WebsiteForum, self)._prepare_user_profile_values(user, **post) @@ -684,17 +684,17 @@ class WebsiteForum(WebsiteProfile): def convert_comment_to_answer(self, forum, post, comment, **kwarg): post = request.env['forum.post'].convert_comment_to_answer(comment.id) if not post: - return werkzeug.utils.redirect("/forum/%s" % slug(forum)) + return request.redirect("/forum/%s" % slug(forum)) question = post.parent_id if post.parent_id else post - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) @http.route('/forum//post//convert_to_comment', type='http', auth="user", methods=['POST'], website=True) def convert_answer_to_comment(self, forum, post, **kwarg): question = post.parent_id new_msg = post.convert_answer_to_comment() if not new_msg: - return werkzeug.utils.redirect("/forum/%s" % slug(forum)) - return werkzeug.utils.redirect("/forum/%s/%s" % (slug(forum), slug(question))) + return request.redirect("/forum/%s" % slug(forum)) + return request.redirect("/forum/%s/%s" % (slug(forum), slug(question))) @http.route('/forum//post//comment//delete', type='json', auth="user", website=True) def delete_comment(self, forum, post, comment, **kwarg): diff --git a/addons/website_links/controller/main.py b/addons/website_links/controller/main.py index 60f6ab2e8e8..40615265d6e 100644 --- a/addons/website_links/controller/main.py +++ b/addons/website_links/controller/main.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import werkzeug - from odoo import http from odoo.http import request @@ -38,4 +36,4 @@ class WebsiteUrl(http.Controller): if code: return request.render("website_links.graphs", code.link_id.read()[0]) else: - return werkzeug.utils.redirect('/', 301) + return request.redirect('/', code=301) diff --git a/addons/website_profile/controllers/main.py b/addons/website_profile/controllers/main.py index 9a1dc3ec312..aab723efdaa 100644 --- a/addons/website_profile/controllers/main.py +++ b/addons/website_profile/controllers/main.py @@ -166,9 +166,9 @@ class WebsiteProfile(http.Controller): whitelisted_values = {key: values[key] for key in user.SELF_WRITEABLE_FIELDS if key in values} user.write(whitelisted_values) if kwargs.get('url_param'): - return werkzeug.utils.redirect("/profile/user/%d?%s" % (user.id, kwargs['url_param'])) + return request.redirect("/profile/user/%d?%s" % (user.id, kwargs['url_param'])) else: - return werkzeug.utils.redirect("/profile/user/%d" % user.id) + return request.redirect("/profile/user/%d" % user.id) # Ranks and Badges # --------------------------------------------------- diff --git a/addons/website_sale_digital/controllers/main.py b/addons/website_sale_digital/controllers/main.py index 264de50c99e..d620dbcfc96 100644 --- a/addons/website_sale_digital/controllers/main.py +++ b/addons/website_sale_digital/controllers/main.py @@ -5,7 +5,6 @@ import base64 import io import os import mimetypes -from werkzeug.utils import redirect from odoo import http from odoo.http import request @@ -66,7 +65,7 @@ class WebsiteSaleDigital(CustomerPortal): if attachment: attachment = attachment[0] else: - return redirect(self.orders_page) + return request.redirect(self.orders_page) # Check if the user has bought the associated product res_model = attachment['res_model'] @@ -75,21 +74,21 @@ class WebsiteSaleDigital(CustomerPortal): if res_model == 'product.product': if res_id not in purchased_products: - return redirect(self.orders_page) + return request.redirect(self.orders_page) # Also check for attachments in the product templates elif res_model == 'product.template': template_ids = request.env['product.product'].sudo().browse(purchased_products).mapped('product_tmpl_id').ids if res_id not in template_ids: - return redirect(self.orders_page) + return request.redirect(self.orders_page) else: - return redirect(self.orders_page) + return request.redirect(self.orders_page) # The client has bought the product, otherwise it would have been blocked by now if attachment["type"] == "url": if attachment["url"]: - return redirect(attachment["url"]) + return request.redirect(attachment["url"]) else: return request.not_found() elif attachment["datas"]: diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index 12a712f361a..eeb268d06e9 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -600,7 +600,7 @@ class WebsiteSlides(WebsiteProfile): @http.route('/slides/channel/add', type='http', auth='user', methods=['POST'], website=True) def slide_channel_create(self, *args, **kw): channel = request.env['slide.channel'].create(self._slide_channel_prepare_values(**kw)) - return werkzeug.utils.redirect("/slides/%s" % (slug(channel))) + return request.redirect("/slides/%s" % (slug(channel))) def _slide_channel_prepare_values(self, **kw): # `tag_ids` is a string representing a list of int with coma. i.e.: '2,5,7' @@ -624,7 +624,7 @@ class WebsiteSlides(WebsiteProfile): if not request.website.is_public_user(): channel = request.env['slide.channel'].browse(int(channel_id)) channel.action_add_member() - return werkzeug.utils.redirect("/slides/%s" % (slug(channel))) + return request.redirect("/slides/%s" % (slug(channel))) @http.route(['/slides/channel/join'], type='json', auth='public', website=True) def slide_channel_join(self, channel_id): @@ -795,7 +795,7 @@ class WebsiteSlides(WebsiteProfile): next_slide = None if next_slide_id: next_slide = self._fetch_slide(next_slide_id).get('slide', None) - return werkzeug.utils.redirect("/slides/slide/%s" % (slug(next_slide) if next_slide else slug(slide))) + return request.redirect("/slides/slide/%s" % (slug(next_slide) if next_slide else slug(slide))) @http.route('/slides/slide/set_completed', website=True, type="json", auth="public") def slide_set_completed(self, slide_id): @@ -1041,7 +1041,7 @@ class WebsiteSlides(WebsiteProfile): request.env['slide.slide'].create(self._get_new_slide_category_values(channel, name)) - return werkzeug.utils.redirect("/slides/%s" % (slug(channel))) + return request.redirect("/slides/%s" % (slug(channel))) # -------------------------------------------------- # SLIDE.UPLOAD diff --git a/addons/website_slides_survey/controllers/slides.py b/addons/website_slides_survey/controllers/slides.py index 7653d8c229a..09b1bdafa34 100644 --- a/addons/website_slides_survey/controllers/slides.py +++ b/addons/website_slides_survey/controllers/slides.py @@ -27,7 +27,7 @@ class WebsiteSlidesSurvey(WebsiteSlides): certification_url = slide._generate_certification_url().get(slide.id) if not certification_url: raise werkzeug.exceptions.NotFound() - return werkzeug.utils.redirect(certification_url) + return request.redirect(certification_url) @http.route(['/slides_survey/certification/search_read'], type='json', auth='user', methods=['POST'], website=True) def slides_certification_search_read(self, fields): diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py index 7b3b9b335bc..d1d9b57aa1a 100644 --- a/odoo/addons/base/models/ir_http.py +++ b/odoo/addons/base/models/ir_http.py @@ -14,13 +14,12 @@ import traceback import werkzeug import werkzeug.exceptions import werkzeug.routing -import werkzeug.urls import werkzeug.utils import odoo from odoo import api, http, models, tools, SUPERUSER_ID from odoo.exceptions import AccessDenied, AccessError, MissingError -from odoo.http import request, content_disposition +from odoo.http import request, content_disposition, Response from odoo.tools import consteq, pycompat from odoo.tools.mimetypes import guess_mimetype from odoo.modules.module import get_resource_path, get_module_path @@ -159,7 +158,7 @@ class IrHttp(models.AbstractModel): if (not datas and name != request.httprequest.path and name.startswith(('http://', 'https://', '/'))): - return werkzeug.utils.redirect(name, 301) + return request.redirect(name, 301, local=False) response = werkzeug.wrappers.Response() response.last_modified = wdate @@ -243,6 +242,10 @@ class IrHttp(models.AbstractModel): return result + @classmethod + def _redirect(cls, location, code=303): + return werkzeug.utils.redirect(location, code=code, Response=Response) + @classmethod def _postprocess_args(cls, arguments, rule): """ post process arg to set uid on browse records """ @@ -485,6 +488,6 @@ class IrHttp(models.AbstractModel): if status == 304: return werkzeug.wrappers.Response(status=status, headers=headers) elif status == 301: - return werkzeug.utils.redirect(content, code=301) + return request.redirect(content, code=301, local=False) elif status != 200: return request.not_found() diff --git a/odoo/http.py b/odoo/http.py index b2feb4f909b..d9343819113 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -159,21 +159,6 @@ def dispatch_rpc(service_name, method, params): odoo.tools.debugger.post_mortem(odoo.tools.config, sys.exc_info()) raise -def local_redirect(path, query=None, keep_hash=False, code=303): - # FIXME: drop the `keep_hash` param, now useless - url = path - if not query: - query = {} - if query: - url += '?' + urls.url_encode(query) - return werkzeug.utils.redirect(url, code) - -def redirect_with_hash(url, code=303): - # Section 7.1.2 of RFC 7231 requires preservation of URL fragment through redirects, - # so we don't need any special handling anymore. This function could be dropped in the future. - # seealso : http://www.rfc-editor.org/info/rfc7231 - # https://tools.ietf.org/html/rfc7231#section-7.1.2 - return werkzeug.utils.redirect(url, code) class WebRequest(object): """ Parent class for all Odoo Web request types, mostly deals with @@ -315,6 +300,18 @@ class WebRequest(object): # callers to check & look at) raise exception.with_traceback(None) from new_cause + def redirect(self, location, code=303, local=True): + if local: + location = urls.url_parse(location).replace(scheme='', netloc='').to_url() + if request and request.db: + return request.registry['ir.http']._redirect(location, code) + return werkzeug.utils.redirect(location, code, Response=Response) + + def redirect_query(self, location, query=None, code=303, local=True): + if query: + location += '?' + urls.url_encode(query) + return self.redirect(location, code=code, local=local) + def _is_cors_preflight(self, endpoint): return False @@ -759,7 +756,7 @@ class HttpRequest(WebRequest): query = werkzeug.urls.url_encode({ 'redirect': redirect, }) - return werkzeug.utils.redirect('/web/login?%s' % query) + return request.redirect('/web/login?%s' % query) except werkzeug.exceptions.HTTPException as e: return e