You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
8.8 KiB
233 lines
8.8 KiB
# -*- 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='Материалы курса',
|
|
)
|
|
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)
|
|
description = models.TextField(verbose_name='Описание', blank=True, null=True)
|
|
icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True)
|
|
sort = models.SmallIntegerField(verbose_name='Поле сортировки')
|
|
|
|
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,
|
|
big_mobile_image=None, slug=None, teachers=None,
|
|
level=None, direction=None, **kwargs):
|
|
|
|
slug = slug if slug else slugify(unidecode.unidecode(kwargs['title']))
|
|
|
|
kwargs['teacher_tokens'] = teachers
|
|
|
|
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)
|
|
|
|
try:
|
|
course = self.get(slug=slug)
|
|
for i in kwargs:
|
|
if kwargs[i]:
|
|
setattr(course, i, kwargs[i])
|
|
course.save()
|
|
|
|
except ObjectDoesNotExist:
|
|
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) -> Lesson:
|
|
lessons = self.get_lesson_list()
|
|
try:
|
|
return lessons[lessons.index(lesson)]
|
|
except IndexError:
|
|
pass
|
|
|
|
def get_previous(self, lesson: Lesson):
|
|
lessons = self.get_lesson_list()
|
|
try:
|
|
return lessons[lessons.index(lesson) - 2]
|
|
except IndexError:
|
|
pass
|
|
|
|
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 = "Верные ответы"
|
|
|