[IMP] website: use custom URL for website in backend

The website architecture has been refactored for the internal users and
admins with [1].
Now, they can access the website in the backend inside the website app.
Long story short, the website will be displayed in an iframe in a client
action. The URL of the browser will be tweaked to reflect the iframe one
instead of the real one (which is something like /web#action=..).

It had a few drawbacks:
- On page refresh (F5 or browser button), the user would land on the
  frontend version of the website instead of remaining in the backend.
- When the user edited the URL (Like removing `/shop` and typing `/jobs`
  instead, he would land on the frontend version too.
- Impossible to directly go to the backend version of the website.

Those are improved with this commit by using a slightly different URL
when we are in the backend. A `/@/` will prefix the iframe URL.

If logged in, the user will land on the backend. If not, it will simply
redirect to the frontend version of the website.

[1]: https://github.com/odoo/odoo/commit/31cc10b91dc7762e23b4bde9b945be0c4ce3fe3b

task-2687506

closes odoo/odoo#94580

Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
Romain Derie
2022-06-30 18:52:01 +02:00
committed by qsm-odoo
parent 2613e663f0
commit 030d3cb10e
3 changed files with 41 additions and 2 deletions
+17
View File
@@ -117,6 +117,23 @@ class Website(Home):
website._force()
return request.redirect(path)
@http.route(['/@/', '/@/<path:path>'], 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
@@ -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;
+21
View File
@@ -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")