Skip to content

Commit 6aee367

Browse files
authored
Merge branch 'main' into updated
2 parents 51845bd + 0b037a0 commit 6aee367

File tree

22 files changed

+726
-237
lines changed

22 files changed

+726
-237
lines changed

.github/workflows/codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
dj51_cms41.txt,
2121
]
2222
os: [
23-
ubuntu-20.04,
23+
ubuntu-latest,
2424
]
2525
exclude:
2626
- python-version: 3.9

CHANGELOG.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22
Changelog
33
=========
44

5+
0.3.2 (2025-03-04)
6+
==================
7+
8+
* fix: Action tab failed form validation if djangocms-link was installed
9+
10+
0.3.1 (2025-03-03)
11+
==================
12+
13+
* fix: Send mail action failed by @fsbraun in https://github.com/django-cms/djangocms-form-builder/pull/21
14+
* fix: Correct send_mail recipients parameter in action.py by @fdik in https://github.com/django-cms/djangocms-form-builder/pull/22
15+
* docs: Update Codecov link in README.rst by @fsbraun in https://github.com/django-cms/djangocms-form-builder/pull/23
16+
* fix: prevent duplicate submit buttons in forms by @earthcomfy in https://github.com/django-cms/djangocms-form-builder/pull/27
17+
18+
* @fdik made their first contribution in https://github.com/django-cms/djangocms-form-builder/pull/22
19+
* @earthcomfy made their first contribution in https://github.com/django-cms/djangocms-form-builder/pull/27
20+
21+
522
0.3.0 (2025-01-07)
623
==================
724

djangocms_form_builder/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
_ = lambda x: x # noqa: E731
77

88

9-
__version__ = "0.3.0"
9+
__version__ = "0.3.2"
1010

1111
_form_registry = {}
1212

djangocms_form_builder/actions.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,16 @@ def get_action_class(action):
5656
return _action_registry.get(action, None)
5757

5858

59+
def get_hash(action_class):
60+
return hashlib.sha1(action_class.__name__.encode("utf-8")).hexdigest()
61+
62+
5963
class ActionMixin:
6064
"""Adds action form elements to Form plugin admin"""
6165

6266
def get_form(self, request, *args, **kwargs):
6367
"""Creates new form class based adding the actions as mixins"""
64-
return type(
65-
"FormActionAdminForm",
66-
(self.form, *_action_registry.values()),
67-
{}
68-
)
68+
return type("FormActionAdminForm", (self.form, *_action_registry.values()), {})
6969

7070
def get_fieldsets(self, request, obj=None):
7171
fieldsets = super().get_fieldsets(request, obj)
@@ -79,7 +79,7 @@ def get_fieldsets(self, request, obj=None):
7979
block=None,
8080
position=-1,
8181
blockname=action.verbose_name,
82-
blockattrs=dict(classes=(hash, 'action-hide')),
82+
blockattrs=dict(classes=(f"c{hash}", "action-hide")),
8383
)
8484
return fieldsets
8585

@@ -126,7 +126,7 @@ def execute(self, form, request):
126126
keys = {}
127127
defaults = {
128128
"form_name": get_option(form, "form_name"),
129-
"form_user": None if request.user.is_anonymous else request.user
129+
"form_user": None if request.user.is_anonymous else request.user,
130130
}
131131
defaults.update(
132132
{
@@ -153,7 +153,9 @@ def execute(self, form, request):
153153
def validate_recipients(value):
154154
recipients = value.split()
155155
for recipient in recipients:
156-
EmailValidator(message=_("Please replace \"%s\" by a valid email address.") % recipient)(recipient)
156+
EmailValidator(
157+
message=_('Please replace "%s" by a valid email address.') % recipient
158+
)(recipient)
157159

158160

159161
@register
@@ -199,17 +201,25 @@ def execute(self, form, request):
199201
cleaned_data=form.cleaned_data,
200202
form_name=getattr(form.Meta, "verbose_name", ""),
201203
user=request.user,
202-
user_agent=request.headers["User-Agent"] if "User-Agent" in request.headers else "",
204+
user_agent=request.headers["User-Agent"]
205+
if "User-Agent" in request.headers
206+
else "",
203207
referer=request.headers["Referer"] if "Referer" in request.headers else "",
204208
)
205209

206-
html_message = render_to_string(f"djangocms_form_builder/mails/{template_set}/mail_html.html", context)
210+
html_message = render_to_string(
211+
f"djangocms_form_builder/mails/{template_set}/mail_html.html", context
212+
)
207213
try:
208-
message = render_to_string(f"djangocms_form_builder/mails/{template_set}/mail.txt", context)
214+
message = render_to_string(
215+
f"djangocms_form_builder/mails/{template_set}/mail.txt", context
216+
)
209217
except TemplateDoesNotExist:
210218
message = strip_tags(html_message)
211219
try:
212-
subject = render_to_string(f"djangocms_form_builder/mails/{template_set}/subject.txt", context)
220+
subject = render_to_string(
221+
f"djangocms_form_builder/mails/{template_set}/subject.txt", context
222+
)
213223
except TemplateDoesNotExist:
214224
subject = self.subject % dict(form_name=context["form_name"])
215225

@@ -254,7 +264,9 @@ def execute(self, form, request):
254264
message = self.get_parameter(form, "submitmessage_message")
255265
# Overwrite the success context and render template
256266
form.get_success_context = lambda *args, **kwargs: {"message": message}
257-
form.Meta.options["render_success"] = "djangocms_form_builder/actions/submit_message.html"
267+
form.Meta.options["render_success"] = (
268+
"djangocms_form_builder/actions/submit_message.html"
269+
)
258270
# Overwrite the default redirect to same page
259271
if form.Meta.options.get("redirect") == SAME_PAGE_REDIRECT:
260272
form.Meta.options["redirect"] = None
@@ -280,5 +292,12 @@ class Meta:
280292
required=True,
281293
)
282294

295+
def __init__(self, *args, **kwargs):
296+
super().__init__(*args, **kwargs)
297+
if args:
298+
self.fields["redirect_link"].required = get_hash(RedirectAction) in args[0].get("form_actions", [])
299+
283300
def execute(self, form, request):
284-
form.Meta.options["redirect"] = get_link(self.get_parameter(form, "redirect_link"))
301+
form.Meta.options["redirect"] = get_link(
302+
self.get_parameter(form, "redirect_link")
303+
)

djangocms_form_builder/cms_plugins/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
EmailFieldPlugin,
1111
IntegerFieldPlugin,
1212
SelectPlugin,
13+
SubmitPlugin,
1314
TextareaPlugin,
1415
TimeFieldPlugin,
1516
URLFieldPlugin,
@@ -26,6 +27,7 @@
2627
"EmailFieldPlugin",
2728
"IntegerFieldPlugin",
2829
"SelectPlugin",
30+
"SubmitPlugin",
2931
"TextareaPlugin",
3032
"TimeFieldPlugin",
3133
"URLFieldPlugin",

djangocms_form_builder/cms_plugins/ajax_plugins.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,24 @@ def render(self, context, instance, placeholder):
240240
form = self.get_ajax_form()
241241
context.update(self.set_context(context, instance, placeholder))
242242
context["form_counter"] = context.get("form_counter", 0) + 1
243-
context.update({
244-
"instance": instance,
245-
"form": form,
246-
"uid": f"{instance.id}{getattr(form, 'slug', '')}-{context['form_counter']}",
247-
})
243+
244+
def has_submit_button(plugins):
245+
for child in plugins:
246+
if child.plugin_type == "SubmitPlugin":
247+
return True
248+
child_plugins = getattr(child, "child_plugin_instances", None) or []
249+
if has_submit_button(child_plugins):
250+
return True
251+
return False
252+
253+
context.update(
254+
{
255+
"instance": instance,
256+
"form": form,
257+
"uid": f"{instance.id}{getattr(form, 'slug', '')}-{context['form_counter']}",
258+
"has_submit_button": has_submit_button(instance.child_plugin_instances),
259+
}
260+
)
248261
return context
249262

250263

@@ -290,7 +303,9 @@ def get_parent_classes(cls, slot, page, instance=None):
290303

291304
def get_fieldsets(self, request, obj=None):
292305
fieldsets = super().get_fieldsets(request, obj)
293-
if obj is None or not obj.form_selection: # No Actions if a Django form has been selected
306+
if (
307+
obj is None or not obj.form_selection
308+
): # No Actions if a Django form has been selected
294309
fieldsets = insert_fields(
295310
fieldsets,
296311
("form_actions",),
@@ -362,22 +377,28 @@ def traverse(instance):
362377
meta_options = dict(form_name=self.instance.form_name)
363378
if self.instance.form_floating_labels:
364379
meta_options["floating_labels"] = True
365-
meta_options[
366-
"field_sep"
367-
] = f'{self.instance.form_spacing}'
368-
meta_options[
369-
"redirect"
370-
] = SAME_PAGE_REDIRECT # Default behavior: redirect to same page
380+
meta_options["field_sep"] = f"{self.instance.form_spacing}"
381+
meta_options["redirect"] = (
382+
SAME_PAGE_REDIRECT # Default behavior: redirect to same page
383+
)
371384
meta_options["login_required"] = self.instance.form_login_required
372385
meta_options["unique"] = self.instance.form_unique
373386
form_actions = self.instance.form_actions or "[]"
374387
meta_options["form_actions"] = json.loads(form_actions.replace("'", '"'))
375-
meta_options["form_parameters"] = getattr(self.instance, "action_parameters", {})
388+
meta_options["form_parameters"] = getattr(
389+
self.instance, "action_parameters", {}
390+
)
376391

377-
fields["Meta"] = type("Meta", (), dict(
378-
options=meta_options,
379-
verbose_name=self.instance.form_name.replace("-", " ").replace("_", " ").capitalize(),
380-
)) # Meta class with options and verbose name
392+
fields["Meta"] = type(
393+
"Meta",
394+
(),
395+
dict(
396+
options=meta_options,
397+
verbose_name=self.instance.form_name.replace("-", " ")
398+
.replace("_", " ")
399+
.capitalize(),
400+
),
401+
) # Meta class with options and verbose name
381402

382403
return type(
383404
"FrontendAutoForm",

djangocms_form_builder/cms_plugins/form_plugins.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ class FormElementPlugin(AttributesMixin, CMSPluginBase):
1919
render_template = f"djangocms_form_builder/{settings.framework}/widgets/base.html"
2020
change_form_template = "djangocms_frontend/admin/base.html"
2121
settings_name = _("Settings")
22+
# Form elements are rendered by the surrounding FormPlugin, hence any change has to be
23+
# propageted up to the FormPlugin:
24+
is_local = False
2225

2326
fieldsets = (
2427
(

djangocms_form_builder/cms_plugins/legacy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from cms.plugin_pool import plugin_pool
22
from django.conf import settings
33

4-
if 'djangocms_frontend.contrib.frontend_forms' in settings.INSTALLED_APPS:
4+
if "djangocms_frontend.contrib.frontend_forms" in settings.INSTALLED_APPS:
55
from djangocms_frontend.contrib.frontend_forms.cms_plugins import (
66
BooleanFieldPlugin,
77
CharFieldPlugin,

0 commit comments

Comments
 (0)