Before this commit, if a link to a page was not correct because of a
case mismatch, it would simply land on a 404 page.
While it's correct, as URL are case sensitive, it leads to a few bad UX
flow at the admin/editor level:
- Create a link in your page (on a text or a button eg), type an URL
which does not exists (to create it after) like /Page
- Click on the link/button you just made, you are redirected to /Page
which display a 404 with the "Create page" option (correct)
- When you click on that button, it will actually create a page with
/page URL, leading to a mismatch between the URL you created and the
page URL.
Your link/button will still lead to a 404 URL as it points to /Page.
Since it's just a fallback when an exact URL match is not found, it
should not break anything and should not have bad impact at any level
(seo/speed etc).
Indeed:
- It's done through a 302 redirect
- `_serve_page()` is already a fallback case, so it will only make
the `website.redirect` and 404 cases a bit slower due to the extra
search query.
The only possible scenario seems to be if the user (mind the uppercase):
- Created a /Page page
- Created a redirect from /page to /another-page
In this case, /page won't land on /another-page but on /Page.
This flow seems unlikely and is not actually wrong either way.
At least, it certainly is less important than ensuring a case
insensitive fallback.
Finally, note that another solution would have been to either:
- Force page URL to lower case.
-> This is not stable friendly, people might be relying on this to
create pages with different casing:
`/Batman-VII-The-Dark-Knight-Whatevers`, while not recommended,
doesn't sounds idiot.
On top of not being stable friendly, we probably want to keep
offering this possibility
- Redirect all URLs to lowercase endpoints.
-> This is obviously not stable and not Odoo's jobs. It should be
something decided by the sysadmin and done at nginx (etc) level.
task-3110294
opw-3104030
closesodoo/odoo#111736
X-original-commit: f05491105f93939490cbeb078cb7653c38685644
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
One can very well select a "auth=user route" as homepage for his
website, like /my.
There would then be an issue with such an URL being set as homepage:
- As the user landed in the homepage controller which is auth=public,
the system will add the public user as env user (see
`_auth_method_public()`).
```
@http.route('/', type='http', auth="public", website=True, sitemap=True)
def index(self, **kw):
```
- Then, that controller will reroute to the homepage url (/my). The
request.httprequest.path will now be /my
- Then, that controller will recall the dispatcher stack:
`request._serve_ir_http()`
- From there, this call won't fail as it should because the user is
considered as logged in as it went already through the
`_auth_method_public()`, adding the public user as env.user.
`_auth_method_user()` won't raise its error.
- The /my page will be rendered despite not being logged in.
Once the user land on that page, the system will actually detect him as
logged out on a page supposed to be accessed when logged in.
It will then:
1. Show a toaster to inform the user
2. Auto reload the page
As the current URL is still `/` (due to the reroute and not a redirect),
the same flow will happen again, and again, looping forever.
--------
Note that accessing /my directly won't be an issue, as it won't go
through the homepage controller (which is auth=public), so there won't
be a user_id set on the env (the public user), meaning that the dispatch
layer will reject the access and raise an access error (through
`_auth_method_user()`.
Also note that the same behavior will occur when going through the first
menu fallback mechanism:
- if the user didn't setup any homepage_url
- and deleted his / website.page
- and his first website menu is /my
In that case, it will go through the first menu redirect fallback, which
will be working fine (as it's a redirect and not a reroute).
With both those 2 flows (going through redirect), the user will
correctly land on the login page (which will redirect to /my once logged
in).
------
Finally, the other solution would be to prevent such a configuration
(/my as homepage_url) but it was not easily doable (if doable at all),
see https://github.com/odoo/odoo/pull/99100#discussion_r963055251
------
A test is also added and over the more complexe case (which should cover
everything):
- With /my as homepage_url
- With the / website.page deleted
- With /my as first menu URL
-> Accessing / as public user should:
1. Reroute to /my (because of the homepage_url set to it) which
should fail now thanks to this commit
2. Since the reroute / re-serve failed, it should reach the
"first menu fallback" mechanism, which is also /my
3. That fallback should be a redirect, not a reroute, so the user
should actually land on the login page
4. Once logged in on that page, it should properly redirect to /my
opw-3077339
X-original-commit: 4f5899f769266edc27a0b2d812df092b95f43c71
Part-of: odoo/odoo#107759
Emptying the domain should be setting it to False, not empty string,
which is saved in DB as such.
This was not problematic at all before but since [1] the domain must be
unique. As we removed the "multi website by domain" feature, we then
were able to add that constraint.
But since then, having two website with domain == '' would raise the
constraint error, while null values (False in python) would not.
[1]: https://github.com/odoo/odoo/commit/507db4e179514d171ec82e8ea0cbaf2323a6c30d
runbot-5041
closesodoo/odoo#100430
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Before this commit, only a website.page could be used as a custom
homepage ('custom' meaning other than '/').
But it is a real use case and requirement for our users to be able to
select a controller as homepage.
For instance, an ecommerce would want its homepage to be the shop and
not a regular page from where you then have to navigate to the shop.
Right now, this can (almost) be achieved by doing some technical
advanced operations:
- Move the 'Shop' menu first in the menu navbar of the website
- Delete the specific '/' website.page for the website
- Delete the generic '/' website.page (no website_id)
That way, the system will redirect `/` to `/shop`, which is not ideal as
it should remain `/` in the URL.
That's because, until now, the homepage (`/` controller) serve order
was:
- Serve the website.page set as homepage (`website.homepage_id`),
happens when one did select another page as homepage through the page
properties dialog
- Serve the website.page having `/` as URL (default)
- Serve the first accessible menu if there no `/` page or other page set
as homepage, it acts as a last resort attempt to not serve a 404 and
to try serving relevant content (the first menu of a website is most
likely always better than a 404)
- Serve 404
This commit allows to introduce an URL as homepage, instead of only a
website.page. It can be done through the website settings in the
backend.
There is 2 main points to keep in mind about serving the homepage:
- make sure we don't serve a 404 as the website homepage. This is the
website entry point, serving a 404 is terrible. That's why we have
some fallback mechanism like serving the first menu.
- We need to serve / before fallbacking to the first menu, as a lot of
site just remove the 'Home' first menu since it is a duplicate of the
logo, which also redirect to the homepage. In such cases, it doesn't
mean that the user want his first menu to be the homepage. We
shouldn't rely on such a behavior, it should just be used as a last
resort.
With this commit, the homepage serve order is now:
- If homepage URL is set (empty by default), serve the website.page
matching it
- If homepage URL is set (empty by default), serve the controller
matching it
- If homepage URL is not set, serve the `/` website.page
- Serve the first accessible menu as last resort. It should be relevant
content, at least better than a 404
- Serve 404
Most DBs will just have a website.page with '/' as URL and keep the
homepage_url setting empty.
task-2969683
closesodoo/odoo#99100
Related: odoo/upgrade#3876
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Since [1] the 403 pages displayed when a website page is restricted to a
different group of users is the default one instead of the website one.
After this commit 403 fallback errors are rendered by the default error
rendering.
Steps to reproduce:
- Go to a page. (e.g. "Contact Us")
- Select "Page Properties" in the "Pages" menu.
- Go to the "Publish" tab.
- Define visibility as "Some Users".
- Select a user group. (e.g. "Administration / Access Rights")
- Access to the same page in an incognito window.
=> The displayed 403 error page was the generic one instead of the
website one (with the navigation header...)
[1]: https://github.com/odoo/odoo/commit/eb7eecec976570ae3301c17a04adc9c110d5b14a
task-2963843
closesodoo/odoo#99671
X-original-commit: fc0a0c2ccea83b3a9a5df0e300eac1fe7eb7a2a2
Signed-off-by: Julien Castiaux <juc@odoo.com>
Signed-off-by: Benoit Socias (bso) <bso@odoo.com>
Just a nice to have. It will prevent those errors to be replicated when
copy pasted and will help reading the files in the IDE.
closesodoo/odoo#97282
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
After [1] moved the website edition in the backend, we feel that the
code required to make the additional debug icon in the footer of the
frontend still work is not worth it.
Before this commit, on a website page, it was not working: clicking on
it from the WebsitePreview client action would only remove the debug
mode of the frontend, and the backend would keep it.
The user can now leave the debug mode from the debug menu systray item
and we consider that leaving debug mode as a visitor (from the
frontend) is not a feature worth keeping.
[1]: https://github.com/odoo/odoo/commit/31cc10b91dc7762e23b4bde9b945be0c4ce3fe3b
task-2687506
closesodoo/odoo#95499
Related: odoo/upgrade#3721
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Install multiple langages, each time translating the website. In a
private browsing session access /contactus, show the page source, the
multiple alternate URL (`<link rel="alternative">` in the `<head>`) are
all pointing the canonical URL instead of the alternative.
closesodoo/odoo#95683
X-original-commit: 3d4b4d3dcff864613a9e7038137e21674425ed08
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Julien Castiaux <juc@odoo.com>
*: test_website
Issue: The url is cached and no longer depends on the url. This part
should not be cached.
closesodoo/odoo#95222
X-original-commit: 4b255ed129b0e458d3cf7f432d076913b14d5450
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
It may happen than the routing map is cleared while rendering a qweb
view. For example, if an asset bundle is regenerated, the previous one
is unlinked, which causes a cache clearing.
Previously-generated EndPoint objects aren't found any more in the new
routing map, so `request.endpoint` cannot be used any more after a cache
clearing.
This commit adds hash and comparison magic methods on http.EndPoint so
that EndPoint objects created by a previous routing map generation can
still be used after a cache clearing.
Two tests were added: one to test the comparison and hash methods, and
the other to test them in a real-case rendering.
Commit 80a04f7ebed fixed this bug too, but introduced another issue
which caused many OPW, so it was quickly reverted by deb23450f18 along
with its performance improvement 33167b3928c. This commit replaces
80a04f7ebed with another way to fix the issue.
A third test has been added in order to avoid reintroducing this other
issue.
By the way, this commit also removes the EndPoint.arguments attribute,
as commit 17f1992698 removed all usages of this attribute in Odoo 9.0,
but left this initialization here.
OPW-2834546
OPW-2834549
OPW-2834625
X-original-commit: bdc45422f5c715782b147eecda2403386ba7eb4a
Part-of: odoo/odoo#91034
Every request comes with a session, a dictionary that is persisted on
the filesystem and that saves various information such as the user
cart on the ecommerce.
When a user simply visits the website, a default session is created and
saved on disk, this bloats the filestore with many sessions. Creating
the session on-the-fly is cheaper than loading it from the filesystem.
With this work the default session is not saved on disk anymore unless
explicitly asked via `session.touch()`.
An exception to the statement "creating the session on-the-fly is
cheaper" is geoip, the ip geolocalization is not cheap. In this work,
geoip have been moved from http_routing/request.session.geoip to a
lazy property core/request.geoip. When requested the info is persisted
on the session. Like other keys from the default session, geoip will not
be persisted unless there is non-default stuff in the session.
Because the CSRF-TOKEN is based on the session-id, it is important the
session-id stays the same across multiples requests even when the
session is not persisted on disk. Even when a session is not persisted
on disk, the session-id cookie is still set so that the next session
created on-the-fly uses the same session-id.
Technical note regarding the session, it has been decided to drop the
session-snapshot protocol and to reintroduce a "modified" flag. It has
been decided not to use werkzeug's session (which natively comes with a
"modified" flag) and to keep our own session object. We decided to
extend MutableMapping instead of dict; using MutableMapping we only
have to override __setitem__ and __detitem__; using dict we would had to
override update()/pop()/... too.
Task: 2789035
Part-of: odoo/odoo#86015
Install website, create a custom web page, we'll call it page_1. Ensure
you are not in debug mode (go to /web/health?debug=0 to disable it).
Open the web page enabling the debug-mode /page_1?debug=1, the page
opens but the debug mode is disabled.
Because web pages are served using another routing mechanism than
controlers we have to ensure we load the debug query-string in those
mechanisms too.
closesodoo/odoo#85340
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Some flows were broken in httpocalypse, sadly those were not tested.
X-original-commit: 6161987c94544162de16eb2544295d152f123d17
Part-of: odoo/odoo#85340
The browser itself would get mostly cleaned up between tours, but the
session object would not get cleaned, and apparently in some cases
that could lead to an incoherent session: a tour would add data to the
session which the next tour (logging in as a different user) would
not (fully) override, leading to a session inconsistency and a Session
Expired exception during the tour.
Fix by not storing the session on the test object, the session is
created during authentication then set on the opener & browser.
The (private) Rule.build method takes a values *dict* parameter. From
the start it was called with an invalid argument, but before 0.15
`append_unknown` would lead to just not using the argument at all
unless the rule is dynamic (aka has converters)[0].
In 0.15 the code was refactored and the `values` mapping is now used
in every case[1], leading to a pretty systematic error when calling
`search_pages`, which occurs any time an auto-completed URL field gets
used on the website e.g. when converting text to a link using the page
editor or when trying to update menu items.
Fixing this in 13.0 because while the current debian stable ("buster")
still bundles 0.14, the soon-to-be-released Ubuntu LTS (20.04) updates
werkzeug to 0.16. Debian Testing (bullseye) also bundles 0.16 but
isn't expected to get released for another year so it's less of a
concern.
Fixes#47356
Relates to odoo/docker#299
[0]
https://github.com/pallets/werkzeug/blob/c769200d1dcf1e21daaa2781f0c5109586daad42/werkzeug/routing.py#L797-L828
[1] https://github.com/pallets/werkzeug/blob/048cdfd9b969c0c3a133d7ff43b8ad1ad6a673ec/src/werkzeug/routing.py#L1020-L1032closesodoo/odoo#50194
X-original-commit: 4f1589075d2aae65c67a01c5c0f75c19c50a61d6
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
in this commit, throw the wizard to enter the new page name, while duplicating
page button and new duplicate page button added in the page properties dialog.
updated the test case related to duplicate page along with duplicate menu
consideration.
task-2088546
closes#40085
Co-authored-by: jpr-odoo <jpr@openerp.com>
When loading a page on an existing starting database, registry is not
fully loaded causing potential error when trying to access model
existing in database (views, menitem, ...) since model added in last
loaded module does not exist in registry.
Thus, executing browser js test may lead to errors when executed during
an update on a database with other modules installed.
HTTPCase should be executed post_install to ensure that registry is
fully loaded to avoid this problem.
Since HTTPCase are slower than other test, it is also a good idea to
execute them at the end, in order to prioritize fast fail.
With this commit, a warning is isued if such a test class is tagged to
run at install time.
While at it, remove deprecated at_install and post_install helpers and
remove the deprecated phantom_js alias.
closesodoo/odoo#39462
Signed-off-by: Christophe Monniez (moc) <moc@odoo.com>
Those tests were raising an assert error if the DB has other websites than the
data/demo ones.
As we have a new module in Odoo 13.0 (odoo/design-themes#178)
which is creating 25 websites, and since the design-themes runbot is now
running tests, we were having a red design-themes runbot.
closesodoo/odoo#39145
X-original-commit: 67df6b91ddb6cb83d558137691481f50834f7fca
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
The `website_published` field from the website's mixins is basically a readonly
from `is_published` field.
On read, this field will simply read `is_published` and check if the record's
website_id is accessible (only for the multi mixin).
On write, it will always write on `is_published`.
This commit improves a few things:
- A lot of code was writting on website_published which was just then writting
on is_published. Writting directly on is_published makes more sense.
- Some backend fields would still reference `website_published` instead of
`is_published` which would just go through the related for no reason.
Plus, using `is_published` will make the field tooltip more accurate as we
are not in a website context ('Visible on current website' to 'Is Published')
- Filter and search on tree view were still using the `website_published`
related field, which is just a readonly when we are not in a frontend
context.
- Some create and write function would have security check on
`website_published` value but that was wrong as the user could bypass that by
simply writting on `is_published`. For the write method, check `is_published`
is more accurate as it will cover both case since `website_published` will
then call the write method on `is_published`
Before this commit, when a view was removed during a module update (eg: the
record was deleted from the file), its COW views would not be deleted.
This could lead to unwanted behaviors including tracebacks(1).
This commit is somehow related/an extension of b5fe23055d that handle COW view
write during module update and 2e32cc5aa3 that remove COW views during module
uninstall.
task-1931683
Note: Some existing tests had to be run post install
(1) A view doing a t-call is COW'd, then that view and its t-called view are
removed. If the cow view is not removed, the t-call will crash (see tests
in this commit for detailed case).
closesodoo/odoo#31295
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
With multi-websites, we expect qweb views to have a key set as it is the key
that is used to find duplicates (two views with same keys are duplicate, the
one with a website_id set is more specific than the one without a website_id)
Thus, 5ff87e8039 sort on key in order to find the most suitable one.
It would crash if a qweb view is created without a key (False) as it can't sort
`bool` and `str`.
This commit:
- Adds a generated key to scss views
- Adds an SQL constraint to avoid QWeb views without a `key`
- Generates a random key when creating a QWeb view without a `key`
- Handle False key in `filter_duplicate()` by extracting views with False key
before sorting, and then adding these views to the recordset
Note: We also want the key to be editable as it is now an important field with
multiwebsite. Thus, we removed the readonly on this field.
+ fix python tests as we now force key on qweb views with sql constraint
+ pep8
Fix bug from the initial poc of JOV
Fix menu creation
- creating a menu would create a 'container' menu in the DB (.create is call without website_id)
then writing on it would copy (if condition to cow) the menu with a website_id leaving the first
one as a menu container unused.
- website_menu should always have a website_id
we dont want to support the multiwebsite system that allow to have generic/specific menu
unlink/write is useless now since we always have a website_id
Make unique_path website dependent, 2 distinct website can have a page with same name
Make Sale report multiwebsite compliant
Make website_id on sale_order / account.invoice as a related stored from partner_id.
Co-authored-by: Derie Romain <rde@odoo.com>
Co-authored-by: Kersten Jérémy <jke@odoo.com>
This implements support to administer multiple websites. Although the
core functionality already existed, managing multiple websites was
fairly technical.
In the interest of database updates and migration this attempts to
keep duplicated data to a minimum. To do this the usual generic
records are rendered unless some website-specific record exists that
replaces it. Copy-on-write (COW) is used to create these
website-specific records. Through this mechanism creating a
website-specific record is delayed until necessary. A COW mechanism
has been implemented on 4 models: ir.ui.view, website.page,
website.menu and ir.attachment. These COW mechanisms are activated
when editing data through the website (aka frontend). These frontend
edits (e.g. with web_editor) will be website-specific, possibly
creating a website-specific record when necessary. When editing data
in the backend nothing special will happen, even when editing a
generic record. Note that because of this mechanism also facilitates
the ability to create new, uncustomized websites because the generic
data is kept.
Support is provided for a website to have any theme. Themes are fairly
complex to handle. Standalone themes can depend on other standalone
themes (e.g. theme_beauty depends on theme_loftspace) and themes
usually modify some data of the themes they depend on. Because a theme
can be installed on multiple websites, using website_id m2o fields
does not work well. It would require duplicate data, making updates
and migration harder. Because of this, data for themes (ir.ui.view and
ir.attachment specifically) have a theme_id m2o. website has a
theme_ids m2m that identifies all theme modules currently installed on
it. Through these fields we figure out what to render. A theme is only
fully uninstalled when it's no longer active on any website. The
advantage of this approach is that upgrading or migrating theme data
is no different from the single-website case.
The website.published.mixin class was modified to handle multiple
websites. A wizard was added in the backend to easily manage this for
multiple website.
Although not used anywhere in this commit, a 'website_id' variable has
been added in the evaluation context of ir.rule. It allows to easily
make any model multi-website aware, all that's needed is a custom
website_id m2o field on a model and a custom record rule.