diff --git a/courses/migrations/0009_auto_20180514_1438.py b/courses/migrations/0009_auto_20180514_1438.py new file mode 100644 index 0000000..c2984c7 --- /dev/null +++ b/courses/migrations/0009_auto_20180514_1438.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2018-05-14 14:38 +from __future__ import unicode_literals + +import courses.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0008_auto_20180511_1208'), + ] + + operations = [ + migrations.AlterField( + model_name='course', + name='big_image', + field=models.ImageField(blank=True, max_length=255, upload_to=courses.models.upload_big_image, verbose_name='Большое изображение'), + ), + migrations.AlterField( + model_name='course', + name='big_mobile_image', + field=models.ImageField(blank=True, help_text='Большая картинка для мобильной версии', max_length=255, upload_to=courses.models.upload_mobile_image, verbose_name='Под мобилку'), + ), + migrations.AlterField( + model_name='course', + name='image', + field=models.ImageField(blank=True, max_length=255, upload_to=courses.models.upload_image, verbose_name='Изображение'), + ), + ] diff --git a/courses/migrations/0010_auto_20180514_1449.py b/courses/migrations/0010_auto_20180514_1449.py new file mode 100644 index 0000000..651cebe --- /dev/null +++ b/courses/migrations/0010_auto_20180514_1449.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2018-05-14 14:49 +from __future__ import unicode_literals + +import courses.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0009_auto_20180514_1438'), + ] + + operations = [ + migrations.AlterField( + model_name='course', + name='slug', + field=models.SlugField(default=courses.models.default_slug, editable=False, max_length=127, unique=True), + ), + ] diff --git a/courses/migrations/0011_auto_20180514_1851.py b/courses/migrations/0011_auto_20180514_1851.py new file mode 100644 index 0000000..5e04df0 --- /dev/null +++ b/courses/migrations/0011_auto_20180514_1851.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2018-05-14 18:51 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0010_auto_20180514_1449'), + ] + + operations = [ + migrations.AlterField( + model_name='course', + name='direction', + field=models.SmallIntegerField(choices=[(3, 'Бизнес'), (2, 'Веб-дизайн'), (1, 'Разработка'), (4, 'Рисование'), (5, 'Музыка')], default=1, verbose_name='Направление'), + ), + ] diff --git a/courses/models.py b/courses/models.py index f7cea7e..f106b5b 100755 --- a/courses/models.py +++ b/courses/models.py @@ -26,7 +26,8 @@ COURSE_DIRECTION = ( def upload_material(instance, filename): - return '/'.join(['materials', str(instance.topic.course.token), str(instance.topic.id), str(instance.token), filename]) + return '/'.join([ + 'materials', str(instance.topic.course.token), str(instance.topic.id), str(instance.token), filename]) class Lesson(models.Model): @@ -81,29 +82,22 @@ class Topic(models.Model): class CourseManager(models.Manager): - def update_or_create_course(self, image=None, big_image=None, statistic=None, old_slug=None, + def update_or_create_course(self, image=None, big_image=None, old_slug=None, big_mobile_image=None, slug=None, teacher_tokens=None, level=None, direction=None, **kwargs): - slug = slug if slug else slugify(unidecode.unidecode(kwargs['title'])) - old_slug = slug if old_slug is None else old_slug + slug = slug if slug else old_slug kwargs['teacher_tokens'] = teacher_tokens if image: - path = 'course/image%s.png' % slug - decode_base64(image, path) - kwargs['image'] = path + kwargs['image'] = image if big_image: - path = 'course/big_image%s.png' % slug - decode_base64(image, path) - kwargs['big_image'] = path + kwargs['big_image'] = big_image if big_mobile_image: - path = 'course/big_mobile_image%s.png' % slug - decode_base64(image, path) - kwargs['big_mobile_image'] = path + kwargs['big_mobile_image'] = big_mobile_image if level: kwargs['level'] = get_real_name(COURSE_LEVEL, level) @@ -119,31 +113,48 @@ class CourseManager(models.Manager): course.slug = slug course.save() - # TODO Костылище - except Exception: - kwargs['slug'] = slug + except self.DoesNotExist: + if not slug is None: + kwargs['slug'] = slug course = self.create(**kwargs) return course +def upload_image(instance, _filename): + return 'courses/%s/image.png' % instance.slug + + +def upload_big_image(instance, _filename): + return 'courses/%s/big_image.png' % instance.slug + + +def upload_mobile_image(instance, _filename): + return 'courses/%s/mobile_image.png' % instance.slug + + +def default_slug(): + return slugify(unidecode.unidecode('Python-разработчик с нуля (2018)')) + + class Course(models.Model): token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False) - slug = models.SlugField(unique=True, editable=False, max_length=127) + slug = models.SlugField(unique=True, editable=False, max_length=127, default=default_slug) title = models.CharField(verbose_name="Заголовок", max_length=255, unique=True) description = models.TextField(verbose_name='Описание', blank=True) level = models.CharField(verbose_name='Уровень', choices=COURSE_LEVEL, default='B', max_length=3) - direction = models.SmallIntegerField(choices=COURSE_DIRECTION, verbose_name='Направление') + direction = models.SmallIntegerField(choices=COURSE_DIRECTION, verbose_name='Направление', default=1) public = models.BooleanField(verbose_name='Опубликовать', default=False) teacher_tokens = ArrayField( models.UUIDField(verbose_name="Токен препода", editable=False), default=get_empty_list, verbose_name='Преподователи курса', ) - image = models.URLField(verbose_name='Изображение', blank=True, max_length=255) - big_image = models.URLField(verbose_name='Большое изображение', blank=True, max_length=255) - big_mobile_image = models.URLField(verbose_name='Под мобилку', blank=True, - help_text='Большая картинка для мобильной версии', max_length=255) + image = models.ImageField(verbose_name='Изображение', blank=True, max_length=255, upload_to=upload_image) + big_image = models.ImageField( + verbose_name='Большое изображение', blank=True, max_length=255, upload_to=upload_big_image) + big_mobile_image = models.ImageField(verbose_name='Под мобилку', blank=True, upload_to=upload_mobile_image, + help_text='Большая картинка для мобильной версии', max_length=255) hidden = models.BooleanField(verbose_name='Видно только оплатившим', default=False) def __str__(self): diff --git a/courses/views.py b/courses/views.py index 53a9822..7217dc0 100644 --- a/courses/views.py +++ b/courses/views.py @@ -3,7 +3,7 @@ import json from jwt import DecodeError from rest_framework.parsers import MultiPartParser -from courses.models import Course, Lesson, Topic, upload_material +from courses.models import Course, Lesson, Topic, upload_material, COURSE_LEVEL, COURSE_DIRECTION from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer from rest_framework.response import Response from rest_framework.views import APIView @@ -15,6 +15,7 @@ import jwt from courses.tasks import add_lesson from lms import settings +from lms.tools import get_real_name class TreeView(APIView): @@ -32,10 +33,73 @@ class TreeView(APIView): class CourseListView(APIView): renderer_classes = (JSONRenderer,) + parser_classes = (MultiPartParser,) status_code = 200 + @staticmethod + def bool_transformer(val): + if val == 'false': + return False + if val == 'true': + return True + return val + + @staticmethod + def get_img(request, key): + image = request.FILES.get(key) + image = request.POST.get(key) if image is None else image + return image + def post(self, request): - course = Course.objects.update_or_create_course(**request.JSON.dict()) + title = request.POST.get('title') + slug = request.POST.get('slug') + old_slug = request.POST.get('old_slug') + + if title is None: + return Response("title не передан", status=400) + + course = None + if old_slug: + try: + course = Course.objects.get(slug=old_slug) + except Course.DoesNotExist: + pass + + if course is None and slug: + try: + course = Course.objects.get(slug=slug) + except Course.DoesNotExist: + pass + + if course is None: + course = Course() + + if slug: + course.slug = slug + + course.title = title + level = request.POST.get('level') + direction = request.POST.get('direction') + description = request.POST.get('description') + + if description: + course.description = description + + if level: + course.level = get_real_name(COURSE_LEVEL, level) + + if direction: + course.direction = get_real_name(COURSE_DIRECTION, direction) + + course.teacher_tokens = request.POST.get('teacher_tokens', '').split(',') + course.hidden = self.bool_transformer(request.POST.get('hidden', False)) + course.public = self.bool_transformer(request.POST.get('public', False)) + course.image = self.get_img(request, 'image') + course.big_image = self.get_img(request, 'big_image') + course.big_mobile_image = self.get_img(request, 'big_mobile_image') + + course.save() + return Response(CourseDetailSerializer(course).data, status=self.status_code) def get(self, request): diff --git a/lms/settings.py b/lms/settings.py index 5894e6f..7fe3729 100644 --- a/lms/settings.py +++ b/lms/settings.py @@ -191,7 +191,7 @@ STATIC_URL = '/static/' SSL_ROOT = os.path.join(BASE_DIR, 'ssl') RAVEN_CONFIG = { - 'dsn': 'http://1a09557dbd144e52af4b14bea569c114:fbb5dfaa39e64f02a1b4cc7ac665d7d7@sentry.skillbox.ru/7' + 'dsn': 'https://1a09557dbd144e52af4b14bea569c114:fbb5dfaa39e64f02a1b4cc7ac665d7d7@sentry.skillbox.ru/7' } LOGGING = {