This commit is contained in:
nvrl committed 2026-04-11 10:37:49 +02:00
1 parent 5e3474dd59
commit e4d59a13ba
119 files changed
+15490 -9975

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
from api.serializers.flavor import CategorySerializer, FlavorSerializer
from api.serializers.rating import RatingSerializer, ReplySerializer
from api.serializers.social import NotificationSerializer, ProfileCommentSerializer
from api.serializers.support import TicketMessageSerializer, TicketSerializer
from api.serializers.system import (
BannerSerializer,
JobSerializer,
SystemConfigSerializer,
)
from api.serializers.user import (
AdminUserDetailSerializer,
AdminUserListSerializer,
UserIPSerializer,
UserSerializer,
)
__all__ = [
"AdminUserDetailSerializer",
"AdminUserListSerializer",
"BannerSerializer",
"CategorySerializer",
"FlavorSerializer",
"JobSerializer",
"NotificationSerializer",
"ProfileCommentSerializer",
"RatingSerializer",
"ReplySerializer",
"SystemConfigSerializer",
"TicketMessageSerializer",
"TicketSerializer",
"UserIPSerializer",
"UserSerializer",
]
+10
View File
@@ -0,0 +1,10 @@
from typing import Any
def absolute_image_url(serializer: Any, image_field: Any) -> str | None:
if not image_field:
return None
request = serializer.context.get("request")
if request:
return request.build_absolute_uri(image_field.url)
return image_field.url
+56
View File
@@ -0,0 +1,56 @@
from rest_framework import serializers
from api.models import Category, Flavor, Rating
from api.serializers._helpers import absolute_image_url
from api.serializers.rating import RatingSerializer
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ["id", "name", "slug"]
class FlavorSerializer(serializers.ModelSerializer):
category_name = serializers.CharField(source="category.name", read_only=True)
category_slug = serializers.CharField(source="category.slug", read_only=True)
average_rating = serializers.FloatField(read_only=True)
followed_average_rating = serializers.FloatField(read_only=True)
user_rating = serializers.SerializerMethodField()
ratings = RatingSerializer(many=True, read_only=True)
image_url = serializers.SerializerMethodField()
class Meta:
model = Flavor
fields = [
"id",
"name",
"category",
"category_name",
"category_slug",
"description",
"average_rating",
"followed_average_rating",
"user_rating",
"ratings",
"image_url",
"image",
"is_available",
"is_legacy",
"shop_url",
]
extra_kwargs = {"image": {"write_only": True}}
def get_image_url(self, obj: Flavor) -> str | None:
if obj.image:
return absolute_image_url(self, obj.image)
return obj.image_url
def get_user_rating(self, obj: Flavor) -> int | None:
request = self.context.get("request")
if request and request.user.is_authenticated:
try:
return request.user.ratings.get(flavor=obj).score
except Rating.DoesNotExist:
return None
return None
+54
View File
@@ -0,0 +1,54 @@
from rest_framework import serializers
from api.models import Rating, Reply
from api.serializers._helpers import absolute_image_url
class ReplySerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True)
class Meta:
model = Reply
fields = ["id", "user", "rating", "text", "created_at"]
read_only_fields = ["rating"]
class RatingSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True)
user_id = serializers.IntegerField(source="user.id", read_only=True)
user_avatar = serializers.SerializerMethodField()
flavor_name = serializers.CharField(source="flavor.name", read_only=True)
flavor_image = serializers.SerializerMethodField()
category_name = serializers.CharField(source="flavor.category.name", read_only=True)
category_slug = serializers.CharField(source="flavor.category.slug", read_only=True)
is_available = serializers.BooleanField(source="flavor.is_available", read_only=True)
is_legacy = serializers.BooleanField(source="flavor.is_legacy", read_only=True)
replies = ReplySerializer(many=True, read_only=True)
class Meta:
model = Rating
fields = [
"id",
"user",
"user_id",
"user_avatar",
"flavor",
"flavor_name",
"flavor_image",
"category_name",
"category_slug",
"is_available",
"is_legacy",
"score",
"comment",
"created_at",
"replies",
]
def get_user_avatar(self, obj: Rating) -> str | None:
return absolute_image_url(self, obj.user.avatar)
def get_flavor_image(self, obj: Rating) -> str | None:
if obj.flavor.image:
return absolute_image_url(self, obj.flavor.image)
return obj.flavor.image_url
+64
View File
@@ -0,0 +1,64 @@
from rest_framework import serializers
from api.models import Notification, ProfileComment
from api.serializers._helpers import absolute_image_url
class ProfileCommentSerializer(serializers.ModelSerializer):
author_username = serializers.CharField(source="author.username", read_only=True)
author_avatar = serializers.SerializerMethodField()
class Meta:
model = ProfileComment
fields = ["id", "author_username", "author_avatar", "text", "created_at"]
def get_author_avatar(self, obj: ProfileComment) -> str | None:
return absolute_image_url(self, obj.author.avatar)
class NotificationSerializer(serializers.ModelSerializer):
actor_username = serializers.CharField(source="actor.username", read_only=True)
actor_avatar = serializers.SerializerMethodField()
flavor_name = serializers.SerializerMethodField()
flavor_id = serializers.SerializerMethodField()
profile_owner_username = serializers.SerializerMethodField()
class Meta:
model = Notification
fields = [
"id",
"actor_username",
"actor_avatar",
"notification_type",
"rating",
"reply",
"ticket",
"profile_comment",
"profile_owner_username",
"is_read",
"created_at",
"flavor_name",
"flavor_id",
]
def get_actor_avatar(self, obj: Notification) -> str | None:
return absolute_image_url(self, obj.actor.avatar)
def get_flavor_name(self, obj: Notification) -> str | None:
if obj.rating:
return obj.rating.flavor.name
if obj.reply:
return obj.reply.rating.flavor.name
return None
def get_flavor_id(self, obj: Notification) -> int | None:
if obj.rating:
return obj.rating.flavor.id
if obj.reply:
return obj.reply.rating.flavor.id
return None
def get_profile_owner_username(self, obj: Notification) -> str | None:
if obj.profile_comment:
return obj.profile_comment.profile_owner.username
return None
+40
View File
@@ -0,0 +1,40 @@
from rest_framework import serializers
from api.models import Ticket, TicketMessage
from api.serializers._helpers import absolute_image_url
class TicketMessageSerializer(serializers.ModelSerializer):
username = serializers.CharField(source="user.username", read_only=True)
is_admin = serializers.BooleanField(source="user.is_superuser", read_only=True)
class Meta:
model = TicketMessage
fields = ["id", "username", "text", "created_at", "is_admin"]
class TicketSerializer(serializers.ModelSerializer):
username = serializers.CharField(source="user.username", read_only=True)
user_email = serializers.EmailField(source="user.email", read_only=True)
user_avatar = serializers.SerializerMethodField()
messages = TicketMessageSerializer(many=True, read_only=True)
class Meta:
model = Ticket
fields = [
"id",
"user",
"username",
"user_email",
"user_avatar",
"subject",
"description",
"status",
"created_at",
"updated_at",
"messages",
]
read_only_fields = ["status", "user"]
def get_user_avatar(self, obj: Ticket) -> str | None:
return absolute_image_url(self, obj.user.avatar)
+57
View File
@@ -0,0 +1,57 @@
from rest_framework import serializers
from api.models import Banner, Job, SystemConfig
class SystemConfigSerializer(serializers.ModelSerializer):
class Meta:
model = SystemConfig
fields = [
"site_name",
"maintenance_mode",
"allow_new_signups",
"require_email_verification",
"updated_at",
]
class JobSerializer(serializers.ModelSerializer):
name_display = serializers.CharField(source="get_name_display", read_only=True)
class Meta:
model = Job
fields = [
"id",
"name",
"name_display",
"status",
"last_run",
"next_run",
"interval_hours",
"last_output",
"error_message",
]
read_only_fields = [
"status",
"last_run",
"next_run",
"last_output",
"error_message",
]
class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = Banner
fields = [
"id",
"name",
"slug",
"description",
"is_active",
"is_enabled",
"settings",
"schema",
"created_at",
"updated_at",
]
+95
View File
@@ -0,0 +1,95 @@
from rest_framework import serializers
from api.models import User, UserIP
from api.serializers._helpers import absolute_image_url
from api.serializers.rating import RatingSerializer
class UserSerializer(serializers.ModelSerializer):
avatar = serializers.SerializerMethodField()
following_count = serializers.IntegerField(source="following.count", read_only=True)
followers_count = serializers.IntegerField(source="followers.count", read_only=True)
is_following = serializers.SerializerMethodField()
unread_notifications_count = serializers.SerializerMethodField()
is_superuser = serializers.BooleanField(read_only=True)
selected_banner_slug = serializers.CharField(
source="selected_banner.slug", read_only=True, allow_null=True
)
class Meta:
model = User
fields = [
"id",
"username",
"email",
"theme",
"language",
"avatar",
"following_count",
"followers_count",
"is_following",
"unread_notifications_count",
"is_superuser",
"selected_banner",
"selected_banner_slug",
]
def get_avatar(self, obj: User) -> str | None:
return absolute_image_url(self, obj.avatar)
def get_is_following(self, obj: User) -> bool:
request = self.context.get("request")
if request and request.user.is_authenticated:
return request.user.following.filter(pk=obj.pk).exists()
return False
def get_unread_notifications_count(self, obj: User) -> int:
return obj.notifications.filter(is_read=False).count()
class UserIPSerializer(serializers.ModelSerializer):
class Meta:
model = UserIP
fields = ["id", "ip_address", "last_login"]
class AdminUserListSerializer(serializers.ModelSerializer):
ips = serializers.SerializerMethodField()
class Meta:
model = User
fields = [
"id",
"username",
"email",
"is_active",
"is_superuser",
"date_joined",
"last_login",
"ips",
]
def get_ips(self, obj: User) -> list[str]:
return [ip.ip_address for ip in obj.ips.all()[:3]]
class AdminUserDetailSerializer(serializers.ModelSerializer):
ips = serializers.SerializerMethodField()
ratings = RatingSerializer(many=True, read_only=True)
class Meta:
model = User
fields = [
"id",
"username",
"email",
"is_active",
"is_superuser",
"date_joined",
"last_login",
"ips",
"ratings",
]
def get_ips(self, obj: User) -> list[str]:
return [ip.ip_address for ip in obj.ips.all()]