# backend/api/views.py from rest_framework import generics, viewsets, permissions, status from django.contrib.auth import get_user_model 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 drf_spectacular.utils import extend_schema, OpenApiParameter from .models import Link, LinkGroup from .serializers import ( RegisterSerializer, UserSerializer, LinkSerializer, LinkGroupSerializer, ) User = get_user_model() @extend_schema( parameters=[ OpenApiParameter( name='id', type=int, location=OpenApiParameter.PATH ) ] ) class RegisterView(generics.CreateAPIView): """ POST /api/auth/register/ Регистрирует нового пользователя. """ queryset = User.objects.all() permission_classes = (permissions.AllowAny,) serializer_class = RegisterSerializer class LoginView(TokenObtainPairView): """ POST /api/auth/login/ Возвращает JWT-токены. """ permission_classes = (permissions.AllowAny,) class LinkGroupViewSet(viewsets.ModelViewSet): """ /api/groups/ CRUD для групп ссылок текущего пользователя. """ queryset = LinkGroup.objects.all() serializer_class = LinkGroupSerializer permission_classes = [permissions.IsAuthenticated] def get_queryset(self): # Возвращаем только свои группы, упорядоченные по полю order return self.queryset.filter(owner=self.request.user).order_by('order') def perform_create(self, serializer): # При создании модели автоматически ставим owner = текущий пользователь serializer.save(owner=self.request.user) class LinkViewSet(viewsets.ModelViewSet): """ /api/links/ CRUD для ссылок текущего пользователя. """ serializer_class = LinkSerializer permission_classes = (permissions.IsAuthenticated,) def get_queryset(self): # Возвращаем только свои ссылки, упорядоченные по полю order return Link.objects.filter(owner=self.request.user).order_by('order') def perform_create(self, serializer): # При создании модели автоматически ставим owner = текущий пользователь serializer.save(owner=self.request.user) class UserLinksListView(generics.ListAPIView): """ GET /api/users/{username}/links/ Список публичных ссылок пользователя (без группировки). """ 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 UserProfileView(generics.RetrieveAPIView): """ GET /api/auth/user/ Возвращает данные авторизованного пользователя. """ serializer_class = UserSerializer permission_classes = [permissions.IsAuthenticated] def get_object(self): return self.request.user class PublicUserGroupsView(APIView): """ GET /api/users/{username}/public/ Возвращает публичные группы и ссылки пользователя. """ permission_classes = [permissions.AllowAny] def get(self, request, username): user = get_object_or_404(User, username=username) # Берем все группы пользователя вместе с их ссылками groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links') result = { "username": user.username, "groups": [] } for grp in groups_qs: # URL иконки группы (поле icon в модели) grp_icon_url = grp.icon.url if grp.icon else None grp_data = { "id": grp.id, "name": grp.name, "icon": grp_icon_url, "links": [], } for ln in grp.links.all(): # URL иконки ссылки (поле icon в модели Link — URLField) link_icon_url = ln.icon if ln.icon else None grp_data["links"].append({ "id": ln.id, "title": ln.title, "url": ln.url, "icon": link_icon_url, }) result["groups"].append(grp_data) return Response(result, status=status.HTTP_200_OK)