Goal:
* Simplified modifiers to only have one way to define modifiers;
* Remove states attributes on python field;
* Use python expression in view `required`, `readonly`, `invisible`;
* More accurate validation of xml views.
This commit change the syntax to python expression. The next commit
will update/convert all xml views.
Before this commit:
* the `required`, `readonly` and `invisible` attributes can only have
values of `True`, `False`, 1, 0 or a python expression to use the
context;
* the `attrs` attribute define a dict. The key of this dict was
`required`, `readonly` and `invisible` and the values are the domain or
a string representing a domain to be evaluate as python expression.
This python expressions was evaluate by the javascript with view fields
and other contextual values as: context, uid, parent, active_id,
active_ids, active_model, allowed_company_ids, current_company_id.
* the `states` attribute in the view was a comma separated list of the
state. This list was combined with the `invisible` attribute;
* the `invisible` attribute on python field is used as default value;
* the `states` attribute on python field was dictionnary with state as
key and list of tuple. This structure was combined with `readonly` view
attribute.
* After combining, the resulting domains of the different attributes
`required`, `readonly` and `invisible` are evaluated with the values of
the fields. The `invisible` attributes is splitted into two use:
`invisible` and `column_invisible`.
After this commit:
* The attributes `required`, `readonly`, `invisible` and
`column_invisible` define python expression. This python expressions
are evaluate by the javascript with view fields and other contextual
values as: context, uid, parent, active_id, active_ids, active_model,
allowed_company_ids, current_company_id.
The domains can contains contextual value and will be evaluate by the
javascript.
```xml
<field name="field_a" readonly="not context.get('show_a')" attrs="{'readonly': [('field_b', '!=', False), ('field_c', '=', parent.c)]}"/>
<field name="field_b" states="draft"/>
```
will be replaced by
```xml
<field name="field_a" readonly="not context.get('show_a') or field_b and field_c == parent.c"/>
<field name="field_b" invisible="state != 'draft'"/>
```
Some inherited views will be modified differently in order to maintain
the previous behavior:
```xml
<field name="field_a" readonly="not context.get('show_a')" attrs="{'invisible': [('field_b', '!=', False)]}">
```
```xml
<field name="field_a" position="attributes">
<attribute name="attrs">{'readonly': [('field_c', '=', False)], 'invisible': [('field_d', '!=', '3')]}<attribute>
</field>
```
will be replaced by
```xml
<field name="field_a" readonly="not context.get('show_a')" invisible="field_b">
```
```xml
<field name="field_a" position="attributes">
<attribute name="readonly" add="(not field_c)" separator=" or "/>
<attribute name="invisible">field_d != 3<attribute>
</field>
```
Validation:
A stricter control is made on the level of the attributes (modifiers)
and the fields necessary for these. The use of the previous attributes
'attr' and 'states' triggers an error (these no longer exist after the
application of the migration script)
task-2495504
Part-of: odoo/odoo#104741
before this commit, the window title is
shown as http_error,error_message and
http_error_debug
after this commit, clean window title will
be shown to end user
closesodoo/odoo#129083
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
One of the main issue with ormcache is that the invalidation clears
everything, meaning that some value, slow to compute but with a long
lifetime, can be removed from the cache because an easy to invalidate
value is cleared, like after writting or creating a product has an
example.
Most example in the code will try to invalidate the cache of the models
doing something like `env['ir.qweb'].clear_caches()` but it is
finally equivalent to `env.registry.clear_cache()`, and cross worker.
The idea is to have multiple cache, maybe with specific sizes for a
specific purpose.
Having one per model is maybe a bad idea because it will be difficult
to size the LRU correcly, and it is too dynamic. Checking invalidation
may be expensive.
The proposed solution is closed allow a limited number of named caches,
using onse sequence per cache. This is actually close to the
cache_longterm.
We want to discourage using a specific cache for one use case in
the buisness code. Adding a cache shouldn't be something easy, doable
in stable.
Note that we could also change the invalisation mecanism using an
insert only table. We an check the sequence of this table, but also
fetch all invalidation messages.
Another possible improvement, especially if we have more than x cache is
to have a global sequence, checking signaling would mean to check the
main sequence, and only the other ones if the main one changed.
Note that this poc is inspired from the long term cache but not all
use case where applie yet.
Part-of: odoo/odoo#119813
Rationale
=========
Since v8, the `display_name` field is present on all models. By default,
`display_name` uses `name_get` which has pretty much the same purpose
(return record name used by the web client). Gradually, many (backend)
developers (and the ORM: https://github.com/odoo/odoo/commit/6da1c3ac4c036eac289597602976538e243cb939)
started using `display_name` (more convenient than
`record.name_get()[0][1]`) but it still had the `name_get` override.
It becomes more complex than necessary and poeple start to misunderstand
the two (and sometimes override both, leading to inconstiencies between
`display_name`/`name_get`).
To simplify the ORM and the API, we decided to keep only one of them,
the `display_name` field:
- It is much more convenient from a backend point of view
(`record.name_get()[0][1]` vs `record.display_name`)
- It is cached during the same transaction (and invalidated if
its dependencies change)
- It can be overridden like any other compute field (override
`_compute_display_name` with any extra dependencies)
- `name_get` is replaced by `read(['display_name'])`
(API perceptive), which can actually be more efficient
(if `display_name`'s depends are correct, the ORM will only fetch the
fields it needs instead of every prefetchable field)
Changes
=======
- Deprecates `name_get` for the v17 and based the method on
`display_name` (the opposite of before)
- Converts all usage of `name_get`
- Overrides of `name_get` are now overrides of `_compute_display_name`
- For `res.partner`, rename the field store `display_name` into
`complete_name` because `display_name` context-dependent and it makes
no sense to have a compute store that is context-dependent.
- Previously, it was possible to return multiple names for the same
record with `name_get`, but it was tricky and most of the usage of
this `name_get` didn't take this into account. The only example of
this is the `name_get` of `product.product`
(now use `", ".join(<names>)`).
Part-of: odoo/odoo#122085
Steps to reproduce, on SaaS only, not reproductible in standard:
1. Start a new SaaS Trial on saas-16.3
2. Install helpdesk, setup an incoming mail server
3. Send an email, one that should create a new helpdesk ticket
4. Traceback, request has not 'is_frontend` attribute.
This commit doesn't solve the root issue, it only makes it possible to
use helpdesk again. Using getattr/hasattr to access request.is_frontend
SHOULD NOT be necessary since [HTTPocalypse] BUT there are some rogue
controllers that bypass the normal flow of execution and fail to meet
the expectations of the new http stack.
This commit only makes the code robust to a missing attribute in this
very case as this is a recurring problem (unusable helpdesk). The root
problem is unlikely to be located nor in http_routing, nor in helpdesk.
THIS SOLUTIONS OF USING `getattr`/`hasattr` TO ACCESS `is_frontend` MUST
NOT BE REPLICATED ELSEWHERE WITHOUT PRIOR CONSULTATION WITH PEOPLE IN
CHARGE.
[HTTPocalypse]: https://github.com/odoo/odoo#78857
See-also: https://github.com/odoo/odoo/pull/99667
See-also: https://github.com/odoo/internal/pull/1902
opw-3359740
opw-3365843
closesodoo/odoo#126386
X-original-commit: c808719619167a582dd28420ff2979b57102d2ab
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
It is a tradeoff since we will add extra requests in case of 404 to
check if a redirect exists. But it will allow to redirect old unlinked
record to a new record.
Until now, if you delete e.g. a product instead to archive it, you have
no way to redirect old url to the new product.
closesodoo/odoo#125828
X-original-commit: 95dd21c4d69a06b56b908e138f7746ef3d131d82
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
Currently, only stable releases see their translations updated. This has
resulted in master accumulating outdated stuff for years, which can be
confusing for users testing master on runbot.
This one-shot commit resynchronizes master translations based on the
content from 16.0 and removes empty PO files (i.e. no longer containing
translations).
closesodoo/odoo#121629
Related: odoo/enterprise#41171
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
*: base, http_routing, mass_mailing, web, web_editor, website_slides
In some situations `werkzeug.wrappers.Response` are used instead of
`odoo.http.Reponse` that extends it.
This is a problem because since [1] the calls to `set_cookie` expect it
to accept the `cookie_type` parameter, which is not the case in the base
werkzeug implementation.
This commit replaces the `werkzeug.wrappers.Response` by
`odoo.http.Response`.
[1]: https://github.com/odoo/odoo/commit/2cbda6c98ee947cea1d06c09880eee8c758304a8closesodoo/odoo#112827
X-original-commit: 28da08292b7028575e628c5ad846fc05d30498f2
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
The path matching logic got reimplemented in werkzeug 2.2[^1] and the
new router is no more compatible with regexp groups[^2]. Our custom
converter for slugged-records in urls (`'/partner/agrolait-5'` => `5`)
has been adapted to match the route using non-capturing groups. It still
extracts the slug/id pair using the groups-capturing regexp.
[^1]: https://github.com/pallets/werkzeug/pull/2433
[^2]: https://github.com/pallets/werkzeug/pull/2519
Part-of: odoo/odoo#112298
This is mostly a cleaning/refactoring change.
The current API for init hooks (pre, post, uninstall) is to pass
`cr, registry`.
But the first thing which was done by most
post init and uninstall hooks was to create an env using
the cr passed
e.g.
`env = api.Environment(cr, SUPERUSER_ID, {})`
and the `registry` argument was unused in all these hooks,
completely.
By changing the API of hooks to pass `env` instead
of `cr, registry`, we gain in average two lines in every
hooks:
- the line creating the env `env = api.Environment(cr, SUPERUSER_ID, {})`
- the line importing `api` and `SUPERUSER_ID`
Therefore removing ~250 lines of repeated code lines accross odoo/odoo and
odoo/enterprise.
In addition to these lines removed,
it also ease the API of init hooks for Odoo developers,
who are used to that `env` and not so much how to create an `env`
from a cursor.
Part-of: odoo/odoo#108254
- Ignore anchors, those are not sent to the server anyway, no way to
compare even if we wanted to
- Ensure query string (qs) are the same to be considered equals
On top of that, it also fixes the case when the user inserted an
absolute URL instead of a relative one, it will now match.
task-3096367
opw-3091427
closesodoo/odoo#107782
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Due to the end part of the regex `(?=$|/)`, it will not find and thus
not unslug string if they end up with a query string or and anchor
except if there is a trailing slash before.
First, it's unlikely that there will be a trailing slash as it's not
common and on top of that, Odoo try to enforce non trailing slash in
URL.
Second, it's not that hard to makes those cases work.
Before this commit, the following string would "match" and be unslug:
- /blog-1
- /blog-1/
- /blog-1/register
- /blog-1/?qs=2
- /blog-1/#anchor
But those would not:
- /blog-1?qs=2
- /blog-1#anchor
Part-of: odoo/odoo#107782
Currently, the character `/` appears at the end of the url of the
language dropdown on the home page e.g. /en/, /fr/. This will cause one
more redirect when performing the language change.
Indeed, this error is only encountered with path = /
Please try the following `url_lang('/', 'en_US')` => /en/
After this fix, the trailing `/` will be removed when using the func
`url_lang` e.g. `url_lang('', 'en_US')` => /en, this means that the
language switching links on the homepage no longer redirect redundantly
again.
closesodoo/odoo#106109
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
When overriding an existing controller route, developers can
easily c/p the route definition and call super() in the overridden method
when the route attributes are automatically deducted by odoo from the parent route.
Removing those redefined attributes simplifies the routes definition,
clearly highlighting what's changed by the override.
Also reduces unexpected behavior when modifying the base route without
noticing/considering the redefined attributes in a overridden route,
which overrides the changes made to the base route when the sub-module is installed.
This commit adds a test to catch routes attributes redefinition, and clean existing routes.
closesodoo/odoo#108512
Related: odoo/enterprise#35176
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
The geoip resolver was moved from http_routing to code/http.py in #86015
and is always available since then. The `_geoip_resolver` global
variable is a leftover we forgot to remove.
closesodoo/odoo#91337
Related: odoo/documentation#2151
Related: odoo/enterprise#27399
Signed-off-by: Julien Castiaux <juc@odoo.com>
Keep the manifests as light as possible, to easily see custom behavior/content.
Complete the work of previous commits cleaning the manifests content:
* 42bad1a6d2
* ef7005f524
and make sure this kind of cleanup commit is not necessary in the future
because it is now automatically verified by a dedicated test.
closesodoo/odoo#107735
Related: odoo/enterprise#34903
Signed-off-by: Julien Castiaux <juc@odoo.com>
Move code to support only the redirect from url containing double '/' in
the middle of the path.
Keep same behavior than v15 and default Apache behavior.
domain.com//shop/product/1 -> 404
domain.com/shop//product/1 -> 301 -> /shop/product/1
opw-3063387
closesodoo/odoo#106137
X-original-commit: fdd6bf9942e2807b6d1460dba1ca5f61404c7b06
Signed-off-by: Julien Castiaux <juc@odoo.com>
Signed-off-by: Jérémy Kersten <jke@odoo.com>
Define a route that is website but not multilang, e.g.
@route('/example', website=True, multilang=False)
Login to the frontend, change the website lang to another (non-default)
lang (e.g. install french, keep english as default lang, log in the
french website) then access the '/example' controller by typing it
directly in your address bar.
You are being redirected to '/fr/example', you should not.
This commit restore the behavior pre-httpocalypse, that is the address
is kept as-is.
Note: in the comment, the 4th and 5th cases were inverted, we use this
commit as an opportunity to reorder the two.
closesodoo/odoo#105686
X-original-commit: be7a02917a66136a8d3b601d61a898b0419ff79d
Signed-off-by: Julien Castiaux <juc@odoo.com>
Translated fields no longer use the model ir.translation. Instead they store
all their values as JSON, and store them into JSONB columns in the model's
table. The field's column value is either NULL or a JSON dict mapping language
codes to text (the field's value in the corresponding language), and must
contain an entry for key 'en_US' (as it is used as a fallback for all other
languages). Empty text is allowed in translation values, but not NULL.
Here are examples for a field with translate=True:
NULL
{"en_US": "Foo"}
{"en_US": "Foo", "fr_FR": "Bar", "nl_NL": "Baz"}
{"en_US": "Foo", "fr_FR": "", "nl_NL": "Baz"}
Like before, writing False to the field makes it NULL, i.e., False in all
languages. However, writing "" to the field makes its value empty in the
current language, but does not discard the values in the other languages.
Here are examples for a field with translate=xml_translate:
NULL
{"en_US": "<div>Foo<p>Bar</p></div>", "fr_FR": "<div>Fou<p>Barre</p></div>"}
Change for callable(translate) fields: one can now write any value in any
language on such a field. The new value will be adapted in all languages, based
on the mapping of terms between languages in the old values. Basically the
structure of the value must remain the same in all languages, like before.
Reading a translated field is now both simpler and faster than the former
implementation. We fetch the value of the field in the current language by
coalescing its value with the 'en_US' value of the field:
SELECT id, COALESCE(name->>'fr_FR', name->>'en_US') AS name ...
The raw cache of the field contains either None or a dict which is conceptually
a subset of the JSON value in database (except for missing languages). For the
sake of simplicity, most cache operations deal with the dict and return the text
value in the current language.
Trigram indexes have been adapted to the new storing strategy, and should enable
to search in any language. Before this change, only the source value of the
field ('en_US') could be indexed.
Computed stored translated fields are not supported by the framework, because of
the complexity of the computation itself: the field would need to be computed in
all active languages. We chose to not provide any hook to compute a field in
all languages at once, and the framework always invokes a compute method once to
recompute it.
Code translations are no longer stored into the database. They become static,
and are extracted from the PO files when needed. The worker simply uses a cache
with extracted code translations for performance. This is reasonable, since
fr_FR code translations for all modules takes around 2MB of memory, and the
cache can be shared among all registries in the worker. Changing code
translations requires to update the corresponding PO file and reloading the
worker(s).
Performance summary:
(+) reading 'model' translated fields is faster
(+) reading 'model_terms' translated fields is much faster (no need to inject
translations into the source value)
(+) searching translated fields with operator 'ilike' is much faster when the
field is indexed with 'trigram'
(+) updating translated fields requires less ORM flushing
(-) importing translations from PO files is 2x slower
Some extra fixes:
- make field 'name' of ir.actions.actions translated; because of the PG
inheritance, this is necessary to make the column definition consistent in
all models that inherit from ir.actions.actions.
- add some backend API for the web/website client for editing translations
- move methods get_field_string() to model ir.model.fields
- move _load_module_terms to model ir.module.module
- adapt tests in test_impex, test_new_api
- because env.lang is injected into SQL queries, its returned value is
now guaranteed to correspond to a valid active language or None
- remove wizard to insert missing translations (no longer makes sense)
task-id: 2081307
Co-authored-by: Fabien Pinckaers <fp@openerp.com>
Co-authored-by: Raphael Collet <rco@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>
Install website_links, create a link e.g. to http://example.com, install
the russian language and translate the default website. Access the short
link you created before-hand, 404 website page not found.
Accessing a website starting with /r is ambiguous, is /r the
link-tracker controller or is /r a russian lang alias (nearest lang
algorithm)? The controller should be prioritary to the lang alias.
This restore the behavior as it was before the httpocalyse.
closesodoo/odoo#99555
X-original-commit: e8a1b4c0cdffb38e48ca980205a61c75c564dee8
Signed-off-by: Jérémy Kersten <jke@odoo.com>
Signed-off-by: Julien Castiaux <juc@odoo.com>
* = base,http_routing,hw_drivers
- Update Bootstrap from 4.3.1 to 5.1.3
- Update PopperJS to version 2 for Bootstrap 5 (JS part)
Some code was for PopperJS V1, but it's not compatible anymore.
- Remove some BS5 classes utilities backport
- Fix path for BS5
Task ID: 2766483
Part-of: odoo/odoo#95450
Since last refactoring of qweb to replace postprocessing cleaning by
onEval cleaning, the space between xml node are now ignored.
It's not a bug, but a tradeoff of the new implementation to avoid empty
line with code like
```xml
<t t-if="condition">
<div>...</div>
</t>
```
closesodoo/odoo#94170
X-original-commit: 18ae4d804064dab284dadf53eed0681b8c56a555
Signed-off-by: Jérémy Kersten <jke@odoo.com>
Install website and website_hr_recruitment, open /web with ?debug=1, go
to website > configuration > redirect, create a temporary (302)
redirection from `/jobs/detail/experienced-developer-4` to `/404`. Open
the `/jobs/detail/experienced-developer-4` as admin and unpublish the
page. Open the same URL via private browsing (so that you are not
connected), you get the default 403 - Forbidden page, you were not
redirected to the 404 - Not Found page.
Custom 301 (permanent) and 302 (temporary) redirections are fallback
redirections when the requested page does not exist or is not accessible
to the current user. The HTTPocalypse broke the later case, it was not
checking for existing redirection upon access error.
The use case is the one supported with [1] where people want/need to
display something better than a 403 when they unpublish a record like a
job position for instance (most of the requested cases on opw).
Indeed:
- People have link to that record/job everywhere on the internet
- The job position / record is no more relevant, and people need to
unpublish it
- People don't want to delete it (or can't sometimes due to record
relations)
- People don't want visitors to land on a 403, mainly because it is a
non customizable advanced/technical page (it displays a technical
message including the record name etc)
- Their need is to either land a their customizable friendly 404 or
sometimes on another record to promote it.
[1]: https://github.com/odoo/odoo/commit/3b9cd536607b1631dd375ab2e5cc94eb814a6e9bclosesodoo/odoo#93981
X-original-commit: eb7eecec976570ae3301c17a04adc9c110d5b14a
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Julien Castiaux <juc@odoo.com>
Co-authored-by: Romain Derie <rde@odoo.com>
Before this commit, the behavior is broken if using lazy values, the
condition using isinstance does not work. It's best to use the slug as
if given the correct value. Indeed, in odoo, we don't have any other
object having `id` as attributes in addition to `seo_name` or
`display_name` and not being a recordset and whose slug we want.
If there is an error, it is imperative that we provided a tuple (from
read).
Part-of: odoo/odoo#88276
Translations from non-standard modules on the website are not properly loaded,
thus no translation is done even though translated terms are valid (e.g.
signing a document shared).
Step to reproduce the issue:
1) Install the sign module & Install French language (or any execpt English)
2) Disable the English language
3) Go to Sign and Share on document
4) Open the link
You will see that the "Click to start" is not translated. Some other strings
too.
Solution: The issue appeared since commit [1]. In there, we changed the argument key
for additional modules while it was not changed on the backend resulting in
the module translation not loaded. Furthermore, in the backend the additional
modules were appended as if they were a list while it is a string.
[1]: https://github.com/odoo/odoo/commit/8cc066173dfb61bd95b8e1f0716f71f4e251810a
opw-2842699
closesodoo/odoo#92546
X-original-commit: b4eaaaa567ea306e6e86d133c3a805145d9ea4d0
Related: odoo/enterprise#27906
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Desausoi Laurent (lade) <lade@odoo.com>
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
Steps to reproduce:
1) start from a clean database (http_routing should not be installed).
2) go to the app menu and install project (don't install via `-i`!!).
3) traceback: `request` has not attribute `is_frontend` while rendering
a template.
The `is_frontend` attribute on request is set by the http_routing
module. At the moment the "install now" button is clicked, http_routing
was not installed so the `is_frontend` attribute was not set.
FF to the end of the installation: the registry is reloaded to include
the modules that have been installed, http_routing among them.
We are in a tricky situation: (1) there is a request, (2) http_routing
is installed and (3) the `is_frontend` attribute is missing from the
request.
This situation is illegal, when http_routing is installed, the
`is_frontend` attribut should always be set. In this work we reset the
missing attributes using sensitive default values via post-init hooks.
closesodoo/odoo#87684
Signed-off-by: Julien Castiaux <juc@odoo.com>
The odoo.addons.web.controllers.main python module have been splitted
over multiple files on the basis 1 controller = 1 file. In this work we
adapt all modules to use the new imports.
A non-exhaustive list of where stuff have been moved:
* main.Home --> home.Home
* main.Session --> session.Session
* main.WebClient --> webclient.WebClient
* main.clean_action --> action.clean_action
* main.ensure_db --> home.ensure_db
The complete list is accessible in odoo.addons.web.controllers.main.
closesodoo/odoo#87571
Related: odoo/enterprise#25746
Signed-off-by: Raphael Collet <rco@odoo.com>
Install auth_signup, go to /web/login, 500 Internal Server Error.
auth_signup extends the /web/login template and in this extension calls
`keep_query()` which has been wrongly moved from base to http_routing in
commit 880954ebfc. Here, we restored `keep_query()` in the base module
but moved in ir_qweb.
closesodoo/odoo#87491
Related: odoo/enterprise#25754
Signed-off-by: Julien Castiaux <juc@odoo.com>
There were inconsistencies in the calls to `_render`.
* the view context could contain information that misled developers.
Indeed, the context and value of the view are not supposed to be found
in the rendering. Thus by calling `ir.qweb` with the name of the
template, we ensure that there is no unwanted information and in
addition the cache key is that of the name of the template which saves
a query.
* the context used for rendering was modified by a method on
`ir.ui.view`, except this is not information used by this model. There
is now a `_prepare_environment` method residing on `ir.qweb`. This
method allows to modify the value dictionary as well as the context in
which the rendering will be done. This preparation of the data as well
as my security check is done only once per rendering. This also saves
some queries
* Freeze options for rendering were inconsistent. It could be that
options on which rendering depends were not part of the cache key. Thus,
depending on the user who generated the generation of the rendering
function, there was or was not information in the template. For example
for automatic branding. This is no longer possible, because it is the
context that is used. The options serving as a cache key are only
recorded for information (for the profiling system for example). A
simplification of the `ir.qweb.field` models could be made.
The report rendering and call `ir.qweb` instead of `ir.ui.view`.
Part-of: odoo/odoo#85110
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>
This commit is the 13th commit of a comprehensive refactor of our HTTP
framework. See odoo/odoo#78857 for complete historic, discussions and
rationnals.
Here be dragons.
First and foremost, `http_routing` is a technical module that aim to
provide the minimum viable compatibility code between portal and
website. Its primary job is to take care of the lang inserted in the
path of URLs, e.g. `en` in `/en/my_blog`. Both when routing a request
with a lang in the URL and when rendering templates with multilang
support.
Next to `http_routing` is website, the module used by customers to
create pretty web page accessible online. Website uses a different
routing logic than the backend, webpages are **not** registered in the
routing map of werkzeug but instead delivered by website dedicated
code. It means that **all** request targeting a website page thrown at
the werkzeug router **fail** with a HTTP 404 error. The reality is that
website abuses the fallback mechanism (`_serve_fallback`) to deliver
its pages.
Using `_serve_fallback` as the standard way to deliver pages is broken
by design. It is the least crappy way to deliver content as long as
website page don't have a dedicated path prefix. Using a path prefix
(e.g. `p` in `/p/fr/mon_blog`) it would have been possible to route the
request to a dedicated endpoint using the same router as the backend and
with no change to the HTTP dispatching code. Sadly, the business does
not want such prefix so we have to stick with a broken design.
It is broken because prior to serving a page, website needs to setup A
LOT of stuff on the system. It needs to ensure a proper user is set on
the environment, it needs to setup the GeoIP database, it also needs
to determine the lang the user requested the page and it also needs to
save multiple attributes on the request objet itself (`is_frontend`,
`is_frontend_multilang`, `routing_iteration`, `website`, `lang`,
`rerouting` and `website_routing`). Since `base/ir.http@_match()` will
fail, everything must be set either prior to calling this method or in
`website/ir.http@_serve_fallback`.
---
The original implementation was overriding the `_dispatch` method which
was responsible to call the four `_match()`, `_authenticate()`,
`_postprocess_args` and finally `WebRequest._dispatch()`. The override
was very special, here is an attempt to explain it:
1) try to match an endpoint using the backend router, 404-errors are
ignored.
2) include the geoip stuff.
3) authenticate using the `auth` @route argument if an endpoint matched
in (1), otherwise authenticate with the public user.
4) if not endpoint matched or if a frontend endpoint matched in (1):
a) call `_add_dispatch_parameters` which sets many arguments on the
`request` object, including the lang found in the request cookies
b) try to extract a lang from the URL: abort with a redirection when
the lang is missing or wrong, remove the lang from the request
path when it is set (updating both `request.lang` and the cookie).
5) return the result of `super()._dispatch()`
Note that `_serve_fallback()` is called during `super()._dispatch()`
when the path still does not route to an endpoint. Thanks to the
`_dispatch` overrides in http_routing and website, it is garanteed that
the system is setup prior to calling `_serve_fallback`.
---
Because it is now `http.py@Request._serve_ir_http()` that is responsible
of calling the four`_match()`, `_authenticate()`, `_pre_dispatch` and
finally `_(http|json)_dispatch()` it is no more possible to override it
to take over the dispatching to perform the http_routing/website magic.
The prior implementation can not work with the new design thus is has
been refactored too.
To render a website page, there must be a user configured on the
environment (not None) and the various special attributes must be set on
the request object. The special `lang` attribute is popped from the
request path but backend endpoints must be delivered in priority.
Using the new design, it has been decided to override the `_match`
method to implement the lang-in-path logic, to override both
`_pre_dispatch` and `_serve_fallback` to call `_add_dispatch_parameters`
which have been renamed `_frontend_pre_dispatch` and to also grant the
public user in the `_serve_fallback` override.
The `_handle_error` override in website has similar needs, the function
is called upon error (4xx/5xx) in order to render a pretty
website-looking page. Because such error can occurs as early as in
`_match()` (page not found and no fallback), when nothing has been setup
yet, website is yet again responsible for setuping everything: request,
orm, frontend.
Many other small improvement are not described here. Hopefully the added
comments in the source code are enought.
PR: odoo#78857
Task: 2571224
QWeb is the primary templating engine used by Odoo. It is an XML
templating engine and used mostly to generate XML, HTML fragments and
pages.
To create new XML template, please see :doc:`QWeb Templates documentation
<https://www.odoo.com/documentation/15.0/developer/reference/frontend/qweb.html>`
In **input** you have an XML template giving the corresponding input
etree. Each etree input nodes are used to generate a python function.
This fonction is called and will give the XML **output**.
The ``_compile`` method is responsible to generate the function from the
etree, that function is a python generator that yield one output line at a
time. This generator is consumed by ``_render``. The generated function is
orm cached.
In the graphic below you can see theresume of the call of the methods
performed in the IrQweb class.
Odoo
┗━► _render (returns MarkupSafe)
┗━► _compile (returns function) ◄━━━━━━━━━┓
┗━► _compile_node (returns code string array) ◄━━━━━━━┓ ┃
┃ (add technical directives: t-inner-content, t-tag) ┃ ┃
┣━► _directives_eval_order (defined directive order) ┃ ┃
┃ ┃ ┃
┣━► _compile_directives (recursive) ◄━━━━┓ ┃ ┃
┃ ┣━► _compile_directive ┃ ┃ ┃
┃ ┃ ┗━► t-if ━━► _compile_directive_if ━┫ ┃ ┃
┃ ┃ ┗━► t-foreach ━━► _compile_directive_foreach ━┫ ┃ ┃
┃ ┃ ┗━► t-* ━━► ... ━┛ ┃ ┃
┃ ┃ ┗━► t-inner-content ━━► _compile_directive_inner_content ◄━━━━┓ ━┛ ┃
┃ ┃ ┗━► t-tag ━━► _compile_directive_tag ━┫ ┃
┃ ┃ ┗━► t-call ━━► _compile_directive_call ━┫ ━━━┛
┃ ┃ ┗━► t-out ━━► _compile_directive_out ◄━┓ ━┫
┃ ┃ ┗━► t-field ━━► _compile_directive_field ━┛ ┃
┃ ┃ ┃
┗━━┻━► _compile_static_node ━┛
Part-of: odoo/odoo#81024
Reproduction:
- have 308 redirection from /shop to /boutique and refresh routes
- go in incognito on /boutique?order=name+asc (don't go on
/boutique first, or restart odoo to clear ORM cache)
- select a sorting option eg. price
=> we are redirected to /boutique?order=name+asc?order=list_price+asc
and this error is shown:
Invalid "order" specified (is_published desc, name asc?order=list_price
asc, id desc).
This is happening because url_rewrite is keeping current query string
(see ir.http()._slug_matching) and caching it. So if the first call
caches:
url_rewrite('/boutique') => /boutique?order=name+asc
all other url_rewrite('/boutique') calls will give you
/boutique?order=name+asc even if the query string has changed.
In addition to that, url_for may append query_string to url_rewrite
return value, so you may get a double query_string such as:
?order=name+asc?order=list_price+asc
which causes the error.
In this fix, we restore the removal of query string that was removed in
3beb4545c4.
opw-2702036
X-original-commit: 5dcf6e91fed769f4ab22ac63d3e5078cdd352e86
Part-of: odoo/odoo#82099
Purpose
=======
Avoid counting requests from social bots (twitter, facebook, linkedin...)
when tracking a link.
Specifications
=============
Social media platforms have a specific user agent in the HTTP headers that
can be used to detect them and to not increment the click count in that case.
Task-2578902
closesodoo/odoo#78806
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Before this commit, since we promote the use of route without trailing / for
best SEO (fee0113), we remove the trailing / during a redirect to avoid an
extra request.
Unfortunately, it will break some route with trailing / in case of multi lang.
So we remove this optimization, it will increase potentially number of http
request before to get the final url, but it will allow to continue to support
trailing slash in v15.
This commit partially revert the commit ae35117
closesodoo/odoo#80191
X-original-commit: 84d2f5b57ccf3dbcefebdbc795ab1872bc1504b9
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
With this commit, the 404 image is now using the theme color.
Not only it will be displayed in the secondary color, but it will also gets
updated when the theme color is changed.
This one was waiting for the new editor to handle inline svg as regular img
(task-2497786) but in the meantime, the website is now capable of doing that
another way, as does in this commit.
task-2659182
closesodoo/odoo#77569
X-original-commit: f1f2ba8ede7641c79eb48412090ce63655ccf831
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
context:
Connected in /fr on a website with /en as default lang.
Before this commit,
/web/session/logout?redirect=/
/
/fr_FR/
/fr_FR
Now
/web/session/logout?redirect=/
/fr_FR
Part 1 -> to say that we are in multilang context and use url_lang.
multilang=False to avoid /web/session -> /fr/web/session
website=True to have url_lang done in the request.redirect.
Part 2 -> to remove the trailing '/' that will be only useful for '/'
closesodoo/odoo#76290
X-original-commit: ae35117ee1e019c3c0c333f291478825a5722706
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>