From 19962768c21a22cdd113c0eb3b64989a65e374c1 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 09:19:44 +0300 Subject: [PATCH 1/7] LIL-214, LIL-215. Add searsh, filter, ordering params to viewsets --- api/v1/views.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/api/v1/views.py b/api/v1/views.py index 9b93f88d..cf323758 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -24,16 +24,22 @@ User = get_user_model() class MaterialViewSet(ExtendedModelViewSet): queryset = Material.objects.all() serializer_class = MaterialSerializer + search_fields = ('title', 'short_description',) + ordering_fields = ('title', 'created_at', 'update_at',) class LikeViewSet(ExtendedModelViewSet): queryset = Like.objects.select_related('user').all() serializer_class = LikeSerializer + search_fields = ('user__email', 'user__firstname', 'user__lastname',) + ordering_fields = ('created_at', 'update_at',) class CategoryViewSet(ExtendedModelViewSet): queryset = Category.objects.all() serializer_class = CategorySerializer + search_fields = ('title',) + ordering_fields = ('title',) class CourseViewSet(ExtendedModelViewSet): @@ -43,7 +49,9 @@ class CourseViewSet(ExtendedModelViewSet): 'likes', 'materials' ).all() serializer_class = CourseSerializer - filter_fields = ('category',) + filter_fields = ('category', 'status', 'is_infinite', 'is_featured',) + search_fields = ('author__email', 'title', 'category__title',) + ordering_fields = ('title', 'created_at', 'update_at',) class ImageViewSet(ExtendedModelViewSet): @@ -51,6 +59,8 @@ class ImageViewSet(ExtendedModelViewSet): 'course', 'lesson' ).all() serializer_class = ImageSerializer + search_fields = ('title',) + ordering_fields = ('title', 'created_at', 'update_at', 'position',) class TextViewSet(ExtendedModelViewSet): @@ -58,6 +68,8 @@ class TextViewSet(ExtendedModelViewSet): 'course', 'lesson' ).all() serializer_class = TextSerializer + search_fields = ('title',) + ordering_fields = ('title', 'created_at', 'update_at', 'position',) class ImageTextViewSet(ExtendedModelViewSet): @@ -65,6 +77,8 @@ class ImageTextViewSet(ExtendedModelViewSet): 'course', 'lesson' ).all() serializer_class = ImageTextSerializer + search_fields = ('title',) + ordering_fields = ('title', 'created_at', 'update_at', 'position',) class VideoViewSet(ExtendedModelViewSet): @@ -72,18 +86,26 @@ class VideoViewSet(ExtendedModelViewSet): 'course', 'lesson' ).all() serializer_class = VideoSerializer + search_fields = ('title',) + ordering_fields = ('title', 'created_at', 'update_at', 'position',) class GalleryViewSet(ExtendedModelViewSet): queryset = Gallery.objects.select_related('course').all() serializer_class = GallerySerializer + search_fields = ('title',) + ordering_fields = ('title', 'created_at', 'update_at',) class GalleryImageViewSet(ExtendedModelViewSet): queryset = GalleryImage.objects.select_related('gallery').all() serializer_class = GalleryImageSerializer + search_fields = ('gallery__title',) class UserViewSet(ExtendedModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer + filter_fields = ('is_staff', 'is_active', 'role', 'gender', 'is_email_proved', 'fb_id',) + search_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'fb_id',) + ordering_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'date_joined',) \ No newline at end of file From c0d310881a2dcb94bcd82418efac0d82a28c40d7 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 09:21:58 +0300 Subject: [PATCH 2/7] LIL-211. Now all tags in swagger docs collapsed --- project/settings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/project/settings.py b/project/settings.py index d52eb79d..17c6ec7e 100644 --- a/project/settings.py +++ b/project/settings.py @@ -206,3 +206,9 @@ REST_FRAMEWORK = { if DEBUG: CORS_ORIGIN_ALLOW_ALL = True + +# Swagger doc settings + +SWAGGER_SETTINGS = { + 'DOC_EXPANSION': 'none', +} From aa7f280a00158bc437fe0211a802da0d65a50d14 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 09:33:11 +0300 Subject: [PATCH 3/7] Add ordering for category model --- .../migrations/0021_auto_20180206_0632.py | 17 +++++++++++++++++ apps/course/models.py | 1 + 2 files changed, 18 insertions(+) create mode 100644 apps/course/migrations/0021_auto_20180206_0632.py diff --git a/apps/course/migrations/0021_auto_20180206_0632.py b/apps/course/migrations/0021_auto_20180206_0632.py new file mode 100644 index 00000000..f527bc4a --- /dev/null +++ b/apps/course/migrations/0021_auto_20180206_0632.py @@ -0,0 +1,17 @@ +# Generated by Django 2.0.2 on 2018-02-06 06:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0020_auto_20180202_1716'), + ] + + operations = [ + migrations.AlterModelOptions( + name='category', + options={'ordering': ['title'], 'verbose_name': 'Категория', 'verbose_name_plural': 'Категории'}, + ), + ] diff --git a/apps/course/models.py b/apps/course/models.py index 954a8160..76c46756 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -86,6 +86,7 @@ class Category(models.Model): class Meta: verbose_name = 'Категория' verbose_name_plural = 'Категории' + ordering = ['title'] class Lesson(models.Model): From 54e98413821e6d8b3b5a84ee282692af6e8a8ed6 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 11:36:53 +0300 Subject: [PATCH 4/7] LIL-177. Add serializer, viewset, route for Lesson model --- api/v1/serializers.py | 23 ++++++++++++++++++++++- api/v1/urls.py | 3 ++- api/v1/views.py | 21 ++++++++++++++++----- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/api/v1/serializers.py b/api/v1/serializers.py index 60a0f77a..2b1bf61a 100644 --- a/api/v1/serializers.py +++ b/api/v1/serializers.py @@ -1,7 +1,7 @@ from django.contrib.auth import get_user_model from rest_framework import serializers -from apps.course.models import Category, Course, Material, Like +from apps.course.models import Category, Course, Material, Lesson, Like from apps.content.models import ( Image, Text, ImageText, Video, Gallery, GalleryImage, @@ -94,6 +94,27 @@ class CourseSerializer(serializers.ModelSerializer): ) +class LessonSerializer(serializers.ModelSerializer): + + class Meta: + model = Lesson + fields = ( + 'id', + 'title', + 'short_description', + 'course', + 'cover', + 'created_at', + 'update_at', + ) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + class ImageSerializer(serializers.ModelSerializer): class Meta: diff --git a/api/v1/urls.py b/api/v1/urls.py index 9a7b1957..6483f23d 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -12,13 +12,14 @@ from .views import ( ImageViewSet, TextViewSet, ImageTextViewSet, VideoViewSet, GalleryViewSet, GalleryImageViewSet, - UserViewSet, + UserViewSet, LessonViewSet, ) router = DefaultRouter() router.register(r'courses', CourseViewSet, base_name='courses') router.register(r'categories', CategoryViewSet, base_name='categories') router.register(r'materials', MaterialViewSet, base_name='materials') +router.register(r'lessons', LessonViewSet, base_name='lessons') router.register(r'likes', LikeViewSet, base_name='likes') router.register(r'images', ImageViewSet, base_name='images') diff --git a/api/v1/views.py b/api/v1/views.py index cf323758..420bdc6d 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -9,10 +9,10 @@ from .serializers import ( ImageSerializer, TextSerializer, ImageTextSerializer, VideoSerializer, GallerySerializer, GalleryImageSerializer, - UserSerializer, + UserSerializer, LessonSerializer, ) -from apps.course.models import Category, Course, Material, Like +from apps.course.models import Category, Course, Material, Lesson, Like from apps.content.models import ( Image, Text, ImageText, Video, Gallery, GalleryImage, @@ -54,6 +54,14 @@ class CourseViewSet(ExtendedModelViewSet): ordering_fields = ('title', 'created_at', 'update_at',) +class LessonViewSet(ExtendedModelViewSet): + queryset = Lesson.objects.select_related('course').all() + serializer_class = LessonSerializer + filter_fields = ('course',) + search_fields = ('title', 'short_description',) + ordering_fields = ('title', 'created_at', 'update_at',) + + class ImageViewSet(ExtendedModelViewSet): queryset = Image.objects.select_related( 'course', 'lesson' @@ -106,6 +114,9 @@ class GalleryImageViewSet(ExtendedModelViewSet): class UserViewSet(ExtendedModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer - filter_fields = ('is_staff', 'is_active', 'role', 'gender', 'is_email_proved', 'fb_id',) - search_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'fb_id',) - ordering_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'date_joined',) \ No newline at end of file + filter_fields = ('is_staff', 'is_active', 'role', + 'gender', 'is_email_proved', 'fb_id',) + search_fields = ('email', 'first_name', 'last_name', + 'country', 'city', 'fb_id',) + ordering_fields = ('email', 'first_name', 'last_name', + 'country', 'city', 'date_joined',) From 2577a286281e7aaddaf46de77d78378c4211c25e Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 12:40:37 +0300 Subject: [PATCH 5/7] LIL-176, LIL-180. Add permissions --- api/v1/permissions.py | 35 +++++++++++++++++++++++++++++++++++ api/v1/views.py | 42 ++++++++++++++++++++++++++++++++++++++++++ apps/user/models.py | 9 ++++++--- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/api/v1/permissions.py b/api/v1/permissions.py index e69de29b..b7f6e693 100644 --- a/api/v1/permissions.py +++ b/api/v1/permissions.py @@ -0,0 +1,35 @@ +from django.contrib.auth import get_user_model + +from rest_framework.permissions import BasePermission + +User = get_user_model() + + +class IsAdmin(BasePermission): + def has_permission(self, request, view): + return request.user.is_authenticated and ( + request.user.role == User.ADMIN_ROLE or request.user.is_staff or request.user.is_superuser + ) + + +class IsAdminOrIsSelf(BasePermission): + def has_object_permission(self, request, view, user): + return request.user.is_authenticated and ( + user == request.user or request.user.is_staff or request.user.is_superuser + ) + + +class IsAuthorOrAdmin(BasePermission): + def has_permission(self, request, view): + return request.user.is_authenticated and ( + request.user.role in [ + User.AUTHOR_ROLE, User.ADMIN_ROLE + ] or request.user.is_staff or request.user.is_superuser + ) + + +class IsAuthorObjectOrAdmin(BasePermission): + def has_object_permission(self, request, view, obj): + return request.user.is_authenticated and ( + request.user.role == User.ADMIN_ROLE or request.user.is_staff or request.user.is_superuser + ) and request.user == obj.author diff --git a/api/v1/views.py b/api/v1/views.py index 420bdc6d..ddebe250 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -11,6 +11,7 @@ from .serializers import ( GallerySerializer, GalleryImageSerializer, UserSerializer, LessonSerializer, ) +from .permissions import IsAdmin, IsAdminOrIsSelf, IsAuthorOrAdmin, IsAuthorObjectOrAdmin from apps.course.models import Category, Course, Material, Lesson, Like from apps.content.models import ( @@ -26,6 +27,7 @@ class MaterialViewSet(ExtendedModelViewSet): serializer_class = MaterialSerializer search_fields = ('title', 'short_description',) ordering_fields = ('title', 'created_at', 'update_at',) + # permission_classes = (IsAdmin,) class LikeViewSet(ExtendedModelViewSet): @@ -33,6 +35,7 @@ class LikeViewSet(ExtendedModelViewSet): serializer_class = LikeSerializer search_fields = ('user__email', 'user__firstname', 'user__lastname',) ordering_fields = ('created_at', 'update_at',) + # permission_classes = (IsAdmin,) class CategoryViewSet(ExtendedModelViewSet): @@ -40,6 +43,7 @@ class CategoryViewSet(ExtendedModelViewSet): serializer_class = CategorySerializer search_fields = ('title',) ordering_fields = ('title',) + # permission_classes = (IsAdmin,) class CourseViewSet(ExtendedModelViewSet): @@ -52,6 +56,11 @@ class CourseViewSet(ExtendedModelViewSet): filter_fields = ('category', 'status', 'is_infinite', 'is_featured',) search_fields = ('author__email', 'title', 'category__title',) ordering_fields = ('title', 'created_at', 'update_at',) + # permission_classes = (IsAuthorObjectOrAdmin,) + # permission_map = { + # 'create': IsAuthorOrAdmin, + # 'delete': IsAdmin, + # } class LessonViewSet(ExtendedModelViewSet): @@ -60,6 +69,11 @@ class LessonViewSet(ExtendedModelViewSet): filter_fields = ('course',) search_fields = ('title', 'short_description',) ordering_fields = ('title', 'created_at', 'update_at',) + # permission_classes = (IsAuthorObjectOrAdmin,) + # permission_map = { + # 'create': IsAuthorOrAdmin, + # 'delete': IsAdmin, + # } class ImageViewSet(ExtendedModelViewSet): @@ -69,6 +83,10 @@ class ImageViewSet(ExtendedModelViewSet): serializer_class = ImageSerializer search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at', 'position',) + # permission_classes = (IsAuthorOrAdmin,) + # permission_map = { + # 'delete': IsAdmin, + # } class TextViewSet(ExtendedModelViewSet): @@ -78,6 +96,10 @@ class TextViewSet(ExtendedModelViewSet): serializer_class = TextSerializer search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at', 'position',) + # permission_classes = (IsAuthorOrAdmin,) + # permission_map = { + # 'delete': IsAdmin, + # } class ImageTextViewSet(ExtendedModelViewSet): @@ -87,6 +109,10 @@ class ImageTextViewSet(ExtendedModelViewSet): serializer_class = ImageTextSerializer search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at', 'position',) + # permission_classes = (IsAuthorOrAdmin,) + # permission_map = { + # 'delete': IsAdmin, + # } class VideoViewSet(ExtendedModelViewSet): @@ -96,6 +122,10 @@ class VideoViewSet(ExtendedModelViewSet): serializer_class = VideoSerializer search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at', 'position',) + # permission_classes = (IsAuthorOrAdmin,) + # permission_map = { + # 'delete': IsAdmin, + # } class GalleryViewSet(ExtendedModelViewSet): @@ -103,12 +133,20 @@ class GalleryViewSet(ExtendedModelViewSet): serializer_class = GallerySerializer search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at',) + # permission_classes = (IsAuthorOrAdmin,) + # permission_map = { + # 'delete': IsAdmin, + # } class GalleryImageViewSet(ExtendedModelViewSet): queryset = GalleryImage.objects.select_related('gallery').all() serializer_class = GalleryImageSerializer search_fields = ('gallery__title',) + # permission_classes = (IsAuthorOrAdmin,) + # permission_map = { + # 'delete': IsAdmin, + # } class UserViewSet(ExtendedModelViewSet): @@ -120,3 +158,7 @@ class UserViewSet(ExtendedModelViewSet): 'country', 'city', 'fb_id',) ordering_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'date_joined',) + # permission_classes = (IsAdminOrIsSelf,) + # permission_map = { + # 'delete': IsAdmin, + # } diff --git a/apps/user/models.py b/apps/user/models.py index d5633f8c..7a59786c 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -5,10 +5,13 @@ from django.utils.translation import gettext_lazy as _ class User(AbstractUser): + USER_ROLE = 0 + AUTHOR_ROLE = 1 + ADMIN_ROLE = 2 ROLE_CHOICES = ( - (0, 'пользователь'), - (1, 'автор'), - (2, 'администратор'), + (USER_ROLE, 'пользователь'), + (AUTHOR_ROLE, 'автор'), + (ADMIN_ROLE, 'администратор'), ) GENDER_CHOICES = ( ('n', 'не указан'), From a21997c0909fb6d82efb642bdf648da215cde5ef Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 13:32:52 +0300 Subject: [PATCH 6/7] LIL-217. Upload user photo. --- api/v1/__init__.py | 33 ++++++++++++++++++++++++++++++++- api/v1/serializers.py | 14 ++++++++++++++ api/v1/views.py | 21 ++++++++++++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/api/v1/__init__.py b/api/v1/__init__.py index 423698bd..8c95c2f2 100644 --- a/api/v1/__init__.py +++ b/api/v1/__init__.py @@ -1,4 +1,11 @@ -from rest_framework import viewsets +import imghdr +import base64 +import six +import uuid + +from django.core.files.base import ContentFile + +from rest_framework import serializers, viewsets from rest_framework.response import Response # https://gist.github.com/ivlevdenis/a0c8f5b472b6b8550bbb016c6a30e0be @@ -41,3 +48,27 @@ class ExtendViewSet(object): class ExtendedModelViewSet(ExtendViewSet, viewsets.ModelViewSet): pass + + +class Base64ImageField(serializers.ImageField): + + def to_internal_value(self, data): + if isinstance(data, six.string_types): + if 'data:' in data and ';base64,' in data: + header, data = data.split(';base64,') + try: + decoded_file = base64.b64decode(data) + except TypeError: + self.fail('invalid_image') + + file_name = str(uuid.uuid4())[:12] + file_extension = self.get_file_extension( + file_name, decoded_file) + complete_file_name = "%s.%s" % (file_name, file_extension,) + data = ContentFile(decoded_file, name=complete_file_name) + return super().to_internal_value(data) + + def get_file_extension(self, file_name, decoded_file): + extension = imghdr.what(file_name, decoded_file) + extension = "jpg" if extension == "jpeg" else extension + return extension diff --git a/api/v1/serializers.py b/api/v1/serializers.py index 2b1bf61a..9bf48ad6 100644 --- a/api/v1/serializers.py +++ b/api/v1/serializers.py @@ -1,6 +1,8 @@ from django.contrib.auth import get_user_model from rest_framework import serializers +from . import Base64ImageField + from apps.course.models import Category, Course, Material, Lesson, Like from apps.content.models import ( Image, Text, ImageText, Video, @@ -89,6 +91,7 @@ class CourseSerializer(serializers.ModelSerializer): read_only_fields = ( 'id', + 'cover', 'created_at', 'update_at', ) @@ -110,6 +113,7 @@ class LessonSerializer(serializers.ModelSerializer): read_only_fields = ( 'id', + 'cover', 'created_at', 'update_at', ) @@ -131,6 +135,7 @@ class ImageSerializer(serializers.ModelSerializer): read_only_fields = ( 'id', + 'img', 'created_at', 'update_at', ) @@ -173,6 +178,7 @@ class ImageTextSerializer(serializers.ModelSerializer): read_only_fields = ( 'id', + 'img', 'created_at', 'update_at', ) @@ -232,6 +238,7 @@ class GalleryImageSerializer(serializers.ModelSerializer): read_only_fields = ( 'id', + 'image', 'created_at', 'update_at', ) @@ -269,8 +276,15 @@ class UserSerializer(serializers.ModelSerializer): read_only_fields = ( 'id', + 'photo', 'date_joined', 'is_staff', 'fb_id', 'fb_data', ) + + +class UserPhotoSerializer(serializers.Serializer): + photo = Base64ImageField( + required=False, allow_empty_file=True, allow_null=True + ) diff --git a/api/v1/views.py b/api/v1/views.py index ddebe250..5dd298bc 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -1,6 +1,8 @@ from django.contrib.auth import get_user_model from rest_framework import viewsets +from rest_framework.decorators import detail_route, list_route +from rest_framework.response import Response from . import ExtendedModelViewSet from .serializers import ( @@ -9,7 +11,8 @@ from .serializers import ( ImageSerializer, TextSerializer, ImageTextSerializer, VideoSerializer, GallerySerializer, GalleryImageSerializer, - UserSerializer, LessonSerializer, + UserSerializer, UserPhotoSerializer, + LessonSerializer, ) from .permissions import IsAdmin, IsAdminOrIsSelf, IsAuthorOrAdmin, IsAuthorObjectOrAdmin @@ -152,13 +155,29 @@ class GalleryImageViewSet(ExtendedModelViewSet): class UserViewSet(ExtendedModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer + serializer_class_map = { + 'upload_photo': UserPhotoSerializer, + } filter_fields = ('is_staff', 'is_active', 'role', 'gender', 'is_email_proved', 'fb_id',) search_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'fb_id',) ordering_fields = ('email', 'first_name', 'last_name', 'country', 'city', 'date_joined',) + # permission_classes = (IsAdminOrIsSelf,) # permission_map = { # 'delete': IsAdmin, # } + + @detail_route(methods=['post'], url_path='upload-photo') + def upload_photo(self, request, pk=None): + user = self.get_object() + serializer = self.get_serializer() + serialized_data = serializer(data=request.data) + if serialized_data.is_valid(): + user.photo = serialized_data['photo'] + user.save() + return Response({'success': True}) + else: + return Response({'success': False}) From 9ebacfcb0fc99b0383192b599bbac756d012eec8 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 6 Feb 2018 14:10:32 +0300 Subject: [PATCH 7/7] LIL-216. Add upload image endpoints and viewsets. --- api/v1/serializers.py | 18 ++++++++++ api/v1/views.py | 81 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/api/v1/serializers.py b/api/v1/serializers.py index 9bf48ad6..8ff6f44a 100644 --- a/api/v1/serializers.py +++ b/api/v1/serializers.py @@ -284,7 +284,25 @@ class UserSerializer(serializers.ModelSerializer): ) +class CoverImageSerializer(serializers.Serializer): + cover = Base64ImageField( + required=False, allow_empty_file=True, allow_null=True + ) + + class UserPhotoSerializer(serializers.Serializer): photo = Base64ImageField( required=False, allow_empty_file=True, allow_null=True ) + + +class ContentImageSerializer(serializers.Serializer): + img = Base64ImageField( + required=False, allow_empty_file=True, allow_null=True + ) + + +class GalleryImageSerializer(serializers.Serializer): + image = Base64ImageField( + required=False, allow_empty_file=True, allow_null=True + ) diff --git a/api/v1/views.py b/api/v1/views.py index 5dd298bc..744e7b13 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -1,5 +1,6 @@ from django.contrib.auth import get_user_model +from rest_framework import status from rest_framework import viewsets from rest_framework.decorators import detail_route, list_route from rest_framework.response import Response @@ -12,7 +13,8 @@ from .serializers import ( ImageTextSerializer, VideoSerializer, GallerySerializer, GalleryImageSerializer, UserSerializer, UserPhotoSerializer, - LessonSerializer, + LessonSerializer, ContentImageSerializer, + GalleryImageSerializer, CoverImageSerializer, ) from .permissions import IsAdmin, IsAdminOrIsSelf, IsAuthorOrAdmin, IsAuthorObjectOrAdmin @@ -56,6 +58,9 @@ class CourseViewSet(ExtendedModelViewSet): 'likes', 'materials' ).all() serializer_class = CourseSerializer + serializer_class_map = { + 'upload_photo': CoverImageSerializer, + } filter_fields = ('category', 'status', 'is_infinite', 'is_featured',) search_fields = ('author__email', 'title', 'category__title',) ordering_fields = ('title', 'created_at', 'update_at',) @@ -65,10 +70,25 @@ class CourseViewSet(ExtendedModelViewSet): # 'delete': IsAdmin, # } + @detail_route(methods=['post'], url_path='upload-photo') + def upload_photo(self, request, pk=None): + course = self.get_object() + serializer = self.get_serializer() + serialized_data = serializer(data=request.data) + if serialized_data.is_valid(): + course.cover = serialized_data['cover'] + course.save() + return Response({'success': True}) + else: + return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) + class LessonViewSet(ExtendedModelViewSet): queryset = Lesson.objects.select_related('course').all() serializer_class = LessonSerializer + serializer_class_map = { + 'upload_photo': CoverImageSerializer, + } filter_fields = ('course',) search_fields = ('title', 'short_description',) ordering_fields = ('title', 'created_at', 'update_at',) @@ -78,12 +98,27 @@ class LessonViewSet(ExtendedModelViewSet): # 'delete': IsAdmin, # } + @detail_route(methods=['post'], url_path='upload-photo') + def upload_photo(self, request, pk=None): + lesson = self.get_object() + serializer = self.get_serializer() + serialized_data = serializer(data=request.data) + if serialized_data.is_valid(): + lesson.cover = serialized_data['cover'] + lesson.save() + return Response({'success': True}) + else: + return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) + class ImageViewSet(ExtendedModelViewSet): queryset = Image.objects.select_related( 'course', 'lesson' ).all() serializer_class = ImageSerializer + serializer_class_map = { + 'upload_photo': ContentImageSerializer, + } search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at', 'position',) # permission_classes = (IsAuthorOrAdmin,) @@ -91,6 +126,18 @@ class ImageViewSet(ExtendedModelViewSet): # 'delete': IsAdmin, # } + @detail_route(methods=['post'], url_path='upload-photo') + def upload_photo(self, request, pk=None): + image = self.get_object() + serializer = self.get_serializer() + serialized_data = serializer(data=request.data) + if serialized_data.is_valid(): + image.img = serialized_data['img'] + image.save() + return Response({'success': True}) + else: + return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) + class TextViewSet(ExtendedModelViewSet): queryset = Text.objects.select_related( @@ -110,6 +157,9 @@ class ImageTextViewSet(ExtendedModelViewSet): 'course', 'lesson' ).all() serializer_class = ImageTextSerializer + serializer_class_map = { + 'upload_photo': ContentImageSerializer, + } search_fields = ('title',) ordering_fields = ('title', 'created_at', 'update_at', 'position',) # permission_classes = (IsAuthorOrAdmin,) @@ -117,6 +167,18 @@ class ImageTextViewSet(ExtendedModelViewSet): # 'delete': IsAdmin, # } + @detail_route(methods=['post'], url_path='upload-photo') + def upload_photo(self, request, pk=None): + image_text = self.get_object() + serializer = self.get_serializer() + serialized_data = serializer(data=request.data) + if serialized_data.is_valid(): + image_text.img = serialized_data['img'] + image_text.save() + return Response({'success': True}) + else: + return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) + class VideoViewSet(ExtendedModelViewSet): queryset = Video.objects.select_related( @@ -145,12 +207,27 @@ class GalleryViewSet(ExtendedModelViewSet): class GalleryImageViewSet(ExtendedModelViewSet): queryset = GalleryImage.objects.select_related('gallery').all() serializer_class = GalleryImageSerializer + serializer_class_map = { + 'upload_photo': GalleryImageSerializer, + } search_fields = ('gallery__title',) # permission_classes = (IsAuthorOrAdmin,) # permission_map = { # 'delete': IsAdmin, # } + @detail_route(methods=['post'], url_path='upload-photo') + def upload_photo(self, request, pk=None): + gallery_image = self.get_object() + serializer = self.get_serializer() + serialized_data = serializer(data=request.data) + if serialized_data.is_valid(): + gallery_image.image = serialized_data['image'] + gallery_image.save() + return Response({'success': True}) + else: + return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) + class UserViewSet(ExtendedModelViewSet): queryset = User.objects.all() @@ -180,4 +257,4 @@ class UserViewSet(ExtendedModelViewSet): user.save() return Response({'success': True}) else: - return Response({'success': False}) + return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST)