diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index b807760f43e..66b99c3d752 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -117,6 +117,23 @@ class Website(Home): website._force() return request.redirect(path) + @http.route(['/@/', '/@/'], type='http', auth='public', website=True, sitemap=False, multilang=False) + def client_action_redirect(self, path='', **kw): + """ Redirect internal users to the backend preview of the requested path + URL (client action iframe). + Non internal users will be redirected to the regular frontend version of + that URL. + """ + path = '/' + path + mode_edit = bool(kw.pop('enable_editor', False)) + if kw: + path += '?' + werkzeug.urls.url_encode(kw) + + if request.env.user._is_internal(): + path = request.website.get_client_action_url(path, mode_edit) + + return request.redirect(path) + # ------------------------------------------------------ # Login - overwrite of the web login so that regular users are redirected to the backend # while portal users are redirected to the frontend by default diff --git a/addons/website/static/src/client_actions/website_preview/website_preview.js b/addons/website/static/src/client_actions/website_preview/website_preview.js index 8336dd7c1bf..f263c75ac38 100644 --- a/addons/website/static/src/client_actions/website_preview/website_preview.js +++ b/addons/website/static/src/client_actions/website_preview/website_preview.js @@ -184,9 +184,10 @@ export class WebsitePreview extends Component { // This replaces the browser url (/web#action=website...) with // the iframe's url (it is clearer for the user). - this.currentUrl = this.iframe.el.contentDocument.location.href; + const currentUrl = new URL(this.iframe.el.contentDocument.location.href); + currentUrl.pathname = `/@${currentUrl.pathname}`; this.currentTitle = this.iframe.el.contentDocument.title; - history.replaceState({}, this.currentTitle, this.currentUrl); + history.replaceState({}, this.currentTitle, currentUrl.href); this.title.setParts({ action: this.currentTitle }); this.websiteService.pageDocument = this.iframe.el.contentDocument; diff --git a/addons/website/tests/test_controllers.py b/addons/website/tests/test_controllers.py index 9bb167fedd5..2b9acdf929a 100644 --- a/addons/website/tests/test_controllers.py +++ b/addons/website/tests/test_controllers.py @@ -3,6 +3,8 @@ import json +from werkzeug.urls import url_encode + from odoo import tests from odoo.tools import mute_logger @@ -44,3 +46,22 @@ class TestControllers(tests.HttpCase): matching_pages = set(map(lambda o: o['value'], suggested_links['matching_pages'])) self.assertEqual(set(last_modified_values), set(last_5_url_edited) - matching_pages) + + def test_02_client_action_iframe_url(self): + base_url = self.base_url() + urls = [ + '/', # Homepage URL (special case) + '/contactus', # Regular website.page URL + '/website/info', # Controller (!!also testing multi slashes URL!!) + '/contactus?name=testing', # Query string URL + ] + for url in urls: + resp = self.url_open(f'/@{url}') + self.assertEqual(resp.url, base_url + url, "Public user should have landed in the frontend") + self.authenticate("admin", "admin") + for url in urls: + resp = self.url_open(f'/@{url}') + backend_params = url_encode(dict(action='website.website_preview', path=url)) + self.assertEqual( + resp.url, f'{base_url}/web#{backend_params}', + "Internal user should have landed in the backend")