Бекап перед переходом в принципиально новую систему

feature/fix_generate_pass
Andrey 8 years ago
parent 0dbf1c514e
commit ccac432200
  1. 3
      _utils/gen_diploms.py
  2. 71
      access/access_update.py
  3. 6
      access/admin.py
  4. 47
      access/migrations/0094_auto_20170929_1026.py
  5. 26
      access/migrations/0095_auto_20170929_1545.py
  6. 25
      access/models.py
  7. 7
      access/serializers.py
  8. 21
      courses/course_update.py
  9. 20
      courses/migrations/0048_auto_20170929_1026.py
  10. 21
      courses/migrations/0049_auto_20171002_1841.py
  11. 112
      courses/models.py
  12. 2
      courses/new_urls.py
  13. 59
      courses/new_view.py
  14. 42
      courses/serializers.py
  15. 2
      courses/signals.py
  16. 70
      journals/default_ations.py
  17. 342
      journals/default_threads.py
  18. 20
      journals/migrations/0077_journal_extra_data.py
  19. 26
      journals/migrations/0078_auto_20171009_0952.py
  20. 20
      journals/migrations/0079_thread_is_child.py
  21. 20
      journals/migrations/0080_auto_20171009_1736.py
  22. 24
      journals/migrations/0081_auto_20171009_1742.py
  23. 38
      journals/models.py
  24. 2
      journals/new_urls.py
  25. 27
      journals/new_view.py
  26. 36
      journals/serilizers.py
  27. 7
      lms/settings.py
  28. 29
      reactions/migrations/0002_like.py

@ -1,7 +1,6 @@
# coding=utf-8 # coding=utf-8
import os import os
from django.core.files import File from django.core.files import File
import datetime
import django import django
import sys import sys
@ -10,7 +9,6 @@ from django.db.models import Q
sys.path.append("/var/www/projects/lms/") sys.path.append("/var/www/projects/lms/")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup() django.setup()
from courses.models import Diploma, User
from journals.models import DiplomaJ from journals.models import DiplomaJ
for tm in DiplomaJ.objects.filter(Q(in_image=None)|Q(out_image=None)): for tm in DiplomaJ.objects.filter(Q(in_image=None)|Q(out_image=None)):
@ -20,7 +18,6 @@ for tm in DiplomaJ.objects.filter(Q(in_image=None)|Q(out_image=None)):
_in = open(_in) _in = open(_in)
tm.in_image.save(File(_in).name, File(_in), save=True) tm.in_image.save(File(_in).name, File(_in), save=True)
if _out: if _out:
_out = open(_out) _out = open(_out)
tm.out_image.save(File(_out).name, File(_out), save=True) tm.out_image.save(File(_out).name, File(_out), save=True)

@ -1,12 +1,77 @@
import os, sys import os, sys
import django, json import django
sys.path.append("../") sys.path.append("../")
os.environ['PG_PORT_5432_TCP_ADDR'] = '127.0.0.1' 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 access.models import Privilege from access.models import ActiveObject
from courses.models import Vertex, Lesson, Homework, Exam
from journals.models import TeacherJ, LessonJ, HomeworkJ, ExamJ
from finance.models import Bill
from django.contrib.auth import get_user_model
def get_first(course,):
l = Lesson.objects.filter(course=course).order_by('sort')
hw = Homework.objects.filter(course=course).order_by('sort')
e = Exam.objects.filter(course=course).order_by('sort')
try:
old_id = 'l_' + str(l[0].id) if l.exists() else ('h_' + str(hw[0].id) if hw.exists() else 'e_' + str(e[0].id))
return Vertex.manager.get(old_id=old_id)
except IndexError:
return None
if __name__ == '__main__': if __name__ == '__main__':
Privilege for user in get_user_model().objects.all():
bills = Bill.objects.filter(user=user, status='F')
if bills.exists():
for i in bills:
try:
tj = TeacherJ.objects.get(course=i.service.course, student=user)
if tj.status == 'F':
ActiveObject.objects.create(course=i.service.course, user=user, success=True)
else:
lesson = LessonJ.objects.filter(parent__parent=tj, success=True, student=tj.student)
homework = HomeworkJ.objects.filter(parent__parent=tj, success=True, student=tj.student)
exam = ExamJ.objects.filter(parent__parent=tj, success=True, student=tj.student)
lesson = lesson.order_by('-material__sort', '-parent__material__sort')[0] if lesson.exists() else None
homework = homework.order_by('-material__sort', '-parent__material__sort')[0] if homework.exists() else None
exam = exam.order_by('-material__sort', '-parent__material__sort')[0] if exam.exists() else None
lesson_p = lesson.parent.material.sort if lesson else 0
homework_p = homework.parent.material.sort + 0.5 if homework else 0
exam_p = exam.parent.material.sort + 0.75 if exam else 0
obj = (lesson_p > homework_p and lesson_p > exam_p and 'l_' + str(lesson.material.id)) or \
(homework_p > exam_p and 'h_' + str(homework.material.id)) or \
(exam and 'e_' + str(exam.material.id)) or\
None
if not obj:
active_obj = get_first(i.service.course)
if active_obj:
ActiveObject.objects.create(
course=i.service.course,
user=user,
active_obj=active_obj,
)
else:
vertex = Vertex.manager.get(old_id=obj)
ActiveObject.objects.create(
course=i.service.course,
user=user,
active_obj=vertex.get_next()
)
except TeacherJ.DoesNotExist:
active_obj = get_first(i.service.course)
if active_obj:
ActiveObject.objects.create(
course=i.service.course,
user=user,
active_obj=active_obj,
)

@ -1,9 +1,13 @@
from django.contrib import admin from django.contrib import admin
from access.models import User, Subscription, ActionJ, TrafSource, TrafHistory, TrafTokenHistory, Questionnaire, \ from access.models import User, Subscription, ActionJ, TrafSource, TrafHistory, TrafTokenHistory, Questionnaire, \
UserRequest, UserRequestData, Document#, UserSync UserRequest, UserRequestData, Document, ActiveObject, ExtraPrivilege
from django.contrib.auth.admin import Group from django.contrib.auth.admin import Group
admin.site.register(ExtraPrivilege)
admin.site.register(ActiveObject)
class UserAdmin(admin.ModelAdmin): class UserAdmin(admin.ModelAdmin):
list_filter = ['in_role', 'refer', 'date_joined', 'last_time', 'status', 'customer'] list_filter = ['in_role', 'refer', 'date_joined', 'last_time', 'status', 'customer']
list_display = ('id', 'email', 'is_active', 'fname', 'name', 'reg_status', 'phone', 'refer', 'date_joined', 'status', ) list_display = ('id', 'email', 'is_active', 'fname', 'name', 'reg_status', 'phone', 'refer', 'date_joined', 'status', )

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-29 10:26
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 = [
('courses', '0048_auto_20170929_1026'),
('access', '0093_auto_20170928_1625'),
]
operations = [
migrations.CreateModel(
name='ActiveObject',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('active_obj', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='Активный объект')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='Курс')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Студент')),
],
),
migrations.CreateModel(
name='ExtraPrivilege',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_done', models.BooleanField(default=False, verbose_name='Выполнено?')),
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='Объект')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Правообладатель')),
],
),
migrations.RemoveField(
model_name='privilege',
name='subject',
),
migrations.RemoveField(
model_name='privilege',
name='user',
),
migrations.DeleteModel(
name='Privilege',
),
]

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-29 15:45
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('access', '0094_auto_20170929_1026'),
]
operations = [
migrations.AddField(
model_name='activeobject',
name='success',
field=models.BooleanField(default=False, verbose_name='Завершён ли курс'),
),
migrations.AlterField(
model_name='activeobject',
name='active_obj',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='Активный объект'),
),
]

@ -7,7 +7,7 @@ import datetime
from django.db.models import SET_NULL from django.db.models import SET_NULL
from courses.models import Vertex from courses.models import Vertex, Course
from lms.regex import check_email from lms.regex import check_email
from lms.settings import STATIC_ROOT, DOMAIN from lms.settings import STATIC_ROOT, DOMAIN
from lms.tools import random_string, random_int, out_date_format, get_client_ip from lms.tools import random_string, random_int, out_date_format, get_client_ip
@ -627,13 +627,24 @@ class Questionnaire(models.Model):
# Новое API # Новое API
class ActiveObject(models.Model):
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=u'Студент')
course = models.ForeignKey(to=Course, verbose_name=u'Курс')
active_obj = models.ForeignKey(to=Vertex, verbose_name=u'Активный объект', blank=True, null=True)
success = models.BooleanField(default=False, verbose_name=u'Завершён ли курс')
class Privilege(models.Model): def __str__(self):
TYPES = ( return u'%s %s %s' % (
('r', 'Доступно для выполнению'), self.user.email,
('w', 'Ждёт ответа'), ('завершил курс' if self.success else 'в процессе изучения курса'),
('d', 'Выполнено'), self.course.title,
) )
def is_access(self, vertex):
return not vertex.is_more(self.active_obj)
class ExtraPrivilege(models.Model):
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=u'Правообладатель') user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=u'Правообладатель')
value = models.CharField(verbose_name=u'Права', choices=TYPES, max_length=1, default='r') is_done = models.BooleanField(default=False, verbose_name=u'Выполнено?')
subject = models.ForeignKey(to=Vertex, verbose_name=u'Объект') subject = models.ForeignKey(to=Vertex, verbose_name=u'Объект')

@ -1,5 +1,6 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from access.models import ExtraPrivilege
class UserInitSerializer(serializers.ModelSerializer): class UserInitSerializer(serializers.ModelSerializer):
@ -13,3 +14,9 @@ class UserInitSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_in_role(self): def get_in_role(self):
return self.get_in_role_display() return self.get_in_role_display()
class ExtraPrivilegeSerializer(serializers.ModelSerializer):
class Meta:
model = ExtraPrivilege
exclude = ('user',)

@ -8,6 +8,13 @@ django.setup()
from courses.models import Course, NormalMap, CourseTheme, Lesson, Homework, Exam, Vertex from courses.models import Course, NormalMap, CourseTheme, Lesson, Homework, Exam, Vertex
def get_url(frame):
frame = frame[frame.find('src=')+5:]
url = frame[:frame.find('\"')]
return url
if __name__ == '__main__': if __name__ == '__main__':
for course in Course.objects.all(): for course in Course.objects.all():
course_list = [] course_list = []
@ -19,10 +26,12 @@ if __name__ == '__main__':
description=theme.description, description=theme.description,
model='topic', model='topic',
icon=theme.icon, icon=theme.icon,
old_id='t_' + str(theme.id),
) )
course_list.append(topic_vertex.id) course_list.append(topic_vertex.id)
topic_list = [] topic_list = []
pay_lesson_exist = False
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
@ -32,9 +41,12 @@ if __name__ == '__main__':
description=i.description, description=i.description,
model='tutorial', model='tutorial',
on_comment=on_comment, on_comment=on_comment,
video=i.video, video=get_url(i.video),
materials=i.materials.all(), materials=i.materials.all(),
free=i.free,
old_id='l_' + str(i.id),
) )
pay_lesson_exist = pay_lesson_exist or not i.free
topic_vertex.children.add(vertex) topic_vertex.children.add(vertex)
topic_list.append(vertex.id) topic_list.append(vertex.id)
@ -46,6 +58,8 @@ if __name__ == '__main__':
model='task', model='task',
is_exam=False, is_exam=False,
materials=i.materials.all(), materials=i.materials.all(),
free=not pay_lesson_exist,
old_id='h_' + str(i.id),
) )
topic_vertex.children.add(vertex) topic_vertex.children.add(vertex)
topic_list.append(vertex.id) topic_list.append(vertex.id)
@ -58,10 +72,15 @@ if __name__ == '__main__':
model='task', model='task',
is_exam=True, is_exam=True,
materials=i.materials.all(), materials=i.materials.all(),
free=not pay_lesson_exist,
old_id='e_' + str(i.id),
) )
topic_vertex.children.add(vertex) topic_vertex.children.add(vertex)
topic_list.append(vertex.id) topic_list.append(vertex.id)
topic_vertex.free = not pay_lesson_exist
topic_vertex.save()
course_list.append(topic_list) 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)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-29 10:26
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('courses', '0047_auto_20170928_1625'),
]
operations = [
migrations.AlterField(
model_name='vertex',
name='free',
field=models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться'),
),
]

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-10-02 18:41
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('courses', '0048_auto_20170929_1026'),
]
operations = [
migrations.AddField(
model_name='vertex',
name='old_id',
field=models.CharField(default='', max_length=10, verbose_name='Поле создаётся на время миграции'),
preserve_default=False,
),
]

@ -6,6 +6,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from redactor.fields import RedactorField from redactor.fields import RedactorField
import json
from courses.templates import search_in_collection, LEVELS_COLLECTION, MATERIAL_TYPE_COLLECTION, material_fabric, \ from courses.templates import search_in_collection, LEVELS_COLLECTION, MATERIAL_TYPE_COLLECTION, material_fabric, \
comment_fabric comment_fabric
@ -78,7 +79,8 @@ class Course(models.Model):
slug = models.SlugField(max_length=255, editable=False, blank=True, default='', unique=True) 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') icon = models.ImageField(verbose_name=u'Иконка курса', blank=True, null=True, upload_to='course')
direction = models.ForeignKey(MaterialDirection, verbose_name=u'Направление', null=True) direction = models.ForeignKey(MaterialDirection, verbose_name=u'Направление', null=True)
mentors = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Кураторы', blank=True, related_name='course_mentors') mentors = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Кураторы', blank=True,
related_name='course_mentors')
public = models.BooleanField(verbose_name=u'Опубликовать', default=False) public = models.BooleanField(verbose_name=u'Опубликовать', default=False)
title = models.CharField(verbose_name=u"Заголовок", max_length=255) title = models.CharField(verbose_name=u"Заголовок", max_length=255)
description = RedactorField(verbose_name=u'Описание', blank=True) description = RedactorField(verbose_name=u'Описание', blank=True)
@ -88,7 +90,8 @@ class Course(models.Model):
help_text=u'Большая картинка для мобильной версии') help_text=u'Большая картинка для мобильной версии')
page = models.URLField(verbose_name=u'Страничка описания', blank=True, default='') page = models.URLField(verbose_name=u'Страничка описания', blank=True, default='')
preview = models.CharField(verbose_name=u'Трэйл', blank=True, default='', max_length=255) preview = models.CharField(verbose_name=u'Трэйл', blank=True, default='', max_length=255)
teachers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Преподаватели', related_name='course_teachers') teachers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Преподаватели',
related_name='course_teachers')
sort = models.IntegerField(verbose_name=u'Порядок сортировки', default=0) sort = models.IntegerField(verbose_name=u'Порядок сортировки', default=0)
use_fail = models.BooleanField(verbose_name=u'Использовать фейковую информацию', default=False) use_fail = models.BooleanField(verbose_name=u'Использовать фейковую информацию', default=False)
basic_len = models.IntegerField(verbose_name=u'Основных модулей', default=0) basic_len = models.IntegerField(verbose_name=u'Основных модулей', default=0)
@ -100,13 +103,42 @@ class Course(models.Model):
recommend = models.ManyToManyField('self', verbose_name=u'Связанные курсы', blank=True, recommend = models.ManyToManyField('self', verbose_name=u'Связанные курсы', blank=True,
help_text=u'Курсы, которые стоит порекомендовать вместе с этим') help_text=u'Курсы, которые стоит порекомендовать вместе с этим')
def __str__(self): def __str__(self):
return self.title return self.title
def __unicode__(self): def __unicode__(self):
return u"%s" % self.title return u"%s" % self.title
def get_tree(self, serializer):
"""
Способ отображения дочерних элементов.
Принимает на вход сериалайзер узла
"""
course_map = json.loads(NormalMap.objects.get(course=self).dependent_elements)
def helper(tree_id):
acc = []
for j, i in enumerate(tree_id):
if type([]) == type(i):
acc[-1]['children'] = helper(i)
else:
acc.append(serializer(Vertex.manager.get(id=i)).data)
return acc
return helper(course_map)
def get_statistic(self):
"""
Минималистичная статистика по уроку,
количество тем, уроков, домашек.
"""
topic_count = Vertex.manager.filter(course=self, content_type__model='topic').count()
task_count = Vertex.manager.filter(course=self, content_type__model='task').count()
tutorial_count = Vertex.manager.filter(course=self, content_type__model='tutorial').count()
return {"topic_count": topic_count, "tutorial_count": tutorial_count, "task_count": task_count}
def get_direction(self): def get_direction(self):
return self.direction if self.direction else '' return self.direction if self.direction else ''
@ -347,7 +379,8 @@ class Lesson(models.Model):
('T', 'Подчиняется теме') ('T', 'Подчиняется теме')
) )
free = models.BooleanField(verbose_name=u'Бесплатное видео', default=False) free = models.BooleanField(verbose_name=u'Бесплатное видео', default=False)
on_comment = models.CharField(verbose_name=u'Блок комментариев', default='T', choices=COMMENT_SWITCH, help_text=u'{0}/management/faq/37'.format(DOMAIN), max_length=1) on_comment = models.CharField(verbose_name=u'Блок комментариев', default='T', choices=COMMENT_SWITCH,
help_text=u'{0}/management/faq/37'.format(DOMAIN), max_length=1)
token = models.CharField(verbose_name=u'Токен доступа', default='', blank=True, max_length=100, editable=False) token = models.CharField(verbose_name=u'Токен доступа', default='', blank=True, max_length=100, editable=False)
title = models.TextField(verbose_name=u'Заголовок', blank=True) title = models.TextField(verbose_name=u'Заголовок', blank=True)
sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1) sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1)
@ -436,10 +469,12 @@ class Homework(models.Model):
sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1) sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1)
def __unicode__(self): def __unicode__(self):
return u'%s ID: %s Тема: %s Порядок темы: %s' % (self.course.get_title(), self.id, self.theme.title, self.theme.sort) return u'%s ID: %s Тема: %s Порядок темы: %s' % (
self.course.get_title(), self.id, self.theme.title, self.theme.sort)
def __str__(self): def __str__(self):
return '%s ID: %s Тема: %s Порядок темы: %s' % (self.course.get_title(), self.id, self.theme.title, self.theme.sort) return '%s ID: %s Тема: %s Порядок темы: %s' % (
self.course.get_title(), self.id, self.theme.title, self.theme.sort)
def get_skills(self): def get_skills(self):
# Получить скилы темы # Получить скилы темы
@ -500,7 +535,8 @@ class Exam(models.Model):
course = models.ForeignKey(Course, verbose_name=u'Курс', null=True) course = models.ForeignKey(Course, verbose_name=u'Курс', null=True)
theme = models.ForeignKey(CourseTheme, verbose_name=u'Тема курса', null=True) theme = models.ForeignKey(CourseTheme, verbose_name=u'Тема курса', null=True)
description = RedactorField(verbose_name=u'Описание для студентов') description = RedactorField(verbose_name=u'Описание для студентов')
materials = models.ManyToManyField(Storage, verbose_name=u'Материалы экзамена', related_name='exam_materials', blank=True) materials = models.ManyToManyField(Storage, verbose_name=u'Материалы экзамена', related_name='exam_materials',
blank=True)
def __str__(self): def __str__(self):
return '%s' % self.course return '%s' % self.course
@ -1021,18 +1057,52 @@ class Topic(models.Model):
class VertexManager(models.Manager): class VertexManager(models.Manager):
# Менеджер вершин графа. # Менеджер вершин графа.
def create_with_dependencies(self, model, course, title, description, def create_with_dependencies(self, model, course, old_id, title, description,
materials=None, **kwargs): free=True, 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, _is_create = content_type.model_class().objects.update_or_create(**kwargs)
[obj.materials.add(i) for i in materials] if materials else None [obj.materials.add(i) for i in materials] if materials else None
return self.create( res, _is_create = self.update_or_create(
content_type=content_type, content_type=content_type,
object_id=obj.id, object_id=obj.id,
course=course, course=course,
title=title, title=title,
description=description, description=description,
free=free,
old_id=old_id,
) )
return res
class NormalMap(models.Model):
"""
Так как курс евляется связным графом мы можем отобразить его бесконечным количеством способов,
а нам нужен один самый красивый, мы должный в явном виде указать способ отображения.
"""
course = models.OneToOneField(to=Course)
dependent_elements = models.TextField(default='[]')
independent_elements = models.TextField(default='[]')
def map_to_list(self) -> list:
def helper(root_list):
res = []
for i in root_list:
if type(i) == type([]):
res += helper(i)
else:
res.append(i)
return res
return helper(json.loads(self.dependent_elements))
def get_next(self, vertex_id) -> str:
res_list = self.map_to_list()
try:
return res_list[res_list.index(vertex_id)]
except ValueError:
raise ValueError("vertex_id " + str(vertex_id) + " not in list " + ",".join(res_list))
class Vertex(models.Model): class Vertex(models.Model):
@ -1045,12 +1115,14 @@ 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)
free = models.BooleanField(default=True, verbose_name=u'Привилегии для узла не будут проверяться')
description = models.TextField( description = models.TextField(
verbose_name=u'Описание', default='', blank=True, null=True) verbose_name=u'Описание', default='', blank=True, null=True)
children = models.ManyToManyField(to='Vertex', blank=True) children = models.ManyToManyField(to='Vertex', blank=True)
content_type = models.ForeignKey(to=ContentType) content_type = models.ForeignKey(to=ContentType)
object_id = models.PositiveIntegerField() object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id') content_object = GenericForeignKey('content_type', 'object_id')
old_id = models.CharField(max_length=10, verbose_name='Поле создаётся на время миграции')
manager = VertexManager() manager = VertexManager()
@ -1060,12 +1132,12 @@ class Vertex(models.Model):
def get_type(self): def get_type(self):
return self.content_type.__str__() return self.content_type.__str__()
def get_next(self):
class NormalMap(models.Model): vertex_id = NormalMap.objects.get(course=self.course).get_next(self.id)
""" return Vertex.manager.get(id=int(vertex_id), )
Так как курс евляется связным графом мы можем отобразить его бесконечным количеством способов,
а нам нужен один самый красивый, мы должный в явном виде указать способ отображения. def is_more(self, vertex) -> bool:
""" if not self.course == vertex.course:
course = models.OneToOneField(to=Course) raise ValueError('Vertexes of different course')
dependent_elements = models.TextField(default='[]') course_map = NormalMap.objects.get(course=self.course)
independent_elements = models.TextField(default='[]') return course_map.map_to_list().index(self.id) > course_map.map_to_list().index(vertex.id)

@ -4,7 +4,7 @@ from courses import new_view as views
urlpatterns = [ urlpatterns = [
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'vertex/([0-9]{1,99})/$', views.VertexDetail.as_view()),
url(r'tree/([0-9]{1,99})/$', views.TreeView.as_view()), url(r'tree/(?P<slug>[-\w]+)/$', 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,7 +1,10 @@
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 access.serializers import ExtraPrivilegeSerializer
from courses.models import Course, MaterialDirection, Vertex from courses.models import Course, MaterialDirection, Vertex
from access.models import ActiveObject, ExtraPrivilege
from courses.serializers import CourseDetailSerializer, CourseListSerializer, VertexSerializer, CourseTreeSerializer from courses.serializers import CourseDetailSerializer, CourseListSerializer, VertexSerializer, CourseTreeSerializer
from finance.models import Bill from finance.models import Bill
@ -10,7 +13,7 @@ class DirectionListView(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)
status_code = 200 status_code = 200
def get(self, request): def get(self, _request):
return Response([direction.title for direction in MaterialDirection.objects.all()], self.status_code) return Response([direction.title for direction in MaterialDirection.objects.all()], self.status_code)
@ -23,18 +26,35 @@ class TreeView(APIView):
print(request) print(request)
return Response(status=204) return Response(status=204)
def get(self, request, pk): def get(self, request, slug):
try: try:
return Response(CourseTreeSerializer(Course.objects.get(id=pk)).data, self.status_code) course = Course.objects.get(slug=slug)
except Course.DoesNotExist: except Course.DoesNotExist:
return Response("Course doesn't exist", status=404) return Response("Course doesn't exist", status=404)
res = CourseTreeSerializer(course).data
try:
res['active_id'] = ActiveObject.objects.get(course=course, user=request.user).active_obj.id
except ActiveObject.DoesNotExist:
res['active_id'] = False
res['extra_privilege'] = [
ExtraPrivilegeSerializer(i).data for i in ExtraPrivilege.objects.filter(
user=request.user,
subject__course=course,
)
]
return Response(res, 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, pk): def get(self, request, pk):
if not request.user.is_authenticated and request.user.in_role in ['A']:
return Response("Course detail access only for admin users", status=403)
try: try:
return Response(CourseDetailSerializer(Course.objects.get(id=pk)).data, self.status_code) return Response(CourseDetailSerializer(Course.objects.get(id=pk)).data, self.status_code)
except Course.DoesNotExist: except Course.DoesNotExist:
@ -46,7 +66,9 @@ class CourseListView(APIView):
status_code = 200 status_code = 200
def get(self, request): def get(self, request):
if not request.GET.get('staff', 'true') == 'false': if (not (request.user.is_authenticated or request.user.in_role == 'U'))\
or request.GET.get('staff') == 'true':
return Response([CourseListSerializer(i).data for i in Course.objects.all()], self.status_code) return Response([CourseListSerializer(i).data for i in Course.objects.all()], self.status_code)
res = [] res = []
@ -64,10 +86,31 @@ class CourseListView(APIView):
class VertexDetail(APIView): class VertexDetail(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)
def get(self, request, pk): @staticmethod
if not request.user.is_authenticated: def get(request, pk):
return Response("Access to detail of vertex, exist only for authenticated users", status=404) status = int(request.GET.get('status', '200'))
try: try:
return Response(VertexSerializer(Vertex.manager.get(id=pk)).data, status=200) vertex = Vertex.manager.get(id=pk)
except Vertex.DoesNotExist: except Vertex.DoesNotExist:
return Response("Vertex doesn't exist", status=404) return Response("Vertex doesn't exist", status=404)
res_a = Response(VertexSerializer(vertex).data, status=200) if status == 200 else Response(status=204)
if vertex.free:
return res_a
if not request.user.is_authenticated:
return Response("Access to detail of vertex, exist only for authenticated users", status=403)
if ExtraPrivilege.objects.filter(user=request.user, subject=vertex).exists():
return res_a
try:
if not ActiveObject.objects.get(course=vertex.course, user=request.user).is_access(vertex):
return Response("permission denied", status=403)
except ActiveObject.DoesNotExist:
return Response("permission denied", status=403)
return res_a

@ -3,7 +3,7 @@ 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, Vertex, Tutorial, Topic, Task from courses.models import Course, Vertex, Tutorial, Topic, Task, NormalMap
class TutorialSerializer(serializers.ModelSerializer): class TutorialSerializer(serializers.ModelSerializer):
@ -27,56 +27,49 @@ class TopicSerializer(serializers.ModelSerializer):
class MiniVertexSerializer(serializers.ModelSerializer): class MiniVertexSerializer(serializers.ModelSerializer):
object = serializers.SerializerMethodField() object = serializers.SerializerMethodField()
type = serializers.SerializerMethodField() type = serializers.SerializerMethodField()
children = serializers.SerializerMethodField()
class Meta: class Meta:
model = Vertex model = Vertex
fields = ('id', 'title', 'type', 'object', 'children') fields = ('id', 'title', 'type', 'object', 'free')
@staticmethod @staticmethod
def get_object(self): def get_object(self):
if self.content_type.model == 'tutorial': if self.content_type.model == 'topic':
return TutorialSerializer(self.content_object).data
elif self.content_type.model == 'topic':
return TopicSerializer(self.content_object).data return TopicSerializer(self.content_object).data
return False
elif self.content_type.model == 'task':
return TaskSerializer(self.content_object).data
@staticmethod @staticmethod
def get_type(self): def get_type(self):
return self.content_type.model return self.content_type.model
@staticmethod
def get_children(self):
return json.loads(self.sort_map.dependent_elements)
class VertexSerializer(MiniVertexSerializer): class VertexSerializer(MiniVertexSerializer):
class Meta: class Meta:
model = Vertex model = Vertex
fields = ('id', 'title', 'type', 'object', 'children', 'description') fields = ('id', 'title', 'type', 'object', "description")
@staticmethod @staticmethod
def get_children(self): def get_object(self):
return [VertexSerializer(Vertex.manager.get(id=i)).data if self.content_type.model == 'tutorial':
for i in json.loads(self.sort_map.dependent_elements)] return TutorialSerializer(self.content_object).data
if self.content_type.model == 'task':
return TaskSerializer(self.content_object).data
return False
class CourseListSerializer(serializers.ModelSerializer): class CourseListSerializer(serializers.ModelSerializer):
length = serializers.SerializerMethodField() statistic = serializers.SerializerMethodField()
level = serializers.SerializerMethodField() level = serializers.SerializerMethodField()
direction = serializers.SerializerMethodField() direction = serializers.SerializerMethodField()
class Meta: class Meta:
model = Course model = Course
fields = ['id', 'title', 'length', fields = ['id', 'title', 'statistic',
'level', 'direction', 'image', ] 'level', 'direction', 'image', 'slug']
@staticmethod @staticmethod
def get_length(self): def get_statistic(self):
return 15 return self.get_statistic()
@staticmethod @staticmethod
def get_level(self): def get_level(self):
@ -96,8 +89,7 @@ class CourseTreeSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_children(self): def get_children(self):
return [MiniVertexSerializer(Vertex.manager.get(id=i)).data return self.get_tree(MiniVertexSerializer)
for i in json.loads(self.sort_map.dependent_elements)]
class CourseDetailSerializer(serializers.ModelSerializer): class CourseDetailSerializer(serializers.ModelSerializer):

@ -9,5 +9,3 @@ def delete_dependencies(instance, **kwargs):
"""Удаляем зависимости вместе с узлом""" """Удаляем зависимости вместе с узлом"""
if instance.content_object: if instance.content_object:
instance.content_object.delete() instance.content_object.delete()
if instance.sort_map:
instance.sort_map.delete()

@ -0,0 +1,70 @@
import os, sys, django
sys.path.append("../")
os.environ['PG_PORT_5432_TCP_ADDR'] = '127.0.0.1'
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup()
from journals.models import Action
if __name__ == '__main__':
Action.objects.update_or_create(
name='try',
text='попытка сдачи чего-либо',
)
Action.objects.update_or_create(
name='yes',
text='одобрение чего-либо',
)
Action.objects.update_or_create(
name='no',
text='отказ от чего-либо',
)
Action.objects.update_or_create(
name='like',
text='нравится что-либо',
)
Action.objects.update_or_create(
name='dislike',
text='не нравится что-либо',
)
Action.objects.update_or_create(
name='favorite',
text='добавить в избранное',
)
Action.objects.update_or_create(
name='watch',
text='просмотр',
)
Action.objects.update_or_create(
name='start',
text='начало чего-либо',
)
Action.objects.update_or_create(
name='end',
text='окончание чего-либо',
)
Action.objects.update_or_create(
name='create',
text='создание чего-либо',
)
Action.objects.update_or_create(
name='delete',
text='удаление чего-либо',
)
Action.objects.update_or_create(
name='update',
text='изминение чего-либо',
)

@ -5,10 +5,101 @@ 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 journals.models import Thread from management.models import Comment
from django.contrib.contenttypes.models import ContentType
from courses.models import Vertex, Lesson
from access.models import ActiveObject
from journals.models import Thread, HomeworkTry, ExamTry, Journal, Action, \
LessonJ, CourseThemeJ, TeacherJ, HomeworkJ, ExamJ
from library.models import Article
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db import transaction
def transaction_decorator(function_to_decorate):
def wrap(*args, **kwargs):
transaction.set_autocommit(False)
try:
result = function_to_decorate(*args, **kwargs)
except Exception as ex:
transaction.rollback()
raise ex
else:
transaction.commit()
return result
finally:
transaction.set_autocommit(True)
return wrap
@transaction_decorator
def start_end_object(instance, pref, student, course, start_th_user, end_th_user):
for thj in instance.objects.filter(date__isnull=False, student=student, material__course__in=course):
obj_id = pref + str(thj.material.id)
vertex = Vertex.manager.get(old_id=obj_id)
Journal.objects.get_or_create(
thread=start_th_user,
user=student,
content_type=vertex_type,
date=thj.date,
object_id=vertex.id,
action_type=start_action,
)
if thj.f_date:
Journal.objects.get_or_create(
thread=end_th_user,
user=student,
content_type=vertex_type,
date=thj.f_date,
object_id=vertex.id,
action_type=end_action,
)
def task_obj_try(instance, pref, teacher, task_thread):
for obj_try in instance.objects.filter(teacher=teacher):
vt_id = Vertex.manager.get(old_id=pref + str(obj_try.material.id)).id
s_t_thread, _is_create = Thread.objects.get_or_create(
key='task_%d__student_%d__teacher_%d' % (vt_id, obj_try.student.id, obj_try.teacher.id),
is_staff=False,
)
s_t_thread.parent.add(task_thread)
s_t_thread.subscribers.add(obj_try.student)
s_t_thread.subscribers.add(obj_try.teacher)
user = obj_try.teacher
action = Action.objects.get(name='no')
if obj_try.success:
action = Action.objects.get(name='yes')
if obj_try.f_date is None:
user = obj_try.student
action = Action.objects.get(name='try')
Journal.objects.get_or_create(
thread=s_t_thread,
user=user,
content_type=vertex_type,
date=obj_try.date,
object_id=vt_id,
action_type=action
)
#
# Выше - хелперы, ниже - основная часть программы
#
@transaction_decorator
def main_threads():
print("Инициализация основных тредов")
res = {}
if __name__ == '__main__':
support_list = [ support_list = [
'kate.gazukina@skillbox.ru', 'kate.gazukina@skillbox.ru',
'katerina.ragozina@skillbox.ru', 'katerina.ragozina@skillbox.ru',
@ -17,20 +108,61 @@ if __name__ == '__main__':
admin_list = [ admin_list = [
'andrey.korolev@skillbox.ru', 'andrey.korolev@skillbox.ru',
'pavel.matveev@skillbox.ru', 'pavel.matveev@skillbox.ru',
'anton.kopylov@skillbox.ru',
] ]
admin_thread, _is_create = Thread.objects.get_or_create( admin_thread, _is_create = Thread.objects.get_or_create(
key='Admin', key='Admin',
text='Тред для админов сюда падают все журналируемые сообщения в системе', text='Тред для админов, сюда падают все журналируемые сообщения в системе',
is_staff=True, is_staff=True,
) )
for i in get_user_model().objects.filter(email__in=admin_list): for i in get_user_model().objects.filter(email__in=admin_list):
admin_thread.subscribers.add(i) admin_thread.subscribers.add(i)
management_thread, _is_create = Thread.objects.get_or_create(
key='Project_management',
text='Тред для проджект-менеджеров, сюда падает статистика разного рода',
is_staff=True,
)
management_thread.parent.add(admin_thread)
res['library_thread'], _is_create = Thread.objects.get_or_create(
key='Library',
text='Тред <<Библиотека>> сюда прилетает вся инфа по статьям',
is_staff=True,
)
res['library_thread'].parent.add(management_thread)
start_and_end_thread, _is_create = Thread.objects.get_or_create(
key='Start_and_end',
text='Тред начала и завершения прохождения какого-либо этапа обучения',
is_staff=True,
)
start_and_end_thread.parent.add(management_thread)
res['start_thread'], _is_create = Thread.objects.get_or_create(
key='Start',
text='Тред начала прохождения какого-либо этапа обучения',
is_staff=True,
)
res['start_thread'].parent.add(start_and_end_thread)
res['end_thread'], _is_create = Thread.objects.get_or_create(
key='End',
text='Тред окончания прохождения какого-либо этапа обучения',
is_staff=True,
)
res['end_thread'].parent.add(start_and_end_thread)
support_thread, _is_create = Thread.objects.get_or_create( support_thread, _is_create = Thread.objects.get_or_create(
key='Support', key='Support',
text='Тред сапортов занимаются поддержкой клиента', text='Тред сапортов, занимаются поддержкой клиента',
is_staff=True, is_staff=True,
) )
@ -38,3 +170,205 @@ if __name__ == '__main__':
for i in get_user_model().objects.filter(email__in=support_list): for i in get_user_model().objects.filter(email__in=support_list):
support_thread.subscribers.add(i) support_thread.subscribers.add(i)
res['task_thread'], _is_create = Thread.objects.get_or_create(
key='Tasks',
text='Сюда пободают все переписки студентов и преподов',
is_staff=True,
)
res['task_thread'].parent.add(support_thread)
res['comment_thread'], _is_create = Thread.objects.get_or_create(
key='Comments',
text='Сюда пободают все лайки дизлайки и так далее по коментам',
is_staff=True,
)
res['comment_thread'].parent.add(support_thread)
return res
@transaction_decorator
def create_article_journals(library_thread):
print("Создание журналов для статей")
for article in Article.objects.all():
article_kwarg = {
'content_type': article_type,
'object_id': article.id,
'thread': library_thread,
}
for author in article.favorite.all():
Journal.objects.get_or_create(
user=author,
action_type=Action.objects.get(name='favorite'),
**article_kwarg,
)
for author in article.likes.all():
Journal.objects.get_or_create(
user=author,
action_type=Action.objects.get(name='like'),
**article_kwarg,
)
for author in article.views.all():
Journal.objects.get_or_create(
user=author,
action_type=Action.objects.get(name='watch'),
**article_kwarg,
)
def start_end_journals(start_thread, end_thread):
print("Создание журналов начала и завершения какого-либо этапа")
for ao in ActiveObject.objects.all():
try:
start_th_user, _is_create = Thread.objects.get_or_create(
is_staff=False,
key='start_thread_course_%d__user_%d' % (ao.course.id, ao.user.id),
)
end_th_user, _is_create = Thread.objects.get_or_create(
is_staff=False,
key='end_thread_course_%d__user_%d' % (ao.course.id, ao.user.id),
)
tj = TeacherJ.objects.get(course=ao.course, student=ao.user)
Journal.objects.get_or_create(
thread=start_th_user,
user=ao.user,
content_type=course_type,
date=tj.start_date,
object_id=ao.course.id,
action_type=start_action,
)
start_th_user.parent.add(start_thread)
end_th_user.parent.add(end_thread)
kwarg = {
'student': ao.user,
'course': ao.course,
'start_th_user': start_th_user,
'end_th_user': end_th_user,
}
start_end_object(
instance=CourseThemeJ,
pref='t_',
**kwarg,
)
start_end_object(
instance=LessonJ,
pref='l_',
**kwarg,
)
start_end_object(
instance=HomeworkJ,
pref='h_',
**kwarg,
)
start_end_object(
instance=ExamJ,
pref='e_',
**kwarg,
)
except TeacherJ.DoesNotExist:
pass
@transaction_decorator
def task_try(task_tread):
print("Журналы попыток домашек")
for teacher in get_user_model().objects.filter(in_role='T'):
task_obj_try(
instance=HomeworkTry,
pref='h_',
teacher=teacher,
task_thread=task_tread
)
task_obj_try(
instance=ExamTry,
pref='e_',
teacher=teacher,
task_thread=task_tread
)
@transaction_decorator
def init_comment(comment_thread):
comment_type = ContentType.objects.get(app_label='management', model='comment')
for comment in Comment.objects.all():
comment_kwarg = {
"content_type": course_type,
"thread": comment_thread,
"object_id": comment.id,
}
for user in comment.minus_rating.all():
Journal.objects.get_or_create(
user=user,
action_type=Action.objects.get(name="dislike"),
**comment_kwarg,
)
for user in comment.plus_rating.all():
Journal.objects.get_or_create(
user=user,
action_type=Action.objects.get(name="like"),
**comment_kwarg,
)
for user in comment.saw.all():
Journal.objects.get_or_create(
user=user,
action_type=Action.objects.get(name="watch"),
**comment_kwarg,
)
if __name__ == '__main__':
if not "help" in sys.argv:
vertex_type = ContentType.objects.get(app_label='courses', model='vertex')
article_type = ContentType.objects.get(app_label='library', model='article')
course_type = ContentType.objects.get(app_label='courses', model='course')
start_action = Action.objects.get(name='start')
end_action = Action.objects.get(name='end')
boot_list = ['article', 'start_end', 'task_try', 'comment'] if len(sys.argv) == 1 else sys.argv[1:]
main_threads_info = main_threads()
if 'article' in boot_list:
create_article_journals(main_threads_info['library_thread'])
if 'start_end' in boot_list:
start_end_journals(main_threads_info['start_thread'], main_threads_info['end_thread'])
if 'task_try' in boot_list:
task_try(main_threads_info['task_thread'])
if 'comment' in boot_list:
init_comment(main_threads_info['lesson_thread'])
else:
print("""
Это скрипт миграции в новую систему данных условно его
можно разделить на несколько частей:\n
1 Инициализация основных тредов,\n
2 Создание журналов для статей,\n
3 Создание журналов начала и завершения какого-либо этапа,\n
4 Журналы попыток домашек,\n
5 Создание журналов для коментов,\n
При запуске без флагов выполняются все этапы, но можно указать какой-то конкретный или несколько,
article, start_end, task_try, comment (инициализация является обязательной)
""")

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-10-06 16:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0076_auto_20170928_1625'),
]
operations = [
migrations.AddField(
model_name='journal',
name='extra_data',
field=models.TextField(default=''),
),
]

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-10-09 09:52
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0077_journal_extra_data'),
]
operations = [
migrations.AddField(
model_name='thread',
name='check_subscribe',
field=models.BooleanField(default=True, verbose_name='Проверять ли подписки'),
),
migrations.AlterField(
model_name='thread',
name='subscribers',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Подписчики'),
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-10-09 17:33
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0078_auto_20171009_0952'),
]
operations = [
migrations.AddField(
model_name='thread',
name='is_child',
field=models.BooleanField(default=False, verbose_name='Поле аптимизации поиска'),
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-10-09 17:36
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('journals', '0079_thread_is_child'),
]
operations = [
migrations.RenameField(
model_name='thread',
old_name='is_child',
new_name='is_recursively',
),
]

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-10-09 17:42
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('journals', '0080_auto_20171009_1736'),
]
operations = [
migrations.RemoveField(
model_name='thread',
name='is_recursively',
),
migrations.AddField(
model_name='thread',
name='recurse_step',
field=models.SmallIntegerField(default=0, verbose_name='Поле аптимизации поиска'),
),
]

@ -1673,20 +1673,23 @@ class Journal(models.Model):
thread = models.ForeignKey(to='Thread', verbose_name=u'Тред') thread = models.ForeignKey(to='Thread', verbose_name=u'Тред')
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=u'Инициатор действия') user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=u'Инициатор действия')
content_type = models.ForeignKey(to=ContentType) content_type = models.ForeignKey(to=ContentType)
extra_data = models.TextField(default='')
object_id = models.PositiveIntegerField() object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id') content_object = GenericForeignKey('content_type', 'object_id')
action_type = models.ForeignKey(to='Action') action_type = models.ForeignKey(to='Action')
date = models.DateTimeField(auto_now=True) date = models.DateTimeField(auto_now=True)
def __str__(self): def __str__(self):
return 'Пользователь %s %s' % (self.user.email, self.action_type.name) return '%d Пользователь %s %s %s' % (self.id, self.user.email, self.action_type.name, self.thread.key)
class Thread(models.Model): class Thread(models.Model):
key = models.CharField(max_length=200) key = models.CharField(max_length=200)
text = models.TextField(default='', verbose_name=u'Описание треда') text = models.TextField(default='', verbose_name=u'Описание треда')
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'Подписчики') recurse_step = models.SmallIntegerField(default=0, verbose_name=u'Поле аптимизации поиска')
subscribers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Подписчики', blank=True)
check_subscribe = models.BooleanField(default=True, verbose_name='Проверять ли подписки')
parent = models.ManyToManyField(to='self', blank=True, symmetrical=False) parent = models.ManyToManyField(to='self', blank=True, symmetrical=False)
x = models.SmallIntegerField(default=300) x = models.SmallIntegerField(default=300)
y = models.SmallIntegerField(default=300) y = models.SmallIntegerField(default=300)
@ -1698,6 +1701,34 @@ class Thread(models.Model):
def check_perm(self, user): def check_perm(self, user):
return (user in self.subscribers.all()) or bool(sum([int(i.check_perm(user)) for i in self.parent.all()])) return (user in self.subscribers.all()) or bool(sum([int(i.check_perm(user)) for i in self.parent.all()]))
def child_thread_count(self, step=None):
step = self.recurse_step if step is None else step
if step == 0:
return self.thread_set.count()
return sum([i.child_thread_count(step-1) for i in self.thread_set.all()])
def journals_count(self, step=None):
step = self.recurse_step if step is None else step
children = list(self.get_children(step))
children.append(self)
return Journal.objects.filter(thread__in=children).count()
def get_children(self, step):
children = self.thread_set.filter(is_staff=False)
if step == 0:
list(children).append(self)
return children
res = [self]
for child in children:
res += child.get_children(step=step-1)
return res
def __str__(self): def __str__(self):
return self.key return self.key
@ -1705,3 +1736,6 @@ class Thread(models.Model):
class Action(models.Model): class Action(models.Model):
name = models.CharField(max_length=255, verbose_name=u'Наименование действия (на английском)') name = models.CharField(max_length=255, verbose_name=u'Наименование действия (на английском)')
text = models.TextField(verbose_name=u'Описание действия') text = models.TextField(verbose_name=u'Описание действия')
def __str__(self):
return "%s (%s)" % (self.name, self.text)

@ -3,5 +3,5 @@ from journals import new_view as views
urlpatterns = [ urlpatterns = [
url(r'thread/$', views.ThreadListView.as_view()), url(r'thread/$', views.ThreadListView.as_view()),
url(r'thread/([0-9]{1,99})/$', views.ThreadDetailView.as_view()), url(r'thread/(?P<key>[-\w]+)/$', views.ThreadDetailView.as_view()),
] ]

@ -3,7 +3,7 @@ from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from rest_framework.response import Response
from journals.models import Thread from journals.models import Thread
from journals.serilizers import ThreadSerializer from journals.serilizers import ThreadUserSerializer, ThreadAdminSerializer
class ThreadListView(APIView): class ThreadListView(APIView):
@ -12,7 +12,7 @@ class ThreadListView(APIView):
def get(self, request): def get(self, request):
return Response( return Response(
[ThreadSerializer(thread).data for thread in Thread.objects.filter(is_staff=True)], [ThreadAdminSerializer(thread).data for thread in Thread.objects.filter(is_staff=True)],
self.status_code, self.status_code,
) )
@ -21,14 +21,31 @@ class ThreadDetailView(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)
status_code = 200 status_code = 200
def post(self, request, pk): def post(self, request, key):
try: try:
thread = Thread.objects.get(id=pk) thread = Thread.objects.get(key=key)
thread.text = request.JSON.get('text', thread.text) thread.text = request.JSON.get('text', thread.text)
thread.key = request.JSON.get('key', thread.key) thread.key = request.JSON.get('key', thread.key)
thread.x = request.JSON.get('x', thread.x) thread.x = request.JSON.get('x', thread.x)
thread.y = request.JSON.get('y', thread.y) thread.y = request.JSON.get('y', thread.y)
thread.save() thread.save()
return Response(ThreadSerializer(thread).data, self.status_code,) return Response(ThreadAdminSerializer(thread).data, self.status_code,)
except Thread.DoesNotExist: except Thread.DoesNotExist:
return Response("Thread doesn't exist.", self.status_code,) return Response("Thread doesn't exist.", self.status_code,)
def get(self, request, key):
try:
return Response(ThreadUserSerializer(Thread.objects.get(key=key)).data, self.status_code)
except Thread.DoesNotExist:
return Response("Thread not found", status=404)
# class FindThreadView(APIView):
# renderer_classes = (JSONRenderer,)
# status_code = 200
#
# def get(self, request):
# is_full = request.GET.get('full', True)
# if is_full:
# key = request.GET['key']
# return Response(ThreadSerializer(Thread.objects.get(key=key)).data, self.status_code)

@ -1,10 +1,42 @@
from rest_framework import serializers from rest_framework import serializers
from journals.models import Thread from journals.models import Thread, Journal
class JournalSerializer(serializers.ModelSerializer):
class Meta:
model = Journal
exclude = ('content_type', 'object_id')
class ThreadSerializer(serializers.ModelSerializer): class ThreadSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Thread model = Thread
exclude = ['is_staff'] exclude = ('is_staff', 'recurse_step')
class ThreadAdminSerializer(ThreadSerializer):
count_children = serializers.SerializerMethodField()
count_journals = serializers.SerializerMethodField()
@staticmethod
def get_count_children(self):
return self.child_thread_count()
@staticmethod
def get_count_journals(self):
return self.journals_count()
class ThreadUserSerializer(serializers.ModelSerializer):
journals = serializers.SerializerMethodField()
class Meta:
model = Thread
fields = ('journals', 'key')
@staticmethod
def get_journals(self):
return [JournalSerializer(i).data for i in self.journal_set.all()]

@ -61,8 +61,8 @@ EMAIL_PORT = '587'
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'robo@skillbox.ru' DEFAULT_FROM_EMAIL = 'robo@skillbox.ru'
YANDEX_MONEY_SHOP_PASSWORD = 'nu5Xefise' YANDEX_MONEY_SHOP_PASSWORD = 'nu5Xefise'
YANDEX_SHOP_ID = '84348' YANDEX_SHOP_ID = '157133'
YANDEX_scid = '78309' YANDEX_scid = '149639'
# Application definition # Application definition
# место куда сохраняем пользовательские файлы # место куда сохраняем пользовательские файлы
@ -92,7 +92,6 @@ INSTALLED_APPS = [
'library', 'library',
'practice', 'practice',
'precise_bbcode', 'precise_bbcode',
'reactions',
] ]
MIDDLEWARE_CLASSES = [ MIDDLEWARE_CLASSES = [
@ -139,7 +138,7 @@ DATABASES = {
'NAME': os.environ.get('DB_NAME', 'codemy'), 'NAME': os.environ.get('DB_NAME', 'codemy'),
'USER': os.environ.get('PG_ENV_POSTGRES_USER', 'team'), 'USER': os.environ.get('PG_ENV_POSTGRES_USER', 'team'),
'PASSWORD': os.environ.get('PG_ENV_POSTGRES_PASSWORD', 'nu5Xefise'), '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'), 'PORT': os.environ.get('PG_PORT_5432_TCP_PORT', '5432'),
}, },
} }

@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.3 on 2017-09-21 17:58
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'),
('reactions', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Like',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_positive', models.BooleanField(default=True)),
('object_id', models.PositiveIntegerField()),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Инициатор действия')),
],
),
]
Loading…
Cancel
Save