Commit Graph
201 Commits
Author SHA1 Message Date
Odoo Translation Bot 5d2bc9e9b3 [I18N] Update translation terms from Transifex 2023-11-05 00:21:55 +01:00
Odoo Translation Bot 6739c317d1 [I18N] Update translation terms from Transifex 2023-10-29 00:07:17 +02:00
Louis (wil) 3f6f949fa5 [I18N] export sources
closes odoo/odoo#140002

Related: odoo/enterprise#49687
Signed-off-by: Louis Wicket (wil) <wil@odoo.com>
2023-10-27 08:36:16 +00:00
Gorash cdaa761ced [REF] base: Update modifier syntax (invisible, required, readonly)
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
2023-08-18 09:49:08 +02:00
mehjabinfarsana 4ca77c8833 [IMP] http_routing: window title
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

closes odoo/odoo#129083

Signed-off-by: Romain Derie (rde) <rde@odoo.com>
2023-07-24 20:18:08 +02:00
Xavier-Do 88786dde49 [IMP] base, website: add an api to populate the cache
Part-of: odoo/odoo#119813
2023-07-18 11:42:26 +02:00
Xavier-Do 595aa24843 [IMP] registry: multiple ormcache
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
2023-07-18 11:42:26 +02:00
Rémy Voet (ryv) 3c62ca1eb9 [REM] core: remove name_get API
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
2023-06-28 17:41:19 +02:00
Julien Castiaux 3c174802f8 [FIX] http_routing: be loose on request.is_frontend
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

closes odoo/odoo#126386

X-original-commit: c808719619167a582dd28420ff2979b57102d2ab
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
2023-06-26 22:15:13 +02:00
Jeremy Kersten 939b61822e [IMP] http_routing: server_redirect in case of 404
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.

closes odoo/odoo#125828

X-original-commit: 95dd21c4d69a06b56b908e138f7746ef3d131d82
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
2023-06-21 01:24:20 +02:00
Martin Trigaux 53ca9840d8 [IMP] base: remove read on ir.default
And make get private

Part-of: odoo/odoo#118701
2023-06-12 22:39:25 +02:00
Louis Wicket (wil) 04189318cc [I18N] *: update master translations
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).

closes odoo/odoo#121629

Related: odoo/enterprise#41171
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2023-05-22 17:52:07 +02:00
Benoit Socias fb9efde4f3 [FIX] *: replace werkzeug's Response by odoo's Response
*: 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/2cbda6c98ee947cea1d06c09880eee8c758304a8

closes odoo/odoo#112827

X-original-commit: 28da08292b7028575e628c5ad846fc05d30498f2
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
2023-02-16 09:01:07 +01:00
Julien Castiaux 01b30c2cbf [FIX] http_routing: compat for werkzeug 2.2.x
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
2023-02-10 14:37:31 +01:00
Denis Ledoux b4a7996e96 [IMP] base, *: change the API of init hooks to pass env
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
2023-02-01 10:25:01 +01:00
Romain Derie 065ca151d7 [IMP] website: ignore anchor but not qs when comparing menu URL
- 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

closes odoo/odoo#107782

Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
2023-01-30 19:45:54 +01:00
Romain Derie 371cbe472b [FIX] http_routing: prevent unslug to fail when there is anchor or qs
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
2023-01-30 19:45:53 +01:00
Huy Le c70842e254 [FIX] http_routing: remove trailing /
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.

closes odoo/odoo#106109

Signed-off-by: Romain Derie (rde) <rde@odoo.com>
2023-01-24 21:10:36 +01:00
Victor Feyens 1a1ce16265 [IMP] core,*: check routes decorators
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.

closes odoo/odoo#108512

Related: odoo/enterprise#35176
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
2023-01-16 19:45:57 +01:00
Julien Castiaux 270672daa8 [FIX] http_routing: leftover old geoip resolver
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.

closes odoo/odoo#91337

Related: odoo/documentation#2151
Related: odoo/enterprise#27399
Signed-off-by: Julien Castiaux <juc@odoo.com>
2023-01-03 13:16:02 +01:00
Victor Feyens 13ccd9cee4 [IMP] test_lint: detect useless manifest content
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.

closes odoo/odoo#107735

Related: odoo/enterprise#34903
Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-12-16 16:17:41 +01:00
Jeremy Kersten 2c4556efd1 [IMP] http_routing: support redirect of double slash in middle of path
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

closes odoo/odoo#106137

X-original-commit: fdd6bf9942e2807b6d1460dba1ca5f61404c7b06
Signed-off-by: Julien Castiaux <juc@odoo.com>
Signed-off-by: Jérémy Kersten <jke@odoo.com>
2022-11-21 11:50:26 +01:00
Julien Castiaux 1219f043fe [FIX] http_routing: should redirect only for multilang
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.

closes odoo/odoo#105686

X-original-commit: be7a02917a66136a8d3b601d61a898b0419ff79d
Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-11-14 17:17:59 +01:00
ef00294e71 [IMP] core: store translated fields as JSONB columns
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>
2022-09-15 22:37:50 +02:00
Benoit Socias fc168b17a8 [FIX] http_routing, website: render error page if 403 fallback fails
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

closes odoo/odoo#99671

X-original-commit: fc0a0c2ccea83b3a9a5df0e300eac1fe7eb7a2a2
Signed-off-by: Julien Castiaux <juc@odoo.com>
Signed-off-by: Benoit Socias (bso) <bso@odoo.com>
2022-09-07 17:26:42 +02:00
Julien Castiaux 4174b330f7 [FIX] http_routing: /r russian vs /r link tracker
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.

closes odoo/odoo#99555

X-original-commit: e8a1b4c0cdffb38e48ca980205a61c75c564dee8
Signed-off-by: Jérémy Kersten <jke@odoo.com>
Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-09-05 20:13:17 +02:00
Romeo Fragomeli 1fcd098af5 [REF] *: BS5: migration
Automated change made by a lot of RegEx to change all think that is
possible to automate.

https://getbootstrap.com/docs/5.1/migration

Task ID: 2766483

Part-of: odoo/odoo#95450
2022-07-07 13:30:24 +02:00
Romeo Fragomeli c48f57ea25 [IMP] web,*: upgrade to Bootstrap 5.1.3
* = 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
2022-07-07 13:30:15 +02:00
Jeremy Kersten a9b2ac0f06 [FIX] http_routing: add missing space in qweb template
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>
```

closes odoo/odoo#94170

X-original-commit: 18ae4d804064dab284dadf53eed0681b8c56a555
Signed-off-by: Jérémy Kersten <jke@odoo.com>
2022-06-21 17:58:10 +02:00
Julien CastiauxandRomain Derie fd5c6a861c [FIX] http_routing: missing 301/302 on access err
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/3b9cd536607b1631dd375ab2e5cc94eb814a6e9b

closes odoo/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>
2022-06-18 00:50:34 +02:00
Denis Ledoux bfdd54e815 [FIX] http_routing: support invalid ipv6 URL
opw-2870792

closes odoo/odoo#93138

X-original-commit: 4e052a387885890d9b0950fae825624b7f7a3f2b
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
2022-06-08 19:00:20 +02:00
Gorash 391eb18eb2 [IMP] website: slug method also works with lazy values
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
2022-06-03 16:40:38 +02:00
Laurent Desausoi (lade) 27ff79bf37 [FIX] http_routing, web: fix translation on additional modules
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

closes odoo/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>
2022-05-31 19:17:55 +02:00
Martin Trigaux 158b537c28 [I18N] *: export saas-15.2 source terms
closes odoo/odoo#89225

X-original-commit: 5925a83d87fa4702f4c0f22346304dc2da47c728
Related: odoo/enterprise#26435
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2022-04-23 08:33:43 +02:00
Julien Castiaux 04e972660b [IMP] core: don't save visitor default session
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
2022-04-05 14:13:54 +02:00
Julien Castiaux 814a34c3c9 [FIX] http_routing,website: missing request attribute during install
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.

closes odoo/odoo#87684

Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-04-01 17:56:45 +02:00
Julien Castiaux 1dd3865208 [IMP] *: odoo.addons.web.controllers.main splitted
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.

closes odoo/odoo#87571

Related: odoo/enterprise#25746
Signed-off-by: Raphael Collet <rco@odoo.com>
2022-03-31 02:10:53 +02:00
Julien Castiaux 5ced646b3f [FIX] auth_signup: impossible to login
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.

closes odoo/odoo#87491

Related: odoo/enterprise#25754
Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-03-30 17:35:06 +02:00
Gorash 880954ebfc [IMP] *: remove _render from ir.ui.view and simplify report
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
2022-03-29 10:56:15 +02:00
Gorash a327b2ec8a [IMP] http_routing: display UserError from Qweb error
Part-of: odoo/odoo#85110
2022-03-29 10:56:15 +02:00
Julien Castiaux 8639f9b257 [FIX] website: restore debug mode in website pages
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.

closes odoo/odoo#85340

Signed-off-by: Romain Derie (rde) <rde@odoo.com>
2022-02-28 13:53:09 +00:00
Julien Castiaux 06cc322e7e [REF] core: HTTPocalypse (13) http_routing/website
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
2022-02-24 13:30:50 +00:00
Wolfgang Taferner c099709b85 [FIX] http_routing: mitigate key does not exist in context for lang
closes odoo/odoo#84478

X-original-commit: bdde46dad4d5886a8423bfaa0cac316784c7d382
Signed-off-by: Olivier Dony <odo@odoo.com>
2022-02-14 19:25:02 +00:00
Gorash e830953570 [IMP] IrQweb: refactoring and add technical documentation
Major changes:
- Remove some of the recursively when compiling
- Compile attributes became a directive
- Compile options became a directive
- `t-field` compilation now uses the same logic as `t-out`
- Simplification of ``t-if`` directive compilation
- Improved handling of errors wrapped by QWebException
- Constants defined outside the class

    Odoo
     ┗━► _render (returns MarkupSafe)
        ┗━► _compile (returns function)                                        ◄━━━━━━━━━━┓
           ┗━► _compile_node (returns code string array)                       ◄━━━━━━━━┓ ┃
              ┃  (skip the current node if found t-qweb-skip)                           ┃ ┃
              ┃  (add technical directives: t-tag-open, t-tag-close, t-inner-content)   ┃ ┃
              ┃                                                                         ┃ ┃
              ┣━► _directives_eval_order (defined directive order)                      ┃ ┃
              ┣━► _compile_directives (loop)    Consume all remaining directives ◄━━━┓  ┃ ┃
              ┃  ┃                              (e.g.: to change the indentation)    ┃  ┃ ┃
              ┃  ┣━► _compile_directive                                              ┃  ┃ ┃
              ┃  ┃    ┗━► t-if            ━━► _compile_directive_if                 ━┫  ┃ ┃
              ┃  ┃    ┗━► t-foreach       ━━► _compile_directive_foreach            ━┛  ┃ ┃
              ┃  ┃    ┗━► t-inner-content ━━► _compile_directive_inner_content ◄━━━━━┓ ━┛ ┃
              ┃  ┃    ┗━► t-options       ━━► _compile_directive_options             ┃    ┃
              ┃  ┃    ┗━► t-call          ━━► _compile_directive_call               ━┫ ━━━┛
              ┃  ┃    ┗━► t-att           ━━► _compile_directive_att                 ┃
              ┃  ┃    ┗━► t-tag-open      ━━► _compile_directive_open          ◄━━┓  ┃
              ┃  ┃    ┗━► t-tag-close     ━━► _compile_directive_close         ◄━━┫  ┃
              ┃  ┃    ┗━► t-out           ━━► _compile_directive_out             ━┛ ━┫ ◄━━┓
              ┃  ┃    ┗━► t-field         ━━► _compile_directive_field               ┃   ━┫
              ┃  ┃    ┗━► t-esc           ━━► _compile_directive_esc                 ┃   ━┛
              ┃  ┃    ┗━► t-*             ━━► ...                                    ┃
              ┃  ┃                                                                   ┃
              ┗━━┻━► _compile_static_node                                           ━┛

closes odoo/odoo#81024

Related: odoo/enterprise#22942
Signed-off-by: Christophe Monniez (moc) <moc@odoo.com>
2022-02-03 08:09:31 +00:00
Gorash 9ce5bc8881 [IMP] IrQweb: merge Qweb engine file qweb.py and ir_qweb.py
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
2022-02-03 08:09:31 +00:00
Nicolas Lempereur 4e24115a31 [FIX] http_routing: redirect no double query_string
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
2022-01-04 10:26:16 +00:00
Fabio Barbero a66cdf3f7f [IMP] link_tracker, http_routing: ignore requests from social bots for link tracker
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

closes odoo/odoo#78806

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2021-12-14 09:11:15 +00:00
Jeremy Kersten 5945e8e4e3 [FIX] http_routing: don't remove trailing / during redirect
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

closes odoo/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>
2021-11-22 16:27:09 +00:00
Martin Trigaux a8e50921af [FIX] *: correct typos and English errors
closes odoo/odoo#80181

X-original-commit: efd178daee689192d4e930a075475587038b3e0d
Related: odoo/enterprise#22439
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2021-11-22 14:48:04 +00:00
Xavier Morel b51b094c2b [IMP] http: avoid cycle on request 2021-01-26 09:05:35 +01:00