mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-04 00:47:02 +01:00
redesign taste profile
This commit is contained in:
1 parent
b096192b57
commit
a6e946444a
5 files changed
+450
-182
No files matched your search
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 6.0.2 on 2026-02-18 03:31
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('api', '0016_notification_ticket_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProfileComment',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='authored_profile_comments', to=settings.AUTH_USER_MODEL)),
|
||||
('profile_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='profile_comments', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -176,3 +176,12 @@ class TicketMessage(models.Model):
|
||||
|
||||
class Meta:
|
||||
ordering = ['created_at']
|
||||
|
||||
class ProfileComment(models.Model):
|
||||
profile_owner = models.ForeignKey(User, related_name='profile_comments', on_delete=models.CASCADE)
|
||||
author = models.ForeignKey(User, related_name='authored_profile_comments', on_delete=models.CASCADE)
|
||||
text = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
@@ -136,6 +136,23 @@ class TicketSerializer(serializers.ModelSerializer):
|
||||
return obj.user.avatar.url
|
||||
return None
|
||||
|
||||
class ProfileCommentSerializer(serializers.ModelSerializer):
|
||||
author_username = serializers.CharField(source='author.username', read_only=True)
|
||||
author_avatar = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
from .models import ProfileComment
|
||||
model = ProfileComment
|
||||
fields = ['id', 'author_username', 'author_avatar', 'text', 'created_at']
|
||||
|
||||
def get_author_avatar(self, obj):
|
||||
if obj.author.avatar:
|
||||
request = self.context.get('request')
|
||||
if request:
|
||||
return request.build_absolute_uri(obj.author.avatar.url)
|
||||
return obj.author.avatar.url
|
||||
return None
|
||||
|
||||
class AdminUserListSerializer(serializers.ModelSerializer):
|
||||
ips = serializers.SerializerMethodField()
|
||||
|
||||
|
||||
+45
-5
@@ -8,8 +8,13 @@ from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_ratelimit.decorators import ratelimit
|
||||
from django.utils.decorators import method_decorator
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from .models import User, Flavor, Category, Rating, Reply, Notification, Ticket, TicketMessage, UserIP
|
||||
from .serializers import UserSerializer, FlavorSerializer, CategorySerializer, RatingSerializer, ReplySerializer, NotificationSerializer, TicketSerializer, TicketMessageSerializer, AdminUserListSerializer, AdminUserDetailSerializer
|
||||
from .models import User, Flavor, Category, Rating, Reply, Notification, Ticket, TicketMessage, UserIP, ProfileComment
|
||||
from .serializers import (
|
||||
UserSerializer, FlavorSerializer, CategorySerializer, RatingSerializer,
|
||||
ReplySerializer, NotificationSerializer, TicketSerializer,
|
||||
TicketMessageSerializer, AdminUserListSerializer, AdminUserDetailSerializer,
|
||||
ProfileCommentSerializer
|
||||
)
|
||||
|
||||
def log_user_ip(user, request):
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
@@ -345,18 +350,53 @@ class UserViewSet(viewsets.ModelViewSet):
|
||||
return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
ratings = user.ratings.select_related('flavor', 'flavor__category').order_by('-score')
|
||||
comments = user.profile_comments.select_related('author').order_by('-created_at')
|
||||
|
||||
followers = user.followers.all()
|
||||
following = user.following.all()
|
||||
|
||||
return Response({
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'theme': user.theme,
|
||||
'avatar': request.build_absolute_uri(user.avatar.url) if user.avatar else None,
|
||||
'following_count': user.following.count(),
|
||||
'followers_count': user.followers.count(),
|
||||
'following_count': following.count(),
|
||||
'followers_count': followers.count(),
|
||||
'is_following': request.user.following.filter(pk=user.pk).exists() if request.user.is_authenticated else False,
|
||||
'ratings': RatingSerializer(ratings, many=True, context={'request': request}).data
|
||||
'ratings': RatingSerializer(ratings, many=True, context={'request': request}).data,
|
||||
'comments': ProfileCommentSerializer(comments, many=True, context={'request': request}).data,
|
||||
'followers': UserSerializer(followers, many=True, context={'request': request}).data,
|
||||
'following': UserSerializer(following, many=True, context={'request': request}).data
|
||||
})
|
||||
|
||||
@action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
|
||||
def add_comment(self, request, pk=None):
|
||||
profile_owner = self.get_object()
|
||||
text = request.data.get('text')
|
||||
if not text:
|
||||
return Response({'error': 'Text is required'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
comment = ProfileComment.objects.create(
|
||||
profile_owner=profile_owner,
|
||||
author=request.user,
|
||||
text=text
|
||||
)
|
||||
return Response(ProfileCommentSerializer(comment, context={'request': request}).data, status=status.HTTP_201_CREATED)
|
||||
|
||||
@action(detail=True, methods=['delete'], url_path='delete_comment/(?P<comment_id>[^/.]+)', permission_classes=[permissions.IsAuthenticated])
|
||||
def delete_comment(self, request, pk=None, comment_id=None):
|
||||
profile_owner = self.get_object()
|
||||
try:
|
||||
comment = ProfileComment.objects.get(pk=comment_id, profile_owner=profile_owner)
|
||||
except ProfileComment.DoesNotExist:
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
if comment.author != request.user and not request.user.is_superuser and profile_owner != request.user:
|
||||
return Response(status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
comment.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def me(self, request):
|
||||
log_user_ip(request.user, request)
|
||||
|
||||
Reference in new issue
Block a user