new models, frontend functions, public pages

This commit is contained in:
2025-05-07 15:41:03 +09:00
parent 91f0d54563
commit 18497d4343
784 changed files with 124024 additions and 289 deletions

View File

@@ -0,0 +1,35 @@
from django.db import models
from django.conf import settings
class LinkGroup(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
)
name = models.CharField(max_length=100)
order = models.PositiveIntegerField(default=0)
description = models.TextField(blank=True, null=True)
def __str__(self):
return f"{self.owner.username} - {self.name}"
class Link(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='links'
)
group = models.ForeignKey(
LinkGroup,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='links'
)
title = models.CharField(max_length=200)
url = models.URLField()
icon = models.URLField(blank=True, null=True)
order = models.PositiveIntegerField(default=0)
def __str__(self):
return self.title

View File

@@ -0,0 +1,41 @@
from django.db import models
from django.conf import settings
class LinkGroup(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
)
name = models.CharField(max_length=100)
order = models.PositiveIntegerField(default=0)
description = models.TextField(blank=True, null=True)
icon = models.ImageField(
upload_to='link_groups/',
null=True,
blank=True,
help_text='Иконка группы ссылок'
)
def __str__(self):
return f"{self.owner.username} - {self.name}"
class Link(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='links'
)
group = models.ForeignKey(
LinkGroup,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='links'
)
title = models.CharField(max_length=200)
url = models.URLField()
icon = models.URLField(blank=True, null=True)
order = models.PositiveIntegerField(default=0)
def __str__(self):
return self.title

View File

@@ -0,0 +1,45 @@
from django.db import models
from django.conf import settings
class LinkGroup(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
)
name = models.CharField(max_length=100)
order = models.PositiveIntegerField(default=0)
description = models.TextField(blank=True, null=True)
icon = models.ImageField(
upload_to='link_groups/',
null=True,
blank=True,
help_text='Иконка группы ссылок'
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_public = models.BooleanField(default=False, help_text='Публичная группа ссылок')
is_favorite = models.BooleanField(default=False, help_text='Избранная группа ссылок')
def __str__(self):
return f"{self.owner.username} - {self.name}"
class Link(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='links'
)
group = models.ForeignKey(
LinkGroup,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='links'
)
title = models.CharField(max_length=200)
url = models.URLField()
icon = models.URLField(blank=True, null=True)
order = models.PositiveIntegerField(default=0)
def __str__(self):
return self.title

View File

@@ -0,0 +1,54 @@
# backend/api/models.py
from django.db import models
from django.conf import settings
class LinkGroup(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='api_link_groups'
)
name = models.CharField(max_length=100)
order = models.PositiveIntegerField(default=0)
description = models.TextField(blank=True, null=True)
icon = models.ImageField(
upload_to='link_groups/',
null=True,
blank=True,
help_text='Иконка группы ссылок'
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_public = models.BooleanField(default=False)
is_favorite = models.BooleanField(default=False)
def __str__(self):
return f"{self.owner.username}{self.name}"
class Link(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='links'
)
group = models.ForeignKey(
LinkGroup,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='links'
)
title = models.CharField(max_length=200)
url = models.URLField()
icon = models.ImageField(
upload_to='links/',
null=True,
blank=True,
help_text='Иконка для этой ссылки'
)
order = models.PositiveIntegerField(default=0)
def __str__(self):
return self.title

View File

@@ -0,0 +1,60 @@
# api/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Link, LinkGroup
User = get_user_model()
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ('username', 'email', 'password')
def create(self, validated_data):
user = User(
username=validated_data['username'],
email=validated_data.get('email', '')
)
user.set_password(validated_data['password'])
user.save()
return user
# api/serializers.py
from rest_framework import serializers
from django.conf import settings
from .models import Link, LinkGroup
# сериализатор для ссылок
class LinkSerializer(serializers.ModelSerializer):
class Meta:
model = Link
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
# сериализатор для групп со вложенными ссылками
class LinkGroupSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = LinkGroup
fields = [
'id',
'name',
'description',
'icon',
'owner',
'created_at',
]
read_only_fields = ['id', 'owner', 'created_at']
from django.contrib.auth import get_user_model
from rest_framework import serializers
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# поля, которые хотите отдавать на фронт:
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']

View File

@@ -0,0 +1,65 @@
# api/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Link, LinkGroup
User = get_user_model()
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ('username', 'email', 'password')
def create(self, validated_data):
user = User(
username=validated_data['username'],
email=validated_data.get('email', '')
)
user.set_password(validated_data['password'])
user.save()
return user
# api/serializers.py
from rest_framework import serializers
from django.conf import settings
from .models import Link, LinkGroup
# сериализатор для ссылок
class LinkSerializer(serializers.ModelSerializer):
class Meta:
model = Link
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
# сериализатор для групп со вложенными ссылками
class LinkGroupSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = LinkGroup
fields = [
'id',
'name',
'description',
'icon',
'owner',
'created_at',
]
read_only_fields = ['id', 'owner', 'created_at']
from django.contrib.auth import get_user_model
from rest_framework import serializers
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# поля, которые хотите отдавать на фронт:
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
class PublicUserGroupsSerializer(serializers.Serializer):
username = serializers.CharField()
groups = LinkGroupSerializer(many=True)

View File

@@ -0,0 +1,66 @@
# api/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Link, LinkGroup
User = get_user_model()
class RegisterSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name', 'password', 'password2']
extra_kwargs = {'password': {'write_only': True}}
def validate(self, attrs):
if attrs['password'] != attrs.pop('password2'):
raise serializers.ValidationError("Пароли не совпадают")
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
# api/serializers.py
from rest_framework import serializers
from django.conf import settings
from .models import Link, LinkGroup
# сериализатор для ссылок
class LinkSerializer(serializers.ModelSerializer):
class Meta:
model = Link
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
# сериализатор для групп со вложенными ссылками
class LinkGroupSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = LinkGroup
fields = [
'id',
'name',
'description',
'icon',
'owner',
'created_at',
]
read_only_fields = ['id', 'owner', 'created_at']
from django.contrib.auth import get_user_model
from rest_framework import serializers
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# поля, которые хотите отдавать на фронт:
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
class PublicUserGroupsSerializer(serializers.Serializer):
username = serializers.CharField()
groups = LinkGroupSerializer(many=True)

View File

@@ -0,0 +1,48 @@
# api/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Link, LinkGroup
from django.conf import settings
from .models import Link, LinkGroup
User = get_user_model()
class RegisterSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name', 'password', 'password2']
extra_kwargs = {'password': {'write_only': True}}
def validate(self, attrs):
if attrs['password'] != attrs.pop('password2'):
raise serializers.ValidationError("Пароли не совпадают")
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
# сериализатор для ссылок
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
class LinkGroupSerializer(serializers.ModelSerializer):
icon = serializers.ImageField(required=False, allow_null=True)
class Meta:
model = LinkGroup
fields = ['id', 'name', 'description', 'icon', 'order', 'is_public', 'is_favorite',
'created_at', 'updated_at']
read_only_fields = ['id', 'created_at', 'updated_at']
class LinkSerializer(serializers.ModelSerializer):
icon = serializers.ImageField(required=False, allow_null=True)
class Meta:
model = Link
fields = ['id', 'title', 'url', 'icon', 'group', 'order']
read_only_fields = ['id']

View File

@@ -0,0 +1,24 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet
)
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
] + router.urls

View File

@@ -0,0 +1,25 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet,
PublicUserGroupsView
)
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
] + router.urls

View File

@@ -0,0 +1,28 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet,
PublicUserGroupsView
)
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
path('schema/', SpectacularAPIView.as_view(), name='schema'),
path('swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
] + router.urls

View File

@@ -0,0 +1,29 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet,
PublicUserGroupsView
)
from rest_framework.routers import DefaultRouter
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
path('schema/', SpectacularAPIView.as_view(), name='schema'),
path('swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
] + router.urls

View File

@@ -0,0 +1,35 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet,
PublicUserGroupsView
)
from rest_framework.routers import DefaultRouter
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
# схема OpenAPI
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
path(
'api/swagger/',
SpectacularSwaggerView.as_view(url_name='schema'),
name='swagger-ui'
),
] + router.urls

View File

@@ -0,0 +1,35 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet,
PublicUserGroupsView
)
from rest_framework.routers import DefaultRouter
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
# схема OpenAPI
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
path(
'api/swagger/',
SpectacularSwaggerView.as_view(url_name='schema'),
name='swagger-ui'
),
] + router.urls

View File

@@ -0,0 +1,35 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (
RegisterView,
UserProfileView,
LinkViewSet,
LinkGroupViewSet,
PublicUserGroupsView
)
from rest_framework.routers import DefaultRouter
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
router = DefaultRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'
),
# схема OpenAPI
path('schema/', SpectacularAPIView.as_view(), name='schema'),
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
path(
'swagger/',
SpectacularSwaggerView.as_view(url_name='schema'),
name='swagger-ui'
),
] + router.urls

View File

@@ -0,0 +1,113 @@
# api/views.py
from rest_framework import generics, viewsets, permissions
from django.contrib.auth import get_user_model
from rest_framework_simplejwt.views import TokenObtainPairView
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
User = get_user_model()
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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/
Возвращает публичную страницу пользователя:
{
"username": "...",
"groups": [
{
"id": 1,
"name": "...",
"icon": "/storage/images/link_groups/1.png",
"links": [
{
"id": 5,
"title": "...",
"url": "...",
"icon": "/storage/images/links/5.png"
},
]
},
]
}
"""
permission_classes = [permissions.AllowAny]
def get(self, request, username):
User = get_user_model()
user = get_object_or_404(User, username=username)
# достаём все группы пользователя вместе с их ссылками
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
data = {
"username": user.username,
"groups": []
}
for grp in groups_qs:
grp_data = {
"id": grp.id,
"name": grp.name,
"icon": grp.icon.url if grp.icon else None,
"links": []
}
for ln in grp.links.all():
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": ln.icon.url if ln.icon else None
})
data["groups"].append(grp_data)
return Response(data, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,118 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
User = get_user_model()
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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/
Возвращает публичную страницу пользователя:
{
"username": "...",
"groups": [
{
"id": 1,
"name": "...",
"icon": "/storage/images/link_groups/1.png",
"links": [
{
"id": 5,
"title": "...",
"url": "...",
"icon": "/storage/images/links/5.png"
},
]
},
]
}
"""
permission_classes = [permissions.AllowAny]
def get(self, request, username):
User = get_user_model()
user = get_object_or_404(User, username=username)
# достаём все группы пользователя вместе с их ссылками
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
data = {
"username": user.username,
"groups": []
}
for grp in groups_qs:
grp_data = {
"id": grp.id,
"name": grp.name,
"icon": grp.icon.url if grp.icon else None,
"links": []
}
for ln in grp.links.all():
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": ln.icon.url if ln.icon else None
})
data["groups"].append(grp_data)
return Response(data, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,109 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
User = get_user_model()
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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_user_model()
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:
# поле image у группы
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_image_url,
"links": [],
}
for ln in grp.links.all():
# поле image у отдельной ссылки
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_image_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,109 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
User = get_user_model()
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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_user_model()
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:
# поле image у группы
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_image_url,
"links": [],
}
for ln in grp.links.all():
# поле image у отдельной ссылки
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_image_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,119 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
User = get_user_model()
@extend_schema(
parameters=[
OpenApiParameter(
name='id',
type=int,
location=OpenApiParameter.PATH
)
]
)
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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_user_model()
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:
# поле image у группы
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_image_url,
"links": [],
}
for ln in grp.links.all():
# поле image у отдельной ссылки
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_image_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,119 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
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
User = get_user_model()
@extend_schema(
parameters=[
OpenApiParameter(
name='id',
type=int,
location=OpenApiParameter.PATH
)
]
)
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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_user_model()
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:
# поле image у группы
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_image_url,
"links": [],
}
for ln in grp.links.all():
# поле image у отдельной ссылки
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_image_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,95 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
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
User = get_user_model()
@extend_schema(
parameters=[
OpenApiParameter(
name='id',
type=int,
location=OpenApiParameter.PATH
)
]
)
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
class UserProfileView(generics.RetrieveAPIView):
"""
Возвращает данные авторизованного пользователя.
GET /api/auth/user/
"""
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def get_object(self):
return self.request.user
@extend_schema(
responses=PublicUserGroupsSerializer
)
class PublicUserGroupsView(generics.GenericAPIView):
"""
Возвращает публичные группы и их ссылки для заданного username.
GET /api/users/{username}/public/
"""
serializer_class = PublicUserGroupsSerializer
permission_classes = [permissions.AllowAny]
def get(self, request, username):
user = get_object_or_404(User, username=username)
groups = LinkGroup.objects.filter(owner=user, is_public=True).prefetch_related('links')
# Формируем ответ в виде словаря — GenericAPIView сам вызовет нужный сериализатор:
return Response({
'username': user.username,
'groups': groups
})

View File

@@ -0,0 +1,98 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
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
User = get_user_model()
@extend_schema(
parameters=[
OpenApiParameter(
name='id',
type=int,
location=OpenApiParameter.PATH
)
]
)
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
class UserProfileView(generics.RetrieveAPIView):
"""
Возвращает данные авторизованного пользователя.
GET /api/auth/user/
"""
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def get_object(self):
return self.request.user
from users.models import User
from links.models import LinkGroup
from .serializers import PublicUserGroupsSerializer
@extend_schema(
responses=PublicUserGroupsSerializer
)
class PublicUserGroupsView(generics.GenericAPIView):
"""
Возвращает публичные группы и их ссылки для заданного username.
GET /api/users/{username}/public/
"""
serializer_class = PublicUserGroupsSerializer
permission_classes = [permissions.AllowAny]
def get(self, request, username):
user = get_object_or_404(User, username=username)
groups = LinkGroup.objects.filter(owner=user, is_public=True).prefetch_related('links')
# Формируем ответ в виде словаря — GenericAPIView сам вызовет нужный сериализатор:
return Response({
'username': user.username,
'groups': groups
})

View File

@@ -0,0 +1,119 @@
# 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 .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
from .models import Link, LinkGroup
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
User = get_user_model()
@extend_schema(
parameters=[
OpenApiParameter(
name='id',
type=int,
location=OpenApiParameter.PATH
)
]
)
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = RegisterSerializer
class LoginView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
class LinkGroupViewSet(viewsets.ModelViewSet):
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# возвращаем только группы текущего пользователя
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
serializer_class = LinkSerializer
permission_classes = (permissions.IsAuthenticated,)
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 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')
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
User = get_user_model()
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_user_model()
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:
# поле image у группы
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_image_url,
"links": [],
}
for ln in grp.links.all():
# поле image у отдельной ссылки
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_image_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,151 @@
# 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)

View File

@@ -0,0 +1,248 @@
# # 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)
# backend/api/views.py
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 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
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):
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:
grp_icon = grp.icon.url if grp.icon else None
grp_data = {"id": grp.id, "name": grp.name, "icon": grp_icon, "links": []}
for ln in grp.links.all():
link_icon = ln.icon.url if hasattr(ln.icon, 'url') else ln.icon
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": link_icon,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,272 @@
# # 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)
# backend/api/views.py
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 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
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. Берём его группы со ссылками
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
result = {
"username": user.username,
"groups": []
}
for grp in groups_qs:
# icon у группы (абсолютный URL)
grp_icon_url = None
if grp.icon:
grp_icon_url = request.build_absolute_uri(grp.icon.url)
grp_data = {
"id": grp.id,
"name": grp.name,
"icon": grp_icon_url,
"links": [],
}
for ln in grp.links.all():
# icon у ссылки
ln_icon_url = None
if ln.icon:
ln_icon_url = request.build_absolute_uri(ln.icon.url)
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": ln_icon_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,267 @@
# # 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)
# backend/api/views.py
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 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
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):
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:
# поле icon у группы — это ImageField
grp_icon_url = grp.icon.url if grp.icon else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_icon_url, # отдаём под ключом "image", как ждёт фронт
"links": [],
}
for ln in grp.links.all():
# поле icon у ссылки — это URLField, сразу строка
link_icon_url = ln.icon if ln.icon else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_icon_url, # тоже "image"
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,272 @@
# # 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)
# backend/api/views.py
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 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
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. Берём его группы со ссылками
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
result = {
"username": user.username,
"groups": []
}
for grp in groups_qs:
# icon у группы (абсолютный URL)
grp_icon_url = None
if grp.icon:
grp_icon_url = request.build_absolute_uri(grp.icon.url)
grp_data = {
"id": grp.id,
"name": grp.name,
"icon": grp_icon_url,
"links": [],
}
for ln in grp.links.all():
# icon у ссылки
ln_icon_url = None
if ln.icon:
ln_icon_url = request.build_absolute_uri(ln.icon.url)
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": ln_icon_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,119 @@
# 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 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
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. Берём его группы со ссылками
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
result = {
"username": user.username,
"groups": []
}
for grp in groups_qs:
# icon у группы (абсолютный URL)
grp_icon_url = None
if grp.icon:
grp_icon_url = request.build_absolute_uri(grp.icon.url)
grp_data = {
"id": grp.id,
"name": grp.name,
"icon": grp_icon_url,
"links": [],
}
for ln in grp.links.all():
# icon у ссылки
ln_icon_url = None
if ln.icon:
ln_icon_url = request.build_absolute_uri(ln.icon.url)
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": ln_icon_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,150 @@
# api/views.py
from django.contrib.auth import get_user_model
from django.shortcuts import get_object_or_404
from rest_framework import generics, viewsets, permissions, status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.views import TokenObtainPairView
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,
description='ID создаваемого или изменяемого объекта',
)
]
)
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):
"""
CRUD для групп ссылок текущего пользователя.
/api/groups/
"""
queryset = LinkGroup.objects.all()
serializer_class = LinkGroupSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# Только свои группы
return self.queryset.filter(owner=self.request.user).order_by('order')
class LinkViewSet(viewsets.ModelViewSet):
"""
CRUD для ссылок текущего пользователя.
/api/links/
"""
serializer_class = LinkSerializer
permission_classes = [permissions.IsAuthenticated]
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 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:
# иконка группы (ImageField)
grp_icon_url = grp.icon.url if grp.icon else None
grp_data = {
"id": grp.id,
"name": grp.name,
"image": grp_icon_url,
"links": []
}
for ln in grp.links.all():
# иконка ссылки (URLField)
link_icon_url = ln.icon if ln.icon else None
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"image": link_icon_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,119 @@
# 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 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
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. Берём его группы со ссылками
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
result = {
"username": user.username,
"groups": []
}
for grp in groups_qs:
# icon у группы (абсолютный URL)
grp_icon_url = None
if grp.icon:
grp_icon_url = request.build_absolute_uri(grp.icon.url)
grp_data = {
"id": grp.id,
"name": grp.name,
"icon": grp_icon_url,
"links": [],
}
for ln in grp.links.all():
# icon у ссылки
ln_icon_url = None
if ln.icon:
ln_icon_url = request.build_absolute_uri(ln.icon.url)
grp_data["links"].append({
"id": ln.id,
"title": ln.title,
"url": ln.url,
"icon": ln_icon_url,
})
result["groups"].append(grp_data)
return Response(result, status=status.HTTP_200_OK)