diff --git a/cypress/integration/web_form.js b/cypress/integration/web_form.js index e9cd8100a7..c93593908d 100644 --- a/cypress/integration/web_form.js +++ b/cypress/integration/web_form.js @@ -87,6 +87,10 @@ context("Web Form", () => { cy.visit("/app/web-form/note"); cy.findByRole("tab", { name: "Settings" }).click(); + + cy.wait(100); + cy.get(".section-head").contains("List Settings").scrollIntoView(); + cy.fill_field("list_title", "Note List"); cy.save(); diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json index 9509ceae0a..bae6b6e46a 100644 --- a/frappe/website/doctype/web_form/web_form.json +++ b/frappe/website/doctype/web_form/web_form.json @@ -17,22 +17,25 @@ "introduction_text", "web_form_fields", "settings_tab", - "login_required", - "allow_multiple", - "allow_edit", - "allow_delete", + "access_control_section", "anonymous", - "hide_navbar", - "hide_footer", + "login_required", "column_break_2", "apply_document_permissions", + "allow_edit", + "allow_multiple", + "allow_delete", + "form_settings_section", + "allow_incomplete", + "allow_comments", "allow_print", "print_format", - "allow_comments", - "show_attachments", - "allow_incomplete", - "section_break_2", "max_attachment_size", + "show_attachments", + "column_break_hhec", + "hide_navbar", + "hide_footer", + "allowed_embedding_domains", "condition_section", "condition_description", "condition_json", @@ -181,27 +184,28 @@ "options": "Web Form Field" }, { + "description": "Set size in MB", "fieldname": "max_attachment_size", "fieldtype": "Int", - "label": "Max Attachment Size (in MB)" + "label": "Max attachment size" }, { "description": "For help see Client Script API and Examples", "fieldname": "client_script", "fieldtype": "Code", - "label": "Client Script" + "label": "Client script" }, { "default": "Save", "fieldname": "button_label", "fieldtype": "Data", - "label": "Submit Button Label" + "label": "Submit button label" }, { "description": "Message to be displayed on successful completion", "fieldname": "success_message", "fieldtype": "Text", - "label": "Success Message" + "label": "Success message" }, { "description": "Go to this URL after completing the form", @@ -263,7 +267,7 @@ { "fieldname": "list_setting_message", "fieldtype": "HTML", - "label": "List Setting Message" + "label": "List setting message" }, { "fieldname": "customization_tab", @@ -273,7 +277,7 @@ { "fieldname": "success_title", "fieldtype": "Data", - "label": "Success Title" + "label": "Success title" }, { "fieldname": "banner_image", @@ -298,10 +302,6 @@ "fieldname": "column_break_2", "fieldtype": "Column Break" }, - { - "fieldname": "section_break_2", - "fieldtype": "Section Break" - }, { "collapsible": 1, "collapsible_depends_on": "show_list", @@ -349,12 +349,12 @@ { "fieldname": "meta_title", "fieldtype": "Data", - "label": "Meta Title" + "label": "Meta title" }, { "fieldname": "meta_description", "fieldtype": "Small Text", - "label": "Meta Description" + "label": "Meta description" }, { "fieldname": "column_break_khxs", @@ -363,7 +363,7 @@ { "fieldname": "meta_image", "fieldtype": "Attach Image", - "label": "Meta Image" + "label": "Meta image" }, { "fieldname": "column_break_vdhm", @@ -371,14 +371,15 @@ }, { "default": "0", + "description": "If enabled, all responses on the web form will be submitted anonymously", "fieldname": "anonymous", "fieldtype": "Check", - "label": "Anonymous" + "label": "Anonymous responses" }, { "fieldname": "condition_description", "fieldtype": "HTML", - "label": "Condition Description", + "label": "Condition description", "options": "

Multiple webforms can be created for a single doctype. Add filters specific to this webform to display correct record after submission.

For Example:

\n

If you create a separate webform every year to capture feedback from employees add a \n field named year in doctype and add a filter year = 2023

\n" }, { @@ -401,13 +402,33 @@ "fieldname": "hide_footer", "fieldtype": "Check", "label": "Hide footer" + }, + { + "description": "Specify the domains or origins that are permitted to embed this form. Enter one domain per line (e.g., https://example.com). If no domains are specified, the form can only be embedded on the same origin.", + "fieldname": "allowed_embedding_domains", + "fieldtype": "Small Text", + "label": "Allowed embedding domains" + }, + { + "fieldname": "access_control_section", + "fieldtype": "Section Break", + "label": "Access Control" + }, + { + "fieldname": "form_settings_section", + "fieldtype": "Section Break", + "label": "Form Settings" + }, + { + "fieldname": "column_break_hhec", + "fieldtype": "Column Break" } ], "has_web_view": 1, "icon": "icon-edit", "is_published_field": "published", "links": [], - "modified": "2024-09-11 14:28:39.391595", + "modified": "2024-10-21 12:04:47.314849", "modified_by": "Administrator", "module": "Website", "name": "Web Form", diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index 03c87b68e7..3c52f4af5b 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -34,6 +34,7 @@ class WebForm(WebsiteGenerator): allow_incomplete: DF.Check allow_multiple: DF.Check allow_print: DF.Check + allowed_embedding_domains: DF.SmallText | None anonymous: DF.Check apply_document_permissions: DF.Check banner_image: DF.AttachImage | None diff --git a/frappe/website/page_renderers/web_form.py b/frappe/website/page_renderers/web_form.py index 74996e4a78..2567451bd3 100644 --- a/frappe/website/page_renderers/web_form.py +++ b/frappe/website/page_renderers/web_form.py @@ -1,3 +1,4 @@ +import frappe from frappe.website.page_renderers.document_page import DocumentPage from frappe.website.router import get_page_info_from_web_form @@ -8,6 +9,14 @@ class WebFormPage(DocumentPage): if web_form: self.doctype = "Web Form" self.docname = web_form.name + self.set_headers() return True else: return False + + def set_headers(self): + doc = frappe.get_cached_doc(self.doctype, self.docname) + allowed_embedding_domains = doc.allowed_embedding_domains + if allowed_embedding_domains: + allowed_embedding_domains = allowed_embedding_domains.replace("\n", " ") + self.headers = {"Content-Security-Policy": f"frame-ancestors 'self' {allowed_embedding_domains}"}