from rest_framework import serializers from apps.books.models import Book, EBook, FontStyle, BackgroundColor, ReadingProgress, ReadingSettings, ReadingStatus class BookListSerializer(serializers.ModelSerializer): reading_status_display = serializers.CharField(source="get_reading_status_display", read_only=True) class Meta: model = Book fields = ["id", "title", "author", "genre", "reading_status", "reading_status_display", "cover_image"] class BookDetailSerializer(serializers.ModelSerializer): reading_status_display = serializers.CharField(source="get_reading_status_display", read_only=True) class Meta: model = Book fields = ["id", "title", "author", "genre", "description", "reading_status", "reading_status_display", "cover_image", "total_pages", "created_at", "updated_at"] read_only_fields = ["id", "created_at", "updated_at"] class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ["id", "title", "author", "genre", "description", "reading_status", "cover_image", "total_pages", "created_at", "updated_at"] read_only_fields = ["id", "created_at", "updated_at"] class EBookListSerializer(serializers.ModelSerializer): filename = serializers.CharField(read_only=True) progress = serializers.SerializerMethodField() class Meta: model = EBook fields = ["id", "title", "author", "filename", "cover_image", "created_at", "progress"] def get_progress(self, obj): try: return obj.reading_progress.current_position except ReadingProgress.DoesNotExist: return None class EBookDetailSerializer(serializers.ModelSerializer): filename = serializers.CharField(read_only=True) file_url = serializers.SerializerMethodField() progress = serializers.SerializerMethodField() class Meta: model = EBook fields = ["id", "title", "author", "filename", "file_url", "cover_image", "created_at", "updated_at", "progress"] def get_file_url(self, obj): request = self.context.get("request") if request and obj.file: return request.build_absolute_uri(obj.file.url) return "" def get_progress(self, obj): try: rp = obj.reading_progress return {"current_position": rp.current_position, "last_page": rp.last_page} except ReadingProgress.DoesNotExist: return None class EBookUploadSerializer(serializers.ModelSerializer): class Meta: model = EBook fields = ["title", "author", "file", "cover_image"] extra_kwargs = {"title": {"required": True}, "file": {"required": True}} def validate_file(self, value): import os if value is None: return value ext = os.path.splitext(str(getattr(value, "name", "")))[1].lower() if ext not in (".epub", ".pdf"): raise serializers.ValidationError("Only EPUB and PDF files are supported.") return value def create(self, validated_data): validated_data["user"] = self.context["request"].user return super().create(validated_data) class ReadingProgressSerializer(serializers.ModelSerializer): class Meta: model = ReadingProgress fields = ["current_position", "last_page"] extra_kwargs = {"current_position": {"required": True, "min_value": 0.0, "max_value": 100.0}} def validate_current_position(self, value): if value < 0.0 or value > 100.0: raise serializers.ValidationError("Position must be between 0.0 and 100.0.") return value class ReadingSettingsSerializer(serializers.ModelSerializer): class Meta: model = ReadingSettings fields = ["font_size", "font_style", "background_color"] def validate_font_size(self, value): if value < 12 or value > 36: raise serializers.ValidationError("Font size must be between 12 and 36.") return value def validate_font_style(self, value): valid = [s.value for s in FontStyle] if value not in valid: raise serializers.ValidationError(f"Font style must be one of: {', '.join(valid)}") return value def validate_background_color(self, value): valid = [c.value for c in BackgroundColor] if value not in valid: raise serializers.ValidationError(f"Background color must be one of: {', '.join(valid)}") return value