# coding: utf-8 from rest_framework import generics, viewsets, permissions, status from rest_framework.parsers import MultiPartParser, FormParser, JSONParser from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework.views import APIView from rest_framework.response import Response from django.shortcuts import get_object_or_404 from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from drf_spectacular.utils import extend_schema, OpenApiParameter from django.contrib.auth import get_user_model from .models import Link, LinkGroup from .serializers import ( RegisterSerializer, UserSerializer, LinkSerializer, LinkGroupSerializer, ) User = get_user_model() class RegisterView(generics.CreateAPIView): queryset = User.objects.all() permission_classes = [permissions.AllowAny] serializer_class = RegisterSerializer @method_decorator(csrf_exempt, name='dispatch') class LoginView(TokenObtainPairView): permission_classes = [permissions.AllowAny] class LinkGroupViewSet(viewsets.ModelViewSet): queryset = LinkGroup.objects.all() serializer_class = LinkGroupSerializer permission_classes = [permissions.IsAuthenticated] parser_classes = [MultiPartParser, FormParser, JSONParser] def get_queryset(self): return self.queryset.filter(owner=self.request.user).order_by('order') def perform_create(self, serializer): serializer.save(owner=self.request.user) class LinkViewSet(viewsets.ModelViewSet): queryset = Link.objects.all() serializer_class = LinkSerializer permission_classes = [permissions.IsAuthenticated] parser_classes = [MultiPartParser, FormParser, JSONParser] def get_queryset(self): return Link.objects.filter(owner=self.request.user).order_by('order') def perform_create(self, serializer): serializer.save(owner=self.request.user) class UserProfileView(generics.RetrieveAPIView): serializer_class = UserSerializer permission_classes = [permissions.IsAuthenticated] def get_object(self): return self.request.user class UserLinksListView(generics.ListAPIView): serializer_class = LinkSerializer permission_classes = [permissions.AllowAny] def get_queryset(self): username = self.kwargs['username'] return Link.objects.filter(owner__username=username).order_by('order') class PublicUserGroupsView(APIView): """ GET /api/users/{username}/public/ """ permission_classes = [permissions.AllowAny] def get(self, request, username): # 1. Ищем пользователя user = get_object_or_404(User, username=username) # 2. Получаем настройки дизайна пользователя from customization.models import DesignSettings try: design_settings = DesignSettings.objects.get(user=user) # Заменяем Docker URL на localhost для клиента background_image_url = None if design_settings.background_image: background_image_url = request.build_absolute_uri(design_settings.background_image.url) # Заменяем различные варианты внутренних Docker URL background_image_url = background_image_url.replace('http://web:8000', 'http://localhost:8000') background_image_url = background_image_url.replace('http://links-web-1:8000', 'http://localhost:8000') background_image_url = background_image_url.replace('http://backend:8000', 'http://localhost:8000') design_data = { 'theme_color': design_settings.theme_color, 'background_image': background_image_url, 'dashboard_layout': design_settings.dashboard_layout, 'groups_default_expanded': design_settings.groups_default_expanded, 'show_group_icons': design_settings.show_group_icons, 'show_link_icons': design_settings.show_link_icons, 'dashboard_background_color': design_settings.dashboard_background_color, 'font_family': design_settings.font_family, 'header_text_color': getattr(design_settings, 'header_text_color', '#000000'), 'group_text_color': getattr(design_settings, 'group_text_color', '#333333'), 'link_text_color': getattr(design_settings, 'link_text_color', '#666666'), 'cover_overlay_enabled': getattr(design_settings, 'cover_overlay_enabled', False), 'cover_overlay_color': getattr(design_settings, 'cover_overlay_color', '#000000'), 'cover_overlay_opacity': getattr(design_settings, 'cover_overlay_opacity', 0.5), } except DesignSettings.DoesNotExist: # Настройки по умолчанию design_data = { 'theme_color': '#ffffff', 'background_image': None, 'dashboard_layout': 'list', 'groups_default_expanded': True, 'show_group_icons': True, 'show_link_icons': True, 'dashboard_background_color': '#f8f9fa', 'font_family': 'sans-serif', } # 3. Берём только публичные группы со ссылками groups_qs = LinkGroup.objects.filter( owner=user, is_public=True # Показываем только публичные группы ).prefetch_related('links') # Формируем URL аватара и обложки с заменой Docker URL avatar_url = None if user.avatar: avatar_url = request.build_absolute_uri(user.avatar.url) # Заменяем различные варианты внутренних Docker URL avatar_url = avatar_url.replace('http://web:8000', 'http://localhost:8000') avatar_url = avatar_url.replace('http://links-web-1:8000', 'http://localhost:8000') avatar_url = avatar_url.replace('http://backend:8000', 'http://localhost:8000') cover_url = None if user.cover: cover_url = request.build_absolute_uri(user.cover.url) # Заменяем различные варианты внутренних Docker URL cover_url = cover_url.replace('http://web:8000', 'http://localhost:8000') cover_url = cover_url.replace('http://links-web-1:8000', 'http://localhost:8000') cover_url = cover_url.replace('http://backend:8000', 'http://localhost:8000') result = { "username": user.username, "full_name": user.full_name, "bio": user.bio, "avatar": avatar_url, "cover": cover_url, "design_settings": design_data, "groups": [] } for grp in groups_qs: # icon у группы (абсолютный URL с заменой Docker URL) grp_icon_url = None if grp.icon: grp_icon_url = request.build_absolute_uri(grp.icon.url) # Заменяем различные варианты внутренних Docker URL grp_icon_url = grp_icon_url.replace('http://web:8000', 'http://localhost:8000') grp_icon_url = grp_icon_url.replace('http://links-web-1:8000', 'http://localhost:8000') grp_icon_url = grp_icon_url.replace('http://backend:8000', 'http://localhost:8000') # background_image у группы grp_bg_url = None if grp.background_image: grp_bg_url = request.build_absolute_uri(grp.background_image.url) # Заменяем различные варианты внутренних Docker URL grp_bg_url = grp_bg_url.replace('http://web:8000', 'http://localhost:8000') grp_bg_url = grp_bg_url.replace('http://links-web-1:8000', 'http://localhost:8000') grp_bg_url = grp_bg_url.replace('http://backend:8000', 'http://localhost:8000') grp_data = { "id": grp.id, "name": grp.name, "description": grp.description, "icon_url": grp_icon_url, # Используем icon_url для консистентности с API "background_image": grp_bg_url, "header_color": grp.header_color, "is_favorite": grp.is_favorite, "links": [], } for ln in grp.links.all(): # icon у ссылки с заменой Docker URL ln_icon_url = None if ln.icon: ln_icon_url = request.build_absolute_uri(ln.icon.url) # Заменяем различные варианты внутренних Docker URL ln_icon_url = ln_icon_url.replace('http://web:8000', 'http://localhost:8000') ln_icon_url = ln_icon_url.replace('http://links-web-1:8000', 'http://localhost:8000') ln_icon_url = ln_icon_url.replace('http://backend:8000', 'http://localhost:8000') grp_data["links"].append({ "id": ln.id, "title": ln.title, "url": ln.url, "icon_url": ln_icon_url, # Используем icon_url для консистентности "description": ln.description, }) result["groups"].append(grp_data) return Response(result, status=status.HTTP_200_OK)