from django.contrib.auth import get_user_model from ipware import get_client_ip from rest_framework import serializers from rest_framework.validators import UniqueValidator from drf_dynamic_fields import DynamicFieldsMixin from apps.course.models import ( Category, Course, Comment, CourseComment, LessonComment, Material, Lesson, Like, LiveLessonComment, Tag) from .content import ( ImageObjectSerializer, ContentSerializer, ContentCreateSerializer, GallerySerializer, ) from .mixins import DispatchContentMixin, DispatchGalleryMixin, DispatchMaterialMixin, DispatchTagsMixin from .user import UserSerializer User = get_user_model() class TagSerializer(serializers.ModelSerializer): class Meta: model = Tag fields = ('__all__') class MaterialCreateSerializer(serializers.ModelSerializer): class Meta: model = Material fields = ( 'id', 'title', 'cover', 'short_description', 'created_at', 'update_at', ) read_only_fields = ( 'id', 'created_at', 'update_at', ) class MaterialSerializer(MaterialCreateSerializer): cover = ImageObjectSerializer(allow_null=True) class LikeSerializer(serializers.ModelSerializer): class Meta: model = Like fields = ( 'id', 'user', 'created_at', 'update_at', ) read_only_fields = ( 'id', 'created_at', 'update_at', ) class LikeCreateSerializer(serializers.ModelSerializer): class Meta: model = Like fields = ['user'] def create(self, validated_data): # FIXME if validated_data.get('user'): user = validated_data.get('user') else: user = self.context['request'].user client_ip, is_routable = get_client_ip(self.context['request']) like = Like.objects.create(user=user, ip=client_ip) return like def to_representation(self, instance): return LikeSerializer(instance, context=self.context).to_representation(instance) class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ( 'id', 'title', ) read_only_fields = ( 'id', ) class CourseBulkChangeCategorySerializer(serializers.Serializer): old_category = serializers.IntegerField() new_category = serializers.IntegerField() class CourseCreateSerializer(DispatchContentMixin, DispatchGalleryMixin, DispatchMaterialMixin, DispatchTagsMixin, serializers.ModelSerializer ): title = serializers.CharField(allow_blank=True) short_description = serializers.CharField(allow_blank=True) slug = serializers.SlugField( allow_unicode=True, allow_blank=True, allow_null=True, required=False, validators=[UniqueValidator(queryset=Course.objects.all())]) content = serializers.ListSerializer( child=ContentCreateSerializer(), required=False, ) materials = MaterialSerializer(many=True, required=False) gallery = GallerySerializer() tags = TagSerializer(many=True, required=False) class Meta: model = Course fields = ( 'id', 'slug', 'author', 'title', 'short_description', 'from_author', 'cover', 'price', 'old_price', 'age', 'is_infinite', 'deferred_start_at', 'category', 'access_duration', 'is_featured', 'url', 'status', 'likes', 'materials', 'created_at', 'update_at', 'deactivated_at', 'content', 'gallery', 'lessons', 'tags', ) read_only_fields = ( 'id', 'url', 'lessons', 'created_at', 'update_at', 'deactivated_at', ) def create(self, validated_data): content = validated_data.pop('content', []) materials = validated_data.pop('materials', []) gallery = validated_data.pop('gallery', {}) author = validated_data.get('author', None) tags = validated_data.pop('tags', []) if not author: validated_data['author'] = self.context['request'].user course = super().create(validated_data) self.dispatch_content(course, content) self.dispatch_materials(course, materials) self.dispatch_gallery(course, gallery) self.dispatch_tags(course, tags) return course def update(self, instance, validated_data): content = validated_data.pop('content', []) materials = validated_data.pop('materials', []) gallery = validated_data.pop('gallery', {}) author = validated_data.get('author', None) tags = validated_data.pop('tags', []) if not instance.author or author and instance.author != author: validated_data['author'] = self.context['request'].user course = super().update(instance, validated_data) self.dispatch_materials(course, materials) self.dispatch_content(course, content) self.dispatch_gallery(course, gallery) self.dispatch_tags(course, tags) return course def to_representation(self, instance): return CourseSerializer(instance=instance, context=self.context).to_representation(instance) class LessonCreateSerializer(DispatchContentMixin, serializers.ModelSerializer): content = serializers.ListSerializer( child=ContentCreateSerializer(), required=False, ) class Meta: model = Lesson fields = ( 'id', 'title', 'short_description', 'course', 'cover', 'content', 'created_at', 'update_at', 'deactivated_at', 'position', ) read_only_fields = ( 'id', 'created_at', 'update_at', 'deactivated_at', ) def create(self, validated_data): content = validated_data.pop('content', []) lesson = super().create(validated_data) if not validated_data.get('position'): lesson.set_last_position() lesson.save() self.dispatch_content(lesson, content) return lesson def update(self, instance, validated_data): content = validated_data.pop('content', []) lesson = super().update(instance, validated_data) self.dispatch_content(lesson, content) return lesson def to_representation(self, instance): return LessonSerializer(instance, context=self.context).to_representation(instance) class LessonSerializer(serializers.ModelSerializer): # course = CourseSerializer() cover = ImageObjectSerializer() content = ContentSerializer(many=True) class Meta: model = Lesson fields = ( 'id', 'title', 'short_description', 'course', 'cover', 'content', 'created_at', 'update_at', 'deactivated_at', 'position', ) read_only_fields = ( 'id', 'created_at', 'update_at', 'deactivated_at', ) class CourseSerializer(DynamicFieldsMixin, serializers.ModelSerializer): author = UserSerializer() category = CategorySerializer() materials = MaterialSerializer(many=True) cover = ImageObjectSerializer() gallery = GallerySerializer() content = ContentSerializer(many=True) lessons = LessonSerializer(many=True) tags = TagSerializer(many=True, required=False) class Meta: model = Course fields = ( 'id', 'slug', 'author', 'title', 'short_description', 'from_author', 'cover', 'price', 'old_price', 'age', 'is_infinite', 'deferred_start_at', 'category', 'access_duration', 'is_featured', 'url', 'status', 'likes', 'materials', 'created_at', 'update_at', 'deactivated_at', 'content', 'gallery', 'lessons', 'tags', ) read_only_fields = ( 'id', 'url', 'lessons', 'created_at', 'update_at', 'deactivated_at', ) class CommentSerializer(serializers.ModelSerializer): author = UserSerializer() class Meta: model = Comment fields = ( 'id', 'content', 'author', 'parent', 'deactivated_at', 'created_at', 'created_at_humanize', 'update_at', ) read_only_fields = ( 'id', 'deactivated_at', 'created_at', 'update_at', ) def to_representation(self, instance): if isinstance(instance, CourseComment): return CourseCommentSerializer(instance, context=self.context).to_representation(instance) elif isinstance(instance, LessonComment): return LessonCommentSerializer(instance, context=self.context).to_representation(instance) elif isinstance(instance, LiveLessonComment): return LiveLessonCommentSerializer(instance, context=self.context).to_representation(instance) class CourseCommentSerializer(serializers.ModelSerializer): author = UserSerializer() children = CommentSerializer(many=True) class Meta: model = CourseComment fields = CommentSerializer.Meta.fields + ( 'course', 'children', ) read_only_fields = CommentSerializer.Meta.read_only_fields + ( 'children', ) class LessonCommentSerializer(serializers.ModelSerializer): author = UserSerializer() children = CommentSerializer(many=True) class Meta: model = LessonComment fields = CommentSerializer.Meta.fields + ( 'lesson', 'children', ) read_only_fields = CommentSerializer.Meta.read_only_fields + ( 'children', ) class LiveLessonCommentSerializer(serializers.ModelSerializer): author = UserSerializer() children = CommentSerializer(many=True) class Meta: model = LiveLessonComment fields = CommentSerializer.Meta.fields + ( 'live_lesson', 'children', ) read_only_fields = CommentSerializer.Meta.read_only_fields + ( 'children', ) class CommentCreateSerializer(serializers.ModelSerializer): obj_type = serializers.CharField(required=True) obj_id = serializers.IntegerField(required=True) class Meta: model = Comment fields = ( 'id', 'content', 'author', 'parent', 'deactivated_at', 'created_at', 'update_at', 'obj_type', 'obj_id', ) read_only_fields = ( 'id', 'deactivated_at', 'created_at', 'update_at', ) def create(self, validated_data): obj_type = validated_data.pop('obj_type', None) obj_id = validated_data.pop('obj_id', None) if obj_type == Comment.OBJ_TYPE_COURSE: validated_data['course_id'] = obj_id return CourseCommentSerializer().create(validated_data) elif obj_type == Comment.OBJ_TYPE_LESSON: validated_data['lesson_id'] = obj_id return LessonCommentSerializer().create(validated_data) elif obj_type == Comment.OBJ_TYPE_LIVE_LESSON: validated_data['live_lesson_id'] = obj_id return LiveLessonCommentSerializer().create(validated_data) def to_representation(self, instance): if isinstance(instance, CourseComment): return CourseCommentSerializer(instance, context=self.context).to_representation(instance) elif isinstance(instance, LessonComment): return LessonCommentSerializer(instance, context=self.context).to_representation(instance) elif isinstance(instance, LiveLessonComment): return LiveLessonCommentSerializer(instance, context=self.context).to_representation(instance)