From 9cf631aa5b41ed16b98229ded0df7f389021be26 Mon Sep 17 00:00:00 2001 From: andrey Date: Wed, 30 Aug 2017 16:49:01 +0300 Subject: [PATCH 01/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20djangorestframework=20=D0=B2=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=20(=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=B5=D0=BD=D0=B8=D1=8F=20api)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 08a729c..8acb06a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ contextlib2==0.5.4 cycler==0.10.0 decorator==4.0.10 diff-match-patch==20110725.1 +djangorestframework==3.6.4 django-admin-tools==0.8.0 django-celery==3.1.17 django-import-export==0.4.5 From 870a7afe007ae2384fca9ca0ddc82022cf6e5611 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 4 Sep 2017 12:29:54 +0300 Subject: [PATCH 02/13] =?UTF-8?q?=D0=B2=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5?= =?UTF-8?q?=D1=81=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- access/models.py | 4 ++-- courses/models.py | 17 +++++++++++------ finance/models.py | 10 +++++----- journals/models.py | 2 +- library/models.py | 8 ++++---- management/models.py | 6 +++--- practice/models.py | 6 +++--- 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/access/models.py b/access/models.py index 9735915..e4bfae5 100755 --- a/access/models.py +++ b/access/models.py @@ -345,10 +345,10 @@ class User(AbstractBaseUser): def check_phone(self, _type='actual'): # actual = self.phone, back = self.back_phone phone = self.phone if _type == 'actual' else self.back_phone - return bool(len(''.join([n for n in phone if n in [str(x) for x in xrange(0,10)]])) > 9) + return bool(len(''.join([n for n in phone if n in [str(x) for x in range(0,10)]])) > 9) def clean_phone(self, _type='actual'): - return ''.join([n for n in self.phone if n in [str(x) for x in xrange(0,10)]]) if self.check_phone() else '' + return ''.join([n for n in self.phone if n in [str(x) for x in range(0,10)]]) if self.check_phone() else '' class Meta: diff --git a/courses/models.py b/courses/models.py index fd25d8c..72c1a6e 100755 --- a/courses/models.py +++ b/courses/models.py @@ -33,7 +33,7 @@ class MaterialDirection(models.Model): title = models.CharField(verbose_name=u'Заголовок', max_length=255) color = models.CharField(verbose_name=u'Цвет', max_length=50) description = RedactorField(verbose_name=u'Описание', blank=True) - mentors = models.ManyToManyField(User, verbose_name=u'Кураторы', null=True) + mentors = models.ManyToManyField(User, verbose_name=u'Кураторы') def __unicode__(self): return u'%s' % self.title @@ -75,7 +75,7 @@ class Course(models.Model): slug = models.SlugField(max_length=255, editable=False, blank=True, default='', unique=True) icon = models.ImageField(verbose_name=u'Иконка курса', blank=True, null=True, upload_to='course') direction = models.ForeignKey(MaterialDirection, verbose_name=u'Направление', null=True) - mentors = models.ManyToManyField(User, verbose_name=u'Кураторы', null=True, blank=True, related_name='course_mentors') + mentors = models.ManyToManyField(User, verbose_name=u'Кураторы', blank=True, related_name='course_mentors') public = models.BooleanField(verbose_name=u'Опубликовать', default=False) title = models.CharField(verbose_name=u"Заголовок", max_length=255) description = RedactorField(verbose_name=u'Описание', blank=True) @@ -732,7 +732,7 @@ class AchievementsMap(models.Model): class Diploma(models.Model): - key = models.IntegerField(verbose_name=u'Последний ключ', max_length=255) + key = models.IntegerField(verbose_name=u'Последний ключ') icon = models.ImageField(verbose_name=u'Мини картинка', upload_to='diploms', null=True) course = models.ForeignKey(Course, verbose_name=u'Курс') out_image = models.ImageField(verbose_name=u'Диплом без печати', upload_to='diploms') @@ -743,21 +743,21 @@ class Diploma(models.Model): date_color = models.CharField(verbose_name=u'Цвет даты', max_length=255, null=True, help_text=u'RGB. Пример: 0,0,0') date_font = models.FileField(verbose_name=u'Шрифт даты', upload_to='diploms', null=True) - date_size = models.IntegerField(verbose_name=u'Размер даты', max_length=255, null=True) + date_size = models.IntegerField(verbose_name=u'Размер даты', null=True) # key_place = models.CharField(verbose_name=u'Размещение ключа', max_length=255, null=True, help_text=u'Пикселей сверху:пикселей слева - 256:256') key_color = models.CharField(verbose_name=u'Цвет ключа', max_length=255, null=True, help_text=u'RGB. Пример: 0,0,0') key_font = models.FileField(verbose_name=u'Шрифт ключа', upload_to='diploms', null=True) - key_size = models.IntegerField(verbose_name=u'Размер ключа', max_length=255, null=True) + key_size = models.IntegerField(verbose_name=u'Размер ключа', null=True) # name_place = models.CharField(verbose_name=u'Размещение имени', max_length=255, null=True, help_text=u'Пикселей сверху:пикселей слева - 256:256') name_color = models.CharField(verbose_name=u'Цвет имени', max_length=255, null=True, help_text=u'RGB. Пример: 0,0,0') name_font = models.FileField(verbose_name=u'Шрифт имени', upload_to='diploms', null=True) - name_size = models.IntegerField(verbose_name=u'Размер имени', max_length=255, null=True) + name_size = models.IntegerField(verbose_name=u'Размер имени', null=True) def __str__(self): return '%s' % self.course @@ -973,3 +973,8 @@ class Flow(models.Model): verbose_name = u'Поток' verbose_name_plural = u'Потоки' ordering = ['-modified'] + + +class NormalMap(models.Model): + course = models.OneToOneField(to=Course) + json_tree = models.TextField(default='') diff --git a/finance/models.py b/finance/models.py index 3ac1b01..e67ccb8 100755 --- a/finance/models.py +++ b/finance/models.py @@ -30,7 +30,7 @@ class Installment(models.Model): u'предоставлять доступ после ' u'просрочки') expired = models.BooleanField(verbose_name=u'Просрочено', default=False) - payments = models.ManyToManyField('Bill', verbose_name=u'Платежи', blank=True, null=True, related_name='bill_point') + payments = models.ManyToManyField('Bill', verbose_name=u'Платежи', blank=True, related_name='bill_point') def __str__(self): return '%s %s' % (self.user, self.price) @@ -54,7 +54,7 @@ class Price(models.Model): cost = models.IntegerField(verbose_name=u'Цена') course = models.ForeignKey(Course, verbose_name=u'Курс', null=True, blank=True) description = models.TextField(verbose_name=u'Описание', help_text=u'Будет показано менеджерам') - included = models.ManyToManyField(CourseMap, verbose_name=u'Включены', null=True, blank=True, + included = models.ManyToManyField(CourseMap, verbose_name=u'Включены', blank=True, help_text=u'Если задействовать эту функцию, стандартная схема подписок будет ' u'не активна') by_time = models.IntegerField(verbose_name=u'Дней доступа', default=0, blank=True, null=True, @@ -157,8 +157,8 @@ class Bill(models.Model): fire_date_sent = models.BooleanField(verbose_name=u'Письмо сгорания', default=False, editable=False) modals_show = models.BooleanField(verbose_name=u'Модалки показаны', default=False, editable=False) created_sent = models.BooleanField(verbose_name=u'Отправлено письмо сформированного счета', default=False, editable=False) - create_letters = models.ManyToManyField(MailBox, verbose_name=u'Письма при создании', null=True, blank=True, related_name='bill_create_letter', editable=False) - finish_letters = models.ManyToManyField(MailBox, verbose_name=u'Письма завершения', null=True, blank=True, related_name='bill_finish_letter', editable=False) + create_letters = models.ManyToManyField(MailBox, verbose_name=u'Письма при создании', blank=True, related_name='bill_create_letter', editable=False) + finish_letters = models.ManyToManyField(MailBox, verbose_name=u'Письма завершения', blank=True, related_name='bill_finish_letter', editable=False) def __unicode__(self): return u'%s:%s %s %s' % (self.id, self.get_status_display(), self.user, self.manager if self.manager else '') @@ -444,7 +444,7 @@ class ServiceRequest(models.Model): class RequestAlert(models.Model): title = models.CharField(verbose_name=u'Классификатор', max_length=255, editable=False) - requests = models.ManyToManyField(ServiceRequest, verbose_name=u'Количество заявок', blank=True, null=True, editable=False) + requests = models.ManyToManyField(ServiceRequest, verbose_name=u'Количество заявок', blank=True, editable=False) mails = models.TextField(verbose_name=u'Список почт', blank=True, help_text=u'Кому разослать дубли заявки. ЧЕРЕЗ ТОЧКУ С ЗАПЯТОЙ') date = models.DateTimeField(verbose_name=u'Начало заявок', default=datetime.datetime.now, editable=False) diff --git a/journals/models.py b/journals/models.py index d37b418..a59b725 100755 --- a/journals/models.py +++ b/journals/models.py @@ -43,7 +43,7 @@ class TeacherJ(models.Model): start_date = models.DateTimeField(verbose_name=u'Дата начала', blank=True, null=True) opens = models.ManyToManyField(CourseMap, verbose_name=u'Насильные открытия', blank=True, editable=False, related_name='map_opens') - waiting = models.ManyToManyField(CourseMap, verbose_name=u'Доп изучения', blank=True, null=True, + waiting = models.ManyToManyField(CourseMap, verbose_name=u'Доп изучения', blank=True, related_name='map_waiting') def __str__(self): diff --git a/library/models.py b/library/models.py index 94bad25..3dd0c20 100755 --- a/library/models.py +++ b/library/models.py @@ -36,12 +36,12 @@ class Article(models.Model): css = models.TextField(verbose_name=u'CSS', blank=True, default='', help_text=u'Можно добавлять все, но только исправить http на https') js = models.TextField(verbose_name=u'JS', blank=True, default='', help_text=u'Удалить bootstrap, jquery и заменить http на https') date = models.DateTimeField(verbose_name=u'Дата публикации', default=datetime.datetime.now, editable=False) - tags = models.ManyToManyField('Tags', verbose_name=u'Теги', blank=True, null=True) - likes = models.ManyToManyField(User, verbose_name=u'Лайки', max_length=255, null=True, blank=True, editable=False, related_name=u'acticle_likes') + tags = models.ManyToManyField('Tags', verbose_name=u'Теги', blank=True) + likes = models.ManyToManyField(User, verbose_name=u'Лайки', max_length=255, blank=True, editable=False, related_name=u'acticle_likes') views = models.ManyToManyField(User, verbose_name=u'Просмотры', max_length=255, default=0, related_name='article_views', editable=False) all_views = models.IntegerField(verbose_name=u'Всего просмотров', default=0, blank=True) - comments = models.ManyToManyField(Comment, verbose_name=u'Комментарии', null=True, blank=True, editable=False) - favorite = models.ManyToManyField(User, verbose_name=u'В фаворитах', blank=True, null=True, related_name='article_as_favorites', editable=False) + comments = models.ManyToManyField(Comment, verbose_name=u'Комментарии', blank=True, editable=False) + favorite = models.ManyToManyField(User, verbose_name=u'В фаворитах', blank=True, related_name='article_as_favorites', editable=False) def __str__(self): return '%s' % self.title diff --git a/management/models.py b/management/models.py index 3333cec..2594365 100755 --- a/management/models.py +++ b/management/models.py @@ -154,8 +154,8 @@ class Comment(models.Model): date = models.DateTimeField(verbose_name=u'Отправка', default=datetime.datetime.now) files = models.ManyToManyField(Storage, verbose_name=u'Прикрепленые файлы', blank=True, editable=False) send = models.BooleanField(verbose_name=u'Отправлено', default=False, editable=False) - replies = models.ManyToManyField('self', verbose_name=u'Ответы', blank=True, null=True, related_name='all_text_response', editable=False) - answers = models.ManyToManyField('self', verbose_name=u'Форумные ответы', blank=True, null=True, related_name='forum_answers', editable=False) + replies = models.ManyToManyField('self', verbose_name=u'Ответы', blank=True, related_name='all_text_response', editable=False) + answers = models.ManyToManyField('self', verbose_name=u'Форумные ответы', blank=True, related_name='forum_answers', editable=False) def __unicode__(self): return str(self.id) @@ -329,7 +329,7 @@ class Faq(models.Model): question = models.CharField(verbose_name=u'Вопрос', max_length=255) answer = RedactorField(verbose_name=u'Ответ') rating = models.IntegerField(verbose_name=u'Рейтинг статьи', default=0) - comments = models.ManyToManyField(Comment, verbose_name=u'Комментарии', blank=True, null=True, editable=False) + comments = models.ManyToManyField(Comment, verbose_name=u'Комментарии', blank=True, editable=False) date = models.DateTimeField(verbose_name=u'Дата создания', default=datetime.datetime.now, editable=False) def __str__(self): diff --git a/practice/models.py b/practice/models.py index d2fc2a1..1fcb7aa 100644 --- a/practice/models.py +++ b/practice/models.py @@ -53,7 +53,7 @@ class DataSheet(models.Model): data = models.TextField(verbose_name=u'Данные') split_char = models.CharField(verbose_name=u'Разделяющий символ', max_length=10, default=', ', blank=True) date = models.DateTimeField(verbose_name=u'Дата создания', default=datetime.datetime.now, editable=False) - users = models.ManyToManyField(User, verbose_name=u'Пользователи', blank=True, null=True, editable=False) + users = models.ManyToManyField(User, verbose_name=u'Пользователи', blank=True, editable=False) def __unicode__(self): return u'%s' % self.title @@ -117,13 +117,13 @@ class Workshop(models.Model): content = RedactorField(verbose_name=u'Описание методов', blank=True, default='', help_text=u'Добавление в /, после описаний и решений') variables = RedactorField(verbose_name=u'Описание переменных', blank=True, default='') - tools = models.ManyToManyField(WorkshopTools, verbose_name=u'Используемые инструменты', blank=True, null=True) + tools = models.ManyToManyField(WorkshopTools, verbose_name=u'Используемые инструменты', blank=True) open_resolve = models.BooleanField(verbose_name=u'Открыть ответ', default=False) resolve = RedactorField(verbose_name=u'Ответ', blank=True, default='') will_open_resolve = models.DateTimeField(verbose_name=u'Открыть ответ в дату', blank=True, null=True, help_text=u'Доступ к ответу открыть в указанную дату, если это вообще нужно') date = models.DateTimeField(verbose_name=u'Дата создания', default=datetime.datetime.now, editable=False) - users = models.ManyToManyField(User, verbose_name=u'Пользователи', blank=True, null=True, editable=False) + users = models.ManyToManyField(User, verbose_name=u'Пользователи', blank=True, editable=False) views = models.IntegerField(verbose_name=u'Просмотров комнаты', default=0) def __unicode__(self): From e3e14ebd2172d62681a71632dbf37554d5b24a72 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 4 Sep 2017 12:34:06 +0300 Subject: [PATCH 03/13] =?UTF-8?q?=D0=B2=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5?= =?UTF-8?q?=D1=81=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- access/models.py | 2 +- journals/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/access/models.py b/access/models.py index e4bfae5..33568bc 100755 --- a/access/models.py +++ b/access/models.py @@ -133,7 +133,7 @@ class User(AbstractBaseUser): deactivate = models.BooleanField(verbose_name=u'Не давать новых студентов', default=False) delay = models.BooleanField(verbose_name=u'Могут быть задержки', default=False, help_text=u'Если возможны задержки с проверками') delay_description = models.TextField(verbose_name=u'Повод просрочки', blank=True) - delay_date = models.DateTimeField(verbose_name=u'Задержка до. Не включая этот день.', blank=True, default=datetime.datetime.now(), null=True) + delay_date = models.DateTimeField(verbose_name=u'Задержка до. Не включая этот день.', blank=True, default=django.utils.timezone.now, null=True) email = models.EmailField(verbose_name='email', max_length=255, blank=True, db_index=True, unique=True, help_text=u'Будьте аккуратны. Менять почту можно. Но только если очень нужно.') changed_email = models.EmailField(verbose_name=u'Ящик на замену', blank=True, null=True) diff --git a/journals/models.py b/journals/models.py index a59b725..6616ccf 100755 --- a/journals/models.py +++ b/journals/models.py @@ -1398,7 +1398,7 @@ class DiplomaJ(models.Model): parent = models.ForeignKey(ExamJ, verbose_name=u'Журнал сдачи', blank=True, null=True) material = models.ForeignKey(Diploma, verbose_name=u'Шаблон диплома') date = models.DateField(verbose_name=u'Дата выдачи', default=datetime.date.today) - key = models.IntegerField(verbose_name=u'Ключ', max_length=255, blank=True, null=True) + key = models.IntegerField(verbose_name=u'Ключ', blank=True, null=True) student = models.ForeignKey(User, verbose_name=u'Студент', null=True) out_image = models.ImageField(verbose_name=u'Картинка без печати', upload_to='diploms', blank=True) in_image = models.ImageField(verbose_name=u'Картинка c печатью', upload_to='diploms', blank=True) From 7fd5d662eb347014ce428a1051fafa5f8ca64898 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 6 Sep 2017 18:05:44 +0300 Subject: [PATCH 04/13] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B3=D0=BE=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B0=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 26 +---- access/middleware.py | 24 ++++- access/models.py | 3 + access/new_urls.py | 6 ++ access/new_view.py | 16 +++ api_v1/urls.py | 6 ++ courses/migrations/0048_normalmap.py | 24 +++++ courses/models.py | 2 +- courses/new_urls.py | 10 ++ courses/new_view.py | 50 ++++++++++ courses/serializers.py | 144 +++++++++++++++++++++++++++ courses/update_db.py | 22 ++++ finance/migrations/0071_bill_flow.py | 22 ---- lms/settings.py | 3 +- lms/urls.py | 1 + requirements.txt | 1 + 16 files changed, 313 insertions(+), 47 deletions(-) create mode 100644 access/new_urls.py create mode 100644 access/new_view.py create mode 100644 api_v1/urls.py create mode 100644 courses/migrations/0048_normalmap.py create mode 100644 courses/new_urls.py create mode 100644 courses/new_view.py create mode 100644 courses/serializers.py create mode 100644 courses/update_db.py delete mode 100644 finance/migrations/0071_bill_flow.py diff --git a/README.md b/README.md index 3451111..a50f717 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,11 @@ #**SkillBox LMS** -Подробные шаги для проверки работоспособности CI +Нужно выполнить миграции и запустить скрипт update_db.py без параметров в модуле courses (скрипт на всякий случай пока не удалять) -1) Проверяем доступ к репозиторию кода https://gitlab.com/skillbox/go.skillbox.ru -2) Клонируем проект -3) Вносим изменения в код -4) Комитим изменения в новый branch (ОБЯЗАТЕЛЬНО в отдельный Branch) -4.1) Пушим изменения -5) Ждем выполнения создания тестового сайта https://gitlab.com/skillbox/go.skillbox.ru/pipelines -6) Сайт будет доступен по адресу .lms.test.spicycms.com +Фактически в структуре данных изменилось только то, что появилась новая табличка NormalMap. Скрипт собирает все treeview курсов и кладёт в эту табличку -**Правила для разработчика** +Появилась новая зависимость django_rest_framework. -* Разрабока ведется в отдельном брэнче -* После комита изменений можно проверить свою работу по следующему адресу: .lms.test.spicycms.com -* После проверки тестового сайта по имени брэнча, брэнч помечается к мерж реквесту -* Ответсвенный инженер производит код ревью и запускает/отклоняет мерж -* Если сайт запустился на демо сайте, код в ручом режиме можно обновить на продакшен сервере +Изменения никак не трогают старый функционал. -**Замечания** - -* Мерж реквест лучше производить в ветку develop(чтобы исключить случайного обновления кода на демо сайте) -* Внимание! Разработчик обязан проверить работоспособность тестового сайта по имени созданного брэнча .lms.test.spicycms.com -* Если необходимы тестовые данные разработчик их подготавливает дополнительно -* Если нет возможности добавить тестовые данные в авто режиме, разработчик добавляет инструкцию в README файл по запуску необходимых команд -(Под тестовыми данными подразумеваются фикстуры) +Имеет смысл пробежаться по middl diff --git a/access/middleware.py b/access/middleware.py index ed280f9..c29b245 100644 --- a/access/middleware.py +++ b/access/middleware.py @@ -1,11 +1,17 @@ from django.http import HttpResponseForbidden +from django.http import QueryDict +import json + class CheckPerm(object): @staticmethod def process_request(request): - if '/admin' in request.path or "/management" in request.path \ - or '/analytics' in request.path: + if len(request.path) > 6 and \ + ('/admin' == request.path[:6] + or "/manag" == request.path[:6] + or'/analy' == request.path[:6]): + #or "/api/v" == request.path[:6]): if not request.user.is_authenticated(): return HttpResponseForbidden() @@ -14,3 +20,17 @@ class CheckPerm(object): or request.user.in_role == "A" or request.user.is_admin): return HttpResponseForbidden() + + +class RequestToApi(object): + @staticmethod + def process_request(request): + if len(request.path) > 4 and '/api' == request.path[:4]: + if request.method == 'POST': + data = json.loads(request.body.decode('utf-8')) + q_data = QueryDict('', mutable=True) + for value in data: + q_data.update({value: data[value]}) + request.JSON = q_data + if request.method == 'POST' or request.method == 'DELETE': + setattr(request, '_dont_enforce_csrf_checks', True) \ No newline at end of file diff --git a/access/models.py b/access/models.py index 33568bc..6b82ed8 100755 --- a/access/models.py +++ b/access/models.py @@ -185,6 +185,9 @@ class User(AbstractBaseUser): def get_ip_len(self): UserRequest.objects.filter(user=self).count() + def full_name(self): + return str(self.id) + ": " + self.fname + " " + self.name + " " + self.oname + def set_request_data(self, request): ip = get_client_ip(request) try: diff --git a/access/new_urls.py b/access/new_urls.py new file mode 100644 index 0000000..0c78478 --- /dev/null +++ b/access/new_urls.py @@ -0,0 +1,6 @@ +from django.conf.urls import url +from access import new_view as views + +urlpatterns = [ + url(r'teachers/$', views.TeacherListView.as_view()), +] \ No newline at end of file diff --git a/access/new_view.py b/access/new_view.py new file mode 100644 index 0000000..34cf62d --- /dev/null +++ b/access/new_view.py @@ -0,0 +1,16 @@ +from django.contrib.auth import get_user_model +from rest_framework.views import APIView +from rest_framework.renderers import JSONRenderer +from rest_framework.response import Response + + +class TeacherListView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request): + return Response([teacher.full_name() for teacher in get_user_model().objects.filter( + in_role='T', + is_active=True, + reg_status=4, + )], self.status_code) \ No newline at end of file diff --git a/api_v1/urls.py b/api_v1/urls.py new file mode 100644 index 0000000..ab83d98 --- /dev/null +++ b/api_v1/urls.py @@ -0,0 +1,6 @@ +from django.conf.urls import url, include + +urlpatterns = [ + url(r'courses/', include('courses.new_urls')), + url(r'users/', include('access.new_urls')), +] \ No newline at end of file diff --git a/courses/migrations/0048_normalmap.py b/courses/migrations/0048_normalmap.py new file mode 100644 index 0000000..20d3589 --- /dev/null +++ b/courses/migrations/0048_normalmap.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.3 on 2017-09-04 13:56 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0047_auto_20170904_1355'), + ] + + operations = [ + migrations.CreateModel( + name='NormalMap', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('json_tree', models.TextField(default='')), + ('course', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='courses.Course')), + ], + ), + ] diff --git a/courses/models.py b/courses/models.py index 72c1a6e..bb4163c 100755 --- a/courses/models.py +++ b/courses/models.py @@ -66,7 +66,7 @@ class MaterialDirection(models.Model): class Course(models.Model): COURSE_LEVEL = ( ('B', u'Базовый'), - ('A', u'Продвинутый '), + ('A', u'Продвинутый'), ('E', u'Экспертный'), ('B+A', u'Базовый + Продвинутый') ) diff --git a/courses/new_urls.py b/courses/new_urls.py new file mode 100644 index 0000000..86ec6b2 --- /dev/null +++ b/courses/new_urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import url +from courses import new_view as views + +urlpatterns = [ + url(r'theme/detail/([0-9]{1,99})/$', views.ThemeDetailView.as_view()), + url(r'detail/([0-9]{1,99})/$', views.CourseDetailView.as_view()), + url(r'tree/([0-9]{1,99})/$', views.TreeView.as_view()), + url(r'directions/$', views.DirectionListView.as_view()), + url(r'^$', views.CourseListView.as_view()), +] \ No newline at end of file diff --git a/courses/new_view.py b/courses/new_view.py new file mode 100644 index 0000000..fd92c5f --- /dev/null +++ b/courses/new_view.py @@ -0,0 +1,50 @@ +from rest_framework.views import APIView +from rest_framework.renderers import JSONRenderer +from rest_framework.response import Response +from courses.models import Course, MaterialDirection, CourseTheme +from courses.serializers import CourseTreeSerializer, CourseDetailSerializer, CourseListSerializer, ThemeSerializer + + +class DirectionListView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request): + return Response([direction.title for direction in MaterialDirection.objects.all()], self.status_code) + + +class TreeView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + @staticmethod + def post(request): + print(request) + return Response(status=204) + + def get(self, request, id): + return Response(CourseTreeSerializer(Course.objects.get(id=id)).data, self.status_code) + + +class ThemeDetailView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request, id): + return Response(ThemeSerializer(CourseTheme.objects.get(id=id)).data, self.status_code) + + +class CourseDetailView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request, id): + return Response(CourseDetailSerializer(Course.objects.get(id=id)).data, self.status_code) + + +class CourseListView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request): + return Response([CourseListSerializer(i).data for i in Course.objects.all()], self.status_code) \ No newline at end of file diff --git a/courses/serializers.py b/courses/serializers.py new file mode 100644 index 0000000..33f4d7b --- /dev/null +++ b/courses/serializers.py @@ -0,0 +1,144 @@ +from rest_framework import serializers +import json +# from django.contrib.auth import get_user_model +# from django.core.exceptions import ObjectDoesNotExist + +from courses.models import Course, CourseTheme, Lesson, Homework, Exam + + +class LessonSerializer(serializers.ModelSerializer): + + class Meta: + model = Lesson + fields = '__all__' + + +class HomeworkSerializer(serializers.ModelSerializer): + + class Meta: + model = Homework + fields = '__all__' + + +class ExamSerializer(serializers.ModelSerializer): + + class Meta: + model = Exam + fields = '__all__' + + +class ThemeSerializer(serializers.ModelSerializer): + + class Meta: + model = CourseTheme + fields = '__all__' + + +class CourseListSerializer(serializers.ModelSerializer): + + class Meta: + model = Course + fields = ['id', 'title'] + + +class CourseTreeSerializer(serializers.ModelSerializer): + children = serializers.SerializerMethodField() + + class Meta: + model = Course + fields = ['id', 'title', 'children'] + + @staticmethod + def get_children(self): + theme_list = json.loads(self.normalmap.json_tree) + map = [] + for theme_slim in theme_list: + theme = CourseTheme.objects.get(id=theme_slim['id']) + theme_obj = { + 'id': theme.id, + 'title': theme.title, + 'lessons': [], + 'tasks': [], + } + for simple_object in theme_slim['body']: + val = simple_object.split('_')[0] + if simple_object.split('_')[1] == 'L': + lesson = Lesson.objects.get(id=val) + lesson_obj = {'id': lesson.id, 'title': lesson.title} + theme_obj['lessons'].append(lesson_obj) + + if simple_object.split('_')[1] == 'H': + task = Homework.objects.get(id=val) + task_obj = { + 'id': task.id, + 'is_exam': False, + } + theme_obj['tasks'].append(task_obj) + + if simple_object.split('_')[1] == 'E': + task = Exam.objects.get(id=val) + task_obj = { + 'id': task.id, + 'is_exam': True, + } + theme_obj['tasks'].append(task_obj) + + map.append(theme_obj) + + return map + + +class CourseDetailSerializer(serializers.ModelSerializer): + level = serializers.SerializerMethodField() + direction = serializers.SerializerMethodField() + teachers = serializers.SerializerMethodField() + + class Meta: + model = Course + exclude = ( + 'slug', 'mentors', 'page', 'sort', + 'preview', 'use_fail', 'basic_len', + 'addition_len', 'min_price', 'buy_icon', + 'must_build', 'keywords', 'recommend' + ) + + @staticmethod + def get_level(self): + return self.get_level_display() + + @staticmethod + def get_direction(self): + return self.direction.title + + @staticmethod + def get_teachers(self): + return [teacher.full_name() for teacher in self.teachers.all()] + + +# class UserSerializer(serializers.ModelSerializer): +# statistics = serializers.SerializerMethodField('get_statistic') +# games = serializers.SerializerMethodField('get_my_games') +# is_anonymous = serializers.BooleanField() +# +# @staticmethod +# def get_my_games(self): +# res = {} +# try: +# res['active'] = GameSerializer(self.game_set.get(state__lte=1)).data +# except ObjectDoesNotExist: +# res['active'] = {} +# +# res['archive'] = [GameSerializer(i).data for i in self.game_set.all().filter(state=2)] +# return res +# +# @staticmethod +# def get_statistic(self): +# try: +# statistics = StatisticSerializer(Statistic.objects.get(user=self)).data +# except ObjectDoesNotExist: +# statistics = {} +# return statistics +# +# class Meta: +# model = get_user_model() +# fields = ['id', 'username', 'email', 'is_active', 'statistics', 'games', 'is_anonymous'] \ No newline at end of file diff --git a/courses/update_db.py b/courses/update_db.py new file mode 100644 index 0000000..c7075cc --- /dev/null +++ b/courses/update_db.py @@ -0,0 +1,22 @@ +import os, sys +import django, json + +sys.path.append("../") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings") +django.setup() + +from courses.models import Course, NormalMap, CourseTheme, Lesson, Homework, Exam + +if __name__ == '__main__': + for course in Course.objects.all(): + tree = [] + for theme in CourseTheme.objects.filter(course=course).order_by('sort'): + tree.append({'id': theme.id, 'body': + [str(i.id) + "_L" for i in Lesson.objects.filter(theme=theme).order_by('sort')] + + [str(i.id) + "_H" for i in Homework.objects.filter(theme=theme).order_by('sort')] + + [str(i.id) + "_E" for i in Exam.objects.filter(theme=theme).order_by('sort')] + }) + + obj, _is_create = NormalMap.objects.get_or_create(course=course) + obj.json_tree = json.dumps(tree) + obj.save() \ No newline at end of file diff --git a/finance/migrations/0071_bill_flow.py b/finance/migrations/0071_bill_flow.py deleted file mode 100644 index 0732ea7..0000000 --- a/finance/migrations/0071_bill_flow.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.3 on 2017-08-10 09:04 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('courses', '0045_auto_20170810_0904'), - ('finance', '0070_auto_20170424_1638'), - ] - - operations = [ - migrations.AddField( - model_name='bill', - name='flow', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.Flow', verbose_name='Поток'), - ), - ] diff --git a/lms/settings.py b/lms/settings.py index 930b62a..0e0b485 100644 --- a/lms/settings.py +++ b/lms/settings.py @@ -104,6 +104,7 @@ MIDDLEWARE_CLASSES = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'access.middleware.CheckPerm', + 'access.middleware.RequestToApi', ] ROOT_URLCONF = 'lms.urls' @@ -137,7 +138,7 @@ DATABASES = { 'NAME': os.environ.get('DB_NAME', 'codemy'), 'USER': os.environ.get('PG_ENV_POSTGRES_USER', 'team'), 'PASSWORD': os.environ.get('PG_ENV_POSTGRES_PASSWORD', 'nu5Xefise'), - 'HOST': os.environ.get('PG_PORT_5432_TCP_ADDR', '192.168.0.6'), + 'HOST': os.environ.get('PG_PORT_5432_TCP_ADDR', '127.0.0.1'), 'PORT': os.environ.get('PG_PORT_5432_TCP_PORT', '5432'), }, } diff --git a/lms/urls.py b/lms/urls.py index a389dde..8d6616d 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -24,6 +24,7 @@ urlpatterns = [ url(r'^management/', include('management.urls')), url(r'^teacher/', include('access.teach_urls')), url(r'^wallet/', include('finance.urls')), + url(r'^api/v1/', include('api_v1.urls')), url(r'^courses/', include('courses.urls')), url(r'^journals/', include('journals.urls')), url(r'^library/', include('library.urls')), diff --git a/requirements.txt b/requirements.txt index 08a729c..6e14adf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +djangorestframework Babel==2.3.4 Django==1.9.3 Jinja2==2.8 From d1759a5fe42d0d8c0908a108e947cc0bf8ae8148 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 6 Sep 2017 19:00:02 +0300 Subject: [PATCH 05/13] =?UTF-8?q?=D0=9E=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B2=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- courses/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/courses/serializers.py b/courses/serializers.py index 33f4d7b..284139c 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -31,7 +31,7 @@ class ThemeSerializer(serializers.ModelSerializer): class Meta: model = CourseTheme - fields = '__all__' + exclude = ('price_type', '_type', 'sort') class CourseListSerializer(serializers.ModelSerializer): From 24adcd29277ee5ad050f3be9292073f59b5821e5 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 7 Sep 2017 15:03:36 +0300 Subject: [PATCH 06/13] =?UTF-8?q?=D0=B2=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5?= =?UTF-8?q?=D1=81=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- access/middleware.py | 1 - courses/new_urls.py | 1 + courses/new_view.py | 13 +++++++++++-- courses/serializers.py | 10 ++++++++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/access/middleware.py b/access/middleware.py index c29b245..d749b62 100644 --- a/access/middleware.py +++ b/access/middleware.py @@ -9,7 +9,6 @@ class CheckPerm(object): def process_request(request): if len(request.path) > 6 and \ ('/admin' == request.path[:6] - or "/manag" == request.path[:6] or'/analy' == request.path[:6]): #or "/api/v" == request.path[:6]): diff --git a/courses/new_urls.py b/courses/new_urls.py index 86ec6b2..f531528 100644 --- a/courses/new_urls.py +++ b/courses/new_urls.py @@ -3,6 +3,7 @@ from courses import new_view as views urlpatterns = [ url(r'theme/detail/([0-9]{1,99})/$', views.ThemeDetailView.as_view()), + url(r'lesson/detail/([0-9]{1,99})/$', views.LessonDetailView.as_view()), url(r'detail/([0-9]{1,99})/$', views.CourseDetailView.as_view()), url(r'tree/([0-9]{1,99})/$', views.TreeView.as_view()), url(r'directions/$', views.DirectionListView.as_view()), diff --git a/courses/new_view.py b/courses/new_view.py index fd92c5f..eaa4139 100644 --- a/courses/new_view.py +++ b/courses/new_view.py @@ -1,8 +1,9 @@ from rest_framework.views import APIView from rest_framework.renderers import JSONRenderer from rest_framework.response import Response -from courses.models import Course, MaterialDirection, CourseTheme -from courses.serializers import CourseTreeSerializer, CourseDetailSerializer, CourseListSerializer, ThemeSerializer +from courses.models import Course, MaterialDirection, CourseTheme, Lesson +from courses.serializers import CourseTreeSerializer, CourseDetailSerializer, CourseListSerializer,\ + ThemeSerializer, LessonSerializer class DirectionListView(APIView): @@ -34,6 +35,14 @@ class ThemeDetailView(APIView): return Response(ThemeSerializer(CourseTheme.objects.get(id=id)).data, self.status_code) +class LessonDetailView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request, id): + return Response(LessonSerializer(Lesson.objects.get(id=id)).data, self.status_code) + + class CourseDetailView(APIView): renderer_classes = (JSONRenderer,) status_code = 200 diff --git a/courses/serializers.py b/courses/serializers.py index 284139c..c382bae 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -7,10 +7,15 @@ from courses.models import Course, CourseTheme, Lesson, Homework, Exam class LessonSerializer(serializers.ModelSerializer): + on_comment = serializers.SerializerMethodField() class Meta: model = Lesson - fields = '__all__' + fields = ('id', 'title', 'on_comment', 'free') + + @staticmethod + def get_on_comment(self): + return self.on_comment == 'N' or self.on_comment == 'T' and self.theme.on_comment class HomeworkSerializer(serializers.ModelSerializer): @@ -99,7 +104,8 @@ class CourseDetailSerializer(serializers.ModelSerializer): 'slug', 'mentors', 'page', 'sort', 'preview', 'use_fail', 'basic_len', 'addition_len', 'min_price', 'buy_icon', - 'must_build', 'keywords', 'recommend' + 'must_build', 'keywords', 'recommend', + 'on_comment' ) @staticmethod From 394e2b7881edbbff95d664f9438f19bb11822ce8 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 7 Sep 2017 15:07:14 +0300 Subject: [PATCH 07/13] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B5=20=D0=BE=D0=B3?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2.=20=D0=AD=D1=82=D0=BE=20=D0=BD=D1=83=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=B2=D1=8B=D0=BA=D0=B0=D1=82=D0=B8=D1=82=D1=8C?= =?UTF-8?q?,=20=D0=BA=D0=B0=D0=BA=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=B1=D1=8B=D1=81=D1=82=D1=80=D0=B5=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- access/middleware.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/access/middleware.py b/access/middleware.py index ed280f9..f225bda 100644 --- a/access/middleware.py +++ b/access/middleware.py @@ -4,8 +4,7 @@ from django.http import HttpResponseForbidden class CheckPerm(object): @staticmethod def process_request(request): - if '/admin' in request.path or "/management" in request.path \ - or '/analytics' in request.path: + if '/admin' in request.path or '/analytics' in request.path: if not request.user.is_authenticated(): return HttpResponseForbidden() From 1910b05a95ef9665fadba0640c0a563915e95825 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 7 Sep 2017 17:53:17 +0300 Subject: [PATCH 08/13] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D0=BE=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D0=B5=20=D0=B2=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- courses/models.py | 1 + courses/serializers.py | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/courses/models.py b/courses/models.py index bb4163c..1c3c41a 100755 --- a/courses/models.py +++ b/courses/models.py @@ -978,3 +978,4 @@ class Flow(models.Model): class NormalMap(models.Model): course = models.OneToOneField(to=Course) json_tree = models.TextField(default='') + independent_elements = models.TextField(default='') diff --git a/courses/serializers.py b/courses/serializers.py index c382bae..e8c19e7 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -11,7 +11,10 @@ class LessonSerializer(serializers.ModelSerializer): class Meta: model = Lesson - fields = ('id', 'title', 'on_comment', 'free') + fields = ( + 'id', 'title', 'on_comment', 'materials', + 'free', 'video', 'video_id', + ) @staticmethod def get_on_comment(self): @@ -36,7 +39,7 @@ class ThemeSerializer(serializers.ModelSerializer): class Meta: model = CourseTheme - exclude = ('price_type', '_type', 'sort') + exclude = ('price_type', '_type', 'sort', 'on_comment') class CourseListSerializer(serializers.ModelSerializer): @@ -105,7 +108,6 @@ class CourseDetailSerializer(serializers.ModelSerializer): 'preview', 'use_fail', 'basic_len', 'addition_len', 'min_price', 'buy_icon', 'must_build', 'keywords', 'recommend', - 'on_comment' ) @staticmethod From 9ea4b9e822ab6816cb8065363c0cdcccab9bb4ca Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 8 Sep 2017 15:51:35 +0300 Subject: [PATCH 09/13] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=84=D0=B0=D0=B9=D0=BB=20=D0=BD=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=B5=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lms/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/settings.py b/lms/settings.py index 0e0b485..2813897 100644 --- a/lms/settings.py +++ b/lms/settings.py @@ -138,7 +138,7 @@ DATABASES = { 'NAME': os.environ.get('DB_NAME', 'codemy'), 'USER': os.environ.get('PG_ENV_POSTGRES_USER', 'team'), 'PASSWORD': os.environ.get('PG_ENV_POSTGRES_PASSWORD', 'nu5Xefise'), - 'HOST': os.environ.get('PG_PORT_5432_TCP_ADDR', '127.0.0.1'), + 'HOST': os.environ.get('PG_PORT_5432_TCP_ADDR', '192.168.0.6'), 'PORT': os.environ.get('PG_PORT_5432_TCP_PORT', '5432'), }, } From 62d65aef6ae079a4e034d7998244b17175389a8b Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 8 Sep 2017 16:24:33 +0300 Subject: [PATCH 10/13] =?UTF-8?q?=D0=9D=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20=D1=84=D0=B8=D1=87=20?= =?UTF-8?q?=D0=B2=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/urls.py | 0 courses/serializers.py | 14 -------------- 2 files changed, 14 deletions(-) create mode 100644 api/urls.py diff --git a/api/urls.py b/api/urls.py new file mode 100644 index 0000000..e69de29 diff --git a/courses/serializers.py b/courses/serializers.py index e8c19e7..c05f2ee 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -21,20 +21,6 @@ class LessonSerializer(serializers.ModelSerializer): return self.on_comment == 'N' or self.on_comment == 'T' and self.theme.on_comment -class HomeworkSerializer(serializers.ModelSerializer): - - class Meta: - model = Homework - fields = '__all__' - - -class ExamSerializer(serializers.ModelSerializer): - - class Meta: - model = Exam - fields = '__all__' - - class ThemeSerializer(serializers.ModelSerializer): class Meta: From 7e90f2c1d89c1761ebf769fb5ac394b74868461e Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 11 Sep 2017 17:40:36 +0300 Subject: [PATCH 11/13] =?UTF-8?q?=D0=9D=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20=D0=B2=D1=8C=D1=8E?= =?UTF-8?q?=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- access/new_urls.py | 1 + access/new_view.py | 12 ++++++++- access/serializers.py | 9 +++++++ api/urls.py | 0 courses/migrations/0049_auto_20170907_1753.py | 25 +++++++++++++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 access/serializers.py delete mode 100644 api/urls.py create mode 100644 courses/migrations/0049_auto_20170907_1753.py diff --git a/access/new_urls.py b/access/new_urls.py index 0c78478..bf13a00 100644 --- a/access/new_urls.py +++ b/access/new_urls.py @@ -3,4 +3,5 @@ from access import new_view as views urlpatterns = [ url(r'teachers/$', views.TeacherListView.as_view()), + url(r'check/$', views.CheckUserView.as_view()), ] \ No newline at end of file diff --git a/access/new_view.py b/access/new_view.py index 34cf62d..2ae8524 100644 --- a/access/new_view.py +++ b/access/new_view.py @@ -13,4 +13,14 @@ class TeacherListView(APIView): in_role='T', is_active=True, reg_status=4, - )], self.status_code) \ No newline at end of file + )], self.status_code) + + +class CheckUserView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request): + if request.user.is_authenticated() and (request.user.in_role in ['M', 'S', 'S2', 'A'] or request.user.is_admin): + return Response(True, status=self.status_code) + return Response(False, status=self.status_code) \ No newline at end of file diff --git a/access/serializers.py b/access/serializers.py new file mode 100644 index 0000000..72c81e7 --- /dev/null +++ b/access/serializers.py @@ -0,0 +1,9 @@ +from django.contrib.auth import get_user_model +from rest_framework import serializers + + +class UserInitSerializer(serializers.ModelSerializer): + + class Meta: + model = get_user_model() + fields = '__all__' \ No newline at end of file diff --git a/api/urls.py b/api/urls.py deleted file mode 100644 index e69de29..0000000 diff --git a/courses/migrations/0049_auto_20170907_1753.py b/courses/migrations/0049_auto_20170907_1753.py new file mode 100644 index 0000000..5e51c04 --- /dev/null +++ b/courses/migrations/0049_auto_20170907_1753.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.3 on 2017-09-07 17:53 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0048_normalmap'), + ] + + operations = [ + migrations.AddField( + model_name='normalmap', + name='independent_elements', + field=models.TextField(default=''), + ), + migrations.AlterField( + model_name='course', + name='level', + field=models.CharField(choices=[('B', 'Базовый'), ('A', 'Продвинутый'), ('E', 'Экспертный'), ('B+A', 'Базовый + Продвинутый')], default='B', max_length=3, verbose_name='Уровень'), + ), + ] From 88bae0e8dc1715c60c0d1e965b5b55c849bf509f Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Sep 2017 14:16:39 +0300 Subject: [PATCH 12/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D1=81=D0=BA=D0=BE=D0=B5=20?= =?UTF-8?q?api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- access/new_view.py | 22 ++++++++++++++++++++++ courses/new_view.py | 15 ++++++++++++++- courses/serializers.py | 23 ++++++++++++++++++++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/access/new_view.py b/access/new_view.py index 2ae8524..8dd0b67 100644 --- a/access/new_view.py +++ b/access/new_view.py @@ -1,8 +1,11 @@ from django.contrib.auth import get_user_model +from django.contrib import auth from rest_framework.views import APIView from rest_framework.renderers import JSONRenderer from rest_framework.response import Response +from access.serializers import UserInitSerializer + class TeacherListView(APIView): renderer_classes = (JSONRenderer,) @@ -23,4 +26,23 @@ class CheckUserView(APIView): def get(self, request): if request.user.is_authenticated() and (request.user.in_role in ['M', 'S', 'S2', 'A'] or request.user.is_admin): return Response(True, status=self.status_code) + return Response(False, status=self.status_code) + + +class LoginView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def get(self, request): + if not request.user.is_authenticated(): + user = auth.authenticate(email=request.JSON.get('email'), password=request.JSON.get('password')) + return Response(UserInitSerializer(user).data, status=self.status_code) + return Response(status=403) + + +class LogoutView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 204 + + def get(self, request): return Response(False, status=self.status_code) \ No newline at end of file diff --git a/courses/new_view.py b/courses/new_view.py index eaa4139..ba42044 100644 --- a/courses/new_view.py +++ b/courses/new_view.py @@ -4,6 +4,7 @@ from rest_framework.response import Response from courses.models import Course, MaterialDirection, CourseTheme, Lesson from courses.serializers import CourseTreeSerializer, CourseDetailSerializer, CourseListSerializer,\ ThemeSerializer, LessonSerializer +from finance.models import Bill class DirectionListView(APIView): @@ -56,4 +57,16 @@ class CourseListView(APIView): status_code = 200 def get(self, request): - return Response([CourseListSerializer(i).data for i in Course.objects.all()], self.status_code) \ No newline at end of file + if not request.GET.get('staff', 'true') == 'false': + return Response([CourseListSerializer(i).data for i in Course.objects.all()], self.status_code) + + res = [] + for course in Course.objects.all(): + if course.public: + course_serialize = CourseListSerializer(course).data + course_serialize['is_mine'] = False + if Bill.objects.filter(service__course=course, user=request.user, status='F').exists(): + course_serialize['is_mine'] = True + res.append(course_serialize) + + return Response(res, self.status_code) \ No newline at end of file diff --git a/courses/serializers.py b/courses/serializers.py index c05f2ee..96f467d 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -29,10 +29,31 @@ class ThemeSerializer(serializers.ModelSerializer): class CourseListSerializer(serializers.ModelSerializer): + length = serializers.SerializerMethodField() + level = serializers.SerializerMethodField() + direction = serializers.SerializerMethodField() class Meta: model = Course - fields = ['id', 'title'] + fields = ['id', 'title', 'length', + 'level', 'direction', 'image',] + + @staticmethod + def get_length(self): + summary = 0 + for theme_slim in json.loads(self.normalmap.json_tree): + for simple_object in theme_slim['body']: + if simple_object.split('_')[1] == 'L': + summary += 1 + return summary + + @staticmethod + def get_level(self): + return self.get_level_display() + + @staticmethod + def get_direction(self): + return self.direction.title class CourseTreeSerializer(serializers.ModelSerializer): From 54b0e4f45e1e5fbbd53caab78ff6416f2c6b6062 Mon Sep 17 00:00:00 2001 From: Alexander Zolotarev Date: Fri, 15 Sep 2017 11:51:45 +0300 Subject: [PATCH 13/13] edit req --- fabfile.py | 2 +- requirements.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fabfile.py b/fabfile.py index ff94072..2daf56a 100644 --- a/fabfile.py +++ b/fabfile.py @@ -296,7 +296,7 @@ def create(): with virtualenv(): #manage('migrate --run-syncdb --noinput') #manage('migrate --list') - manage("migrate --noinput") + #manage("migrate --noinput") manage("collectstatic -l --noinput") #if exists('%sgunicorn.pid'): diff --git a/requirements.txt b/requirements.txt index 0e05158..8acb06a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -djangorestframework Babel==2.3.4 Django==1.9.3 Jinja2==2.8