зависимости

feature/fix_generate_pass
Andrey 8 years ago
parent 9ace79accd
commit 89150bb294
  1. 6
      access/admin.py
  2. 41
      access/migrations/0001_initial.py
  3. 20
      access/migrations/0003_auto_20180115_1953.py
  4. 52
      access/models/progress.py
  5. 2
      access/models/user.py
  6. 12
      access/serializers.py
  7. 4
      access/views.py
  8. 4
      achievements/migrations/0001_initial.py
  9. 8
      courses/admin.py
  10. 84
      courses/migrations/0001_initial.py
  11. 42
      courses/migrations/0002_init_demands.py
  12. 20
      courses/migrations/0003_lesson_old_id.py
  13. 123
      courses/models.py
  14. 15
      courses/serializers.py
  15. 4
      courses/views.py
  16. 47
      csv/load_comments.py
  17. 13
      csv/load_courses.py
  18. 2
      csv/load_storage.py
  19. 2
      finance/migrations/0001_initial.py
  20. 2
      library/migrations/0001_initial.py
  21. 14
      storage/api.py
  22. 7
      storage/migrations/0001_initial.py
  23. 7
      storage/models.py
  24. 20
      storage/tests.py

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from access.models.other import Invite, Account, ResetPassword from access.models.other import Invite, Account, ResetPassword
from access.models.progress import ProgressLesson, UserLessonAnswer, AnswerItem from access.models.progress import ProgressLesson
from access.models import Progress from access.models import Progress
from access.models.user import User from access.models.user import User
@ -9,6 +9,4 @@ admin.site.register(Account)
admin.site.register(Progress) admin.site.register(Progress)
admin.site.register(Invite) admin.site.register(Invite)
admin.site.register(ResetPassword) admin.site.register(ResetPassword)
admin.site.register(ProgressLesson) admin.site.register(ProgressLesson)
admin.site.register(AnswerItem)
admin.site.register(UserLessonAnswer)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 15:44 # Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals from __future__ import unicode_literals
import access.models.user import access.models.user
@ -23,10 +23,11 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='User', name='User',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')), ('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('out_key', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='Токен')), ('out_key', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Токен')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
('first_name', models.CharField(blank=True, default='Гость', max_length=63, verbose_name='first name')), ('first_name', models.CharField(blank=True, default='Гость', max_length=63, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=63, verbose_name='last name')), ('last_name', models.CharField(blank=True, max_length=63, verbose_name='last name')),
@ -61,20 +62,6 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Дополнительная информация о пользователе', 'verbose_name_plural': 'Дополнительная информация о пользователе',
}, },
), ),
migrations.CreateModel(
name='AnswerItem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question', models.TextField(verbose_name='Вопрос')),
('value', models.TextField(verbose_name='Ответ')),
('comment', models.TextField(blank=True, null=True, verbose_name='Комент')),
('status', models.CharField(choices=[('done', 'done'), ('wait', 'wait'), ('fail', 'fail')], default='wait', max_length=20)),
],
options={
'verbose_name': 'Ответ пользователя',
'verbose_name_plural': 'Ответы пользователя',
},
),
migrations.CreateModel( migrations.CreateModel(
name='Invite', name='Invite',
fields=[ fields=[
@ -107,6 +94,8 @@ class Migration(migrations.Migration):
('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')),
('lesson_token', models.UUIDField(editable=False, verbose_name='Токен урока')), ('lesson_token', models.UUIDField(editable=False, verbose_name='Токен урока')),
('date', models.DateTimeField(blank=True, null=True, verbose_name='Дата зачтения задания')), ('date', models.DateTimeField(blank=True, null=True, verbose_name='Дата зачтения задания')),
('status', models.CharField(choices=[('done', 'done'), ('wait', 'wait'), ('fail', 'fail')], default='wait', max_length=20)),
('comment_tokens', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, verbose_name='Токен комента'), default=[], size=None)),
('progress', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.Progress')), ('progress', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.Progress')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Преподователь')), ('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Преподователь')),
], ],
@ -115,19 +104,6 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Прохождение урока', 'verbose_name_plural': 'Прохождение урока',
}, },
), ),
migrations.CreateModel(
name='UserLessonAnswer',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата сдачи')),
('progress_lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.ProgressLesson')),
('reviewer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Проверяющий')),
],
options={
'verbose_name': 'Блок ответов пользователя',
'verbose_name_plural': 'Блоки ответов пользователя',
},
),
migrations.CreateModel( migrations.CreateModel(
name='ResetPassword', name='ResetPassword',
fields=[ fields=[
@ -145,10 +121,9 @@ class Migration(migrations.Migration):
name='owner', name='owner',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Кому приглошение'), field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Кому приглошение'),
), ),
migrations.AddField( migrations.AlterUniqueTogether(
model_name='answeritem', name='progresslesson',
name='lesson_answer', unique_together=set([('progress', 'lesson_token')]),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.UserLessonAnswer'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='progress', name='progress',

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-15 19:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0002_init_group'),
]
operations = [
migrations.AlterField(
model_name='progresslesson',
name='date',
field=models.DateTimeField(auto_now_add=True, verbose_name='Дата зачтения задания'),
),
]

@ -28,35 +28,39 @@ class ProgressLesson(models.Model):
progress = models.ForeignKey(to=Progress) progress = models.ForeignKey(to=Progress)
lesson_token = models.UUIDField(verbose_name="Токен урока", editable=False) lesson_token = models.UUIDField(verbose_name="Токен урока", editable=False)
teacher = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь",) teacher = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь",)
date = models.DateTimeField(verbose_name='Дата зачтения задания', blank=True, null=True) date = models.DateTimeField(verbose_name='Дата зачтения задания', auto_now_add=True)
STATUSES = Choices('done', 'wait', 'fail')
status = models.CharField(choices=STATUSES, default=STATUSES.wait, max_length=20)
comment_tokens = ArrayField(models.UUIDField(verbose_name="Токен комента", editable=False), default=[])
def __str__(self): def __str__(self):
return self.lesson_token return self.progress.user.email
class Meta: class Meta:
verbose_name = 'Прохождение уроков' verbose_name = 'Прохождение уроков'
verbose_name_plural = 'Прохождение урока' verbose_name_plural = 'Прохождение урока'
unique_together = ('progress', 'lesson_token')
class UserLessonAnswer(models.Model): # class UserLessonAnswer(models.Model):
progress_lesson = models.ForeignKey(to=ProgressLesson) # progress_lesson = models.ForeignKey(to=ProgressLesson)
date = models.DateTimeField(verbose_name='Дата сдачи', auto_now_add=True) # date = models.DateTimeField(verbose_name='Дата сдачи', auto_now_add=True)
reviewer = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Проверяющий",) # reviewer = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Проверяющий",)
#
class Meta: # class Meta:
verbose_name = 'Блок ответов пользователя' # verbose_name = 'Блок ответов пользователя'
verbose_name_plural = 'Блоки ответов пользователя' # verbose_name_plural = 'Блоки ответов пользователя'
#
#
class AnswerItem(models.Model): # class AnswerItem(models.Model):
STATUSES = Choices('done', 'wait', 'fail') # STATUSES = Choices('done', 'wait', 'fail')
#
lesson_answer = models.ForeignKey(to=UserLessonAnswer) # lesson_answer = models.ForeignKey(to=UserLessonAnswer)
question = models.TextField(verbose_name='Вопрос') # TODO подумать над хранением токена вопроса # question = models.TextField(verbose_name='Вопрос') # TODO подумать над хранением токена вопроса
value = models.TextField(verbose_name='Ответ') # value = models.TextField(verbose_name='Ответ')
comment = models.TextField(verbose_name='Комент', blank=True, null=True) # comment = models.TextField(verbose_name='Комент', blank=True, null=True)
status = models.CharField(choices=STATUSES, default=STATUSES.wait, max_length=20) # status = models.CharField(choices=STATUSES, default=STATUSES.wait, max_length=20)
#
class Meta: # class Meta:
verbose_name = 'Ответ пользователя' # verbose_name = 'Ответ пользователя'
verbose_name_plural = 'Ответы пользователя' # verbose_name_plural = 'Ответы пользователя'

@ -93,7 +93,7 @@ class CustomUserManager(BaseUserManager):
class User(AbstractBaseUser, PermissionsMixin): class User(AbstractBaseUser, PermissionsMixin):
out_key = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False) out_key = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False)
email = models.EmailField(_('email address'), unique=True) email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=63, blank=True, default='Гость') first_name = models.CharField(_('first name'), max_length=63, blank=True, default='Гость')
last_name = models.CharField(_('last name'), max_length=63, blank=True) last_name = models.CharField(_('last name'), max_length=63, blank=True)

@ -7,7 +7,7 @@ from access.models import Progress
from achievements.serialers import DiplomaSerializer, AchievementsSerializer from achievements.serialers import DiplomaSerializer, AchievementsSerializer
class ProgressVertexSerializer(serializers.ModelSerializer): class ProgressLessonSerializer(serializers.ModelSerializer):
teacher = serializers.SerializerMethodField() teacher = serializers.SerializerMethodField()
class Meta: class Meta:
@ -20,15 +20,15 @@ class ProgressVertexSerializer(serializers.ModelSerializer):
class ProgressSerializer(serializers.ModelSerializer): class ProgressSerializer(serializers.ModelSerializer):
vertexes = serializers.SerializerMethodField() lessons = serializers.SerializerMethodField()
class Meta: class Meta:
model = Progress model = Progress
fields = ('route', 'vertexes', 'course') fields = ('lessons', 'course_token')
@staticmethod @staticmethod
def get_vertexes(self): def get_lessons(self):
return [ProgressVertexSerializer(i).data for i in self.progressvertex_set.all()] return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class AccountSerializer(serializers.ModelSerializer): class AccountSerializer(serializers.ModelSerializer):
@ -61,7 +61,7 @@ class UserSelfSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_achievements(self): def get_achievements(self):
return [AchievementsSerializer(i).data for i in self.achievements_set.all()] return [AchievementsSerializer(i).data for i in self.achievement_set.all()]
@staticmethod @staticmethod
def get_account(self): def get_account(self):

@ -15,7 +15,7 @@ from rest_framework.views import APIView
from access.models.other import Invite, ResetPassword from access.models.other import Invite, ResetPassword
from access.models.progress import ProgressLesson from access.models.progress import ProgressLesson
from access.models import Progress from access.models import Progress
from access.serializers import UserSelfSerializer, UserSearchSerializer, ProgressVertexSerializer from access.serializers import UserSelfSerializer, UserSearchSerializer, ProgressLessonSerializer
class TeacherListView(APIView): class TeacherListView(APIView):
@ -260,7 +260,7 @@ class UpdateProgress(APIView):
) )
pv.status = 2 pv.status = 2
pv.save() pv.save()
return Response(ProgressVertexSerializer(pv).data, status=200) return Response(ProgressLessonSerializer(pv).data, status=200)
except Progress.DoesNotExist: except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404) return Response('Не найден прогресс по заданным параметрам', status=404)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 15:44 # Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
@ -12,8 +12,8 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('courses', '0001_initial'), ('courses', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]
operations = [ operations = [

@ -1,10 +1,6 @@
from django.contrib import admin from django.contrib import admin
from courses.models import Course, Topic, Lesson, Requirement, Question, RightAnswer from courses.models import Course, Topic, Lesson
admin.site.register(Topic) admin.site.register(Topic)
admin.site.register(Lesson) admin.site.register(Lesson)
admin.site.register(Course) admin.site.register(Course)
admin.site.register(Requirement)
admin.site.register(Question)
admin.site.register(RightAnswer)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 15:44 # Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals from __future__ import unicode_literals
import django.contrib.postgres.fields import django.contrib.postgres.fields
@ -19,14 +19,15 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Course', name='Course',
fields=[ fields=[
('token', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='Токен')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Токен')),
('slug', models.SlugField(editable=False, max_length=127, unique=True)), ('slug', models.SlugField(editable=False, max_length=127, unique=True)),
('title', models.CharField(max_length=255, unique=True, verbose_name='Заголовок')), ('title', models.CharField(max_length=255, unique=True, verbose_name='Заголовок')),
('description', models.TextField(blank=True, verbose_name='Описание')), ('description', models.TextField(blank=True, verbose_name='Описание')),
('level', models.CharField(choices=[('B', 'Базовый'), ('A', 'Продвинутый'), ('E', 'Экспертный'), ('B+A', 'Базовый + Продвинутый')], default='B', max_length=3, verbose_name='Уровень')), ('level', models.CharField(choices=[('B', 'Базовый'), ('A', 'Продвинутый'), ('E', 'Экспертный'), ('B+A', 'Базовый + Продвинутый')], default='B', max_length=3, verbose_name='Уровень')),
('direction', models.SmallIntegerField(choices=[(3, 'Бизнес'), (2, 'Веб-дизайн'), (1, 'Разработка'), (4, 'Рисование'), (5, 'Музыка')], verbose_name='Направление')), ('direction', models.SmallIntegerField(choices=[(3, 'Бизнес'), (2, 'Веб-дизайн'), (1, 'Разработка'), (4, 'Рисование'), (5, 'Музыка')], verbose_name='Направление')),
('public', models.BooleanField(default=False, verbose_name='Опубликовать')), ('public', models.BooleanField(default=False, verbose_name='Опубликовать')),
('teacher_tokens', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, primary_key=True, verbose_name='Токен препода'), default=[], size=None, verbose_name='Преподователи курса')), ('teacher_tokens', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, verbose_name='Токен препода'), default=[], size=None, verbose_name='Преподователи курса')),
('image', models.URLField(blank=True, max_length=255, verbose_name='Изображение')), ('image', models.URLField(blank=True, max_length=255, verbose_name='Изображение')),
('big_image', models.URLField(blank=True, max_length=255, verbose_name='Большое изображение')), ('big_image', models.URLField(blank=True, max_length=255, verbose_name='Большое изображение')),
('big_mobile_image', models.URLField(blank=True, help_text='Большая картинка для мобильной версии', max_length=255, verbose_name='Под мобилку')), ('big_mobile_image', models.URLField(blank=True, help_text='Большая картинка для мобильной версии', max_length=255, verbose_name='Под мобилку')),
@ -40,13 +41,17 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Lesson', name='Lesson',
fields=[ fields=[
('token', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='Токен')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Токен')),
('key', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Внутрений ключ используется для расшивровки')),
('title', models.CharField(max_length=255, verbose_name='Название')), ('title', models.CharField(max_length=255, verbose_name='Название')),
('description', models.TextField(blank=True, null=True, verbose_name='Описание')), ('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
('video', models.TextField(blank=True, null=True, verbose_name='Код видео')), ('video', models.TextField(blank=True, null=True, verbose_name='Код видео')),
('material_tokens', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=15, verbose_name='Материалы урока'), default=[], size=None)), ('material_tokens', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, verbose_name='Токен материала'), default=[], size=None, verbose_name='Материалы курса')),
('free', models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться')), ('free', models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться')),
('sort', models.SmallIntegerField(unique=True)), ('sort', models.SmallIntegerField(unique=True)),
('is_hm', models.BooleanField(default=False)),
('old_id', models.IntegerField(blank=True, null=True)),
], ],
options={ options={
'verbose_name': 'Урок', 'verbose_name': 'Урок',
@ -54,61 +59,6 @@ class Migration(migrations.Migration):
'ordering': ('sort',), 'ordering': ('sort',),
}, },
), ),
migrations.CreateModel(
name='LessonRequirement',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort', models.SmallIntegerField(default=1)),
('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Lesson')),
],
options={
'verbose_name': 'Порядок требований',
'verbose_name_plural': 'Порядок требований',
'ordering': ('sort',),
},
),
migrations.CreateModel(
name='Question',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(verbose_name='Вопрос')),
('type', models.CharField(choices=[('text', 'text'), ('char', 'char'), ('boolean', 'boolean'), ('file', 'file')], default='char', max_length=20)),
('multiple', models.BooleanField(default=False)),
('null', models.BooleanField(default=False)),
('balls', models.SmallIntegerField(default=100, verbose_name='Вознаграждение')),
],
options={
'verbose_name': 'Вопрос',
'verbose_name_plural': 'Вопросы',
},
),
migrations.CreateModel(
name='Requirement',
fields=[
('token', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='Токен')),
('name', models.CharField(max_length=31, unique=True, verbose_name='Название')),
('checker', models.CharField(choices=[('student', 'student'), ('teacher', 'teacher'), ('auto', 'auto')], default='teacher', max_length=15, verbose_name='Проверяющий')),
('min_balls', models.SmallIntegerField(default=50, verbose_name='Проходной бал')),
],
options={
'verbose_name': 'Требования',
'verbose_name_plural': 'Требования',
},
),
migrations.CreateModel(
name='RightAnswer',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(verbose_name='Верный ответ')),
('success_comment', models.TextField(blank=True, null=True, verbose_name='Комментарий при верном ответе')),
('error_comment', models.TextField(blank=True, null=True, verbose_name='Комментарий при ошибке')),
('question', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='courses.Question')),
],
options={
'verbose_name': 'Верный ответ',
'verbose_name_plural': 'Верные ответы',
},
),
migrations.CreateModel( migrations.CreateModel(
name='Topic', name='Topic',
fields=[ fields=[
@ -124,23 +74,9 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Темы', 'verbose_name_plural': 'Темы',
}, },
), ),
migrations.AddField(
model_name='question',
name='requirement',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Requirement'),
),
migrations.AddField(
model_name='lessonrequirement',
name='requirement',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Requirement'),
),
migrations.AddField( migrations.AddField(
model_name='lesson', model_name='lesson',
name='topic', name='topic',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic', verbose_name='Тема'), field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic', verbose_name='Тема'),
), ),
migrations.AlterUniqueTogether(
name='lessonrequirement',
unique_together=set([('lesson', 'requirement', 'sort')]),
),
] ]

@ -1,42 +0,0 @@
from __future__ import unicode_literals
from courses.models import Requirement, Question
from django.db import migrations
def init_demands(*_args, **_kwargs):
requirement, created = Requirement.objects.get_or_create(
min_balls=51,
name="Стандартные требования",
)
Question.objects.get_or_create(
requirement=requirement,
text='Комментарий',
type='text',
null=True,
balls=50,
)
Question.objects.get_or_create(
requirement=requirement,
text='Приложенные файлы',
type='files',
null=True,
multiple=True,
balls=50,
)
class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0001_initial'),
]
operations = [
migrations.RunPython(init_demands)
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 16:02
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('courses', '0002_init_demands'),
]
operations = [
migrations.AddField(
model_name='lesson',
name='old_id',
field=models.IntegerField(blank=True, null=True),
),
]

@ -64,7 +64,7 @@ class CourseManager(models.Manager):
class Course(models.Model): class Course(models.Model):
token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False) token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False)
slug = models.SlugField(unique=True, editable=False, max_length=127) slug = models.SlugField(unique=True, editable=False, max_length=127)
title = models.CharField(verbose_name="Заголовок", max_length=255, unique=True) title = models.CharField(verbose_name="Заголовок", max_length=255, unique=True)
description = models.TextField(verbose_name='Описание', blank=True) description = models.TextField(verbose_name='Описание', blank=True)
@ -72,7 +72,7 @@ class Course(models.Model):
direction = models.SmallIntegerField(choices=COURSE_DIRECTION, verbose_name='Направление') direction = models.SmallIntegerField(choices=COURSE_DIRECTION, verbose_name='Направление')
public = models.BooleanField(verbose_name='Опубликовать', default=False) public = models.BooleanField(verbose_name='Опубликовать', default=False)
teacher_tokens = ArrayField( teacher_tokens = ArrayField(
models.UUIDField(verbose_name="Токен препода", primary_key=True, editable=False), models.UUIDField(verbose_name="Токен препода", editable=False),
default=[], default=[],
verbose_name='Преподователи курса', verbose_name='Преподователи курса',
) )
@ -88,7 +88,7 @@ class Course(models.Model):
def get_statistic(self): def get_statistic(self):
return { return {
'topic_count': self.topic_set.all().count(), 'topic_count': self.topic_set.all().count(),
'task_count': sum([topic.vertex_set.count() for topic in self.topic_set.all()]) 'task_count': sum([topic.lesson_set.count() for topic in self.topic_set.all()])
} }
objects = CourseManager() objects = CourseManager()
@ -111,15 +111,22 @@ class Topic(models.Model):
class Lesson(models.Model): class Lesson(models.Model):
token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False) token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False)
key = models.UUIDField(
verbose_name="Внутрений ключ используется для расшивровки", default=uuid.uuid4, editable=False)
topic = models.ForeignKey(to=Topic, verbose_name='Тема') topic = models.ForeignKey(to=Topic, verbose_name='Тема')
title = models.CharField(verbose_name='Название', max_length=255) title = models.CharField(verbose_name='Название', max_length=255)
description = models.TextField(verbose_name='Описание', blank=True, null=True) description = models.TextField(verbose_name='Описание', blank=True, null=True)
video = models.TextField(verbose_name='Код видео', blank=True, null=True) video = models.TextField(verbose_name='Код видео', blank=True, null=True)
material_tokens = ArrayField(models.CharField(max_length=15, blank=True, verbose_name='Материалы урока'), default=[]) material_tokens = ArrayField(
models.UUIDField(verbose_name="Токен материала", editable=False),
default=[],
verbose_name='Материалы курса',
)
free = models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться') free = models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться')
sort = models.SmallIntegerField(unique=True) sort = models.SmallIntegerField(unique=True)
is_hm = models.BooleanField(default=False) #TODO костыли
old_id = models.IntegerField(null=True, blank=True) old_id = models.IntegerField(null=True, blank=True)
def __str__(self): def __str__(self):
@ -131,56 +138,56 @@ class Lesson(models.Model):
ordering = ('sort', ) ordering = ('sort', )
class LessonRequirement(models.Model): # class LessonRequirement(models.Model):
lesson = models.ForeignKey(to=Lesson) # lesson = models.ForeignKey(to=Lesson)
requirement = models.ForeignKey(to='courses.Requirement') # requirement = models.ForeignKey(to='courses.Requirement')
sort = models.SmallIntegerField(default=1) # sort = models.SmallIntegerField(default=1)
#
class Meta: # class Meta:
verbose_name = "Порядок требований" # verbose_name = "Порядок требований"
verbose_name_plural = "Порядок требований" # verbose_name_plural = "Порядок требований"
ordering = ('sort', ) # ordering = ('sort', )
unique_together = ('lesson', 'requirement', 'sort') # unique_together = ('lesson', 'requirement', 'sort')
#
#
class Requirement(models.Model): # class Requirement(models.Model):
CHECK_TYPES = Choices('student', 'teacher', 'auto',) # CHECK_TYPES = Choices('student', 'teacher', 'auto',)
#
token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False) # token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False)
name = models.CharField(max_length=31, verbose_name="Название", unique=True) # name = models.CharField(max_length=31, verbose_name="Название", unique=True)
checker = models.CharField( # checker = models.CharField(
choices=CHECK_TYPES, default=CHECK_TYPES.teacher, max_length=15, verbose_name="Проверяющий",) # choices=CHECK_TYPES, default=CHECK_TYPES.teacher, max_length=15, verbose_name="Проверяющий",)
min_balls = models.SmallIntegerField(default=50, verbose_name='Проходной бал') # min_balls = models.SmallIntegerField(default=50, verbose_name='Проходной бал')
#
def __str__(self): # def __str__(self):
return self.name # return self.name
#
class Meta: # class Meta:
verbose_name = "Требования" # verbose_name = "Требования"
verbose_name_plural = "Требования" # verbose_name_plural = "Требования"
#
#
class Question(models.Model): # class Question(models.Model):
FIELD_TYPES = Choices('text', 'char', 'boolean', 'file') # FIELD_TYPES = Choices('text', 'char', 'boolean', 'file')
#
requirement = models.ForeignKey(to=Requirement) # requirement = models.ForeignKey(to=Requirement)
text = models.TextField(verbose_name="Вопрос") # text = models.TextField(verbose_name="Вопрос")
type = models.CharField(choices=FIELD_TYPES, default=FIELD_TYPES.char, max_length=20) # type = models.CharField(choices=FIELD_TYPES, default=FIELD_TYPES.char, max_length=20)
multiple = models.BooleanField(default=False) # multiple = models.BooleanField(default=False)
null = models.BooleanField(default=False) # null = models.BooleanField(default=False)
balls = models.SmallIntegerField(default=100, verbose_name='Вознаграждение') # balls = models.SmallIntegerField(default=100, verbose_name='Вознаграждение')
#
class Meta: # class Meta:
verbose_name = "Вопрос" # verbose_name = "Вопрос"
verbose_name_plural = "Вопросы" # verbose_name_plural = "Вопросы"
#
#
class RightAnswer(models.Model): # class RightAnswer(models.Model):
question = models.OneToOneField(to=Question) # question = models.OneToOneField(to=Question)
text = models.TextField(verbose_name="Верный ответ") # text = models.TextField(verbose_name="Верный ответ")
success_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при верном ответе") # success_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при верном ответе")
error_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при ошибке") # error_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при ошибке")
#
class Meta: # class Meta:
verbose_name = "Верный ответ" # verbose_name = "Верный ответ"
verbose_name_plural = "Верные ответы" # verbose_name_plural = "Верные ответы"

@ -12,27 +12,22 @@ class TopicSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_children(self): def get_children(self):
return [MiniVertexSerializer(i).data for i in self.vertex_set.all()] return [MiniLessonSerializer(i).data for i in self.lesson_set.all()]
class MiniVertexSerializer(serializers.ModelSerializer): class MiniLessonSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Lesson model = Lesson
fields = ('title', 'free', 'token') fields = ('title', 'free', 'token')
class VertexSerializer(MiniVertexSerializer): class LessonSerializer(MiniLessonSerializer):
valid_type = serializers.SerializerMethodField()
class Meta: class Meta:
model = Lesson model = Lesson
exclude = ('id', 'topic', 'free') exclude = ('id', 'topic', 'free')
@staticmethod
def get_valid_type(self):
return self.get_valid_type_display()
class CourseInitSerializer(serializers.ModelSerializer): class CourseInitSerializer(serializers.ModelSerializer):
@ -46,7 +41,7 @@ class CourseTreeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Course model = Course
fields = ('tree', 'route', 'slug') fields = ('tree', 'slug')
@staticmethod @staticmethod
def get_tree(self): def get_tree(self):
@ -60,7 +55,7 @@ class CourseDetailSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Course model = Course
exclude = ('route', 'id') exclude = ('id', )
@staticmethod @staticmethod
def get_level(self): def get_level(self):

@ -3,7 +3,7 @@ from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, VertexSerializer from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer
class TreeView(APIView): class TreeView(APIView):
@ -47,7 +47,7 @@ class VertexDetail(APIView):
# return Response("permission denied", status=403) # return Response("permission denied", status=403)
# TODO: Доделать систему прав на курс # TODO: Доделать систему прав на курс
res = VertexSerializer(vertex).data res = LessonSerializer(vertex).data
# progress = vertex.course.progress_set.filter(user=request.user) # progress = vertex.course.progress_set.filter(user=request.user)
# try: # try:
# if progress.exists(): # if progress.exists():

@ -6,38 +6,53 @@ import django
import os import os
import sys import sys
from django.contrib.auth import get_user_model
from django.db import IntegrityError from django.db import IntegrityError
sys.path.append("../") sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup() django.setup()
from storage.models import File from storage.models import Comment, File
from access.models.progress import UserLessonAnswer, AnswerItem, ProgressLesson from courses.models import Lesson
from access.models.progress import ProgressLesson
if __name__ == '__main__': if __name__ == '__main__':
csv.field_size_limit(500 * 1024 * 1024) csv.field_size_limit(500 * 1024 * 1024)
Comment.objects.all().delete()
with open('./management/comment.csv') as comment_csv: with open('./management/comment.csv') as comment_csv:
comment_reader = csv.DictReader(comment_csv) comment_reader = csv.DictReader(comment_csv)
for row in comment_reader: for row in comment_reader:
if row['type'] == 'task' or row['type'] == 'exam': if row['type'] == 'task' or row['type'] == 'exam':
l = Lesson.objects.get(old_id=row['parent_id'])
try: try:
c = Comment.objects.create( p = ProgressLesson.objects.get(
id=row['id'], lesson_token=l.token,
email=row['owner__email'], progress__user__email=row['student'],
)
files = [File.objects.get(id=file) for file in row['files'].split("[")[1].split("]")[0].split(',')
if not file == '']
comment = Comment.objects.create(
text=row['text'], text=row['text'],
key=''.join(random.choice(string.ascii_letters) for x in range(15)), email=row['owner__email'],
) )
except IntegrityError:
c = Comment.objects.get(id=row['id'])
for file_id in row['files'].split("[")[1].split("]")[0].split(", "): if row['status'] == 'Одобренно':
if file_id: p.status = ProgressLesson.STATUSES.done
c.files.add(File.objects.get(id=file_id)) p.date = row['date']
elif row['status'] == 'Отклонено':
p.status = ProgressLesson.STATUSES.fail
else:
p.status = ProgressLesson.STATUSES.wait
p.save()
c.date = row['date'] [comment.files.add(file) for file in files]
c.save() comment.date = row['date']
comment.save()
parent_id = int(row['parent_id']) p.comment_tokens.append(comment.token)
if row['type'] == 'task': except ProgressLesson.DoesNotExist:
parent_id += 50 pass

@ -10,7 +10,7 @@ django.setup()
from courses.api import InApiTeacher from courses.api import InApiTeacher
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from courses.models import Course, Lesson, Topic, Requirement, LessonRequirement from courses.models import Course, Lesson, Topic
from storage.models import File from storage.models import File
if __name__ == '__main__': if __name__ == '__main__':
@ -47,7 +47,7 @@ if __name__ == '__main__':
try: try:
m = row.pop('materials', None) m = row.pop('materials', None)
if m: if m:
materials = [File.objects.get(id=i).key for i in m.split("[")[1].split("]")[0].split(", ")] materials = [File.objects.get(id=i).token for i in m.split("[")[1].split("]")[0].split(", ")]
except ValueError: except ValueError:
pass pass
@ -76,10 +76,5 @@ if __name__ == '__main__':
title=title, title=title,
sort=l_sort, sort=l_sort,
old_id=pk, old_id=pk,
) is_hm=model_type == 'task',
)
if model_type == 'task':
LessonRequirement.objects.create(
lesson=small_vertex,
requirement=Requirement.objects.get(name="Стандартные требования"),
)

@ -19,4 +19,4 @@ if __name__ == '__main__':
for row in storage_reader: for row in storage_reader:
if row['original']: if row['original']:
key = ''.join(random.choice(string.ascii_letters) for _x in range(15)) key = ''.join(random.choice(string.ascii_letters) for _x in range(15))
File.objects.create(original=row['original'], id=row['id'], key=key) File.objects.create(original=row['original'], id=row['id'])

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 15:44 # Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 15:44 # Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime

@ -1,13 +1,9 @@
import random
import string
from storage.models import Comment, File from storage.models import Comment, File
def upload_file(original=None, name=None, base64=None) -> File: def upload_file(original=None, name=None, base64=None) -> File:
key = ''.join(random.choice(string.ascii_letters) for _x in range(15))
if original: if original:
new_file = File.objects.create(key=key, original=original) new_file = File.objects.create(original=original)
else: else:
new_file = File.objects.upload_as_base64(base64) new_file = File.objects.upload_as_base64(base64)
@ -27,11 +23,9 @@ def add_comment(text: str, email: str, files=None) -> Comment:
files = [] if files is None else files files = [] if files is None else files
key = ''.join(random.choice(string.ascii_letters) for _x in range(15))
comment = Comment.objects.create( comment = Comment.objects.create(
text=text, text=text,
email=email, email=email,
key=key,
) )
for file in files: for file in files:
@ -42,17 +36,17 @@ def add_comment(text: str, email: str, files=None) -> Comment:
def get_comment(key): def get_comment(key):
comment = Comment.objects.get(key=key) comment = Comment.objects.get(token=key)
return comment return comment
def update_comment(key, **kwargs): def update_comment(key, **kwargs):
comment = Comment.objects.get(key=key) comment = Comment.objects.get(token=key)
comment.__dict__.update(kwargs) comment.__dict__.update(kwargs)
comment.save() comment.save()
return comment return comment
def delete_comment(key): def delete_comment(key):
comment = Comment.objects.get(key=key).delete() comment = Comment.objects.get(token=key).delete()
return comment return comment

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-12 15:44 # Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
import uuid
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -19,7 +20,7 @@ class Migration(migrations.Migration):
('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')),
('email', models.CharField(max_length=63, verbose_name='email автора')), ('email', models.CharField(max_length=63, verbose_name='email автора')),
('text', models.TextField(default='', verbose_name='Текст комментария')), ('text', models.TextField(default='', verbose_name='Текст комментария')),
('key', models.SlugField(editable=False, unique=True, verbose_name='Получения комментария по ключу')), ('token', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Ключ')),
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата коментария')), ('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата коментария')),
], ],
options={ options={
@ -31,7 +32,7 @@ class Migration(migrations.Migration):
name='File', name='File',
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')),
('key', models.CharField(editable=False, max_length=15, unique=True, verbose_name='Внешний ключ')), ('token', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Ключ')),
('original', models.FileField(max_length=255, unique=True, upload_to='files', verbose_name='Файл')), ('original', models.FileField(max_length=255, unique=True, upload_to='files', verbose_name='Файл')),
('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Видимое имя файла')), ('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Видимое имя файла')),
], ],

@ -2,6 +2,7 @@
import base64 import base64
import random import random
import string import string
import uuid
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.db import models from django.db import models
@ -20,7 +21,7 @@ class FileManager(models.Manager):
class File(models.Model): class File(models.Model):
key = models.CharField(max_length=15, verbose_name="Внешний ключ", unique=True, editable=False) token = models.UUIDField(verbose_name="Ключ", default=uuid.uuid4, editable=False)
original = models.FileField(max_length=255, verbose_name='Файл', upload_to="files", unique=True) original = models.FileField(max_length=255, verbose_name='Файл', upload_to="files", unique=True)
name = models.CharField(max_length=255, null=True, blank=True, verbose_name='Видимое имя файла') name = models.CharField(max_length=255, null=True, blank=True, verbose_name='Видимое имя файла')
@ -38,11 +39,11 @@ class Comment(models.Model):
email = models.CharField(verbose_name="email автора", max_length=63) email = models.CharField(verbose_name="email автора", max_length=63)
text = models.TextField(default="", verbose_name="Текст комментария") text = models.TextField(default="", verbose_name="Текст комментария")
files = models.ManyToManyField(to=File, blank=True, verbose_name='Файлы') files = models.ManyToManyField(to=File, blank=True, verbose_name='Файлы')
key = models.SlugField(unique=True, verbose_name="Получения комментария по ключу", editable=False) token = models.UUIDField(verbose_name="Ключ", default=uuid.uuid4, editable=False)
date = models.DateTimeField(auto_now_add=True, verbose_name="Дата коментария") date = models.DateTimeField(auto_now_add=True, verbose_name="Дата коментария")
def __str__(self): def __str__(self):
return '%s' % self.key return '%s' % self.token
class Meta: class Meta:
verbose_name = 'Коммент' verbose_name = 'Коммент'

@ -17,12 +17,12 @@ class CommentTestCase(TestCase):
Comment.objects.all().delete() Comment.objects.all().delete()
def test_comment_get(self): def test_comment_get(self):
self.assertEqual(self.first_comment, get_comment(self.first_comment.key)) self.assertEqual(self.first_comment, get_comment(self.first_comment.token))
def test_comment_update(self): def test_comment_update(self):
new_text = "Новый текст для коммента" new_text = "Новый текст для коммента"
update_comment(key=self.first_comment.key, text=new_text) update_comment(key=self.first_comment.token, text=new_text)
self.assertEqual(get_comment(self.first_comment.key).text, new_text) self.assertEqual(get_comment(self.first_comment.token).text, new_text)
# def test_comment_create(self): # def test_comment_create(self):
# token = 'fskjfskj' # token = 'fskjfskj'
@ -37,9 +37,9 @@ class CommentTestCase(TestCase):
# self.assertEqual(comment2.files.all()[0].name, file_name) # self.assertEqual(comment2.files.all()[0].name, file_name)
def test_comment_delete(self): def test_comment_delete(self):
delete_comment(self.first_comment.key) delete_comment(self.first_comment.token)
try: try:
comment = get_comment(self.first_comment.id) comment = get_comment(self.first_comment.token)
except Comment.DoesNotExist: except Comment.DoesNotExist:
comment = None comment = None
@ -52,12 +52,12 @@ class FileTestCase(TestCase):
self.second_comment = add_comment(text="Привет, отличная работа", email="artem4000@gmail.com") self.second_comment = add_comment(text="Привет, отличная работа", email="artem4000@gmail.com")
def test_comment_get(self): def test_comment_get(self):
self.assertEqual(self.first_comment, get_comment(self.first_comment.key)) self.assertEqual(self.first_comment, get_comment(self.first_comment.token))
def test_comment_update(self): def test_comment_update(self):
new_text = "Новый текст для коммента" new_text = "Новый текст для коммента"
update_comment(key=self.first_comment.key, text=new_text) update_comment(key=self.first_comment.token, text=new_text)
self.assertEqual(get_comment(self.first_comment.key).text, new_text) self.assertEqual(get_comment(self.first_comment.token).text, new_text)
def test_comment_create(self): def test_comment_create(self):
token = 'fskjfskj' token = 'fskjfskj'
@ -71,9 +71,9 @@ class FileTestCase(TestCase):
self.assertEqual(comment2.files.all()[0].name, file_name) self.assertEqual(comment2.files.all()[0].name, file_name)
def test_comment_delete(self): def test_comment_delete(self):
delete_comment(self.first_comment.key) delete_comment(self.first_comment.token)
try: try:
comment = get_comment(self.first_comment.id) comment = get_comment(self.first_comment.token)
except Comment.DoesNotExist: except Comment.DoesNotExist:
comment = None comment = None

Loading…
Cancel
Save