В процессе

feature/fix_generate_pass
Andrey 8 years ago
parent af4261f409
commit b42a589c28
  1. 11
      README.md
  2. 4
      access/migrations/0091_privilege.py
  3. 4
      access/migrations/0092_auto_20170925_1829.py
  4. 3
      access/new_view.py
  5. 9
      access/serializers.py
  6. 1
      api_v1/urls.py
  7. 54
      courses/course_update.py
  8. 80
      courses/migrations/0046_auto_20170925_1829.py
  9. 29
      courses/migrations/0047_auto_20170921_1746.py
  10. 45
      courses/models.py
  11. 3
      courses/new_urls.py
  12. 49
      courses/new_view.py
  13. 140
      courses/serializers.py
  14. 6
      courses/signals.py
  15. 22
      courses/update_db.py
  16. 58
      journals/migrations/0074_auto_20170925_1829.py
  17. 13
      journals/migrations/0075_auto_20170926_1238.py
  18. 25
      journals/migrations/0076_auto_20170922_1116.py
  19. 20
      journals/migrations/0077_auto_20170922_1117.py
  20. 20
      journals/migrations/0078_auto_20170922_1118.py
  21. 2
      journals/models.py
  22. 7
      journals/new_urls.py
  23. 34
      journals/new_view.py
  24. 10
      journals/serilizers.py

@ -1,11 +1,4 @@
#**SkillBox LMS** #**SkillBox LMS**
Нужно выполнить миграции и запустить скрипт update_db.py без параметров в модуле courses (скрипт на всякий случай пока не удалять) DROP TABLE courses_normalmap;
снести табличку вручную
Фактически в структуре данных изменилось только то, что появилась новая табличка NormalMap. Скрипт собирает все treeview курсов и кладёт в эту табличку
Появилась новая зависимость django_rest_framework.
Изменения никак не трогают старый функционал.
Имеет смысл пробежаться по middl

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-21 17:07 # Generated by Django 1.9.3 on 2017-09-25 18:29
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -16,7 +16,7 @@ class Migration(migrations.Migration):
name='Privilege', name='Privilege',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.CharField(choices=[('r', 'Отображение'), ('u', 'Использование'), ('w', 'Изменение')], default='r', max_length=1, verbose_name='Права')), ('value', models.CharField(choices=[('r', 'Доступно для выполнению'), ('w', 'Ждёт ответа'), ('d', 'Выполнено')], default='r', max_length=1, verbose_name='Права')),
], ],
), ),
] ]

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-21 17:07 # Generated by Django 1.9.3 on 2017-09-25 18:29
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
@ -10,8 +10,8 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('courses', '0046_auto_20170925_1829'),
('access', '0091_privilege'), ('access', '0091_privilege'),
('courses', '0046_auto_20170921_1707'),
] ]
operations = [ operations = [

@ -32,7 +32,8 @@ class CheckUserView(APIView):
status_code = 200 status_code = 200
def get(self, request): def get(self, request):
if request.user.is_authenticated() and (request.user.in_role in ['M', 'S', 'S2', 'A'] or request.user.is_admin): if request.user.is_authenticated() and\
(request.user.in_role in ['M', 'S', 'S2', 'A', 'T'] or request.user.is_admin):
return Response(True, status=self.status_code) return Response(True, status=self.status_code)
return Response(False, status=self.status_code) return Response(False, status=self.status_code)

@ -3,8 +3,13 @@ from rest_framework import serializers
class UserInitSerializer(serializers.ModelSerializer): class UserInitSerializer(serializers.ModelSerializer):
in_role = serializers.SerializerMethodField()
class Meta: class Meta:
model = get_user_model() model = get_user_model()
fields = ['id', 'email', 'phone', 'name', fields = ['id', 'email', 'phone', 'name', 'in_avatar',
'fname', 'oname', 'city', 'b_day'] 'fname', 'oname', 'city', 'b_day', 'in_role',]
@staticmethod
def get_in_role(self):
return self.get_in_role_display()

@ -3,4 +3,5 @@ from django.conf.urls import url, include
urlpatterns = [ urlpatterns = [
url(r'courses/', include('courses.new_urls')), url(r'courses/', include('courses.new_urls')),
url(r'users/', include('access.new_urls')), url(r'users/', include('access.new_urls')),
url(r'journals/', include('journals.new_urls')),
] ]

@ -6,13 +6,11 @@ os.environ['PG_PORT_5432_TCP_ADDR'] = '127.0.0.1'
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup() django.setup()
from django.contrib.contenttypes.models import ContentType from courses.models import Course, NormalMap, CourseTheme, Lesson, Homework, Exam, Vertex
from courses.models import Course, NormalMap, CourseTheme, Lesson, Homework, Exam, \
Tutorial, Task, Topic, Vertex
if __name__ == '__main__': if __name__ == '__main__':
for course in Course.objects.all(): for course in Course.objects.all():
tree = [] course_list = []
for theme in CourseTheme.objects.filter(course=course).order_by('sort'): for theme in CourseTheme.objects.filter(course=course).order_by('sort'):
topic_vertex = Vertex.manager.create_with_dependencies( topic_vertex = Vertex.manager.create_with_dependencies(
@ -22,54 +20,50 @@ if __name__ == '__main__':
model='topic', model='topic',
icon=theme.icon, icon=theme.icon,
) )
course_list.append(topic_vertex.id)
topic_list = []
tree.append(topic_vertex.id)
children = []
for i in Lesson.objects.filter(theme=theme).order_by('sort'): for i in Lesson.objects.filter(theme=theme).order_by('sort'):
on_comment = i.on_comment == 'N' or i.on_comment == 'T' and i.theme.on_comment on_comment = i.on_comment == 'N' or i.on_comment == 'T' and i.theme.on_comment
tutor = Tutorial.objects.create(video=i.video, on_comment=on_comment) vertex = Vertex.manager.create_with_dependencies(
[tutor.materials.add(j) for j in i.materials.all()]
lesson_type = ContentType.objects.get(app_label="courses", model="tutorial")
vertex = Vertex.objects.create(
course=course, course=course,
title=i.title, title=i.title,
description=i.description, description=i.description,
content_type=lesson_type, model='tutorial',
object_id=tutor.id, on_comment=on_comment,
video=i.video,
materials=i.materials.all(),
) )
topic_vertex.children.add(vertex) topic_vertex.children.add(vertex)
children.append(vertex.id) topic_list.append(vertex.id)
for i in Homework.objects.filter(theme=theme).order_by('sort'): for i in Homework.objects.filter(theme=theme).order_by('sort'):
task = Task.objects.create(is_exam=False,) vertex = Vertex.manager.create_with_dependencies(
[task.materials.add(j) for j in i.materials.all()]
task_type = ContentType.objects.get(app_label="courses", model="task")
vertex = Vertex.objects.create(
course=course, course=course,
title='Домашняя работа', title='Домашняя работа',
description=i.description, description=i.description,
content_type=task_type, model='task',
object_id=task.id, is_exam=False,
materials=i.materials.all(),
) )
topic_vertex.children.add(vertex) topic_vertex.children.add(vertex)
children.append(vertex.id) topic_list.append(vertex.id)
for i in Exam.objects.filter(theme=theme).order_by('sort'): for i in Exam.objects.filter(theme=theme).order_by('sort'):
task=Task.objects.create(is_exam=True,) vertex = Vertex.manager.create_with_dependencies(
[task.materials.add(j) for j in i.materials.all()]
task_type = ContentType.objects.get(app_label="courses", model="task")
vertex = Vertex.objects.create(
course=course, course=course,
title='Экзамен', title='Экзамен',
description=i.description, description=i.description,
content_type=task_type, model='task',
object_id=task.id, is_exam=True,
materials=i.materials.all(),
) )
topic_vertex.children.add(vertex) topic_vertex.children.add(vertex)
children.append(vertex.id) topic_list.append(vertex.id)
tree.append(children) course_list.append(topic_list)
course_map, _is_create = NormalMap.objects.get_or_create(course=course) course_map, _is_create = NormalMap.objects.get_or_create(course=course)
course_map.json_tree=json.dumps(tree) course_map.dependent_elements = json.dumps(course_list)
course_map.save() course_map.save()

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-25 18:29
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import django.db.models.manager
class Migration(migrations.Migration):
dependencies = [
('storage', '0002_auto_20160831_1638'),
('contenttypes', '0002_remove_content_type_name'),
('courses', '0045_auto_20170918_0811'),
]
operations = [
migrations.CreateModel(
name='NormalMap',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('dependent_elements', models.TextField(default='[]')),
('independent_elements', models.TextField(default='[]')),
],
),
migrations.CreateModel(
name='Task',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_exam', models.BooleanField(default=False, verbose_name='Экзамен или домашка')),
('materials', models.ManyToManyField(blank=True, to='storage.Storage', verbose_name='Материалы для домашней работы')),
],
),
migrations.CreateModel(
name='Topic',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('icon', models.ImageField(blank=True, null=True, upload_to='CourseTheme', verbose_name='Иконка темы')),
],
),
migrations.CreateModel(
name='Tutorial',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('on_comment', models.BooleanField(default=True, verbose_name='Комментарии')),
('video', models.TextField(blank=True, default='', verbose_name='Код видео')),
('materials', models.ManyToManyField(blank=True, to='storage.Storage', verbose_name='Материалы урока')),
],
),
migrations.CreateModel(
name='Vertex',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='Название')),
('description', models.TextField(blank=True, default='', null=True, verbose_name='Описание')),
('object_id', models.PositiveIntegerField()),
('children', models.ManyToManyField(blank=True, to='courses.Vertex')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
],
managers=[
('manager', django.db.models.manager.Manager()),
],
),
migrations.AlterField(
model_name='course',
name='level',
field=models.CharField(choices=[('B', 'Базовый'), ('A', 'Продвинутый'), ('E', 'Экспертный'), ('B+A', 'Базовый + Продвинутый')], default='B', max_length=3, verbose_name='Уровень'),
),
migrations.AddField(
model_name='vertex',
name='course',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course'),
),
migrations.AddField(
model_name='normalmap',
name='course',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='courses.Course'),
),
]

@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-21 17:46
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('courses', '0046_auto_20170921_1707'),
]
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='')),
('independent_elements', models.TextField(default='')),
],
),
migrations.AddField(
model_name='normalmap',
name='course',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='courses.Course'),
),
]

@ -980,26 +980,52 @@ class CourseBuilder:
# Модели нового API со временем всё, что выше будет выпилено # Модели нового API со временем всё, что выше будет выпилено
class Tutorial(models.Model): class Tutorial(models.Model):
"""
Модель урока.
Урок может быть открыт для комментирования и закрыт, по дефолту открыт,
вероятно закрывать нужно будет крайне редко.
Видео к уроку фрейм который лежит прямо в базе, конечно же костыль и со временем
мы уйдём от этого, все видео хостятся на двух онлайн сервисах на клиент нужно передовать
id и сервис на котором, это дело хостится, а правило отображения оставить клиенту.
Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице
и дублирования метазаголовков файла
"""
on_comment = models.BooleanField(verbose_name=u'Комментарии', default=True) on_comment = models.BooleanField(verbose_name=u'Комментарии', default=True)
video = models.TextField(verbose_name=u'Код видео', default='', blank=True) video = models.TextField(verbose_name=u'Код видео', default='', blank=True)
materials = models.ManyToManyField(Storage, verbose_name=u'Материалы урока', blank=True) materials = models.ManyToManyField(Storage, verbose_name=u'Материалы урока', blank=True)
class Task(models.Model): class Task(models.Model):
"""
Модель таска.
Исторически сложилось, что на сервере хостятся два типа тасков отличающихся лишь наименованием
домашние работы и экзамены, не нужно быть гением, чтобы понять для чего нужно булево значение
is_exam
Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице
и дублирования метазаголовков файла
"""
materials = models.ManyToManyField(Storage, verbose_name=u'Материалы для домашней работы', blank=True) materials = models.ManyToManyField(Storage, verbose_name=u'Материалы для домашней работы', blank=True)
is_exam = models.BooleanField(default=False, verbose_name=u'Экзамен или домашка') is_exam = models.BooleanField(default=False, verbose_name=u'Экзамен или домашка')
class Topic(models.Model): class Topic(models.Model):
"""
Модель темы, нужно просто для объединения тасков и уроков.
У некоторых тем есть иконка.
Возможно поле icon перекачует в Vertex, а данная модель отвалится за ненадобностью
"""
icon = models.ImageField(verbose_name=u'Иконка темы', upload_to='CourseTheme', null=True, blank=True) icon = models.ImageField(verbose_name=u'Иконка темы', upload_to='CourseTheme', null=True, blank=True)
class VertexManager(models.Manager): class VertexManager(models.Manager):
# Менеджер вершин графа. На самом деле # Менеджер вершин графа.
def create_with_dependencies(self, model, course, title, description, **kwargs): def create_with_dependencies(self, model, course, title, description,
materials=None, **kwargs):
content_type = ContentType.objects.get(app_label='courses', model=model) content_type = ContentType.objects.get(app_label='courses', model=model)
obj = content_type.model_class().objects.create(**kwargs) obj = content_type.model_class().objects.create(**kwargs)
[obj.materials.add(i) for i in materials] if materials else None
return self.create( return self.create(
content_type=content_type, content_type=content_type,
object_id=obj.id, object_id=obj.id,
@ -1010,6 +1036,13 @@ class VertexManager(models.Manager):
class Vertex(models.Model): class Vertex(models.Model):
"""
Основная структурная единица узел графа курса.
Может быть привязана к теме уроку или заданию.
Модель создана для минимизации трёх выше указанных.
Позволяет работать со структурой курса на более высоком уровне абстракции.
"""
course = models.ForeignKey(to=Course) course = models.ForeignKey(to=Course)
title = models.CharField(verbose_name=u'Название', max_length=255) title = models.CharField(verbose_name=u'Название', max_length=255)
description = models.TextField( description = models.TextField(
@ -1029,6 +1062,10 @@ class Vertex(models.Model):
class NormalMap(models.Model): class NormalMap(models.Model):
"""
Так как курс евляется связным графом мы можем отобразить его бесконечным количеством способов,
а нам нужен один самый красивый, мы должный в явном виде указать способ отображения.
"""
course = models.OneToOneField(to=Course) course = models.OneToOneField(to=Course)
json_tree = models.TextField(default='') dependent_elements = models.TextField(default='[]')
independent_elements = models.TextField(default='') independent_elements = models.TextField(default='[]')

@ -2,9 +2,8 @@ from django.conf.urls import url
from courses import new_view as views from courses import new_view as views
urlpatterns = [ 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'detail/([0-9]{1,99})/$', views.CourseDetailView.as_view()),
url(r'vertex/([0-9]{1,99})/$', views.VertexDetail.as_view()),
url(r'tree/([0-9]{1,99})/$', views.TreeView.as_view()), url(r'tree/([0-9]{1,99})/$', views.TreeView.as_view()),
url(r'directions/$', views.DirectionListView.as_view()), url(r'directions/$', views.DirectionListView.as_view()),
url(r'^$', views.CourseListView.as_view()), url(r'^$', views.CourseListView.as_view()),

@ -1,9 +1,8 @@
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from rest_framework.response import Response
from courses.models import Course, MaterialDirection, CourseTheme, Lesson from courses.models import Course, MaterialDirection, Vertex
from courses.serializers import CourseTreeSerializer, CourseDetailSerializer, CourseListSerializer,\ from courses.serializers import CourseDetailSerializer, CourseListSerializer, VertexSerializer, CourseTreeSerializer
ThemeSerializer, LessonSerializer
from finance.models import Bill from finance.models import Bill
@ -24,32 +23,22 @@ class TreeView(APIView):
print(request) print(request)
return Response(status=204) return Response(status=204)
def get(self, request, id): def get(self, request, pk):
return Response(CourseTreeSerializer(Course.objects.get(id=id)).data, self.status_code) try:
return Response(CourseTreeSerializer(Course.objects.get(id=pk)).data, self.status_code)
except Course.DoesNotExist:
class ThemeDetailView(APIView): return Response("Course doesn't exist", status=404)
renderer_classes = (JSONRenderer,)
status_code = 200
def get(self, request, id):
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): class CourseDetailView(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)
status_code = 200 status_code = 200
def get(self, request, id): def get(self, request, pk):
return Response(CourseDetailSerializer(Course.objects.get(id=id)).data, self.status_code) try:
return Response(CourseDetailSerializer(Course.objects.get(id=pk)).data, self.status_code)
except Course.DoesNotExist:
return Response("Course doesn't exist", status=404)
class CourseListView(APIView): class CourseListView(APIView):
@ -69,4 +58,16 @@ class CourseListView(APIView):
course_serialize['is_mine'] = True course_serialize['is_mine'] = True
res.append(course_serialize) res.append(course_serialize)
return Response(res, self.status_code) return Response(res, self.status_code)
class VertexDetail(APIView):
renderer_classes = (JSONRenderer,)
def get(self, request, pk):
if not request.user.is_authenticated:
return Response("Access to detail of vertex, exist only for authenticated users", status=404)
try:
return Response(VertexSerializer(Vertex.manager.get(id=pk)).data, status=200)
except Vertex.DoesNotExist:
return Response("Vertex doesn't exist", status=404)

@ -3,29 +3,65 @@ import json
# from django.contrib.auth import get_user_model # from django.contrib.auth import get_user_model
# from django.core.exceptions import ObjectDoesNotExist # from django.core.exceptions import ObjectDoesNotExist
from courses.models import Course, CourseTheme, Lesson, Homework, Exam from courses.models import Course, Vertex, Tutorial, Topic, Task
class LessonSerializer(serializers.ModelSerializer): class TutorialSerializer(serializers.ModelSerializer):
on_comment = serializers.SerializerMethodField() class Meta:
model = Tutorial
exclude = ['id']
class TaskSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Lesson model = Task
fields = ( exclude = ['id']
'id', 'title', 'on_comment', 'materials',
'free', 'video', 'video_id',
) class TopicSerializer(serializers.ModelSerializer):
class Meta:
model = Topic
exclude = ['id']
class MiniVertexSerializer(serializers.ModelSerializer):
object = serializers.SerializerMethodField()
type = serializers.SerializerMethodField()
children = serializers.SerializerMethodField()
class Meta:
model = Vertex
fields = ('id', 'title', 'type', 'object', 'children')
@staticmethod @staticmethod
def get_on_comment(self): def get_object(self):
return self.on_comment == 'N' or self.on_comment == 'T' and self.theme.on_comment if self.content_type.model == 'tutorial':
return TutorialSerializer(self.content_object).data
elif self.content_type.model == 'topic':
return TopicSerializer(self.content_object).data
class ThemeSerializer(serializers.ModelSerializer): elif self.content_type.model == 'task':
return TaskSerializer(self.content_object).data
@staticmethod
def get_type(self):
return self.content_type.model
@staticmethod
def get_children(self):
return json.loads(self.sort_map.dependent_elements)
class VertexSerializer(MiniVertexSerializer):
class Meta: class Meta:
model = CourseTheme model = Vertex
exclude = ('price_type', '_type', 'sort', 'on_comment') fields = ('id', 'title', 'type', 'object', 'children', 'description')
@staticmethod
def get_children(self):
return [VertexSerializer(Vertex.manager.get(id=i)).data
for i in json.loads(self.sort_map.dependent_elements)]
class CourseListSerializer(serializers.ModelSerializer): class CourseListSerializer(serializers.ModelSerializer):
@ -36,16 +72,11 @@ class CourseListSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Course model = Course
fields = ['id', 'title', 'length', fields = ['id', 'title', 'length',
'level', 'direction', 'image',] 'level', 'direction', 'image', ]
@staticmethod @staticmethod
def get_length(self): def get_length(self):
summary = 0 return 15
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 @staticmethod
def get_level(self): def get_level(self):
@ -61,46 +92,12 @@ class CourseTreeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Course model = Course
fields = ['id', 'title', 'children'] fields = ['id', 'children']
@staticmethod @staticmethod
def get_children(self): def get_children(self):
theme_list = json.loads(self.normalmap.json_tree) return [MiniVertexSerializer(Vertex.manager.get(id=i)).data
map = [] for i in json.loads(self.sort_map.dependent_elements)]
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): class CourseDetailSerializer(serializers.ModelSerializer):
@ -128,32 +125,3 @@ class CourseDetailSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_teachers(self): def get_teachers(self):
return [teacher.full_name() for teacher in self.teachers.all()] 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']

@ -6,4 +6,8 @@ from courses.models import Vertex
@receiver(pre_delete, sender=Vertex) @receiver(pre_delete, sender=Vertex)
def delete_dependencies(instance, **kwargs): def delete_dependencies(instance, **kwargs):
instance.content_object.delete() """Удаляем зависимости вместе с узлом"""
if instance.content_object:
instance.content_object.delete()
if instance.sort_map:
instance.sort_map.delete()

@ -1,22 +0,0 @@
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()

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-25 18:29
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contenttypes', '0002_remove_content_type_name'),
('journals', '0073_auto_20170918_0811'),
]
operations = [
migrations.CreateModel(
name='Action',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Наименование действия (на английском)')),
('text', models.TextField(verbose_name='Описание действия')),
],
),
migrations.CreateModel(
name='Journal',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('date', models.DateTimeField(auto_now=True)),
('action_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='journals.Action')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
],
),
migrations.CreateModel(
name='Thread',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(max_length=200)),
('text', models.TextField(default='', verbose_name='Описание треда')),
('is_staff', models.BooleanField(default=False, verbose_name='Админская ли табличка')),
('parent', models.ManyToManyField(blank=True, related_name='_thread_parent_+', to='journals.Thread')),
('subscribers', models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='Подписчики')),
],
),
migrations.AddField(
model_name='journal',
name='thread',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='journals.Thread', verbose_name='Тред'),
),
migrations.AddField(
model_name='journal',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Инициатор действия'),
),
]

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-22 11:23 # Generated by Django 1.9.3 on 2017-09-26 12:38
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -8,17 +8,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('journals', '0078_auto_20170922_1118'), ('journals', '0074_auto_20170925_1829'),
] ]
operations = [ operations = [
migrations.RemoveField( migrations.AddField(
model_name='thread', model_name='thread',
name='children', name='x',
field=models.SmallIntegerField(default=0),
), ),
migrations.AddField( migrations.AddField(
model_name='thread', model_name='thread',
name='parent', name='y',
field=models.ManyToManyField(blank=True, related_name='_thread_parent_+', to='journals.Thread'), field=models.SmallIntegerField(default=0),
), ),
] ]

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-22 11:16
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0075_remove_journal_body'),
]
operations = [
migrations.AddField(
model_name='thread',
name='is_staff',
field=models.BooleanField(default=True, verbose_name='Видно ли в админке'),
),
migrations.AlterField(
model_name='thread',
name='text',
field=models.TextField(default='', verbose_name='Описание треда'),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-22 11:17
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0076_auto_20170922_1116'),
]
operations = [
migrations.AlterField(
model_name='thread',
name='is_staff',
field=models.BooleanField(default=False, verbose_name='Видно ли в админке'),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-22 11:18
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0077_auto_20170922_1117'),
]
operations = [
migrations.AlterField(
model_name='thread',
name='is_staff',
field=models.BooleanField(default=False, verbose_name='Админская ли табличка'),
),
]

@ -1688,6 +1688,8 @@ class Thread(models.Model):
is_staff = models.BooleanField(default=False, verbose_name=u'Админская ли табличка') is_staff = models.BooleanField(default=False, verbose_name=u'Админская ли табличка')
subscribers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Подписчики') subscribers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Подписчики')
parent = models.ManyToManyField(to='self', blank=True) parent = models.ManyToManyField(to='self', blank=True)
x = models.SmallIntegerField(default=300)
y = models.SmallIntegerField(default=300)
def get_journals(self, **filter_extra): def get_journals(self, **filter_extra):
threads = [i for i in self.thread_set.all()].append(self) threads = [i for i in self.thread_set.all()].append(self)

@ -0,0 +1,7 @@
from django.conf.urls import url
from journals import new_view as views
urlpatterns = [
url(r'thread/$', views.ThreadListView.as_view()),
url(r'thread/([0-9]{1,99})/$', views.ThreadDetailView.as_view()),
]

@ -0,0 +1,34 @@
from rest_framework.views import APIView
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from journals.models import Thread
from journals.serilizers import ThreadSerializer
class ThreadListView(APIView):
renderer_classes = (JSONRenderer,)
status_code = 200
def get(self, request):
return Response(
[ThreadSerializer(thread).data for thread in Thread.objects.filter(is_staff=True)],
self.status_code,
)
class ThreadDetailView(APIView):
renderer_classes = (JSONRenderer,)
status_code = 200
def post(self, request, pk):
try:
thread = Thread.objects.get(id=pk)
thread.text = request.JSON.get('text', thread.text)
thread.key = request.JSON.get('key', thread.key)
thread.x = request.JSON.get('x', thread.x)
thread.y = request.JSON.get('y', thread.y)
thread.save()
return Response(ThreadSerializer(thread).data, self.status_code,)
except Thread.DoesNotExist:
return Response("Thread doesn't exist.", self.status_code,)

@ -0,0 +1,10 @@
from rest_framework import serializers
from journals.models import Thread
class ThreadSerializer(serializers.ModelSerializer):
class Meta:
model = Thread
exclude = ['is_staff']
Loading…
Cancel
Save