diff --git a/backend/account/tasks.py b/backend/account/tasks.py
index 565d65a..c8427ad 100644
--- a/backend/account/tasks.py
+++ b/backend/account/tasks.py
@@ -10,34 +10,25 @@ from .models import CustomUser
logger = get_task_logger(__name__)
-# TODO: předělat funkci ať funguje s base.html šablonou na emaily !!!
-def send_email_with_context(recipients, subject, message=None, template_name=None, html_template_name=None, context=None):
+def send_email_with_context(recipients, subject, template_path=None, context=None, message: str | None = None):
"""
- General function to send emails with a specific context.
- Supports rendering plain text and HTML templates.
- Converts `user` in context to a plain dict to avoid template access to the model.
+ Send emails rendering a single HTML template.
+ - `template_name` is a simple base name without extension, e.g. "email/test".
+ - Renders only HTML (".html"), no ".txt" support.
+ - Converts `user` in context to a plain dict to avoid passing models to templates.
"""
if isinstance(recipients, str):
recipients = [recipients]
html_message = None
- if template_name or html_template_name:
- # Best effort to resolve both templates if only one provided
- if not template_name and html_template_name:
- template_name = html_template_name.replace(".html", ".txt")
- if not html_template_name and template_name:
- html_template_name = template_name.replace(".txt", ".html")
-
+ if template_path:
ctx = dict(context or {})
- # Sanitize user if someone passes the model by mistake
- if "user" in ctx and not isinstance(ctx["user"], dict):
- try:
- ctx["user"] = _build_user_template_ctx(ctx["user"])
- except Exception:
- ctx["user"] = {}
-
- message = render_to_string(template_name, ctx)
- html_message = render_to_string(html_template_name, ctx)
+ # Render base layout and include the provided template as the main content.
+ # The included template receives the same context as the base.
+ html_message = render_to_string(
+ "email/components/base.html",
+ {"content_template": template_path, **ctx},
+ )
try:
send_mail(
@@ -48,33 +39,13 @@ def send_email_with_context(recipients, subject, message=None, template_name=Non
fail_silently=False,
html_message=html_message,
)
- if settings.EMAIL_BACKEND == 'django.core.mail.backends.console.EmailBackend':
+ if settings.EMAIL_BACKEND == 'django.core.mail.backends.console.EmailBackend' and message:
logger.debug(f"\nEMAIL OBSAH:\n{message}\nKONEC OBSAHU")
return True
except Exception as e:
logger.error(f"E-mail se neodeslal: {e}")
return False
-
-
-def _build_user_template_ctx(user: CustomUser) -> dict:
- """
- Return a plain dict for templates instead of passing the DB model.
- Provides aliases to avoid template errors (firstname vs first_name).
- Adds a backward-compatible key 'get_full_name' for templates using `user.get_full_name`.
- """
- first_name = getattr(user, "first_name", "") or ""
- last_name = getattr(user, "last_name", "") or ""
- full_name = f"{first_name} {last_name}".strip()
- return {
- "id": user.pk,
- "email": getattr(user, "email", "") or "",
- "first_name": first_name,
- "firstname": first_name, # alias for templates using `firstname`
- "last_name": last_name,
- "lastname": last_name, # alias for templates using `lastname`
- "full_name": full_name,
- "get_full_name": full_name, # compatibility for templates using method-style access
- }
+
#----------------------------------------------------------------------------------------------------
@@ -93,7 +64,7 @@ def send_email_verification_task(user_id):
verify_url = f"{settings.FRONTEND_URL}/email-verification/?uidb64={uid}&token={token}"
context = {
- "user": _build_user_template_ctx(user),
+ "user": user,
"action_url": verify_url,
"frontend_url": settings.FRONTEND_URL,
"cta_label": "Ověřit e‑mail",
@@ -102,8 +73,7 @@ def send_email_verification_task(user_id):
send_email_with_context(
recipients=user.email,
subject="Ověření e‑mailu",
- template_name="email/email_verification.txt",
- html_template_name="email/email_verification.html",
+ template_path="email/email_verification.html",
context=context,
)
@@ -119,8 +89,7 @@ def send_email_test_task(email):
send_email_with_context(
recipients=email,
subject="Testovací e‑mail",
- template_name="email/test.txt",
- html_template_name="email/test.html",
+ template_path="email/test.html",
context=context,
)
@@ -138,7 +107,7 @@ def send_password_reset_email_task(user_id):
reset_url = f"{settings.FRONTEND_URL}/reset-password/{uid}/{token}"
context = {
- "user": _build_user_template_ctx(user),
+ "user": user,
"action_url": reset_url,
"frontend_url": settings.FRONTEND_URL,
"cta_label": "Obnovit heslo",
@@ -147,7 +116,6 @@ def send_password_reset_email_task(user_id):
send_email_with_context(
recipients=user.email,
subject="Obnova hesla",
- template_name="email/password_reset.txt",
- html_template_name="email/password_reset.html",
+ template_path="email/password_reset.html",
context=context,
)
\ No newline at end of file
diff --git a/backend/account/templates/email/email_verification.html b/backend/account/templates/email/email_verification.html
index 0802339..8381034 100644
--- a/backend/account/templates/email/email_verification.html
+++ b/backend/account/templates/email/email_verification.html
@@ -1,46 +1,21 @@
-
-
-
-
-
-
-
-
- |
- Ověření e‑mailu
- |
-
-
- |
- {% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
- Dobrý den{% if name %} {{ name }}{% endif %},
- {% endwith %}
- Děkujeme za registraci. Prosíme, ověřte svou e‑mailovou adresu kliknutím na tlačítko níže.
+Ověření e‑mailu
- {% if action_url and cta_label %}
-
- Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz: {{ action_url }}
- {% endif %}
- |
-
-
-
-
- |
- Tento e‑mail byl odeslán z aplikace e‑tržnice.
- |
-
-
- |
-
-
-
-
+
+ {% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
+
Dobrý den{% if name %} {{ name }}{% endif %},
+ {% endwith %}
+
Děkujeme za registraci. Prosíme, ověřte svou e‑mailovou adresu kliknutím na tlačítko níže.
+
+ {% if action_url and cta_label %}
+
+
Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:
{{ action_url }}
+ {% endif %}
+
diff --git a/backend/account/templates/email/email_verification.txt b/backend/account/templates/email/email_verification.txt
deleted file mode 100644
index 042e029..0000000
--- a/backend/account/templates/email/email_verification.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}Dobrý den{% if name %} {{ name }}{% endif %},{% endwith %}
-
-Děkujeme za registraci. Prosíme, ověřte svou e‑mailovou adresu kliknutím na následující odkaz:
-
-{{ action_url }}
-
-Pokud jste účet nevytvořili vy, tento e‑mail ignorujte.
diff --git a/backend/account/templates/email/password_reset.html b/backend/account/templates/email/password_reset.html
index 58d403f..30baeaf 100644
--- a/backend/account/templates/email/password_reset.html
+++ b/backend/account/templates/email/password_reset.html
@@ -1,46 +1,21 @@
-
-
-
-
-
-
-
-
- |
- Obnova hesla
- |
-
-
- |
- {% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
- Dobrý den{% if name %} {{ name }}{% endif %},
- {% endwith %}
- Obdrželi jste tento e‑mail, protože byla požádána obnova hesla k vašemu účtu. Pokud jste o změnu nepožádali, tento e‑mail ignorujte.
+Obnova hesla
- {% if action_url and cta_label %}
-
- Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz: {{ action_url }}
- {% endif %}
- |
-
-
-
-
- |
- Tento e‑mail byl odeslán z aplikace e‑tržnice.
- |
-
-
- |
-
-
-
-
+
+ {% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
+
Dobrý den{% if name %} {{ name }}{% endif %},
+ {% endwith %}
+
Obdrželi jste tento e‑mail, protože byla požádána obnova hesla k vašemu účtu. Pokud jste o změnu nepožádali, tento e‑mail ignorujte.
+
+ {% if action_url and cta_label %}
+
+
Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:
{{ action_url }}
+ {% endif %}
+
diff --git a/backend/account/templates/email/password_reset.txt b/backend/account/templates/email/password_reset.txt
deleted file mode 100644
index 27638d5..0000000
--- a/backend/account/templates/email/password_reset.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}Dobrý den{% if name %} {{ name }}{% endif %},{% endwith %}
-
-Obdrželi jste tento e‑mail, protože byla požádána obnova hesla k vašemu účtu.
-Pokud jste o změnu nepožádali, tento e‑mail ignorujte.
-
-Pro nastavení nového hesla použijte tento odkaz:
-{{ action_url }}
diff --git a/backend/account/templates/email/test.html b/backend/account/templates/email/test.html
index 6721080..55685d7 100644
--- a/backend/account/templates/email/test.html
+++ b/backend/account/templates/email/test.html
@@ -1,44 +1,19 @@
-
-
-
-
-
-
-
-
- |
- Testovací e‑mail
- |
-
-
- |
- Dobrý den,
- Toto je testovací e‑mail z aplikace e‑tržnice.
+Testovací e‑mail
- {% if action_url and cta_label %}
-
- Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz: {{ action_url }}
- {% endif %}
- |
-
-
-
-
- |
- Tento e‑mail byl odeslán z aplikace e‑tržnice.
- |
-
-
- |
-
-
-
-
+
+
Dobrý den,
+
Toto je testovací e‑mail z aplikace e‑tržnice.
+
+ {% if action_url and cta_label %}
+
+
Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:
{{ action_url }}
+ {% endif %}
+
diff --git a/backend/account/templates/email/test.txt b/backend/account/templates/email/test.txt
deleted file mode 100644
index 79ecc54..0000000
--- a/backend/account/templates/email/test.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Dobrý den,
-
-Toto je testovací e‑mail z aplikace e‑tržnice.
-
-Odkaz na aplikaci:
-{{ action_url }}
diff --git a/backend/advertisement/models.py b/backend/advertisement/models.py
index 71a8362..fbe91db 100644
--- a/backend/advertisement/models.py
+++ b/backend/advertisement/models.py
@@ -1,3 +1,14 @@
from django.db import models
# Create your models here.
+
+class ContactMe(models.Model):
+ client_email = models.EmailField()
+ content = models.TextField()
+
+ sent_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return f"Email to {self.client_email} sent at {self.sent_at}"
+
+
\ No newline at end of file
diff --git a/backend/advertisement/serializer.py b/backend/advertisement/serializer.py
new file mode 100644
index 0000000..87fc8a0
--- /dev/null
+++ b/backend/advertisement/serializer.py
@@ -0,0 +1,9 @@
+from rest_framework import serializers
+from .models import ContactMe
+
+
+class ContactMeSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = ContactMe
+ fields = ["id", "client_email", "content", "sent_at"]
+ read_only_fields = ["id", "sent_at"]
diff --git a/backend/advertisement/tasks.py b/backend/advertisement/tasks.py
index a5bec03..e9d97c5 100644
--- a/backend/advertisement/tasks.py
+++ b/backend/advertisement/tasks.py
@@ -1,2 +1,17 @@
-#udělat zasílaní reklamních emailů uživatelům.
-#newletter --> když se vytvoří nový record s reklamou email se uloží pomocí zaškrtnutí tlačítka v záznamu
\ No newline at end of file
+from account.tasks import send_email_with_context
+from configuration.models import SiteConfiguration
+
+from celery import shared_task
+
+@shared_task
+def send_contact_me_email_task(client_email, message_content):
+ context = {
+ "client_email": client_email,
+ "message_content": message_content
+ }
+ send_email_with_context(
+ recipients=SiteConfiguration.get_solo().contact_email,
+ subject="Poptávka z kontaktního formuláře!!!",
+ template_path="email/contact_me.html",
+ context=context,
+ )
\ No newline at end of file
diff --git a/backend/advertisement/templates/email/contact_me.html b/backend/advertisement/templates/email/contact_me.html
new file mode 100644
index 0000000..2c0adb4
--- /dev/null
+++ b/backend/advertisement/templates/email/contact_me.html
@@ -0,0 +1,6 @@
+Nová zpráva z kontaktního formuláře
+
+
Email odesílatele: {{ client_email }}
+
Zpráva:
+
{{ message_content }}
+
diff --git a/backend/advertisement/urls.py b/backend/advertisement/urls.py
new file mode 100644
index 0000000..ad96ccc
--- /dev/null
+++ b/backend/advertisement/urls.py
@@ -0,0 +1,15 @@
+from django.urls import path, include
+from rest_framework.routers import DefaultRouter
+
+from .views import ContactMePublicView, ContactMeAdminViewSet
+
+router = DefaultRouter()
+router.register(r"contact-messages", ContactMeAdminViewSet, basename="contactme")
+
+urlpatterns = [
+ # Public endpoint
+ path("contact-me/", ContactMePublicView.as_view(), name="contact-me"),
+
+ # Admin endpoints
+ path("", include(router.urls)),
+]
diff --git a/backend/advertisement/views.py b/backend/advertisement/views.py
index 91ea44a..bb2e42a 100644
--- a/backend/advertisement/views.py
+++ b/backend/advertisement/views.py
@@ -1,3 +1,46 @@
-from django.shortcuts import render
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status, viewsets
+from rest_framework.permissions import AllowAny, IsAdminUser
+from rest_framework.authentication import SessionAuthentication
+
+from .models import ContactMe
+from .serializer import ContactMeSerializer
+from .tasks import send_contact_me_email_task
+
+
+class ContactMePublicView(APIView):
+ permission_classes = [AllowAny]
+ # Avoid CSRF for public endpoint by disabling SessionAuthentication
+ authentication_classes = []
+
+ def post(self, request):
+ email = request.data.get("email")
+ message = request.data.get("message")
+ honeypot = request.data.get("hp") # hidden honeypot field
+
+ # If honeypot is filled, pretend success without processing
+ if honeypot:
+ return Response({"status": "ok"}, status=status.HTTP_200_OK)
+
+ if not email or not message:
+ return Response({"detail": "Missing email or message."}, status=status.HTTP_400_BAD_REQUEST)
+
+ # Save to DB
+ cm = ContactMe.objects.create(client_email=email, content=message)
+
+ # Send email via Celery task
+ try:
+ send_contact_me_email_task.delay(email, message)
+ except Exception:
+ # Fallback to direct call if Celery is not running in DEV
+ send_contact_me_email_task(email, message)
+
+ return Response({"id": cm.id, "status": "queued"}, status=status.HTTP_201_CREATED)
+
+
+class ContactMeAdminViewSet(viewsets.ModelViewSet):
+ queryset = ContactMe.objects.all().order_by("-sent_at")
+ serializer_class = ContactMeSerializer
+ permission_classes = [IsAdminUser]
-# Create your views here.
diff --git a/backend/commerce/models.py b/backend/commerce/models.py
index ea41cef..7eae1ae 100644
--- a/backend/commerce/models.py
+++ b/backend/commerce/models.py
@@ -10,7 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from weasyprint import HTML
import os
-from configuration.models import ShopConfiguration
+from configuration.models import SiteConfiguration
from thirdparty.zasilkovna.models import ZasilkovnaPacket
from thirdparty.stripe.models import StripeModel
@@ -240,7 +240,7 @@ class Carrier(models.Model):
def get_price(self):
if self.shipping_method == self.SHIPPING.ZASILKOVNA:
- return ShopConfiguration.get_solo().zasilkovna_shipping_price
+ return SiteConfiguration.get_solo().zasilkovna_shipping_price
else:
return Decimal('0.0')
@@ -285,10 +285,10 @@ class Carrier(models.Model):
class Payment(models.Model):
class PAYMENT(models.TextChoices):
- SHOP = "shop", "cz#Platba v obchodě"
+ Site = "Site", "cz#Platba v obchodě"
STRIPE = "stripe", "cz#Bankovní převod"
CASH_ON_DELIVERY = "cash_on_delivery", "cz#Dobírka"
- payment_method = models.CharField(max_length=30, choices=PAYMENT.choices, default=PAYMENT.SHOP)
+ payment_method = models.CharField(max_length=30, choices=PAYMENT.choices, default=PAYMENT.Site)
#FIXME: potvrdit že logika platby funguje správně
#veškera logika a interakce bude na stripu (třeba aktualizovaní objednávky na zaplacenou apod.)
@@ -360,7 +360,7 @@ class OrderItem(models.Model):
def get_total_price(self, discounts: list[DiscountCode] = None):
"""Vrátí celkovou cenu položky po aplikaci relevantních kupónů.
- Logika dle ShopConfiguration:
+ Logika dle SiteConfiguration:
- multiplying_coupons=True: procentuální slevy se násobí (sekvenčně)
P * (1 - p1) -> výsledné * (1 - p2) ...
jinak se použije pouze nejlepší (nejvyšší procento).
@@ -375,7 +375,7 @@ class OrderItem(models.Model):
return base_price
- config = ShopConfiguration.get_solo()
+ config = SiteConfiguration.get_solo()
#seznám slev
applicable_percent_discounts: list[int] = []
diff --git a/backend/configuration/apps.py b/backend/configuration/apps.py
index 8cc1282..a938a13 100644
--- a/backend/configuration/apps.py
+++ b/backend/configuration/apps.py
@@ -6,14 +6,13 @@ class ConfigurationConfig(AppConfig):
name = 'configuration'
def ready(self):
- """Ensure the ShopConfiguration singleton exists at startup.
-
+ """Ensure the SiteConfiguration singleton exists at startup.
Wrapped in broad DB error handling so that commands like
makemigrations/migrate don't fail when the table does not yet exist.
"""
try:
- from .models import ShopConfiguration # local import to avoid premature app registry access
- ShopConfiguration.get_solo() # creates if missing
+ from .models import SiteConfiguration # local import to avoid premature app registry access
+ SiteConfiguration.get_solo() # creates if missing
except (OperationalError, ProgrammingError):
# DB not ready (e.g., before initial migrate); ignore silently
diff --git a/backend/configuration/models.py b/backend/configuration/models.py
index c69de8f..be1085b 100644
--- a/backend/configuration/models.py
+++ b/backend/configuration/models.py
@@ -2,7 +2,7 @@ from django.db import models
# Create your models here.
-class ShopConfiguration(models.Model):
+class SiteConfiguration(models.Model):
name = models.CharField(max_length=100, default="Shop name", unique=True)
logo = models.ImageField(upload_to='shop_logos/', blank=True, null=True)
diff --git a/backend/configuration/serializers.py b/backend/configuration/serializers.py
index 9979183..4b7af80 100644
--- a/backend/configuration/serializers.py
+++ b/backend/configuration/serializers.py
@@ -1,10 +1,10 @@
from rest_framework import serializers
-from .models import ShopConfiguration
+from .models import SiteConfiguration
-class ShopConfigurationAdminSerializer(serializers.ModelSerializer):
+class SiteConfigurationAdminSerializer(serializers.ModelSerializer):
class Meta:
- model = ShopConfiguration
+ model = SiteConfiguration
fields = [
"id",
"name",
@@ -29,9 +29,9 @@ class ShopConfigurationAdminSerializer(serializers.ModelSerializer):
]
-class ShopConfigurationPublicSerializer(serializers.ModelSerializer):
+class SiteConfigurationPublicSerializer(serializers.ModelSerializer):
class Meta:
- model = ShopConfiguration
+ model = SiteConfiguration
# Expose only non-sensitive fields
fields = [
"id",
diff --git a/backend/configuration/urls.py b/backend/configuration/urls.py
index c84fcaf..b3cdfd9 100644
--- a/backend/configuration/urls.py
+++ b/backend/configuration/urls.py
@@ -1,8 +1,7 @@
from rest_framework.routers import DefaultRouter
-from .views import ShopConfigurationAdminViewSet, ShopConfigurationPublicViewSet
+from .views import SiteConfigurationAdminViewSet, SiteConfigurationPublicViewSet
router = DefaultRouter()
-router.register(r"admin/shop-configuration", ShopConfigurationAdminViewSet, basename="shop-config-admin")
-router.register(r"public/shop-configuration", ShopConfigurationPublicViewSet, basename="shop-config-public")
-
+router.register(r"admin/shop-configuration", SiteConfigurationAdminViewSet, basename="shop-config-admin")
+router.register(r"public/shop-configuration", SiteConfigurationPublicViewSet, basename="shop-config-public")
urlpatterns = router.urls
diff --git a/backend/configuration/views.py b/backend/configuration/views.py
index 33be7e9..6d92d6e 100644
--- a/backend/configuration/views.py
+++ b/backend/configuration/views.py
@@ -1,25 +1,25 @@
from rest_framework import viewsets, mixins
from rest_framework.permissions import IsAdminUser, AllowAny
-from .models import ShopConfiguration
+from .models import SiteConfiguration
from .serializers import (
- ShopConfigurationAdminSerializer,
- ShopConfigurationPublicSerializer,
+ SiteConfigurationAdminSerializer,
+ SiteConfigurationPublicSerializer,
)
class _SingletonQuerysetMixin:
def get_queryset(self):
- return ShopConfiguration.objects.filter(pk=1)
+ return SiteConfiguration.objects.filter(pk=1)
def get_object(self):
- return ShopConfiguration.get_solo()
+ return SiteConfiguration.get_solo()
-class ShopConfigurationAdminViewSet(_SingletonQuerysetMixin, viewsets.ModelViewSet):
+class SiteConfigurationAdminViewSet(_SingletonQuerysetMixin, viewsets.ModelViewSet):
permission_classes = [IsAdminUser]
- serializer_class = ShopConfigurationAdminSerializer
+ serializer_class = SiteConfigurationAdminSerializer
-class ShopConfigurationPublicViewSet(_SingletonQuerysetMixin, viewsets.ReadOnlyModelViewSet):
+class SiteConfigurationPublicViewSet(_SingletonQuerysetMixin, viewsets.ReadOnlyModelViewSet):
permission_classes = [AllowAny]
- serializer_class = ShopConfigurationPublicSerializer
\ No newline at end of file
+ serializer_class = SiteConfigurationPublicSerializer
\ No newline at end of file
diff --git a/backend/templates/email/base.html b/backend/templates/email/components/base.html
similarity index 100%
rename from backend/templates/email/base.html
rename to backend/templates/email/components/base.html
diff --git a/backend/thirdparty/zasilkovna/models.py b/backend/thirdparty/zasilkovna/models.py
index 174911e..0dee6f6 100644
--- a/backend/thirdparty/zasilkovna/models.py
+++ b/backend/thirdparty/zasilkovna/models.py
@@ -26,7 +26,7 @@ from rest_framework.exceptions import ValidationError
from .client import PacketaAPI
-from configuration.models import ShopConfiguration
+from configuration.models import SiteConfiguration
packeta_client = PacketaAPI() # single reusable instance
@@ -103,8 +103,8 @@ class ZasilkovnaPacket(models.Model):
cod=order.total_price if cash_on_delivery else 0, # dobírka
value=order.total_price,
- currency=ShopConfiguration.get_solo().currency, #CZK
- eshop= ShopConfiguration.get_solo().name,
+ currency=SiteConfiguration.get_solo().currency, #CZK
+ eSite= SiteConfiguration.get_solo().name,
)
self.packet_id = response['packet_id']
self.barcode = response['barcode']
diff --git a/backend/thirdparty/zasilkovna/views.py b/backend/thirdparty/zasilkovna/views.py
index 333fd28..54c3797 100644
--- a/backend/thirdparty/zasilkovna/views.py
+++ b/backend/thirdparty/zasilkovna/views.py
@@ -5,7 +5,7 @@ from django.template import loader
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse, OpenApiParameter, OpenApiTypes
-from backend.configuration.models import ShopConfiguration
+from backend.configuration.models import SiteConfiguration
from .models import ZasilkovnaShipment, ZasilkovnaPacket
from .serializers import (
@@ -135,7 +135,7 @@ class ZasilkovnaPacketViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet
widget_html = loader.render_to_string(
"zasilkovna/pickup_point_widget.html",
{
- "api_key": ShopConfiguration.get_solo().zasilkovna_widget_api_key,
+ "api_key": SiteConfiguration.get_solo().zasilkovna_widget_api_key,
}
)
diff --git a/backend/vontor_cz/urls.py b/backend/vontor_cz/urls.py
index b797976..53a3593 100644
--- a/backend/vontor_cz/urls.py
+++ b/backend/vontor_cz/urls.py
@@ -37,7 +37,7 @@ urlpatterns = [
path('api/account/', include('account.urls')),
path('api/commerce/', include('commerce.urls')),
path('api/configuration/', include('configuration.urls')),
- #path('api/advertisments/', include('advertisements.urls')),
+ path('api/advertisement/', include('advertisement.urls')),
path('api/stripe/', include('thirdparty.stripe.urls')),
path('api/trading212/', include('thirdparty.trading212.urls')),
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index a8832f4..f5c8d2b 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -7,7 +7,6 @@ import PrivateRoute from "./routes/PrivateRoute";
// Pages
import PortfolioPage from "./pages/portfolio/PortfolioPage";
-import HostingSecurityPage from "./pages/hosting/HostingSecurityPage";
import ContactPage from "./pages/contact/ContactPage";
import ScrollToTop from "./components/common/ScrollToTop";
@@ -21,7 +20,6 @@ export default function App() {
}>
} />
} />
- } />
} />
{/* Utilities */}
diff --git a/frontend/src/components/Forms/ContactMe/ContactMeForm.tsx b/frontend/src/components/Forms/ContactMe/ContactMeForm.tsx
index b4f1b1c..ff4387b 100644
--- a/frontend/src/components/Forms/ContactMe/ContactMeForm.tsx
+++ b/frontend/src/components/Forms/ContactMe/ContactMeForm.tsx
@@ -73,6 +73,7 @@ export default function ContactMeForm() {
placeholder="Vaše zpráva"
required
/>
+
diff --git a/frontend/src/components/hero/HeroCarousel.tsx b/frontend/src/components/hero/HeroCarousel.tsx
deleted file mode 100644
index b2ec490..0000000
--- a/frontend/src/components/hero/HeroCarousel.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import { useEffect, useState } from "react";
-
-export default function HeroCarousel() {
- return (
- <>
- >
- );
-}
\ No newline at end of file
diff --git a/frontend/src/components/hosting/HostingSecuritySection.tsx b/frontend/src/components/hosting/HostingSecuritySection.tsx
deleted file mode 100644
index 5c30646..0000000
--- a/frontend/src/components/hosting/HostingSecuritySection.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-
-export default function HostingSecuritySection() {
- return (
-
-
-
Hosting & Protection
-
-
We host our applications ourselves, which reduces hosting costs as projects scale.
-
All websites are protected by Cloudflare and optimized for performance.
-
- {['Server', 'Cloudflare', 'Docker', 'SSL', 'Monitoring', 'Scaling'].map(item => (
-
- {item}
-
- ))}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend/src/components/navbar/SiteNav.tsx b/frontend/src/components/navbar/SiteNav.tsx
index e84daf1..ba01e9a 100644
--- a/frontend/src/components/navbar/SiteNav.tsx
+++ b/frontend/src/components/navbar/SiteNav.tsx
@@ -113,7 +113,6 @@ export default function Navbar({ user, onLogin, onLogout }: NavbarProps) {
Kontakt
- Projekty
{/* right: user area */}
{!user ? (
@@ -136,9 +135,9 @@ export default function Navbar({ user, onLogin, onLogout }: NavbarProps) {
-
Profil
-
Nastavení
-
Platby
+
Profil
+
Nastavení
+
Platby