Refactor frontend components and backend migrations
- Removed TradingGraph component from frontend/src/components/trading. - Updated home page to import Services component and TradingGraph from new path. - Modified PortfolioPage to return null instead of PortfolioGrid. - Added initial migrations for account, advertisement, commerce, configuration, downloader, gopay, stripe, trading212, and zasilkovna apps in the backend. - Created Services component with subcomponents for Kinematografie, Drone Service, and Website Service. - Implemented TradingGraph component with dynamic data generation and canvas rendering. - Updated DonationShop component to display donation tiers with icons and descriptions.
This commit is contained in:
61
backend/account/migrations/0001_initial.py
Normal file
61
backend/account/migrations/0001_initial.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-14 02:23
|
||||
|
||||
import account.models
|
||||
import django.contrib.auth.validators
|
||||
import django.core.validators
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('is_deleted', models.BooleanField(default=False)),
|
||||
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
||||
('role', models.CharField(choices=[('admin', 'cz#Administrátor'), ('mod', 'cz#Moderator'), ('regular', 'cz#Regular')], default='regular', max_length=20)),
|
||||
('phone_number', models.CharField(blank=True, max_length=16, null=True, unique=True, validators=[django.core.validators.RegexValidator('^\\+?\\d{9,15}$', message='Zadejte platné telefonní číslo.')])),
|
||||
('email_verified', models.BooleanField(default=False)),
|
||||
('email', models.EmailField(db_index=True, max_length=254, unique=True)),
|
||||
('email_verification_token', models.CharField(blank=True, db_index=True, max_length=128, null=True)),
|
||||
('email_verification_sent_at', models.DateTimeField(blank=True, null=True)),
|
||||
('gdpr', models.BooleanField(default=False)),
|
||||
('is_active', models.BooleanField(default=False)),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('city', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('street', models.CharField(blank=True, max_length=200, null=True)),
|
||||
('street_number', models.PositiveIntegerField(blank=True, null=True)),
|
||||
('country', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('company_name', models.CharField(blank=True, max_length=255)),
|
||||
('ico', models.CharField(blank=True, max_length=20)),
|
||||
('dic', models.CharField(blank=True, max_length=20)),
|
||||
('postal_code', models.CharField(blank=True, max_length=5, null=True, validators=[django.core.validators.RegexValidator(code='invalid_postal_code', message='Postal code must contain exactly 5 digits.', regex='^\\d{5}$')])),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to.', related_name='customuser_set', related_query_name='customuser', to='auth.group')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='customuser_set', related_query_name='customuser', to='auth.permission')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', account.models.CustomUserManager()),
|
||||
('active', account.models.ActiveUserManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
backend/account/migrations/__init__.py
Normal file
0
backend/account/migrations/__init__.py
Normal file
@@ -16,7 +16,6 @@ urlpatterns = [
|
||||
# Registration & email endpoints
|
||||
path('register/', views.UserRegistrationViewSet.as_view({'post': 'create'}), name='register'),
|
||||
path('verify-email/<uidb64>/<token>/', views.EmailVerificationView.as_view(), name='verify-email'),
|
||||
path('activate/', views.UserActivationViewSet.as_view(), name='activate-user'),
|
||||
|
||||
# Password reset endpoints
|
||||
path('password-reset/', views.PasswordResetRequestView.as_view(), name='password-reset-request'),
|
||||
|
||||
@@ -6,7 +6,7 @@ from .serializers import *
|
||||
from .permissions import *
|
||||
from .models import CustomUser
|
||||
from .tokens import *
|
||||
from .tasks import send_password_reset_email_task, send_email_verification_task, send_email_clerk_accepted_task # FIXME: send_email_clerk_accepted_task neexistuje !!!
|
||||
from .tasks import send_password_reset_email_task, send_email_verification_task
|
||||
from django.conf import settings
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -186,7 +186,6 @@ 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={
|
||||
@@ -223,6 +222,15 @@ class UserView(viewsets.ModelViewSet):
|
||||
"is_active": {"help_text": "Stav aktivace uživatele."},
|
||||
}
|
||||
|
||||
@extend_schema(
|
||||
tags=["User"],
|
||||
summary="Get permissions based on user role and action.",
|
||||
description="Determines permissions for various actions based on user role and ownership.",
|
||||
responses={
|
||||
200: OpenApiResponse(description="Permissions determined successfully."),
|
||||
403: OpenApiResponse(description="Permission denied."),
|
||||
},
|
||||
)
|
||||
def get_permissions(self):
|
||||
# Only admin can list or create users
|
||||
if self.action in ['list', 'create']:
|
||||
@@ -243,6 +251,7 @@ class UserView(viewsets.ModelViewSet):
|
||||
return [OnlyRolesAllowed("admin")()]
|
||||
|
||||
# Any authenticated user can retrieve (view) any user's profile
|
||||
#FIXME: popřemýšlet co vše může získat
|
||||
elif self.action == 'retrieve':
|
||||
return [IsAuthenticated()]
|
||||
|
||||
@@ -326,40 +335,13 @@ class EmailVerificationView(APIView):
|
||||
|
||||
if account_activation_token.check_token(user, token):
|
||||
user.email_verified = True
|
||||
user.is_active = True # Aktivace uživatele po ověření e-mailu
|
||||
user.save()
|
||||
|
||||
return Response({"detail": "E-mail byl úspěšně ověřen. Účet čeká na schválení."})
|
||||
return Response({"detail": "E-mail byl úspěšně ověřen. Účet je aktivován."})
|
||||
else:
|
||||
return Response({"error": "Token je neplatný nebo expirovaný."}, status=400)
|
||||
|
||||
#3. seller activation API (var_symbol)
|
||||
@extend_schema(
|
||||
tags=["User Registration"],
|
||||
summary="Activate user and set variable symbol (admin/cityClerk only)",
|
||||
description="Activate user and set variable symbol. Only accessible by admin or cityClerk.",
|
||||
request=UserActivationSerializer,
|
||||
responses={
|
||||
200: OpenApiResponse(response=UserActivationSerializer, description="User activated successfully."),
|
||||
400: OpenApiResponse(description="Invalid activation data."),
|
||||
404: OpenApiResponse(description="User not found."),
|
||||
},
|
||||
)
|
||||
class UserActivationViewSet(APIView):
|
||||
permission_classes = [OnlyRolesAllowed('cityClerk', 'admin')]
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
serializer = UserActivationSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.save()
|
||||
|
||||
try:
|
||||
send_email_clerk_accepted_task.delay(user.id) # posílaní emailu pro informování uživatele o dokončení registrace, uředník doplnil variabilní symbol - CELERY TASK
|
||||
except Exception as e:
|
||||
logger.error(f"Celery not available, using fallback. Error: {e}")
|
||||
send_email_clerk_accepted_task(user.id) # posílaní emailu pro informování uživatele o dokončení registrace, uředník doplnil variabilní symbol
|
||||
|
||||
return Response(serializer.to_representation(user), status=status.HTTP_200_OK)
|
||||
|
||||
#-------------------------------------------------END REGISTRACE-------------------------------------------------------------
|
||||
|
||||
#1. PasswordReset + send Email
|
||||
|
||||
Reference in New Issue
Block a user