Porównaj commity
11 Commity
Autor | SHA1 | Data |
---|---|---|
mtyton | f8f3d35935 | |
mtyton | 6bc385e47d | |
mtyton | 345dbe3f46 | |
mtyton | a5e243c55c | |
mtyton | 1ab8537c64 | |
mtyton | d365a1ee98 | |
mtyton | 19078bd03f | |
mtyton | dd0998b96b | |
mtyton | b07561d34c | |
mtyton | 80ddd65ea6 | |
mtyton | c762438439 |
|
@ -139,8 +139,8 @@ GitHub.sublime-settings
|
|||
#postgres pass files
|
||||
*.my_pgpass
|
||||
*.sql
|
||||
artel/static/
|
||||
wagtail_store/static/
|
||||
|
||||
# media
|
||||
artel/media/*
|
||||
artel/store/data/*
|
||||
wagtail_store/media/*
|
||||
wagtail_store/store/data/*
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
{% load static %}
|
||||
{% load menu_tags %}
|
||||
{% load wagtailcore_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-shrink-0 p-3 mr-5">
|
||||
<img src="{{logo}}" class="img-fluid rounded mx-auto d-block mt-3" style="width: 10rem; height: 10 rem;" alt="Portal Logo"/>
|
||||
<hr>
|
||||
<ul class="nav navbar-nav">
|
||||
|
||||
{% for item in menu_items %}
|
||||
<li class="{{ item.active_class }}">
|
||||
<a href="{{ item.href }}">{{ item.text }}</a>
|
||||
{% if item.has_children_in_menu %}
|
||||
<button class="btn btn-toggle" data-bs-target="#ddtoggle_{{ item.link_page.pk }}" data-bs-toggle="collapse"
|
||||
aria-expanded={% if item.active_class %}"true" {% else %} "false" {% endif %}
|
||||
aria-controls="#ddtoggle_{{ item.link_page.pk }}">
|
||||
<img src = "{% static 'images/icons/caret-down.svg' %}" alt="∨"/> </button>
|
||||
{% sub_menu item template="menu/custom_submenu.html" %}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="d-flex flex-column flex-shrink-0 p-3 mr-5">
|
||||
<hr>
|
||||
{% if shop_enabled %}
|
||||
<a href={% url 'cart' %} alt="Koszyk" >{% trans "Cart" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
|
@ -1,7 +0,0 @@
|
|||
{% load menu_tags %}
|
||||
<ul class={% if item.active_class %} "sub-menu collapse show fw-normal pb-1 small" {% else %} "sub-menu collapse fw-normal pb-1 small" {% endif %}
|
||||
id="ddtoggle_{{ item.link_page.pk }}">
|
||||
{% for sub_item in menu_items %}
|
||||
<li><a href="{{ sub_item.href }}" class="{{ sub_item.active_class }}">{{ sub_item.text }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
|
@ -1,32 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load wagtailcore_tags wagtailimages_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ page.title }}</h1>
|
||||
<p class="meta">{{ page.date }}</p>
|
||||
{% if form %}
|
||||
<div>{{ page.intro|richtext }}</div>
|
||||
<form enctype="multipart/form-data" action="{% pageurl page %}" method="POST">
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
<div class="form-group mt-3">
|
||||
<label for="{{field.id}}" class="form-label">
|
||||
{% trans field.label %}
|
||||
</label>
|
||||
{{field}}
|
||||
<small id="emailHelp" class="form-text text-muted">
|
||||
{% trans field.help_text %}
|
||||
</small>
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="text-end mt-3">
|
||||
<input class="btn btn-lg btn-success" type="submit" value='{% trans "Submit" %}'>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div>You can fill in the from only one time.</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -25,6 +25,9 @@ services:
|
|||
ports:
|
||||
- "5672:5672" # We forward this port because it's useful for debugging
|
||||
- "15672:15672" # Here, we can access RabbitMQ management plugin
|
||||
networks:
|
||||
- nginx_network
|
||||
|
||||
|
||||
comfy:
|
||||
build:
|
||||
|
@ -77,6 +80,9 @@ services:
|
|||
depends_on:
|
||||
- comfy
|
||||
- rabbit
|
||||
- db
|
||||
networks:
|
||||
- nginx_network
|
||||
|
||||
worker:
|
||||
build:
|
||||
|
@ -94,7 +100,10 @@ services:
|
|||
depends_on:
|
||||
- comfy
|
||||
- rabbit
|
||||
- db
|
||||
- beat
|
||||
networks:
|
||||
- nginx_network
|
||||
|
||||
networks:
|
||||
nginx_network:
|
|
@ -20,9 +20,9 @@ services:
|
|||
environment:
|
||||
- RABBITMQ_DEFAULT_USER
|
||||
- RABBITMQ_DEFAULT_PASS
|
||||
ports:
|
||||
- "5672:5672" # We forward this port because it's useful for debugging
|
||||
- "15672:15672" # Here, we can access RabbitMQ management plugin
|
||||
# ports:
|
||||
# - "5672:5672" # We forward this port because it's useful for debugging
|
||||
# - "15672:15672" # Here, we can access RabbitMQ management plugin
|
||||
|
||||
smtp-server:
|
||||
image: mailhog/mailhog
|
|
@ -1,4 +1,9 @@
|
|||
from django import forms
|
||||
from dynamic_forms.widgets import (
|
||||
CheckboxSelectMultiple,
|
||||
CheckboxInput,
|
||||
RadioSelect
|
||||
)
|
||||
|
||||
|
||||
class MultipleFileInput(forms.ClearableFileInput):
|
||||
|
@ -19,6 +24,23 @@ class MultipleFileField(forms.FileField):
|
|||
return result
|
||||
|
||||
|
||||
class HoneypotField(forms.BooleanField):
|
||||
default_widget = forms.HiddenInput(
|
||||
{'style': 'display:none !important;', 'tabindex': '-1', 'autocomplete': 'off'}
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('widget', HoneypotField.default_widget)
|
||||
kwargs['required'] = False
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if cleaned_value := super().clean(value):
|
||||
raise forms.ValidationError('')
|
||||
else:
|
||||
return cleaned_value
|
||||
|
||||
|
||||
class DynamicForm(forms.Form):
|
||||
|
||||
FIELD_TYPE_MAPPING = {
|
||||
|
@ -27,11 +49,11 @@ class DynamicForm(forms.Form):
|
|||
"email": forms.EmailField(max_length=255, widget=forms.EmailInput(attrs={"class": "form-control"})),
|
||||
"number": forms.IntegerField(widget=forms.NumberInput(attrs={"class": "form-control"})),
|
||||
"url": forms.URLField(max_length=255, widget=forms.URLInput(attrs={"class": "form-control"})),
|
||||
"checkbox": forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={"class": "form-control"})),
|
||||
"checkboxes": forms.MultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple(attrs={"class": "form-control"})),
|
||||
"checkbox": forms.BooleanField(required=False, widget=CheckboxInput(attrs={"class": "form-check"})),
|
||||
"checkboxes": forms.MultipleChoiceField(required=False, widget=CheckboxSelectMultiple(attrs={"class": "form-check"})),
|
||||
"dropdown": forms.ChoiceField(widget=forms.Select(attrs={"class": "form-control"})),
|
||||
"multiselect": forms.MultipleChoiceField(widget=forms.SelectMultiple(attrs={"class": "form-control"})),
|
||||
"radio": forms.ChoiceField(widget=forms.RadioSelect(attrs={"class": "form-control"})),
|
||||
"radio": forms.ChoiceField(widget=RadioSelect(attrs={"class": "form-control"})),
|
||||
"date": forms.DateField(widget=forms.DateInput(attrs={"class": "form-control"})),
|
||||
"datetime": forms.DateTimeField(widget=forms.DateTimeInput(attrs={"class": "form-control"})),
|
||||
"hidden": forms.CharField(widget=forms.HiddenInput()),
|
||||
|
@ -49,6 +71,7 @@ class DynamicForm(forms.Form):
|
|||
if hasattr(f, "choices"):
|
||||
f.choices = [(v, v) for v in field.choices.split(",")]
|
||||
f.required = field.required
|
||||
f.help_text = field.help_text or ""
|
||||
self.fields[field.clean_name] = f
|
||||
if file_uploads:
|
||||
self.fields["attachments"] = MultipleFileField(
|
||||
|
@ -56,3 +79,21 @@ class DynamicForm(forms.Form):
|
|||
attrs={"class": "form-control"}
|
||||
)
|
||||
)
|
||||
# add honeypot field
|
||||
self.fields["secret_honey"] = HoneypotField()
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
new_cleaned_data = {}
|
||||
for key, value in cleaned_data.items():
|
||||
if isinstance(value, list):
|
||||
if isinstance(self.fields[key], MultipleFileField):
|
||||
continue
|
||||
|
||||
cleaned_data[key] = ",".join(value)
|
||||
if key=="secret_honey":
|
||||
continue
|
||||
|
||||
new_cleaned_data[key] = value
|
||||
|
||||
return new_cleaned_data
|
|
@ -59,7 +59,12 @@ class Form(FormMixin, Page):
|
|||
|
||||
|
||||
class EmailFormSubmission(AbstractFormSubmission):
|
||||
|
||||
|
||||
# TODO - make this optional, allow to set pattern in admin
|
||||
def get_submission_id(self, form_slug):
|
||||
case_number_daily = EmailFormSubmission.objects.filter(submit_time__date=datetime.date.today()).count()
|
||||
return f"{form_slug}-{datetime.date.today()}-{case_number_daily}"
|
||||
|
||||
def send_mail(self, data):
|
||||
# modify this, get proper template
|
||||
to_addresses = data.pop("to_address").split(",")
|
||||
|
@ -69,7 +74,8 @@ class EmailFormSubmission(AbstractFormSubmission):
|
|||
)
|
||||
for file in data.pop("attachments", [])
|
||||
]
|
||||
subject = data.get("subject")
|
||||
subject = data.pop("subject")
|
||||
form_slug = data.pop("form_slug")
|
||||
from_address = data.pop("from_address", settings.DEFAULT_FROM_EMAIL)
|
||||
for address in to_addresses:
|
||||
OutgoingEmail.objects.send(
|
||||
|
@ -77,7 +83,7 @@ class EmailFormSubmission(AbstractFormSubmission):
|
|||
template_name="form_mail",
|
||||
recipient=address,
|
||||
sender=from_address,
|
||||
context=data,
|
||||
context={"form_data": data, "submission_id": self.get_submission_id(form_slug)},
|
||||
attachments=attachments
|
||||
)
|
||||
|
||||
|
@ -112,7 +118,8 @@ class CustomEmailForm(Form):
|
|||
"from_address": self.from_address,
|
||||
"to_address": self.to_address,
|
||||
"subject": self.subject,
|
||||
"attachments": attachments
|
||||
"attachments": attachments,
|
||||
"form_slug": self.slug
|
||||
})
|
||||
submission.send_mail(data=mail_data)
|
||||
return submission
|
|
@ -0,0 +1,40 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load wagtailcore_tags wagtailimages_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ page.title }}</h1>
|
||||
<p class="meta">{{ page.date }}</p>
|
||||
{% if form %}
|
||||
{{form.errors}}
|
||||
<div>{{ page.intro|richtext }}</div>
|
||||
<form enctype="multipart/form-data" action="{% pageurl page %}" method="POST">
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
{% if field.is_hidden %}
|
||||
<!--Empty space for reason, we don't want to show anything on empty fields-->
|
||||
{{field}}
|
||||
{% else %}
|
||||
<div class="form-group mt-3">
|
||||
<label for="{{field.id}}" class="form-label">
|
||||
{% trans field.label %}
|
||||
</label>
|
||||
{{field}}
|
||||
<small id="emailHelp" class="form-text text-muted">
|
||||
{% trans field.help_text %}
|
||||
</small>
|
||||
{% if field.error %}
|
||||
{{error}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div class="text-end mt-3">
|
||||
<input class="btn btn-lg btn-success" type="submit" value='{% trans "Submit" %}'>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div>You can fill in the from only one time.</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
|||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="{{ widget.attrs.id }}"
|
||||
name="{{ widget.name }}">
|
||||
<label class="form-check-label" for="{{ widget.attrs.id }}">
|
||||
{{ widget.name }}
|
||||
</label>
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
{% for group, options, index in widget.optgroups %}
|
||||
{% if group %}
|
||||
<label>{{ group }}</label>
|
||||
{% endif %}
|
||||
{% for option in options %}
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="{{ option.value }}" id="{{ option.attrs.id }}"
|
||||
name="{{ option.name }}">
|
||||
<label class="form-check-label" for="{{ option.attrs.id }}">
|
||||
{{ option.value }}
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
|
@ -0,0 +1,15 @@
|
|||
{% for group, options, index in widget.optgroups %}
|
||||
{% if group %}
|
||||
<label>{{ group }}</label>
|
||||
{% endif %}
|
||||
{% for option in options %}
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
value="{{ option.value }}" id="{{ option.attrs.id }}"
|
||||
name="{{ option.name }}">
|
||||
<label class="form-check-label" for="{{ option.attrs.id }}">
|
||||
{{ option.value }}
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
|
@ -104,7 +104,7 @@ class CustomEmailFormTestCase(WagtailPageTests):
|
|||
def test_generate_html_form_from_model(self):
|
||||
html_form = self.form.get_form()
|
||||
self.assertIsInstance(html_form, DynamicForm)
|
||||
self.assertEqual(len(html_form.fields), 13)
|
||||
self.assertEqual(len(html_form.fields), 14)
|
||||
self.assertEqual(html_form.fields["name"].label, "Name")
|
||||
self.assertEqual(html_form.fields["name"].required, True)
|
||||
self.assertEqual(html_form.fields["name"].widget.attrs["class"], "form-control")
|
||||
|
@ -275,3 +275,30 @@ class CustomEmailFormTestCase(WagtailPageTests):
|
|||
self.assertEqual(form.errors["name"], ['This field is required.'])
|
||||
self.assertEqual(form.errors["url"], ['This field is required.'])
|
||||
self.assertEqual(form.errors["attachments"], ['This field is required.'])
|
||||
|
||||
def test_no_hidden_field_in_clean_data_success(self):
|
||||
form_data = {
|
||||
# generate data for this class self.form.get_form()
|
||||
"name": "Test",
|
||||
"message": "Test message",
|
||||
"email": "test@test.com",
|
||||
"number": 1,
|
||||
"url": "http://example.com",
|
||||
"checkbox": True,
|
||||
"checkboxes": ["a", "b"],
|
||||
"dropdown": "a",
|
||||
"multiselect": ["a", "b"],
|
||||
"radio": "a",
|
||||
"date": "2020-01-01",
|
||||
"datetime": "2020-01-01 00:00:00",
|
||||
"hidden": "hidden",
|
||||
}
|
||||
form = self.form.get_form(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
cleaned_data = form.cleaned_data
|
||||
self.assertIn("hidden", cleaned_data)
|
||||
self.assertNotIn("secret_honey", cleaned_data)
|
||||
self.assertIn("hidden", form.fields)
|
||||
self.assertIn("secret_honey", form.fields)
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from django import forms
|
||||
|
||||
|
||||
class CheckboxInput(forms.CheckboxInput):
|
||||
template_name = "widgets/checkbox.html"
|
||||
|
||||
|
||||
class CheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
||||
template_name = "widgets/checkbox_multiple.html"
|
||||
|
||||
|
||||
class RadioSelect(forms.RadioSelect):
|
||||
template_name = "widgets/radio_multiple.html"
|
|
@ -3,7 +3,7 @@ import os
|
|||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "artel.settings.dev")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wagtail_store.settings.dev")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue