Skip to content

Commit

Permalink
[FIX] website: decode special characters of website form
Browse files Browse the repository at this point in the history
Steps to reproduce:
- Add a form on the website.
- Add a field and put `test"` as label.
- Save and send the form.

-> `test"` is displayed in the received mail.

Since [1] (and [2]), some characters are escaped when the user changes
the label of a field. The problem appeared since [3] where fields are
escaped on the server side upon form reception. Indeed, here is what
happens at form reception; the already escaped `test"` is stored as
`test"` in the database. Due to it, the mail displayed contains
`test"` while `test"` is wanted. To solve the problem, the
characters encoded at label change in the client side are decoded on the
server side before the form is processed. This is done at the server
side as we still encode client-side since it appears that if a form is
sent with an input that has a `"` character in its `name` attribute, it
is received as `%22` server side (see previous commit in-code comment
for details).

[1]: odoo@ccaf4f1
[2]: odoo@03f230a
[3]: odoo@db62d8c

task-3510450

closes odoo#135797

Signed-off-by: Quentin Smetz (qsm) <[email protected]>
  • Loading branch information
loco-odoo authored and qsm-odoo committed Apr 25, 2024
1 parent a0f3ed5 commit 0b2b5ef
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
11 changes: 11 additions & 0 deletions addons/website/controllers/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import base64
import json
import re

from markupsafe import escape
from psycopg2 import IntegrityError
Expand Down Expand Up @@ -157,6 +158,16 @@ def extract_data(self, model, values):
custom_fields = []

for field_name, field_value in values.items():
# First decode the field_name encoded at the client side.
html_entities = {
'&quot;': '"',
'&apos;': "'",
'&lsquo;': '`',
'&bsol;': '\\',
}
pattern = '|'.join(html_entities.keys())
field_name = re.sub(pattern, lambda match: html_entities[match.group(0)], field_name)

# If the value of the field if a file
if hasattr(field_value, 'filename'):
# Undo file upload field name indexing
Expand Down
52 changes: 52 additions & 0 deletions addons/website/static/tests/tours/website_form_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1067,5 +1067,57 @@ odoo.define('website.tour.form_editor', function (require) {
},
]);

tour.register("website_form_special_characters", {
test: true,
}, [
{
content: "Enter edit mode",
trigger: "a[data-action=edit]",
}, {
content: "Check that we are in edit mode",
trigger: "#oe_snippets.o_loaded",
run: () => null,
}, {
content: "Drop the form snippet",
trigger: "#oe_snippets .oe_snippet:has(.s_website_form) .oe_snippet_thumbnail",
run: "drag_and_drop #wrap",
}, {
content: "Select form by clicking on an input field",
extra_trigger: ".s_website_form_field",
trigger: "section.s_website_form input",
},
...addCustomField("char", "text", `Test1"'`, false),
...addCustomField("char", "text", 'Test2`\\', false),
{
content: "Save the page",
trigger: "button[data-action=save]",
},
{
content: "Wait for page reload",
trigger: "body:not(.editor_enable) [data-snippet='s_website_form']",
},
...essentialFieldsForDefaultFormFillInSteps,
{
content: "Complete 'Your Question' field",
trigger: "textarea[name='description']",
run: "text test",
}, {
content: "Complete the first added field",
trigger: "input[name='Test1&quot;&apos;']",
run: "text test1",
}, {
content: "Complete the second added field",
trigger: "input[name='Test2&lsquo;&bsol;']",
run: "text test2",
}, {
content: "Click on 'Submit'",
trigger: "a.s_website_form_send",
}, {
content: "Check the form was again sent (success page without form)",
trigger: "body:not(:has([data-snippet='s_website_form'])) .fa-check-circle",
run: () => null,
},
]);

return {};
});
6 changes: 6 additions & 0 deletions addons/website/tests/test_website_form_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ def test_contactus_form_email_stay_dynamic(self):
def test_website_form_editable_content(self):
self.start_tour('/', 'website_form_editable_content', login="admin")

def test_website_form_special_characters(self):
self.start_tour('/', 'website_form_special_characters', login='admin')
mail = self.env['mail.mail'].search([], order='id desc', limit=1)
self.assertIn('Test1&#34;&#39;', mail.body_html, 'The single quotes and double quotes characters should be visible on the received mail')
self.assertIn('Test2`\\', mail.body_html, 'The backtick and backslash characters should be visible on the received mail')


@tagged('post_install', '-at_install')
class TestWebsiteForm(TransactionCase):
Expand Down

0 comments on commit 0b2b5ef

Please sign in to comment.