Add production Docker setup and update backend/frontend configs
Introduces .dockerignore, production Dockerfile and nginx config for frontend, and refactors docker-compose.yml for multi-service deployment. Updates backend and frontend code to support public API tagging, improves refund handling, adds test email endpoint, and migrates Orval config to TypeScript. Removes unused frontend Dockerfile and updates dependencies for React Query and Orval.
This commit is contained in:
@@ -8,7 +8,8 @@ RUN apt update && apt install -y \
|
||||
pango1.0-tools \
|
||||
libpango-1.0-0 \
|
||||
libgobject-2.0-0 \
|
||||
ffmpeg
|
||||
ffmpeg \
|
||||
ca-certificates
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
@@ -38,7 +38,7 @@ from rest_framework_simplejwt.views import TokenObtainPairView
|
||||
|
||||
# Custom Token obtaining view
|
||||
@extend_schema(
|
||||
tags=["Authentication"],
|
||||
tags=["Authentication", "public"],
|
||||
summary="Obtain JWT access and refresh tokens (cookie-based)",
|
||||
description="Authenticate user and obtain JWT access and refresh tokens. You can use either email or username.",
|
||||
request=CustomTokenObtainPairSerializer,
|
||||
@@ -107,7 +107,7 @@ class CookieTokenObtainPairView(TokenObtainPairView):
|
||||
return super().validate(attrs)
|
||||
|
||||
@extend_schema(
|
||||
tags=["Authentication"],
|
||||
tags=["Authentication", "public"],
|
||||
summary="Refresh JWT token using cookie",
|
||||
description="Refresh JWT access and refresh tokens using the refresh token stored in cookie.",
|
||||
responses={
|
||||
@@ -163,7 +163,7 @@ class CookieTokenRefreshView(APIView):
|
||||
#---------------------------------------------LOGOUT------------------------------------------------
|
||||
|
||||
@extend_schema(
|
||||
tags=["Authentication"],
|
||||
tags=["Authentication", "public"],
|
||||
summary="Logout user (delete access and refresh token cookies)",
|
||||
description="Logs out the user by deleting access and refresh token cookies.",
|
||||
responses={
|
||||
@@ -186,6 +186,7 @@ class LogoutView(APIView):
|
||||
|
||||
@extend_schema(
|
||||
tags=["User"],
|
||||
get=extend_schema(tags=["public"]),
|
||||
summary="List, retrieve, update, and delete users.",
|
||||
description="Displays all users with filtering and ordering options. Requires authentication and appropriate role.",
|
||||
responses={
|
||||
|
||||
@@ -10,11 +10,13 @@ from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from weasyprint import HTML
|
||||
import os
|
||||
|
||||
from backend.commerce.tasks import notify_order_sended
|
||||
from configuration.models import ShopConfiguration
|
||||
|
||||
from thirdparty.zasilkovna.models import ZasilkovnaPacket
|
||||
from thirdparty.stripe.models import StripeModel
|
||||
|
||||
from .tasks import notify_refund_accepted, notify_order_sended
|
||||
|
||||
#FIXME: přidat soft delete pro všchny modely !!!!
|
||||
|
||||
class Category(models.Model):
|
||||
@@ -477,6 +479,7 @@ class Refund(models.Model):
|
||||
WRONG_ITEM = "wrong_item", "cz#Špatná položka"
|
||||
OTHER = "other", "cz#Jiný důvod"
|
||||
reason_choice = models.CharField(max_length=30, choices=Reason.choices)
|
||||
|
||||
reason_text = models.TextField(blank=True)
|
||||
|
||||
verified = models.BooleanField(default=False)
|
||||
@@ -507,12 +510,26 @@ class Refund(models.Model):
|
||||
|
||||
# super().save(*args, **kwargs)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Automaticky aktualizovat stav objednávky na "vráceno"
|
||||
if self.pk is None:
|
||||
if self.order.status != Order.Status.REFUNDING:
|
||||
self.order.save(update_fields=["status", "updated_at"])
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def refund_completed(self):
|
||||
# Aktualizovat stav objednávky na "vráceno"
|
||||
self.order.payment.stripe.refund()
|
||||
if self.order.payment and self.order.payment.payment_method == Payment.PAYMENT.STRIPE:
|
||||
self.order.payment.stripe.refund() # Vrácení pěnez přes stripe
|
||||
|
||||
self.order.status = Order.Status.REFUNDED
|
||||
self.order.save(update_fields=["status", "updated_at"])
|
||||
|
||||
|
||||
notify_refund_accepted.delay(order=self.order, user=self.order.user)
|
||||
|
||||
|
||||
def generate_refund_pdf_for_customer(self):
|
||||
"""Vygeneruje PDF formulář k vrácení zboží pro zákazníka.
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
from .models import Order
|
||||
from account.models import User
|
||||
from account.tasks import send_email_with_context
|
||||
from celery import shared_task
|
||||
|
||||
from django.apps import apps
|
||||
from django.utils import timezone
|
||||
|
||||
Order = apps.get_model('commerce', 'Order')
|
||||
|
||||
|
||||
def delete_expired_orders():
|
||||
expired_orders = Order.objects.filter(status=Order.STATUS_CHOICES.CANCELLED, created_at__lt=timezone.now() - timezone.timedelta(hours=24))
|
||||
count = expired_orders.count()
|
||||
|
||||
0
backend/configuration/serializers.py
Normal file
0
backend/configuration/serializers.py
Normal file
@@ -1,3 +1,5 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
||||
#TODO: dej public tag pro view, aby to mohl react číst pomocí public axiosu
|
||||
6
backend/thirdparty/downloader/views.py
vendored
6
backend/thirdparty/downloader/views.py
vendored
@@ -48,7 +48,7 @@ class Downloader(APIView):
|
||||
authentication_classes = []
|
||||
|
||||
@extend_schema(
|
||||
tags=["downloader"],
|
||||
tags=["downloader", "public"],
|
||||
summary="Get video info from URL",
|
||||
parameters=[
|
||||
inline_serializer(
|
||||
@@ -129,7 +129,7 @@ class Downloader(APIView):
|
||||
|
||||
|
||||
@extend_schema(
|
||||
tags=["downloader"],
|
||||
tags=["downloader", "public"],
|
||||
summary="Download video from URL",
|
||||
request=inline_serializer(
|
||||
name="DownloadRequest",
|
||||
@@ -277,7 +277,7 @@ class DownloaderStats(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
@extend_schema(
|
||||
tags=["downloader"],
|
||||
tags=["downloader", "public"],
|
||||
summary="Get aggregated downloader statistics",
|
||||
responses={200: DownloaderStatsSerializer},
|
||||
)
|
||||
|
||||
7
backend/thirdparty/zasilkovna/models.py
vendored
7
backend/thirdparty/zasilkovna/models.py
vendored
@@ -44,9 +44,10 @@ class ZasilkovnaPacket(models.Model):
|
||||
state = models.CharField(max_length=20, choices=STATE.choices, default=STATE.PENDING)
|
||||
|
||||
# ------- API -------
|
||||
class BUISSNESS_ADDRESS_ID(models.IntegerChoices):
|
||||
SHOP = 1, "address of buissnes"
|
||||
addressId = models.IntegerField(help_text="ID adresy, v API rozhraní", choices=BUISSNESS_ADDRESS_ID.choices, default=BUISSNESS_ADDRESS_ID.SHOP)
|
||||
#TODO: změnit na nastavení adresy eshopu/obchodu z modelu konfigurace
|
||||
# https://client.packeta.com/cs/senders (admin rozhraní)
|
||||
|
||||
addressId = models.IntegerField(help_text="ID adresy, v Widgetu zásilkovny který si vybere uživatel.")
|
||||
|
||||
packet_id = models.IntegerField(help_text="Číslo zásilky v Packetě (api)")
|
||||
barcode = models.CharField(max_length=64, help_text="Čárový kód zásilky v Packetě")
|
||||
|
||||
@@ -5,7 +5,11 @@ from rest_framework.response import Response
|
||||
from drf_spectacular.utils import extend_schema, OpenApiParameter
|
||||
from rest_framework.permissions import AllowAny
|
||||
|
||||
from account.tasks import send_email_test_task
|
||||
|
||||
@extend_schema(
|
||||
tags=["public"],
|
||||
|
||||
description="Vrátí všechny možné hodnoty pro ChoiceField s podporou vícejazyčných labelů. "
|
||||
"Umožňuje načíst více modelů a polí najednou.",
|
||||
parameters=[
|
||||
@@ -83,3 +87,24 @@ def choices(request):
|
||||
result[f"{model_name}.{field_name}"] = choices_data
|
||||
|
||||
return Response(result)
|
||||
|
||||
|
||||
|
||||
@extend_schema(
|
||||
tags=["Testing"],
|
||||
description="Testovací endpoint pro odeslání testovacího emailu.",
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="email",
|
||||
description="Emailová adresa příjemce testovacího emailu.",
|
||||
required=True,
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
)
|
||||
@api_view(["GET"])
|
||||
def test_email(request):
|
||||
email = request.query_params.get("email")
|
||||
send_email_test_task.delay(email)
|
||||
|
||||
return Response({"status": "Test task (celery) email sent, await delivery."})
|
||||
Reference in New Issue
Block a user