97ca45e4f348f819f18fdff3693d030d36c2c734
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8d48efeece |
[FIX] web_editor: add snippet_lang as a template cache context key
In commit [1] it was decided that the Snippet Menu would have its UI in the user's language, while the Snippets' Content would be in the language of the website they are currently editing. To do so, a new context key was added: Snippet Lang. Unfortunately, while Odoo handles the compilation according to a language, website_id and more, it does not do so according to the snippet lang. It would not be an issue if the Snippets were compiled only in edit mode, as a Website only has one default language. Unfortunately the Snippet Content is also rendered in translate mode (Since the SnippetMenu is one big XML template), therefore it can be rendered in different Snippet Lang (though it's useless). This commit fixes that by adding Snippet Lang as a cache key so that if the key is present, it will re-compile the template. Steps to reproduce: - Create a new language - Translate a snippet (e.g. search s_cover view and translate contact us) - Create a new website with 2 languages, the new language as default and english - Enter translate mode - Leave it - Enter edit mode via the "Edit master" button - Drop the translated snippet - It will not be translated because the Snippet Menu was rendered in English first. A commit introduced after this one will test these steps. [1]: https://github.com/odoo/odoo/commit/55a978aa86967581956f855a1c5db33b7425bd15 X-original-commit: 6eba6203e9f1b8a730ab53f80fea8e7b78818bc7 Part-of: odoo/odoo#108643 |
||
|
|
e4da04ab78 |
[FIX] website, web_editor: translate snippet menu and snippet content
Prior to this commit, the language of the snippet menu would be the same as the snippet content. This would cause issues if the user's language was not the same as the website they were editing. This commit fixes that by displaying the snippet menu in the user's selected language but getting snippet content in the website's language. This commit also fixes SEO data not being saved according to the website's displayed language. Prior, it was saved according to the user's current display language. This commit also introduces a test for a fix made at [1] that targets a previous version of odoo. [1]: https://github.com/odoo/odoo/commit/db5d1eae2086ff338d8211af70c2f88240393c36 task-2687506 closes odoo/odoo#102799 X-original-commit: 55a978aa86967581956f855a1c5db33b7425bd15 Signed-off-by: Romain Derie (rde) <rde@odoo.com> |
||
|
|
81f13d32cb |
[FIX] website_event: avoid multi tooltips on date edition
Avoid having multiple tooltips. We keep only one "t-field" in the template. The other are replaced by a "t-out". We also add a specific message when the datetime format is not respected. task-2942617 X-original-commit: a99d684507782cd0d9ff700dc7a12f7a46442403 Part-of: odoo/odoo#102545 |
||
|
|
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>
|
||
|
|
cb80c15d3d |
[IMP] web_editor, website: warn restricted editor about forbidden change
See previous commit(s) for more details about the new sanitize feature. This commit implement a solution in the website builder to warn restricted users when they can't edit a field due to the sanitizer restriction. Long story short: a HTML field can be flag as `sanitize_overridable` which will allow users with the `base.group_sanitize_override` group to not go through the sanitize process. It means that such users can write some content which is not sanitize friendly. A restricted user trying to add content in such fields would then break the original content as the sanitizer would remove part of the DOM. In such cases, the field in the website builder is not detected as an editable part and clicking on it will warn the user about it. closes odoo/odoo#97398 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com> |
||
|
|
cf844e34dd |
[IMP] core: allow some users to bypass the sanitize of HTML field
Add the possibility to flag a HTML field as `sanitize_overridable`. The sanitizer will then be bypassed if the user doing the operation is part of the new group `base.group_sanitize_override`. The "Settings" users are part of that new group. If such a user wrote some HTML that would have normally been removed by the sanitizer, then users without the right to bypass the sanitizer won't be able to write on that field anymore. Otherwise, it would sanitize the previously written data. Such cases are detected, and the modification prevented by the system, which will warn the user about it. For instance, with a `field.html(sanitize_overridable=True)`: one being part of `group_sanitize_override` could write `<script></script>`. Then, someone not part of the group trying to add an element inside that field like appending a `<p/>` -> `<script></script><p>New Content</p>` would not be able to because it would go through the sanitizer and ultimately, removing part of the original value: `<p>New Content</p>` (`<script></script>` would be removed). == Real use case == In the website builder, there is 2 editor rights: - group_website_publisher: restricted editor - group_website_designer: editor & designer The designer editor can edit pages and views, while the restricted editor can't do anything unless he is part of other groups. In edit mode, the restricted editor will only be able to edit fields of record he has access to. For instance, being a sales manager allows you to edit a product description on the website. Being an event manager -> edit event. Slide manager -> Slides etc. As those restricted editor are able to edit those fields, they are (almost) always sanitized to prevent them to introduce malicious code. Since those fields are sanitized, even admins / designer editor are not able to fully use the website builder in such fields. Some clients don't really care about that sanitation, they'd prefer to avoid it as they trust their manager and would prefer to have the full builder capability instead. This is typically the case in small project (butcher, hairdresser, reseller etc) and in SMEs. With the new `sanitize_overridable` feature, they will be able to do that, as the "Designer & Editor" group now also receive the group `base.group_sanitize_override` (done in next commit). Part-of: odoo/odoo#97398 |
||
|
|
11572f0f20 |
[FIX] web_editor, *: prevent dropping unsafe snippets in model fields
*: website, website_mass_mailing, website_payment When an unsafe snippet is dropped into a sanitized HTML model field, its unsafe content gets removed on save. We need a way to mark snippets as being (in)compatible with sanitization. It cannot be automatic, as, for example, the snippet introduced at [1] contains an iframe but is compatible with sanitization. In 13.0, we will temporarily set up an automatic mechanism that marks existing snippets containing forms as being incompatible with sanitization. In 14.0 a distinction between full sanitization and form-tolerant sanitization introduced at [2] is added with this forward-ported commit. This commit prevents unsafe snippets from being dropped into sanitized HTML model fields. The "Form Builder", "Product Search" and "Product Search Input" blocks are now prevented from being dropped or moved into form-sanitized HTML fields. To do this, this commit introduces a new `t-forbid-sanitize` attribute on the `t-snippet` tag. It can have the value `true` to prevent it from being dropped into any sanitize fields, or `form` to specifically limit to form-sanitized fields. Steps to reproduce (in 13.0): - Go to a product page - Drop a "Product Search" snippet into the product-specific section of the product - Save => The form was removed. [1]: https://github.com/odoo/odoo/commit/c2e9bd0e60014b6a42931cf300e0f89f8cf7c225 [2]: https://github.com/odoo/odoo/commit/388c222c6c4bb7e2fe3e67009b248359ae0fd3db task-2829961 closes odoo/odoo#96812 X-original-commit: 9eaba23781766730b06e936dbd9c5d0c28c909c6 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com> |
||
|
|
119ad2fb7b |
[FIX] web_editor: validate qweb fields upon submission
When editing database fields via the web editor, their value are not checked. Thus, stack traces can come up to the front-end user. Step to reproduce the issue: 1) Install the E-Learning module and connect to the website 2) On the main website (not the backend), go to Courses > Edit 3) Edit the Next Rank treshold with any non integer string (e.g.: coucou) A stracktrace will be shown upon save. Solution: The issue is that there are no validation on the submitted fields, this can cause stacktraces. A try-catch was used around the parsing of the input value to catch and properly raise these exceptions to show clean errors. On top of this, integers were not properly parsed, they were not taking into account the `thousands_sep` of the user lang (e.g.: 35,000 for 35000). NB: Generic fix of the following PR [1]. [1]: https://github.com/odoo/odoo/pull/85535 opw-2819392 closes odoo/odoo#96187 X-original-commit: edf76dbb0880c9b08354563a3c77e7c06a604802 Signed-off-by: Romain Derie (rde) <rde@odoo.com> Signed-off-by: Desausoi Laurent (lade) <lade@odoo.com> |
||
|
|
b03c227e88 |
[REF] models: refactor fields_view_get, load_views
Refactor the `load_views` API so it no longer sends multiple times the same fields description. e.g. When `load_views` is called to get the kanban, tree and form views, the list of fields of the model was sent 4 times: - Once for each view, with only the fields used in the view, in `['fields_views']['kanban']['fields']` for instance - Once globally, with all the fields of the model, in `['fields']` The goal of this revision is to change that so it sends the list of all fields only once. In addition, if a view contains x2many fields, the fields description of the comodel is also sent. It was sent in the `views` key of the view fields dict. e.g. When calling `load_views` of `res.partner` to get the kanban, tree and form views, the `res.partner` fields description was actually sent 6 times: - Once for each view - Once globally - Once for each view of the many2many field `child_ids` of the form view, in - `['fields_views']['form']['fields']['child_ids']['views']['kanban']['fields']` - `['fields_views']['form']['fields']['child_ids']['views']['form']['fields']` The change suggested in this revision is to: - Remove the fields description for each view in `['fields_views']`. As it no longer contains the fields, the key becomes `['views']` instead of `['fields_views']`. - Replace the dict key `['fields']` by `['models']`, which is a dict with as key the model name and as values the model fields description. It contains the fields description for all models implied in the view: the model of the main view and the model of all one2many and many2many fields. With this change, the fields description will only be sent once by model implied in the view. In addition, the web client was getting the information about the fields sometimes in the global fields description list (e.g. `['fields']`), sometimes in the fields description list of the view type (e.g. `['fields_views']['form']['fields']`), making it a pain to try to make changes / performance gain in these field description dictionaries, because you never knew in which dict the web client was getting its info. Now, as there is only one place to get the fields description from, it's clearer and cleaner. - one2many and many2many fields views are passed directly in the main view architecture rather than being put in the `views` key of the field description. This is actually easier to treat by the web client, and this will allow in a future work to cache an entire view in one block of text rather than having to combine multiple cached blocks of text to return one view. - one2many and many2many fields which do not have directly embedded views have their views directly injected in the architecture, so the web client doesn't have to do RPC calls to `load_views` for each one2many and many2many fields not having embedded views. For instance, this allow to reduce the number of RPC calls to `load_views` from 8 to 1 when loading the form of `product.product`. Currently, this behavior is limited to 1 level deep but we consider making it go all the way down in future works. We did not do it for the moment because in certain cases it rises the processing time and the size (bytes) too much. e.g. the sale.order view can be 5 levels deep, meaning you can reach 4 dialogs on top the main view. ``` sale.order form > order_line > sale.order.line form > invoice_lines > account.move.line form > asset_ids > account.asset form > depreciation_move_ids > account.move form. ``` This will also benefit in future works to cache an entire view in one block of text rather to having to combine multiple cached block of text to get one view. - `fields_view_get` becomes `get_view`. As it no longer returns the fields description, keeping the `fields` in the name `fields_view_get` no longer makes sense. Hence removing `fields` from the method name, it becomes `view_get`. As it gets renamed anyway, we take the opportunity to rename it `get_view`, which is more in line with the general getter/setter guidelines in the model object world. - `_fields_view_get` becomes `_get_view`. For the same reasons than above. - `load_views` becomes `get_views`. This is not mandatory, there is no technical reason to rename `load_views` as it practically sends the same info as before, the view architectures and their fields description. Just in another way. We just take the opportunity of this pull request to suggest a cleaner API: `_get_view`, `get_view` and `get_views`. - Arguments `toolbar=False, submenu=False` fo the methods `_fields_view_get` and `fields_view_get` are converted to a kwargs `**options` in `_get_view` and `get_view`. The rationale is that submenu was already no longer used (deprecated) and the mobile options is introduced. The mobile options is necessary to tell the server to send the mobile views for x2many fields (kanban instead of tree). Instead of adding a new argument each time we add a new option to `fields_view_get`, it seems wiser to have a kwargs `**options` to avoid to re-write all overrides each time a new option is introduced. - `_fields_view_get` returned a dict containing the arch in text and some of the view information. Now, `get_view` returns a tuple with the view architecture as an `etree` node, and the view as a browse record. The rationale is that all overrides of `_fields_view_get` were about modifying the arch only (e.g. changing the address format/re-organizing the address related field nodes of the partner according to the company country). To do so, all these overrides were doing `etree.fromstring` to parse the arch which was sent in text to convert it to an `etree`, then operations were done on the `etree`, and then `etree.tostring` was called to convert back the arch to string. With this change of signature to send the arch as an `etree`, all these back and forth `etree.fromstring` -> `etree.tostring` are avoided, allowing some performance gain and less code in the end. - A cleanup of the keys returned in the dict of `fields_view_get` has been performed in `get_view`: - `fields` is removed, as explained above, - `view_id` is renamed `id`, - `name` is removed, it was unused by the web client, - `type` is removed, it was unused by the web client, - `field_parent` is removed, it was unused by the web client, - `base_model` is removed, it was unused by the web client. - `filters` is moved from the global dict returned by `load_views` (now `get_views`) to the dict returned by `fields_view_get` (now `get_view`) as it applies only to the `search` view type. - Retro-compatible methods for the 3 methods `fields_view_get`, `_fields_view_get` and `load_views` are provided, with deprecation warnings in them. - The web client could cache the model fields description (as it already caches the views), so it doesn't need to fetch them again if it asks for another view of a model for which he already has the fields description. If we do so, `get_views` could return only the list of models used by the views, without the fields description as of now, and the web client would then call `fields_get` independently only for the models for which it doesn't have yet the fields description. This would avoid the server to return the fields description and to call `fields_get`, which is costly, for each `get_views`, therefore gaining performances. - Inject the views of the one2many and many2many fields all the way down, unlimited depth level, as explained above. - Cache with `ormcache` the architecture of back-end views. This is already done for qweb views, it's not done for back-end views. Therefore the postprocessing of the views is performed for each `get_views`, which is costly, while the view architecture doesn't change for users belonging to the same groups, according to the groups implied by the view. This pull request is co-authored by Aaron Bohy (aab) for the web client part and Denis Ledoux (dle) for the server part. Part-of: odoo/odoo#87522 |
||
|
|
55a6f2e996 |
[FIX] web_editor: catch errors during save and allow to fix it
Prior to this commit, when an exception occured during the save of an ir.ui.view, the traceback was shown to the user and an alert directly asks the user to reload or cancel the page. While reloading, the changes that produced the traceback were not saved and the other modifications were saved. If the user choose to cancel the reload, the web editor UI was freezed and there couldn't be any edition anymore. This commit adds correctly the popover to target the invalid element and shows the error rather than reloading the page. The element which caused the error can still be edited. The other are no more editable. task-2700198 closes odoo/odoo#87350 X-original-commit: 10b97f37ab5d78b3a2b0f63fa019ee95bb78ea7d Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com> Signed-off-by: Thibault Libioulle (tle) <tle@odoo.com> |
||
|
|
ca4fe12a37 |
[IMP] base: rename var option into compile_context
In order to make it easier to understand the code of qweb. Part-of: odoo/odoo#85110 |
||
|
|
f41ec39abe |
[IMP] base: get_view_id becomes private
Add new helper get_view Remove dangerous documented comment Part-of: odoo/odoo#85110 |
||
|
|
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 |
||
|
|
2a3d8dd1c2 |
[MOV] various: move ir.qweb.fields code into right files
When working on qweb fields it is difficult to find some custom override as they are never in the right file. Finding them is always a bit of random pick. Task-2607416 Part-of: odoo/odoo#74171 |