# -*- coding: utf-8 -*- import uuid import unidecode from django.contrib.postgres.fields import ArrayField from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.template.defaultfilters import slugify from lms.tools import decode_base64, get_real_name, get_empty_list COURSE_LEVEL = ( ('B', 'Базовый'), ('A', 'Продвинутый'), ('E', 'Экспертный'), ('B+A', 'Базовый + Продвинутый'), ) COURSE_DIRECTION = ( (3, 'Бизнес'), (2, 'Веб-дизайн'), (1, 'Разработка'), (4, 'Рисование'), (5, 'Музыка'), ) class Lesson(models.Model): token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False) key = models.UUIDField( verbose_name="Внутрений ключ используется для расшивровки", default=uuid.uuid4, editable=False) topic = models.ForeignKey(to="Topic", verbose_name='Тема') title = models.CharField(verbose_name='Название', max_length=255) description = models.TextField(verbose_name='Описание', blank=True, null=True) video = models.TextField(verbose_name='Код видео', blank=True, null=True) material_tokens = ArrayField( models.UUIDField(verbose_name="Токен материала", editable=False), default=get_empty_list, verbose_name='Материалы курса', blank=True ) free = models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться') sort = models.SmallIntegerField(verbose_name='Поле сортировки') is_hm = models.BooleanField(default=False) #TODO костыли old_id = models.IntegerField(null=True, blank=True) def __str__(self): return self.title class Meta: verbose_name = "Урок" verbose_name_plural = "Уроки" ordering = ('sort', ) unique_together = ('sort', 'topic') class Topic(models.Model): course = models.ForeignKey(to="Course", verbose_name='курс') title = models.CharField(verbose_name='Название', max_length=255) sort = models.SmallIntegerField(verbose_name='Поле сортировки') def __str__(self): return self.title class Meta: verbose_name = "Тема" verbose_name_plural = "Темы" ordering = ('sort',) unique_together = ('sort', 'course') class CourseManager(models.Manager): def update_or_create_course(self, image=None, big_image=None, statistic=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 kwargs['teacher_tokens'] = teacher_tokens if image: path = 'course/image%s.png' % slug decode_base64(image, path) kwargs['image'] = path if big_image: path = 'course/big_image%s.png' % slug decode_base64(image, path) kwargs['big_image'] = path if big_mobile_image: path = 'course/big_mobile_image%s.png' % slug decode_base64(image, path) kwargs['big_mobile_image'] = path if level: kwargs['level'] = get_real_name(COURSE_LEVEL, level) if direction: kwargs['direction'] = get_real_name(COURSE_DIRECTION, direction[0]) try: course = self.get(slug=old_slug) for i in kwargs: if kwargs[i]: setattr(course, i, kwargs[i]) course.slug = slug course.save() # TODO Костылище except Exception: kwargs['slug'] = slug course = self.create(**kwargs) return course class Course(models.Model): token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False) slug = models.SlugField(unique=True, editable=False, max_length=127) 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='Направление') 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) hidden = models.BooleanField(verbose_name='Видно только оплатившим', default=False) def __str__(self): return self.title def get_teacher(self): return self.teacher_tokens[0] def get_statistic(self): return { 'topic_count': self.topic_set.all().count(), 'task_count': sum([topic.lesson_set.count() for topic in self.topic_set.all()]) } def get_lesson_list(self) -> list: lesson_list = [] for topic in self.topic_set.all(): lesson_list += list(topic.lesson_set.all()) return lesson_list def get_next(self, lesson: Lesson, f=None) -> Lesson: lessons = self.get_lesson_list() try: n = lessons[lessons.index(lesson)+1] if f is None or f(n): return n else: return self.get_next(n, f) except IndexError: pass def get_previous(self, lesson: Lesson, f=None): lessons = self.get_lesson_list() idx = lessons.index(lesson) - 1 if idx > -1: prev = lessons[idx] if f is None or f(prev): return prev else: return self.get_previous(prev, f) def get_first_lesson(self) -> Lesson: lessons = self.get_lesson_list() try: return lessons[0] except IndexError: pass objects = CourseManager() class Meta: verbose_name = "Курс" verbose_name_plural = "Курсы" # class LessonRequirement(models.Model): # lesson = models.ForeignKey(to=Lesson) # requirement = models.ForeignKey(to='courses.Requirement') # sort = models.SmallIntegerField(default=1) # # class Meta: # verbose_name = "Порядок требований" # verbose_name_plural = "Порядок требований" # ordering = ('sort', ) # unique_together = ('lesson', 'requirement', 'sort') # # # class Requirement(models.Model): # CHECK_TYPES = Choices('student', 'teacher', 'auto',) # # token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False) # name = models.CharField(max_length=31, verbose_name="Название", unique=True) # checker = models.CharField( # choices=CHECK_TYPES, default=CHECK_TYPES.teacher, max_length=15, verbose_name="Проверяющий",) # min_balls = models.SmallIntegerField(default=50, verbose_name='Проходной бал') # # def __str__(self): # return self.name # # class Meta: # verbose_name = "Требования" # verbose_name_plural = "Требования" # # # class Question(models.Model): # FIELD_TYPES = Choices('text', 'char', 'boolean', 'file') # # requirement = models.ForeignKey(to=Requirement) # text = models.TextField(verbose_name="Вопрос") # type = models.CharField(choices=FIELD_TYPES, default=FIELD_TYPES.char, max_length=20) # multiple = models.BooleanField(default=False) # null = models.BooleanField(default=False) # balls = models.SmallIntegerField(default=100, verbose_name='Вознаграждение') # # class Meta: # verbose_name = "Вопрос" # verbose_name_plural = "Вопросы" # # # class RightAnswer(models.Model): # question = models.OneToOneField(to=Question) # text = models.TextField(verbose_name="Верный ответ") # success_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при верном ответе") # error_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при ошибке") # # class Meta: # verbose_name = "Верный ответ" # verbose_name_plural = "Верные ответы"