Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/collective/volto/formsupport/adapters/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
import os


GLOBAL_FORM_REGISTRY_RECORD_ID = (
"collective.volto.formsupport.interfaces.IGlobalFormStore.global_forms_config"
)


@implementer(IPostAdapter)
@adapter(Interface, Interface)
class PostAdapter:
Expand All @@ -29,8 +34,12 @@ def __init__(self, context, request):
self.request = request
self.form_data = self.extract_data_from_request()
self.block_id = self.form_data.get("block_id", "")
self.global_form_id = self.extract_data_from_request().get("global_form_id", "")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.global_form_id = self.extract_data_from_request().get("global_form_id", "")
self.global_form_id = self.form_data.get("global_form_id", "")

if self.block_id:
self.block = self.get_block_data(block_id=self.block_id)
self.block = self.get_block_data(
block_id=self.block_id,
global_form_id=self.form_data.get("global_form_id"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
global_form_id=self.form_data.get("global_form_id"),
global_form_id=self.global_form_id,

)

def __call__(self):
"""
Expand All @@ -50,7 +59,10 @@ def extract_data_from_request(self):
fixed_fields = []
transforms = api.portal.get_tool(name="portal_transforms")

block = self.get_block_data(block_id=form_data.get("block_id", ""))
block = self.get_block_data(
block_id=form_data.get("block_id", ""),
global_form_id=form_data.get("global_form_id"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
global_form_id=form_data.get("global_form_id"),
global_form_id=self.global_form_id,

)
block_fields = [x.get("field_id", "") for x in block.get("subblocks", [])]

for form_field in form_data.get("data", []):
Expand All @@ -68,12 +80,24 @@ def extract_data_from_request(self):

return form_data

def get_block_data(self, block_id):
def get_block_data(self, block_id, global_form_id):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably you don't need to pass global_form_id as parameter because is already set in init

blocks = get_blocks(self.context)
global_form_id = global_form_id
if global_form_id:
global_forms = api.portal.get_registry_record(
GLOBAL_FORM_REGISTRY_RECORD_ID
)
if global_forms:
blocks = {**blocks, **global_forms}
if not blocks:
return {}
for id, block in blocks.items():
if id != block_id:
# Prefer local forms it they're available, fall back to global form
if (
id != block_id
and id != global_form_id
and block.get("global_form_id") != global_form_id
):
continue
block_type = block.get("@type", "")
if block_type != "form":
Expand Down
8 changes: 8 additions & 0 deletions src/collective/volto/formsupport/interfaces.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from plone.restapi.controlpanels.interfaces import IControlpanel
from plone.schema import JSONField
from zope.interface import Attribute
from zope.interface import Interface
from zope.interface.interfaces import IObjectEvent
Expand Down Expand Up @@ -69,3 +71,9 @@ def data():
class IDataAdapter(Interface):
def __call__(result, block_id=None):
pass


class IGlobalFormStore(IControlpanel):
global_forms_config = JSONField(
title="Global forms", description="", required=True, default={}
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<metadata>
<version>1301</version>
<version>1302</version>
<dependencies>
<dependency>profile-collective.volto.otp:default</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
>

<!-- -*- extra stuff goes here -*- -->
<records interface="collective.volto.formsupport.interfaces.IGlobalFormStore" />

</registry>
23 changes: 23 additions & 0 deletions src/collective/volto/formsupport/restapi/deserializer/blocks.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
from plone.api.portal import get_registry_record
from plone.api.portal import set_registry_record
from plone.dexterity.interfaces import IDexterityContent
from plone.restapi.bbb import IPloneSiteRoot
from plone.restapi.interfaces import IBlockFieldDeserializationTransformer
from Products.PortalTransforms.transforms.safe_html import SafeHTML
from uuid import uuid4
from zope.component import adapter
from zope.interface import implementer
from zope.publisher.interfaces.browser import IBrowserRequest


GLOBAL_FORM_REGISTRY_RECORD_ID = (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be a good idea moving this constant in a common place and import it also in post adapter?

"collective.volto.formsupport.interfaces.IGlobalFormStore.global_forms_config"
)


def update_global_forms(value):
global_form_id = value.get("global_form_id")

if not global_form_id:
global_form_id = str(uuid4())

global_forms_record = get_registry_record(GLOBAL_FORM_REGISTRY_RECORD_ID)
global_forms_record[global_form_id] = value
set_registry_record(GLOBAL_FORM_REGISTRY_RECORD_ID, global_forms_record)

value["global_form_id"] = global_form_id
return value


class FormBlockDeserializerBase:
"""FormBlockDeserializerBase."""

Expand All @@ -25,6 +47,7 @@ def __call__(self, value):
if value.get("send_message", ""):
transform = SafeHTML()
value["send_message"] = transform.scrub_html(value["send_message"])
value = update_global_forms(value)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me better understand this..when you deserialize the block, you are storing its data twice: in the context and in registry, right?
So if the block is in a context, its data is duplicated? Or am i missing something?

I'm not a big fan of this approach, but i don't know if there is a better way to do it, or avoid setting it globally when we are working on a content item.

Or (maybe better): store form data always in registry, and in the content, only store the block_id reference. What do you think about it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think storing both the saved data and the schema on the root object is the way to go, regardless of if there is a local page context or not. Then it's one implementation so less complicated.
This would mean that

  • its possible to move a form between pages and keep the data
  • it's possible have two forms that submit to the same savedata. For example a slightly altered one with extra info for logged in users
  • it's possible to have a control panel that lets you view all saved data globally and remove it. giving some kind of audibility to collected data.
    • but this does have implications for permissions. because then a private form on a private page is no longer private...

return value


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ def __init__(self, context, request):
self.form_data_adapter = getMultiAdapter(
(self.context, self.request), IPostAdapter
)
self.form_data = self.get_form_data()
self.block_id = self.form_data.get("block_id", "")

if self.block_id:
self.block = self.get_block_data(block_id=self.block_id)
# We've already done all the work to get this data, let's reuse it.
self.form_data = self.form_data_adapter.form_data
self.block_id = self.form_data_adapter.block_id
self.block = self.form_data_adapter.block

def reply(self):
store_action = self.block.get("store", False)
Expand Down
8 changes: 8 additions & 0 deletions src/collective/volto/formsupport/upgrades.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@
handler=".upgrades.to_1301"
/>

<genericsetup:upgradeDepends
title="Add global form registry entry"
profile="collective.volto.formsupport:default"
source="1301"
destination="1302"
import_steps="plone.app.registry"
/>

</configure>
Loading