diff --git a/backend/apps/articles/serializers.py b/backend/apps/articles/serializers.py new file mode 100644 index 0000000..3cd9401 --- /dev/null +++ b/backend/apps/articles/serializers.py @@ -0,0 +1,65 @@ +from rest_framework import serializers +from .models import Article + + +class ArticleSerializer(serializers.ModelSerializer): + """Serializer for Article model.""" + + article_type_display = serializers.CharField(source='get_article_type_display', read_only=True) + status_display = serializers.CharField(source='get_publish_status_display', read_only=True) + moderator_status_display = serializers.CharField(source='get_moderator_status_display', read_only=True) + ai_status_display = serializers.CharField(source='get_ai_status_display', read_only=True) + author_username = serializers.CharField(source='author.username', read_only=True) + region_name = serializers.CharField(source='region.name', read_only=True) + + class Meta: + model = Article + fields = ('id', 'title', 'content', 'region', 'region_name', 'article_type', 'article_type_display', + 'author', 'author_username', 'moderator_status', 'moderator_status_display', + 'moderator_reviewer', 'moderator_reviewed_at', 'moderator_rejection_reason', + 'ai_status', 'ai_status_display', 'ai_reviewed_at', 'ai_rejection_reason', + 'publish_status', 'status_display', 'published_at', 'created_at', 'updated_at') + read_only_fields = ('id', 'author', 'moderator_reviewer', 'moderator_reviewed_at', + 'ai_reviewed_at', 'published_at', 'created_at', 'updated_at') + + +class ArticleCreateSerializer(serializers.ModelSerializer): + """Serializer for creating articles.""" + + class Meta: + model = Article + fields = ('title', 'content', 'region', 'article_type') + + def create(self, validated_data): + validated_data['author'] = self.context['request'].user + return super().create(validated_data) + + +class ArticleUpdateSerializer(serializers.ModelSerializer): + """Serializer for updating articles.""" + + class Meta: + model = Article + fields = ('title', 'content', 'article_type') + + +class ArticleReviewSerializer(serializers.Serializer): + """Serializer for article review actions.""" + + action = serializers.ChoiceField(choices=['approve', 'reject']) + reason = serializers.CharField(required=False, allow_blank=True) + + +class ArticleListSerializer(serializers.ModelSerializer): + """Simplified serializer for article list.""" + + article_type_display = serializers.CharField(source='get_article_type_display', read_only=True) + author_username = serializers.CharField(source='author.username', read_only=True) + region_name = serializers.CharField(source='region.name', read_only=True) + + class Meta: + model = Article + fields = ('id', 'title', 'article_type', 'article_type_display', + 'author', 'author_username', 'region', 'region_name', + 'publish_status', 'created_at') + read_only_fields = ('id', 'created_at') \ No newline at end of file diff --git a/backend/apps/featured_services/serializers.py b/backend/apps/featured_services/serializers.py new file mode 100644 index 0000000..3165251 --- /dev/null +++ b/backend/apps/featured_services/serializers.py @@ -0,0 +1,66 @@ +from rest_framework import serializers +from .models import FeaturedService + + +class FeaturedServiceSerializer(serializers.ModelSerializer): + """Serializer for FeaturedService model.""" + + category_display = serializers.CharField(source='get_category_display', read_only=True) + status_display = serializers.CharField(source='get_publish_status_display', read_only=True) + moderator_status_display = serializers.CharField(source='get_moderator_status_display', read_only=True) + ai_status_display = serializers.CharField(source='get_ai_status_display', read_only=True) + submitter_username = serializers.CharField(source='submitter.username', read_only=True) + region_name = serializers.CharField(source='region.name', read_only=True) + + class Meta: + model = FeaturedService + fields = ('id', 'name', 'description', 'region', 'region_name', 'category', 'category_display', + 'address', 'contact', 'image', 'submitter', 'submitter_username', + 'moderator_status', 'moderator_status_display', 'moderator_reviewer', + 'moderator_reviewed_at', 'moderator_rejection_reason', + 'ai_status', 'ai_status_display', 'ai_reviewed_at', 'ai_rejection_reason', + 'publish_status', 'status_display', 'published_at', 'created_at', 'updated_at') + read_only_fields = ('id', 'submitter', 'moderator_reviewer', 'moderator_reviewed_at', + 'ai_reviewed_at', 'published_at', 'created_at', 'updated_at') + + +class FeaturedServiceCreateSerializer(serializers.ModelSerializer): + """Serializer for creating featured services.""" + + class Meta: + model = FeaturedService + fields = ('name', 'description', 'region', 'category', 'address', 'contact', 'image') + + def create(self, validated_data): + validated_data['submitter'] = self.context['request'].user + return super().create(validated_data) + + +class FeaturedServiceUpdateSerializer(serializers.ModelSerializer): + """Serializer for updating featured services.""" + + class Meta: + model = FeaturedService + fields = ('name', 'description', 'category', 'address', 'contact', 'image') + + +class FeaturedServiceReviewSerializer(serializers.Serializer): + """Serializer for service review actions.""" + + action = serializers.ChoiceField(choices=['approve', 'reject']) + reason = serializers.CharField(required=False, allow_blank=True) + + +class FeaturedServiceListSerializer(serializers.ModelSerializer): + """Simplified serializer for service list.""" + + category_display = serializers.CharField(source='get_category_display', read_only=True) + submitter_username = serializers.CharField(source='submitter.username', read_only=True) + region_name = serializers.CharField(source='region.name', read_only=True) + + class Meta: + model = FeaturedService + fields = ('id', 'name', 'category', 'category_display', 'image', + 'submitter', 'submitter_username', 'region', 'region_name', + 'publish_status', 'created_at') + read_only_fields = ('id', 'created_at') \ No newline at end of file diff --git a/backend/apps/interactions/serializers.py b/backend/apps/interactions/serializers.py new file mode 100644 index 0000000..5256e83 --- /dev/null +++ b/backend/apps/interactions/serializers.py @@ -0,0 +1,117 @@ +from rest_framework import serializers +from .models import Comment, Rating, Like, Favorite + + +class CommentSerializer(serializers.ModelSerializer): + """Serializer for Comment model.""" + + target_type_display = serializers.CharField(source='get_target_type_display', read_only=True) + ai_status_display = serializers.CharField(source='get_ai_status_display', read_only=True) + author_username = serializers.CharField(source='author.username', read_only=True) + + class Meta: + model = Comment + fields = ('id', 'content', 'target_type', 'target_type_display', 'target_id', + 'author', 'author_username', 'ai_status', 'ai_status_display', + 'ai_rejection_reason', 'created_at') + read_only_fields = ('id', 'author', 'ai_status', 'ai_rejection_reason', 'created_at') + + def create(self, validated_data): + validated_data['author'] = self.context['request'].user + return super().create(validated_data) + + +class CommentCreateSerializer(serializers.ModelSerializer): + """Serializer for creating comments.""" + + class Meta: + model = Comment + fields = ('content', 'target_type', 'target_id') + + def create(self, validated_data): + validated_data['author'] = self.context['request'].user + return super().create(validated_data) + + +class RatingSerializer(serializers.ModelSerializer): + """Serializer for Rating model.""" + + target_type_display = serializers.CharField(source='get_target_type_display', read_only=True) + user_username = serializers.CharField(source='user.username', read_only=True) + + class Meta: + model = Rating + fields = ('id', 'user', 'user_username', 'target_type', 'target_type_display', + 'target_id', 'score', 'created_at') + read_only_fields = ('id', 'user', 'created_at') + + def create(self, validated_data): + validated_data['user'] = self.context['request'].user + return super().create(validated_data) + + +class RatingCreateSerializer(serializers.ModelSerializer): + """Serializer for creating/updating ratings.""" + + class Meta: + model = Rating + fields = ('target_type', 'target_id', 'score') + + def create(self, validated_data): + validated_data['user'] = self.context['request'].user + # Check if rating already exists + Rating.objects.filter( + user=validated_data['user'], + target_type=validated_data['target_type'], + target_id=validated_data['target_id'] + ).delete() + return super().create(validated_data) + + +class LikeSerializer(serializers.ModelSerializer): + """Serializer for Like model.""" + + target_type_display = serializers.CharField(source='get_target_type_display', read_only=True) + user_username = serializers.CharField(source='user.username', read_only=True) + + class Meta: + model = Like + fields = ('id', 'user', 'user_username', 'target_type', 'target_type_display', + 'target_id', 'created_at') + read_only_fields = ('id', 'user', 'created_at') + + +class FavoriteSerializer(serializers.ModelSerializer): + """Serializer for Favorite model.""" + + target_type_display = serializers.CharField(source='get_target_type_display', read_only=True) + user_username = serializers.CharField(source='user.username', read_only=True) + + class Meta: + model = Favorite + fields = ('id', 'user', 'user_username', 'target_type', 'target_type_display', + 'target_id', 'created_at') + read_only_fields = ('id', 'user', 'created_at') + + +class FavoriteCreateSerializer(serializers.ModelSerializer): + """Serializer for creating/removing favorites.""" + + class Meta: + model = Favorite + fields = ('target_type', 'target_id') + + def create(self, validated_data): + validated_data['user'] = self.context['request'].user + # Check if favorite already exists + existing = Favorite.objects.filter( + user=validated_data['user'], + target_type=validated_data['target_type'], + target_id=validated_data['target_id'] + ).first() + + if existing: + existing.delete() + return None # Return None to indicate removal + + return super().create(validated_data) \ No newline at end of file diff --git a/backend/apps/moderation/serializers.py b/backend/apps/moderation/serializers.py new file mode 100644 index 0000000..f5a94da --- /dev/null +++ b/backend/apps/moderation/serializers.py @@ -0,0 +1,92 @@ +from rest_framework import serializers +from .models import ( + ModeratorApplication, + ModeratorPermission, + ModeratorSupport, + PermissionRestriction +) + + +class ModeratorApplicationSerializer(serializers.ModelSerializer): + """Serializer for ModeratorApplication model.""" + + status_display = serializers.CharField(source='get_status_display', read_only=True) + rank_display = serializers.CharField(source='get_rank_display', read_only=True) + applicant_username = serializers.CharField(source='applicant.username', read_only=True) + region_name = serializers.CharField(source='region.name', read_only=True) + region_path = serializers.SerializerMethodField() + is_expired = serializers.BooleanField(read_only=True) + + class Meta: + model = ModeratorApplication + fields = ('id', 'applicant', 'applicant_username', 'region', 'region_name', 'region_path', + 'support_count', 'deadline', 'status', 'status_display', 'rank', + 'is_expired', 'reviewed_by', 'reviewed_at', 'created_at') + read_only_fields = ('id', 'created_at', 'reviewed_by', 'reviewed_at') + + def get_region_path(self, obj): + return obj.region.get_full_path() + + +class ModeratorApplicationCreateSerializer(serializers.ModelSerializer): + """Serializer for creating moderator applications.""" + + class Meta: + model = ModeratorApplication + fields = ('region', 'rank', 'deadline') + + def create(self, validated_data): + validated_data['applicant'] = self.context['request'].user + return super().create(validated_data) + + +class ModeratorPermissionSerializer(serializers.ModelSerializer): + """Serializer for ModeratorPermission model.""" + + status_display = serializers.CharField(source='get_status_display', read_only=True) + rank_display = serializers.CharField(source='get_rank_display', read_only=True) + moderator_username = serializers.CharField(source='moderator.username', read_only=True) + region_name = serializers.CharField(source='region.name', read_only=True) + is_active = serializers.BooleanField(read_only=True) + + class Meta: + model = ModeratorPermission + fields = ('id', 'moderator', 'moderator_username', 'region', 'region_name', + 'rank', 'rank_display', 'status', 'status_display', 'is_active', + 'restricted_until', 'created_at') + read_only_fields = ('id', 'created_at') + + +class ModeratorSupportSerializer(serializers.ModelSerializer): + """Serializer for ModeratorSupport model.""" + + supporter_username = serializers.CharField(source='supporter.username', read_only=True) + application_region_name = serializers.CharField(source='application.region.name', read_only=True) + + class Meta: + model = ModeratorSupport + fields = ('id', 'supporter', 'supporter_username', 'application', + 'application_region_name', 'created_at') + read_only_fields = ('id', 'created_at') + + def create(self, validated_data): + validated_data['supporter'] = self.context['request'].user + # Increment support count + application = validated_data['application'] + application.support_count += 1 + application.save() + return super().create(validated_data) + + +class PermissionRestrictionSerializer(serializers.ModelSerializer): + """Serializer for PermissionRestriction model.""" + + restriction_type_display = serializers.CharField(source='get_restriction_type_display', read_only=True) + operator_username = serializers.CharField(source='operator.username', read_only=True) + target_moderator_username = serializers.CharField(source='target_moderator.username', read_only=True) + + class Meta: + model = PermissionRestriction + fields = ('id', 'operator', 'operator_username', 'target_moderator', 'target_moderator_username', + 'restriction_type', 'restriction_type_display', 'start_time', 'end_time', 'created_at') + read_only_fields = ('id', 'created_at') \ No newline at end of file diff --git a/backend/apps/regions/serializers.py b/backend/apps/regions/serializers.py new file mode 100644 index 0000000..459a322 --- /dev/null +++ b/backend/apps/regions/serializers.py @@ -0,0 +1,53 @@ +from rest_framework import serializers +from .models import Region + + +class RegionSerializer(serializers.ModelSerializer): + """Serializer for Region model.""" + + level_display = serializers.CharField(source='get_level_display', read_only=True) + status_display = serializers.CharField(source='get_status_display', read_only=True) + parent_name = serializers.CharField(source='parent.name', read_only=True, allow_null=True) + children_count = serializers.SerializerMethodField() + + class Meta: + model = Region + fields = ('id', 'name', 'level', 'level_display', 'parent', 'parent_name', + 'status', 'status_display', 'children_count', 'created_at', 'updated_at') + read_only_fields = ('id', 'created_at', 'updated_at') + + def get_children_count(self, obj): + return obj.children.count() + + +class RegionDetailSerializer(serializers.ModelSerializer): + """Detailed serializer for Region model.""" + + level_display = serializers.CharField(source='get_level_display', read_only=True) + status_display = serializers.CharField(source='get_status_display', read_only=True) + parent = RegionSerializer(read_only=True) + children = RegionSerializer(many=True, read_only=True) + full_path = serializers.SerializerMethodField() + + class Meta: + model = Region + fields = ('id', 'name', 'level', 'level_display', 'parent', 'children', + 'status', 'status_display', 'full_path', 'created_at', 'updated_at') + read_only_fields = ('id', 'created_at', 'updated_at') + + def get_full_path(self, obj): + return obj.get_full_path() + + +class RegionTreeSerializer(serializers.ModelSerializer): + """Serializer for Region tree structure.""" + + children = serializers.SerializerMethodField() + + class Meta: + model = Region + fields = ('id', 'name', 'level', 'status', 'children') + + def get_children(self, obj): + children = obj.get_children() + return RegionTreeSerializer(children, many=True).data \ No newline at end of file diff --git a/backend/apps/users/serializers.py b/backend/apps/users/serializers.py index 3d2c0d0..4d12e2a 100644 --- a/backend/apps/users/serializers.py +++ b/backend/apps/users/serializers.py @@ -3,12 +3,12 @@ from .models import User class UserSerializer(serializers.ModelSerializer): - """Serializer for User model.""" + """Serializer for User model (basic info).""" class Meta: model = User - fields = ('id', 'username', 'email', 'first_name', 'last_name', 'avatar') - read_only_fields = ('id',) + fields = ('id', 'username', 'email', 'first_name', 'last_name', 'avatar', 'role', 'status') + read_only_fields = ('id', 'role', 'status') class UserDetailSerializer(serializers.ModelSerializer): @@ -17,4 +17,22 @@ class UserDetailSerializer(serializers.ModelSerializer): class Meta: model = User fields = '__all__' - read_only_fields = ('id', 'date_joined', 'last_login') \ No newline at end of file + read_only_fields = ('id', 'date_joined', 'last_login') + + +class UserUpdateSerializer(serializers.ModelSerializer): + """Serializer for updating user profile.""" + + class Meta: + model = User + fields = ('first_name', 'last_name', 'avatar') + + +class UserStatsSerializer(serializers.Serializer): + """Serializer for user statistics.""" + articles_count = serializers.IntegerField() + services_count = serializers.IntegerField() + comments_count = serializers.IntegerField() + likes_count = serializers.IntegerField() + favorites_count = serializers.IntegerField() + ratings_count = serializers.IntegerField() \ No newline at end of file