Merge branch 'new_lms_dev(critical)' into 'new_lms_dev'

New lms dev(critical)

See merge request skillbox/go.skillbox.ru!74
feature/fix_generate_pass
Andrey 8 years ago
commit a731a471de
  1. 7
      access/admin.py
  2. 51
      access/migrations/0001_initial.py
  3. 21
      access/migrations/0002_auto_20171217_1808.py
  4. 26
      access/migrations/0002_init_group.py
  5. 20
      access/migrations/0003_auto_20180115_1953.py
  6. 20
      access/migrations/0003_pivotprogressvertex_date.py
  7. 21
      access/migrations/0004_auto_20171218_1438.py
  8. 20
      access/migrations/0005_auto_20171218_1516.py
  9. 20
      access/migrations/0006_auto_20171220_1228.py
  10. 21
      access/migrations/0007_progress_course.py
  11. 20
      access/migrations/0008_auto_20171220_1325.py
  12. 3
      access/models/__init__.py
  13. 30
      access/models/other.py
  14. 66
      access/models/progress.py
  15. 4
      access/models/user.py
  16. 24
      access/serializers.py
  17. 14
      access/views.py
  18. 6
      achievements/admin.py
  19. 42
      achievements/migrations/0001_initial.py
  20. 10
      achievements/models.py
  21. 4
      achievements/serialers.py
  22. 2
      api_v1/urls.py
  23. 1
      course_service/courses/__init__.py
  24. 7
      course_service/courses/admin.py
  25. 24
      course_service/courses/migrations/0002_course_route.py
  26. 20
      course_service/courses/migrations/0003_auto_20171217_1821.py
  27. 0
      course_service/courses/migrations/__init__.py
  28. 11
      course_service/courses/signals.py
  29. 0
      course_service/maps/__init__.py
  30. 8
      course_service/maps/admin.py
  31. 16
      course_service/maps/api.py
  32. 7
      course_service/maps/apps.py
  33. 2
      course_service/maps/exeptions.py
  34. 83
      course_service/maps/migrations/0001_initial.py
  35. 0
      course_service/maps/migrations/__init__.py
  36. 67
      course_service/maps/models.py
  37. 27
      course_service/maps/serializers.py
  38. 23
      course_service/maps/tests.py
  39. 3
      course_service/maps/views.py
  40. 1
      courses/__init__.py
  41. 6
      courses/admin.py
  42. 8
      courses/api.py
  43. 2
      courses/apps.py
  44. 53
      courses/migrations/0001_initial.py
  45. 0
      courses/migrations/__init__.py
  46. 106
      courses/models.py
  47. 27
      courses/serializers.py
  48. 4
      courses/tsets.py
  49. 2
      courses/urls.py
  50. 10
      courses/views.py
  51. 37885
      csv/access/account.csv
  52. 22540
      csv/access/progress.csv
  53. 2
      csv/access/users.csv
  54. 28
      csv/load_bills.py
  55. 43
      csv/load_comments.py
  56. 88
      csv/load_courses.py
  57. 13
      csv/load_diploma.py
  58. 61
      csv/load_perm.py
  59. 2
      csv/load_storage.py
  60. 7
      csv/load_users.py
  61. 10
      finance/migrations/0001_initial.py
  62. 20
      finance/migrations/0002_auto_20171225_1142.py
  63. 6
      finance/models.py
  64. 2
      library/migrations/0001_initial.py
  65. 3
      lms/settings.py
  66. 1
      requirements.txt
  67. 14
      storage/api.py
  68. 7
      storage/migrations/0001_initial.py
  69. 7
      storage/models.py
  70. 44
      storage/tests.py

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

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
# Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals
import access.models.user
@ -8,6 +8,7 @@ import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
import phonenumber_field.modelfields
import uuid
class Migration(migrations.Migration):
@ -26,7 +27,7 @@ class Migration(migrations.Migration):
('password', models.CharField(max_length=128, verbose_name='password')),
('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')),
('out_key', models.CharField(editable=False, max_length=15, unique=True, 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')),
('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')),
@ -53,7 +54,7 @@ class Migration(migrations.Migration):
('city', models.CharField(blank=True, max_length=63, null=True)),
('gender', models.SmallIntegerField(choices=[(0, 'undefined'), (1, 'male'), (2, 'female')], default=0)),
('photo', models.ImageField(default='/static/default/access/default.png', upload_to='user/photo/')),
('phone', phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128)),
('phone', phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, null=True)),
('owner', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
@ -73,20 +74,12 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Приглошения в систему',
},
),
migrations.CreateModel(
name='PivotProgressVertex',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('vertex', models.CharField(blank=True, max_length=15, unique=True, verbose_name='Ссылки на узлы')),
('status', models.SmallIntegerField(choices=[(2, 'Выполненно'), (1, 'Ожидание'), (0, 'Не выполненно')], default=0)),
('comment', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=15, unique=True, verbose_name='Ссылки на комменты'), size=None)),
],
),
migrations.CreateModel(
name='Progress',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('route', models.CharField(max_length=15, verbose_name='Токен прохождения')),
('hidden_lessons', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, unique=True, verbose_name='Токен урока'), default=[], size=None, verbose_name='Список скрытых уроков')),
('course_token', models.UUIDField(editable=False, verbose_name='Токен курса')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teacher_progress', to=settings.AUTH_USER_MODEL, verbose_name='Преподователь по умолчанию')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Студент')),
],
@ -95,6 +88,22 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Прогресс пользователя',
},
),
migrations.CreateModel(
name='ProgressLesson',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lesson_token', models.UUIDField(editable=False, 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')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Преподователь')),
],
options={
'verbose_name': 'Прохождение уроков',
'verbose_name_plural': 'Прохождение урока',
},
),
migrations.CreateModel(
name='ResetPassword',
fields=[
@ -107,23 +116,17 @@ class Migration(migrations.Migration):
},
bases=('access.invite',),
),
migrations.AddField(
model_name='pivotprogressvertex',
name='progress',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.Progress'),
),
migrations.AddField(
model_name='pivotprogressvertex',
name='teacher',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Преподователь'),
),
migrations.AddField(
model_name='invite',
name='owner',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Кому приглошение'),
),
migrations.AlterUniqueTogether(
name='progresslesson',
unique_together=set([('progress', 'lesson_token')]),
),
migrations.AlterUniqueTogether(
name='progress',
unique_together=set([('user', 'route')]),
unique_together=set([('user', 'course_token')]),
),
]

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:08
from __future__ import unicode_literals
from django.db import migrations
import phonenumber_field.modelfields
class Migration(migrations.Migration):
dependencies = [
('access', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='account',
name='phone',
field=phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, null=True),
),
]

@ -1,14 +1,11 @@
import os, sys, django
from __future__ import unicode_literals
sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup()
from django.contrib.auth.models import Group
# TODO переместить в миграции
from django.db import migrations
from django.contrib.auth.models import Group
if __name__ == '__main__':
def init_group(*_args, **_kwargs):
Group.objects.get_or_create(name='admin')
Group.objects.get_or_create(name='students')
Group.objects.get_or_create(name='teachers')
@ -18,4 +15,17 @@ if __name__ == '__main__':
Group.objects.get_or_create(name='partners')
Group.objects.get_or_create(name='supports')
Group.objects.get_or_create(name='finance')
Group.objects.get_or_create(name='project_managers')
Group.objects.get_or_create(name='project_managers')
class Migration(migrations.Migration):
initial = True
dependencies = [
('access', '0001_initial'),
]
operations = [
migrations.RunPython(init_group)
]

@ -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='Дата зачтения задания'),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-18 14:37
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0002_auto_20171217_1808'),
]
operations = [
migrations.AddField(
model_name='pivotprogressvertex',
name='date',
field=models.DateTimeField(blank=True, null=True, verbose_name='Дата зачтения задания'),
),
]

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-18 14:38
from __future__ import unicode_literals
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0003_pivotprogressvertex_date'),
]
operations = [
migrations.AlterField(
model_name='pivotprogressvertex',
name='comment',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=15, unique=True, verbose_name='Ссылки на комменты'), default=[], size=None),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-18 15:16
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0004_auto_20171218_1438'),
]
operations = [
migrations.AlterField(
model_name='pivotprogressvertex',
name='vertex',
field=models.CharField(blank=True, max_length=15, verbose_name='Ссылки на узлы'),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-20 12:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0005_auto_20171218_1516'),
]
operations = [
migrations.AlterField(
model_name='progress',
name='route',
field=models.CharField(blank=True, max_length=15, null=True, verbose_name='Токен прохождения'),
),
]

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-20 13:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0006_auto_20171220_1228'),
]
operations = [
migrations.AddField(
model_name='progress',
name='course',
field=models.CharField(default='', max_length=15, verbose_name='Токен курса'),
preserve_default=False,
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-20 13:25
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('access', '0007_progress_course'),
]
operations = [
migrations.AlterField(
model_name='progress',
name='course',
field=models.CharField(max_length=127, verbose_name='Слаг курса'),
),
]

@ -1,6 +1,7 @@
# encoding=utf-8
from .other import Account, Progress, Invite
from .other import Account, Invite
from access.models.progress import Progress
from .user import User

@ -1,5 +1,4 @@
from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
@ -43,32 +42,3 @@ class Account(models.Model):
verbose_name_plural = 'Дополнительная информация о пользователе'
class Progress(models.Model):
teacher = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь по умолчанию",
related_name='teacher_progress')
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='Студент')
route = models.CharField(max_length=15, verbose_name='Токен прохождения', blank=True, null=True)
course = models.CharField(max_length=127, verbose_name='Слаг курса')
def __str__(self):
return '%s' % (self.user.email,)
class Meta:
verbose_name = 'Прогресс пользователя'
verbose_name_plural = 'Прогресс пользователя'
unique_together = (("user", "route"),)
class PivotProgressVertex(models.Model):
# TODO переименовать в ProgressVertex
VERTEX_STATUS = (
(2, 'Выполненно'),
(1, 'Ожидание'),
(0, 'Не выполненно'),
) # TODO перейти на Choices из django-model-utils и сделать ключи строками done/wait/fail
progress = models.ForeignKey(to=Progress)
vertex = models.CharField(max_length=15, blank=True, verbose_name='Ссылки на узлы')
status = models.SmallIntegerField(choices=VERTEX_STATUS, default=0)
teacher = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь",)
comment = ArrayField(models.CharField(max_length=15, verbose_name='Ссылки на комменты', unique=True), default=[])
date = models.DateTimeField(verbose_name='Дата зачтения задания', blank=True, null=True)

@ -0,0 +1,66 @@
from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.db import models
from model_utils import Choices
class Progress(models.Model):
hidden_lessons = ArrayField(
models.UUIDField(verbose_name="Токен урока", unique=True, editable=False),
default=[],
verbose_name='Список скрытых уроков',
)
teacher = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь по умолчанию",
related_name='teacher_progress')
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='Студент')
course_token = models.UUIDField(verbose_name="Токен курса", editable=False)
def __str__(self):
return '%s' % (self.user.email,)
class Meta:
verbose_name = 'Прогресс пользователя'
verbose_name_plural = 'Прогресс пользователя'
unique_together = (("user", "course_token"),)
class ProgressLesson(models.Model):
progress = models.ForeignKey(to=Progress)
lesson_token = models.UUIDField(verbose_name="Токен урока", editable=False)
teacher = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь",)
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):
return self.progress.user.email
class Meta:
verbose_name = 'Прохождение уроков'
verbose_name_plural = 'Прохождение урока'
unique_together = ('progress', 'lesson_token')
# class UserLessonAnswer(models.Model):
# progress_lesson = models.ForeignKey(to=ProgressLesson)
# date = models.DateTimeField(verbose_name='Дата сдачи', auto_now_add=True)
# reviewer = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Проверяющий",)
#
# class Meta:
# verbose_name = 'Блок ответов пользователя'
# verbose_name_plural = 'Блоки ответов пользователя'
#
#
# class AnswerItem(models.Model):
# STATUSES = Choices('done', 'wait', 'fail')
#
# lesson_answer = models.ForeignKey(to=UserLessonAnswer)
# question = models.TextField(verbose_name='Вопрос') # TODO подумать над хранением токена вопроса
# value = models.TextField(verbose_name='Ответ')
# comment = models.TextField(verbose_name='Комент', blank=True, null=True)
# status = models.CharField(choices=STATUSES, default=STATUSES.wait, max_length=20)
#
# class Meta:
# verbose_name = 'Ответ пользователя'
# verbose_name_plural = 'Ответы пользователя'

@ -1,5 +1,6 @@
import random
import string
import uuid
from django.contrib.auth.base_user import BaseUserManager, AbstractBaseUser
from django.contrib.auth.models import Group, PermissionsMixin
@ -44,7 +45,6 @@ class CustomUserManager(BaseUserManager):
email = self.normalize_email(email)
user = self.model(email=email, is_staff=is_staff, is_active=is_active, first_name=first_name,
out_key=''.join(random.choice(string.ascii_letters) for x in range(15)),
is_superuser=is_superuser, date_joined=date_joined, last_login=last_login, **extra_fields)
if not password:
@ -93,7 +93,7 @@ class CustomUserManager(BaseUserManager):
class User(AbstractBaseUser, PermissionsMixin):
out_key = models.CharField(max_length=15, unique=True, verbose_name="Ключ для внешних сервисов", editable=False)
out_key = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False)
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=63, blank=True, default='Гость')
last_name = models.CharField(_('last name'), max_length=63, blank=True)

@ -1,38 +1,34 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers
from access.models.other import Account, Progress, PivotProgressVertex
from access.models.other import Account
from access.models.progress import ProgressLesson
from access.models import Progress
from achievements.serialers import DiplomaSerializer, AchievementsSerializer
class PivotProgressSerializer(serializers.ModelSerializer):
# TODO переименовать в ProgressVertexSerializer
status = serializers.SerializerMethodField()
class ProgressLessonSerializer(serializers.ModelSerializer):
teacher = serializers.SerializerMethodField()
class Meta:
model = PivotProgressVertex
model = ProgressLesson
exclude = ('id', 'progress')
@staticmethod
def get_status(self):
return self.get_status_display()
@staticmethod
def get_teacher(self):
return self.teacher.get_full_name()
class ProgressSerializer(serializers.ModelSerializer):
vertexes = serializers.SerializerMethodField()
lessons = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('route', 'vertexes', 'course')
fields = ('lessons', 'course_token')
@staticmethod
def get_vertexes(self):
return [PivotProgressSerializer(i).data for i in self.pivotprogressvertex_set.all()]
def get_lessons(self):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class AccountSerializer(serializers.ModelSerializer):
@ -65,7 +61,7 @@ class UserSelfSerializer(serializers.ModelSerializer):
@staticmethod
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
def get_account(self):

@ -12,8 +12,10 @@ from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from access.models.other import Invite, Progress, ResetPassword, PivotProgressVertex
from access.serializers import UserSelfSerializer, UserSearchSerializer, PivotProgressSerializer
from access.models.other import Invite, ResetPassword
from access.models.progress import ProgressLesson
from access.models import Progress
from access.serializers import UserSelfSerializer, UserSearchSerializer, ProgressLessonSerializer
class TeacherListView(APIView):
@ -244,13 +246,13 @@ class UpdateProgress(APIView):
try:
p = Progress.objects.get(user=request.user, course=course)
try:
pv = PivotProgressVertex.objects.get(
pv = ProgressLesson.objects.get(
progress=p,
vertex=token,
)
except PivotProgressVertex.DoesNotExist:
pv = PivotProgressVertex.objects.create(
except ProgressLesson.DoesNotExist:
pv = ProgressLesson.objects.create(
date=datetime.datetime.now(),
teacher=p.teacher,
progress=p,
@ -258,7 +260,7 @@ class UpdateProgress(APIView):
)
pv.status = 2
pv.save()
return Response(PivotProgressSerializer(pv).data, status=200)
return Response(ProgressLessonSerializer(pv).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)

@ -1,9 +1,9 @@
from django.contrib import admin
from achievements.models import Skills, Achievements, SkillJ, DiplomaGen, Diploma
from achievements.models import Skill, Achievement, SkillJ, DiplomaGen, Diploma
admin.site.register(Skills)
admin.site.register(Achievements)
admin.site.register(Skill)
admin.site.register(Achievement)
admin.site.register(SkillJ)
admin.site.register(Diploma)
admin.site.register(DiplomaGen)

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
# Generated by Django 1.11.6 on 2018-01-15 17:54
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):
@ -10,15 +12,18 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Achievements',
name='Achievement',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('img', models.ImageField(upload_to='achives', verbose_name='Отображение достижения')),
('text', models.CharField(max_length=255, verbose_name='Текст достижения')),
('users', models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Достижение',
@ -41,6 +46,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('template', models.URLField(verbose_name='Путь до шаблона')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course')),
],
options={
'verbose_name': 'Генератор дипломов',
@ -48,27 +54,39 @@ class Migration(migrations.Migration):
},
),
migrations.CreateModel(
name='SkillJ',
name='Skill',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='Наименование')),
('color', models.CharField(max_length=255, verbose_name='Цвет')),
('icon', models.ImageField(help_text='65x65', upload_to='skills', verbose_name='Картинка')),
('description', models.TextField(blank=True, verbose_name='Описание')),
],
options={
'verbose_name': 'Размер навыка',
'verbose_name_plural': 'Размеры навыков',
'verbose_name': 'Навык',
'verbose_name_plural': 'Навыки',
},
),
migrations.CreateModel(
name='Skills',
name='SkillJ',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='Наименование')),
('color', models.CharField(max_length=255, verbose_name='Цвет')),
('icon', models.ImageField(help_text='65x65', upload_to='skills', verbose_name='Картинка')),
('description', models.TextField(blank=True, verbose_name='Описание')),
('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Lesson', verbose_name='Урок')),
('skill', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='achievements.Skill', verbose_name='Навык')),
],
options={
'verbose_name': 'Навык',
'verbose_name_plural': 'Навыки',
'verbose_name': 'Размер навыка',
'verbose_name_plural': 'Размеры навыков',
},
),
migrations.AddField(
model_name='diploma',
name='template',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='achievements.DiplomaGen', verbose_name='Использовать шаблон'),
),
migrations.AddField(
model_name='diploma',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

@ -1,10 +1,10 @@
from django.conf import settings
from django.db import models
from course_service.courses.models import Course, Vertex
from courses.models import Course, Lesson
class Achievements(models.Model):
class Achievement(models.Model):
img = models.ImageField(verbose_name='Отображение достижения', upload_to='achives')
text = models.CharField(max_length=255, verbose_name="Текст достижения")
users = models.ManyToManyField(to=settings.AUTH_USER_MODEL)
@ -14,7 +14,7 @@ class Achievements(models.Model):
verbose_name_plural = 'Достижения'
class Skills(models.Model):
class Skill(models.Model):
title = models.CharField(verbose_name='Наименование', max_length=255)
color = models.CharField(verbose_name='Цвет', max_length=255)
icon = models.ImageField(verbose_name='Картинка', upload_to='skills', help_text='65x65')
@ -28,8 +28,8 @@ class Skills(models.Model):
class SkillJ(models.Model):
skill = models.ForeignKey(to=Skills, verbose_name='Навык')
lesson = models.ForeignKey(to=Vertex, verbose_name='Урок')
skill = models.ForeignKey(to=Skill, verbose_name='Навык')
lesson = models.ForeignKey(to=Lesson, verbose_name='Урок')
def __str__(self): return '%s' % self.skill

@ -1,5 +1,5 @@
from rest_framework import serializers
from achievements.models import Diploma, Achievements
from achievements.models import Diploma, Achievement
class DiplomaSerializer(serializers.ModelSerializer):
@ -12,5 +12,5 @@ class DiplomaSerializer(serializers.ModelSerializer):
class AchievementsSerializer(serializers.ModelSerializer):
class Meta:
model = Achievements
model = Achievement
fields = ('img', 'text')

@ -1,7 +1,7 @@
from django.conf.urls import url, include
urlpatterns = [
url(r'courses/', include('course_service.courses.urls')),
url(r'courses/', include('courses.urls')),
url(r'users/', include('access.urls')),
url(r'library/', include('library.urls')),
url(r'finance/', include('finance.urls')),

@ -1 +0,0 @@
default_app_config = "course_service.courses.apps.CoursesAppConfig"

@ -1,7 +0,0 @@
from django.contrib import admin
from course_service.courses.models import Course, Topic, Vertex
admin.site.register(Topic)
admin.site.register(Vertex)
admin.site.register(Course)

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0001_initial'),
('maps', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='course',
name='route',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='Порядок прохождения по умолчанию'),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('courses', '0002_course_route'),
]
operations = [
migrations.AlterField(
model_name='course',
name='slug',
field=models.SlugField(editable=False, max_length=127, unique=True),
),
]

@ -1,11 +0,0 @@
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from course_service.courses.models import Vertex
@receiver(pre_delete, sender=Vertex)
def delete_dependencies(instance, **kwargs):
"""Удаляем зависимости вместе с узлом"""
if instance.content_object:
instance.content_object.delete()

@ -1,8 +0,0 @@
from django.contrib import admin
from course_service.maps.models import CourseMap, CourseRoute, PivotCourseMap, PivotVertex
admin.site.register(CourseMap)
admin.site.register(CourseRoute)
admin.site.register(PivotCourseMap)
admin.site.register(PivotVertex)

@ -1,16 +0,0 @@
from course_service.maps.models import CourseRoute
class OutApiRoute:
@staticmethod
def change_id(id: int) -> str:
return CourseRoute.objects.get(id=id).out_key
@staticmethod
def get_route_matrix(out_key):
map_list = [i.map_course for i in CourseRoute.objects.get(out_key=out_key).pivotcoursemap_set.all()]
return [[j.vertex.token for j in i.pivotvertex_set.all()] for i in map_list]
@staticmethod
def get_route(out_key):
return CourseRoute.objects.get(out_key=out_key)

@ -1,7 +0,0 @@
from django.apps import AppConfig
class MapsConfig(AppConfig):
name = "course_service.maps"
label = 'maps'
verbose_name = "Отображение курсов"

@ -1,2 +0,0 @@
class MapTypeError(ValueError):
pass

@ -1,83 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='CourseMap',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Имя прохождения')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='К какому курсу привязан')),
],
options={
'verbose_name': 'Карта линейного прохождения курсов',
'verbose_name_plural': 'Карты линейного прохождения курсов',
},
),
migrations.CreateModel(
name='CourseRoute',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('out_key', models.CharField(editable=False, max_length=15, unique=True, verbose_name='Ключ для внешних сервисов')),
('name', models.CharField(max_length=255, verbose_name='Имя шаблона')),
('is_template', models.BooleanField(default=True, verbose_name='Может ли быть использован как шаблон')),
],
options={
'verbose_name': 'Маршрут прохождения',
'verbose_name_plural': 'Маршруты прохождения',
},
),
migrations.CreateModel(
name='PivotCourseMap',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort', models.SmallIntegerField(verbose_name='Порядок сортировки')),
('map_course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='maps.CourseMap', verbose_name='К какой сортировке имеетотношение')),
('route', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='К какому узлу')),
],
options={
'verbose_name': 'Порядок сортировки маршрута',
'verbose_name_plural': 'Порядки сортировок маршрутов',
'ordering': ('sort',),
},
),
migrations.CreateModel(
name='PivotVertex',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort', models.SmallIntegerField(verbose_name='Порядок сортировки')),
('map_course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='maps.CourseMap', verbose_name='К какой сортировке имеетотношение')),
('vertex', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='К какому узлу')),
],
options={
'verbose_name': 'Порядок сортировки узла',
'verbose_name_plural': 'Порядки сортировок узла',
'ordering': ('sort',),
},
),
migrations.AlterUniqueTogether(
name='pivotvertex',
unique_together=set([('sort', 'map_course'), ('map_course', 'vertex')]),
),
migrations.AlterUniqueTogether(
name='pivotcoursemap',
unique_together=set([('sort', 'route'), ('map_course', 'route')]),
),
migrations.AlterUniqueTogether(
name='coursemap',
unique_together=set([('course', 'name')]),
),
]

@ -1,67 +0,0 @@
from django.db import models
from course_service.maps.exeptions import MapTypeError
from lms.global_decorators import transaction_decorator
class CourseRoute(models.Model):
"""
Объединение нескольких мап курса, одназначно
определяет способ прохождения по курсу.
"""
out_key = models.CharField(max_length=15, unique=True, verbose_name="Ключ для внешних сервисов", editable=False)
name = models.CharField(max_length=255, verbose_name='Имя шаблона')
is_template = models.BooleanField(default=True, verbose_name='Может ли быть использован как шаблон')
def __str__(self):
return self.name
class Meta:
verbose_name = 'Маршрут прохождения'
verbose_name_plural = 'Маршруты прохождения'
class CourseMap(models.Model):
"""
Способы отображения курса. Упорядочены в порядке возрастания приоретета.
"""
course = models.ForeignKey(to='courses.Course', verbose_name='К какому курсу привязан')
name = models.CharField(max_length=255, verbose_name="Имя прохождения")
def __str__(self):
return '''Линейное прохождение по курсу "%s"''' % self.course.title
class Meta:
verbose_name = 'Карта линейного прохождения курсов'
verbose_name_plural = 'Карты линейного прохождения курсов'
unique_together =('course', 'name',)
class PivotCourseMap(models.Model):
route = models.ForeignKey(to=CourseRoute, verbose_name="К какому узлу")
sort = models.SmallIntegerField(verbose_name='Порядок сортировки')
map_course = models.ForeignKey(to=CourseMap, verbose_name='К какой сортировке имеетотношение')
def __str__(self):
return '''Карта с №%s по маршруту ID%s''' % (self.sort, self.route_id)
class Meta:
verbose_name = 'Порядок сортировки маршрута'
verbose_name_plural = 'Порядки сортировок маршрутов'
unique_together = (('map_course', 'route'), ('sort', 'route'),)
ordering = ('sort',)
class PivotVertex(models.Model):
vertex = models.ForeignKey(to='courses.Vertex', verbose_name="К какому узлу")
sort = models.SmallIntegerField(verbose_name='Порядок сортировки')
map_course = models.ForeignKey(to=CourseMap, verbose_name='К какой сортировке имеетотношение')
def __str__(self):
return '''Карта с №%s по линейному прохождению ID%s''' % (self.sort, self.map_course_id)
class Meta:
verbose_name = 'Порядок сортировки узла'
verbose_name_plural = 'Порядки сортировок узла'
unique_together = (('map_course', 'vertex'), ('sort', 'map_course'))
ordering = ('sort',)

@ -1,27 +0,0 @@
from rest_framework import serializers
from course_service.maps.models import CourseRoute, CourseMap
class CourseRouteSerializer(serializers.ModelSerializer):
maps = serializers.SerializerMethodField()
class Meta:
model = CourseRoute
fields = ('maps', 'name')
@staticmethod
def get_maps(self):
return [CourseMapSerializer(i.map_course).data for i in self.pivotcoursemap_set.all()]
class CourseMapSerializer(serializers.ModelSerializer):
vertexes = serializers.SerializerMethodField()
class Meta:
model = CourseMap
fields = ('name', 'vertexes')
@staticmethod
def get_vertexes(self):
return [i.vertex.token for i in self.pivotvertex_set.all()]

@ -1,23 +0,0 @@
# from django.test import TestCase
# from course_service.maps.models import CourseRoute
#
# from course_service.maps.api import OutApiRoute
#
#
# class RouteOutApiTestCase(TestCase):
# def setUp(self):
# self.first_course = Course.objects.create(
# title='Первый курс',
# slug='perviy-kuourse',
# )
# self.CDTeacher = OutApiRoute()
#
# def test_teacher(self):
# token1 = "token1"
# token2 = "token2"
# token3 = "token3"
# self.CDTeacher.add_teacher(slug=self.first_course.slug, token=token1)
# self.CDTeacher.add_teacher(slug=self.first_course.slug, token=token2)
# self.CDTeacher.add_teacher(slug=self.first_course.slug, token=token3)
# self.CDTeacher.delete_teacher(slug=self.first_course.slug, token=token2)
# self.assertEqual(self.CDTeacher.get_token_list(self.first_course.slug), ['token1', 'token3'])

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

@ -0,0 +1 @@
default_app_config = "courses.apps.CoursesAppConfig"

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

@ -1,21 +1,21 @@
from course_service.courses.models import Course
from courses.models import Course
class InApiTeacher:
@staticmethod
def add_teacher(slug: str, token: str) -> Course:
course = Course.objects.get(slug=slug)
course.teachers.append(token)
course.teacher_tokens.append(token)
course.save()
return course
@staticmethod
def delete_teacher(slug: str, token: str) -> None:
course = Course.objects.get(slug=slug)
course.teachers.remove(token)
course.teacher_tokens.remove(token)
course.save()
return None
@staticmethod
def get_token_list(slug: str) -> list:
return Course.objects.get(slug=slug).teachers
return Course.objects.get(slug=slug).teacher_tokens

@ -3,7 +3,7 @@ from django.apps import AppConfig
class CoursesAppConfig(AppConfig):
name = "course_service.courses"
name = "courses"
label = 'courses'
verbose_name = "Курсы"

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
# Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
@ -19,17 +20,18 @@ class Migration(migrations.Migration):
name='Course',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hidden', models.BooleanField(default=False, verbose_name='Видно только оплатившим')),
('level', models.CharField(choices=[('B', 'Базовый'), ('A', 'Продвинутый'), ('E', 'Экспертный'), ('B+A', 'Базовый + Продвинутый')], default='B', max_length=3, verbose_name='Уровень')),
('slug', models.SlugField(editable=False, unique=True)),
('direction', models.SmallIntegerField(choices=[(3, 'Бизнес'), (2, 'Веб-дизайн'), (1, 'Разработка'), (4, 'Рисование')], verbose_name='Направление')),
('public', models.BooleanField(default=False, verbose_name='Опубликовать')),
('token', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='Токен')),
('slug', models.SlugField(editable=False, max_length=127, unique=True)),
('title', models.CharField(max_length=255, unique=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='Уровень')),
('direction', models.SmallIntegerField(choices=[(3, 'Бизнес'), (2, 'Веб-дизайн'), (1, 'Разработка'), (4, 'Рисование'), (5, 'Музыка')], verbose_name='Направление')),
('public', models.BooleanField(default=False, 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='Изображение')),
('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='Под мобилку')),
('teachers', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=15, verbose_name='Ссылки на преподов'), default=[], size=None)),
('hidden', models.BooleanField(default=False, verbose_name='Видно только оплатившим')),
],
options={
'verbose_name': 'Курс',
@ -37,35 +39,44 @@ class Migration(migrations.Migration):
},
),
migrations.CreateModel(
name='Topic',
name='Lesson',
fields=[
('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='Название')),
('icon', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Иконка темы')),
('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='курс')),
('video', models.TextField(blank=True, null=True, verbose_name='Код видео')),
('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='Привилегии для узла не будут проверяться')),
('sort', models.SmallIntegerField(unique=True)),
('is_hm', models.BooleanField(default=False)),
('old_id', models.IntegerField(blank=True, null=True)),
],
options={
'verbose_name': 'Тема',
'verbose_name_plural': 'Темы',
'verbose_name': 'Урок',
'verbose_name_plural': 'Уроки',
'ordering': ('sort',),
},
),
migrations.CreateModel(
name='Vertex',
name='Topic',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='Название')),
('free', models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться')),
('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
('video', models.TextField(blank=True, null=True, verbose_name='Код видео')),
('materials', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=15, verbose_name='Материалы урока'), size=None)),
('valid_type', models.SmallIntegerField(choices=[(3, 'Автаматическая валидация'), (2, 'Полуавтаматическая валидация'), (1, 'Ручная валидация'), (0, 'Без валидации')], default=0)),
('token', models.CharField(editable=False, max_length=15, unique=True, verbose_name='Ключ доступа к узлу')),
('topic', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic', verbose_name='Тема')),
('icon', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Иконка темы')),
('sort', models.SmallIntegerField(unique=True)),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='курс')),
],
options={
'verbose_name': 'Урок',
'verbose_name_plural': 'Уроки',
'verbose_name': 'Тема',
'verbose_name_plural': 'Темы',
},
),
migrations.AddField(
model_name='lesson',
name='topic',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic', verbose_name='Тема'),
),
]

@ -1,15 +1,13 @@
# -*- coding: utf-8 -*-
import random
import string
import uuid
import unidecode
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.template.defaultfilters import slugify
from model_utils import Choices
from course_service.maps.models import CourseRoute, CourseMap
from lms.global_decorators import transaction_decorator
from lms.tools import decode_base64, get_real_name
COURSE_LEVEL = (
@ -64,24 +62,20 @@ class CourseManager(models.Manager):
return course
def change_route(self, pk, route):
route = CourseRoute.objects.get(id=route)
course = self.get(id=pk)
course.route = route
course.save()
return course
class Course(models.Model):
token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False)
slug = models.SlugField(unique=True, editable=False, max_length=127)
title = models.CharField(verbose_name="Заголовок", max_length=255, unique=True)
description = models.TextField(verbose_name='Описание', blank=True)
level = models.CharField(verbose_name='Уровень', choices=COURSE_LEVEL, default='B', max_length=3)
direction = models.SmallIntegerField(choices=COURSE_DIRECTION, verbose_name='Направление')
public = models.BooleanField(verbose_name='Опубликовать', default=False)
route = models.OneToOneField(to=CourseRoute, verbose_name="Порядок прохождения по умолчанию", blank=True, null=True)
teachers = ArrayField(
models.CharField(max_length=15, blank=True, verbose_name='Ссылки на преподов'), default=[])
teacher_tokens = ArrayField(
models.UUIDField(verbose_name="Токен препода", editable=False),
default=[],
verbose_name='Преподователи курса',
)
image = models.URLField(verbose_name='Изображение', blank=True, max_length=255)
big_image = models.URLField(verbose_name='Большое изображение', blank=True, max_length=255)
big_mobile_image = models.URLField(verbose_name='Под мобилку', blank=True,
@ -94,7 +88,7 @@ class Course(models.Model):
def get_statistic(self):
return {
'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()
@ -109,31 +103,31 @@ class Topic(models.Model):
title = models.CharField(verbose_name='Название', max_length=255)
description = models.TextField(verbose_name='Описание', blank=True, null=True)
icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True)
sort = models.SmallIntegerField(unique=True)
class Meta:
verbose_name = "Тема"
verbose_name_plural = "Темы"
class Vertex(models.Model):
# TODO переименовать в Lesson
token = models.CharField(max_length=15, verbose_name="Ключ доступа к узлу", unique=True, editable=False)
class Lesson(models.Model):
token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, editable=False)
key = models.UUIDField(
verbose_name="Внутрений ключ используется для расшивровки", default=uuid.uuid4, editable=False)
topic = models.ForeignKey(to=Topic, verbose_name='Тема')
title = models.CharField(verbose_name='Название', max_length=255)
description = models.TextField(verbose_name='Описание', blank=True, null=True)
video = models.TextField(verbose_name='Код видео', blank=True, null=True)
materials = ArrayField(models.CharField(max_length=15, blank=True, verbose_name='Материалы урока'))
# TODO material_tokens ???
material_tokens = ArrayField(
models.UUIDField(verbose_name="Токен материала", editable=False),
default=[],
verbose_name='Материалы курса',
)
free = models.BooleanField(default=False, verbose_name='Привилегии для узла не будут проверяться')
sort = models.SmallIntegerField(unique=True)
# TODO перейти на список валидаторов
VALID_TYPE = (
(3, 'Автаматическая валидация'),
(2, 'Полуавтаматическая валидация'),
(1, 'Ручная валидация'),
(0, 'Без валидации'),
)
valid_type = models.SmallIntegerField(choices=VALID_TYPE, default=0)
is_hm = models.BooleanField(default=False) #TODO костыли
old_id = models.IntegerField(null=True, blank=True)
def __str__(self):
return self.title
@ -141,3 +135,59 @@ class Vertex(models.Model):
class Meta:
verbose_name = "Урок"
verbose_name_plural = "Уроки"
ordering = ('sort', )
# class LessonRequirement(models.Model):
# lesson = models.ForeignKey(to=Lesson)
# requirement = models.ForeignKey(to='courses.Requirement')
# sort = models.SmallIntegerField(default=1)
#
# class Meta:
# verbose_name = "Порядок требований"
# verbose_name_plural = "Порядок требований"
# ordering = ('sort', )
# unique_together = ('lesson', 'requirement', 'sort')
#
#
# class Requirement(models.Model):
# CHECK_TYPES = Choices('student', 'teacher', 'auto',)
#
# token = models.UUIDField(verbose_name="Токен", default=uuid.uuid4, primary_key=True, editable=False)
# name = models.CharField(max_length=31, verbose_name="Название", unique=True)
# checker = models.CharField(
# choices=CHECK_TYPES, default=CHECK_TYPES.teacher, max_length=15, verbose_name="Проверяющий",)
# min_balls = models.SmallIntegerField(default=50, verbose_name='Проходной бал')
#
# def __str__(self):
# return self.name
#
# class Meta:
# verbose_name = "Требования"
# verbose_name_plural = "Требования"
#
#
# class Question(models.Model):
# FIELD_TYPES = Choices('text', 'char', 'boolean', 'file')
#
# requirement = models.ForeignKey(to=Requirement)
# text = models.TextField(verbose_name="Вопрос")
# type = models.CharField(choices=FIELD_TYPES, default=FIELD_TYPES.char, max_length=20)
# multiple = models.BooleanField(default=False)
# null = models.BooleanField(default=False)
# balls = models.SmallIntegerField(default=100, verbose_name='Вознаграждение')
#
# class Meta:
# verbose_name = "Вопрос"
# verbose_name_plural = "Вопросы"
#
#
# class RightAnswer(models.Model):
# question = models.OneToOneField(to=Question)
# text = models.TextField(verbose_name="Верный ответ")
# success_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при верном ответе")
# error_comment = models.TextField(blank=True, null=True, verbose_name="Комментарий при ошибке")
#
# class Meta:
# verbose_name = "Верный ответ"
# verbose_name_plural = "Верные ответы"

@ -1,7 +1,6 @@
from rest_framework import serializers
from course_service.courses.models import Course, Vertex, Topic
from course_service.maps.serializers import CourseRouteSerializer
from courses.models import Course, Lesson, Topic
class TopicSerializer(serializers.ModelSerializer):
@ -13,27 +12,22 @@ class TopicSerializer(serializers.ModelSerializer):
@staticmethod
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:
model = Vertex
model = Lesson
fields = ('title', 'free', 'token')
class VertexSerializer(MiniVertexSerializer):
valid_type = serializers.SerializerMethodField()
class LessonSerializer(MiniLessonSerializer):
class Meta:
model = Vertex
model = Lesson
exclude = ('id', 'topic', 'free')
@staticmethod
def get_valid_type(self):
return self.get_valid_type_display()
class CourseInitSerializer(serializers.ModelSerializer):
@ -44,20 +38,15 @@ class CourseInitSerializer(serializers.ModelSerializer):
class CourseTreeSerializer(serializers.ModelSerializer):
tree = serializers.SerializerMethodField()
route = serializers.SerializerMethodField()
class Meta:
model = Course
fields = ('tree', 'route', 'slug')
fields = ('tree', 'slug')
@staticmethod
def get_tree(self):
return [TopicSerializer(i).data for i in self.topic_set.all()]
@staticmethod
def get_route(self):
return CourseRouteSerializer(self.route).data
class CourseDetailSerializer(serializers.ModelSerializer):
level = serializers.SerializerMethodField()
@ -66,7 +55,7 @@ class CourseDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Course
exclude = ('route', 'id')
exclude = ('id', )
@staticmethod
def get_level(self):

@ -1,8 +1,8 @@
from django.test import TestCase
from course_service.courses.models import Course
from courses.models import Course
from lms.tools import EXAMPLE_BASE64
from course_service.courses.api import InApiTeacher
from courses.api import InApiTeacher
class CourseInApiTestCase(TestCase):

@ -1,6 +1,6 @@
from django.conf.urls import url
from course_service.courses import views as views
from courses import views as views
urlpatterns = [
url(r'vertex/(?P<token>.+)/$', views.VertexDetail.as_view()),

@ -1,9 +1,9 @@
from course_service.courses.models import Course, Vertex
from courses.models import Course, Lesson
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from course_service.courses.serializers import CourseDetailSerializer, CourseTreeSerializer, VertexSerializer
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer
class TreeView(APIView):
@ -39,15 +39,15 @@ class VertexDetail(APIView):
def get(request, token):
try:
vertex = Vertex.objects.get(token=token)
except Vertex.DoesNotExist:
vertex = Lesson.objects.get(token=token)
except Lesson.DoesNotExist:
return Response("Vertex doesn't exist", status=404)
# if not vertex.check_vertex(request.user):
# return Response("permission denied", status=403)
# TODO: Доделать систему прав на курс
res = VertexSerializer(vertex).data
res = LessonSerializer(vertex).data
# progress = vertex.course.progress_set.filter(user=request.user)
# try:
# if progress.exists():

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -16279,7 +16279,6 @@ id,email,first_name,last_name,last_login,role_list,is_superuser,date_joined,is_s
10614,a.by4kova@gmail.com,Анна,Бычкова,2017-12-05 20:21:15.161134,['students'],False,2017-03-01 16:29:11.958988,False,True,False,pbkdf2_sha256$24000$UM6S0tMsSCjq$TS+fqueiIPCnXa1BA95WG+tRn2K+a8L1B45B+l8736M=
16706,nadya_tambov@mail.ru,Надежда,Медвинская,2017-11-10 10:19:30.762866,['students'],False,2017-09-22 17:29:31.635478,False,True,False,pbkdf2_sha256$24000$Oqlr6hGke6rd$LCQrP4Ge/Wk/FyOgd3fvBmlmpTN/zFz/cRWvf4AG9WE=
14778,stfm@inbox.ru,Назар,Безсмертный,2017-10-26 23:48:16.411697,['students'],False,2017-07-19 15:21:20.879007,False,True,False,pbkdf2_sha256$24000$EaLq6P1G1cnc$arI2Mhf1PesY8OH/B2wWh3GdUDUVMuM4CP+otv8hAcQ=
15809,andrey.korolev@skillbox.ru,Андрей,Королёв,2017-12-13 14:56:37.793323,[],True,2017-08-24 18:26:40,True,True,False,pbkdf2_sha256$24000$mjULUfqmRQc5$z+6OcjfoZI8rYyP11/hmDHfqcrVV6fMtwJnqCJh/HSc=
17105,mountop27@gmail.com,Илья,Сопин,2017-12-13 14:50:17.777810,['students'],False,2017-10-09 12:43:14.699604,False,True,False,pbkdf2_sha256$24000$GkyEqau466bL$yrcePorkFZDlCwh8m2ZTzXK/c9iCVjgwC6TbH11FQlE=
16153,m_a_k_c.07@mail.ru,Максим,Григорьев,2017-12-08 15:03:12.135598,['students'],False,2017-09-04 13:42:34.346155,False,True,False,pbkdf2_sha256$24000$tbbjZSYJAST2$ZSF8sIhCFyq9lrTFCFqwpytMDI9u41eSzp5ZGtxpALM=
14183,383misha@mail.ru,Михаил ,Левин ,2017-12-14 08:09:44.239489,['students'],False,2017-06-26 17:30:01.276215,False,True,False,pbkdf2_sha256$24000$ROxPWaRdNNRy$4ZZADG5clRgiecplaycA5CC62pAwItmHpFEcxwACZW4=
@ -18942,3 +18941,4 @@ id,email,first_name,last_name,last_login,role_list,is_superuser,date_joined,is_s
10667,mad-hatter613@yandex.ru,Татьяна ,Тихонова ,2017-08-02 17:23:59.817791,['students'],False,2017-03-03 11:53:39.739851,False,True,False,pbkdf2_sha256$24000$Jc4doAyshxRk$VBqyvAy5PgrXY6Cey+/OGvPIEYLrygvck426snYGPZ8=
19310,vivu2015@yandex.ru,G,G,2017-12-14 10:06:04.299892,['students'],False,2017-12-14 09:14:16.736675,False,False,False,pbkdf2_sha256$24000$FsuJsGAqrUQa$e0dQ49cRXmC2IEiDWEhDX/Ehn0gUOlSUACs4e91xIAk=
10724,7977417@gmail.com,яна,сыревич,2017-12-11 16:39:52.599517,['students'],False,2017-03-06 13:09:37.538459,False,True,False,pbkdf2_sha256$24000$vHfJQApHwy9l$CTwDtt/XbzPX37B/ZD8aqOkwX5WpHrqgTyJlZeiumTc=
15809,andrey.korolev@skillbox.ru,Андрей,Королёв,2018-01-01 15:36:27.211386,[],True,2017-08-24 18:26:40,True,True,False,pbkdf2_sha256$24000$mjULUfqmRQc5$z+6OcjfoZI8rYyP11/hmDHfqcrVV6fMtwJnqCJh/HSc=

Can't render this file because it is too large.

@ -15,8 +15,8 @@ django.setup()
from yandex_money.models import Payment
from finance.models import Bill, Invoice
from access.models.other import Progress
from course_service.courses.models import Course
from access.models import Progress
from courses.models import Course
if __name__ == '__main__':
Payment.objects.all().delete()
@ -28,12 +28,11 @@ if __name__ == '__main__':
bill_kwarg = dict()
row = dict(row)
bill_kwarg['id'] = row.pop('id', None)
bill_kwarg['route'] = Course.objects.get(id=row.pop('course__id', None)).route.out_key
opener_id = row.pop('opener__id', None)
bill_kwarg['opener'] = get_user_model().objects.get(id=opener_id) if opener_id \
opener = row.pop('opener', None)
bill_kwarg['opener'] = get_user_model().objects.get(email=opener) if opener \
else get_user_model().objects.get(email="kate.gazukina@skillbox.ru")
email = row.pop('user__email', None)
email = row.pop('user', None)
try:
email = email[:email.index("\n")]
except ValueError:
@ -46,12 +45,15 @@ if __name__ == '__main__':
bill_kwarg['comment'] = row.pop('comment', None)
bill_kwarg['description'] = row.pop('description', None)
bill_kwarg['course_token'] = Course.objects.get(slug=row.pop('course', None)).token
try:
bill = Bill.objects.create(**bill_kwarg)
except IntegrityError:
pass
bill = Bill.objects.get(course_token=bill_kwarg['course_token'], user=bill_kwarg['user'])
method = row.pop('bill_method', None)
try:
price = int(row.pop('price', None))
except ValueError:
@ -71,12 +73,16 @@ if __name__ == '__main__':
inv.save()
if method == 'Y' and not row['status'] == 'W' and price:
row['yandex_pay'], _is_create = Payment.objects.get_or_create(
yandex_pay, _is_create = Payment.objects.get_or_create(
order_amount=price,
order_number=inv.id,
customer_number=bill.user.id,
customer_number=bill.user.out_key,
user=bill.user,
cps_email=bill.user.email,
shop_amount=real_price,
status='Processed' if 'P' else ('Success' if 'F' else 'Fail')
)
status=Payment.STATUS.PROCESSED if row['status'] == 'P' else
(Payment.STATUS.SUCCESS if row['status'] == 'F' else Payment.STATUS.FAIL)
)
inv.yandex_pay = yandex_pay
inv.save()

@ -14,30 +14,45 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup()
from storage.models import Comment, File
from courses.models import Lesson
from access.models.progress import ProgressLesson
if __name__ == '__main__':
csv.field_size_limit(500 * 1024 * 1024)
Comment.objects.all().delete()
with open('./management/comment.csv') as comment_csv:
comment_reader = csv.DictReader(comment_csv)
for row in comment_reader:
if row['type'] == 'task' or row['type'] == 'exam':
l = Lesson.objects.get(old_id=row['parent_id'])
try:
c = Comment.objects.create(
id=row['id'],
email=row['owner__email'],
p = ProgressLesson.objects.get(
lesson_token=l.token,
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'],
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 file_id:
c.files.add(File.objects.get(id=file_id))
if row['status'] == 'Одобренно':
p.status = ProgressLesson.STATUSES.done
p.date = row['date']
elif row['status'] == 'Отклонено':
p.status = ProgressLesson.STATUSES.fail
else:
p.status = ProgressLesson.STATUSES.wait
p.save()
c.date = row['date']
c.save()
[comment.files.add(file) for file in files]
comment.date = row['date']
comment.save()
parent_id = int(row['parent_id'])
if row['type'] == 'task':
parent_id += 50
p.comment_tokens.append(comment.token)
except ProgressLesson.DoesNotExist:
pass

@ -1,7 +1,5 @@
import csv
import os
import random
import string
import sys
import django
@ -10,18 +8,12 @@ sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup()
from course_service.courses.api import InApiTeacher
from courses.api import InApiTeacher
from django.contrib.auth import get_user_model
from course_service.courses.models import Course, Vertex, Topic
from course_service.maps.models import CourseRoute, CourseMap, PivotVertex, PivotCourseMap
from courses.models import Course, Lesson, Topic
from storage.models import File
if __name__ == '__main__':
CourseMap.objects.all().delete()
CourseRoute.objects.all().delete()
PivotVertex.objects.all().delete()
PivotCourseMap.objects.all().delete()
Vertex.objects.all().delete()
Course.objects.all().delete()
with open('./course/course.csv') as user_csv:
@ -29,28 +21,21 @@ if __name__ == '__main__':
for row in user_reader:
row = dict(row)
teachers = row.pop('teachers', None).split("[")[1].split("]")[0].split(", ")
row.pop('mentors', None).split("[")[1].split("]")[0].split(", ")
course, _is_create = Course.objects.get_or_create(**row)
map_obj = CourseMap.objects.create(course=course)
route_obj = CourseRoute.objects.create(
name='''%s''' % course.title,
out_key=''.join(random.choice(string.ascii_letters) for x in range(15)),
)
PivotCourseMap.objects.create(map_course=map_obj, route=route_obj, sort=0)
course.route = route_obj
course.save()
try:
for teacher in teachers:
teacher = teacher.replace("\'", "")
if teacher:
teacher = get_user_model().objects.get(id=teacher).out_key
teacher = get_user_model().objects.get(email=teacher).out_key
InApiTeacher.add_teacher(course.slug, teacher)
except get_user_model().DoesNotExist:
print('Плохо')
with open('./course/vertex.csv') as vertex_csv:
t_sort = 0
l_sort = 0
vertex_reader = csv.DictReader(vertex_csv)
for row in vertex_reader:
row = dict(row)
@ -58,61 +43,38 @@ if __name__ == '__main__':
description = row.pop('description', None)
title = row.pop('title', None)
pk = row.pop('id', None)
materials = []
try:
m = row.pop('materials', None)
materials = []
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:
pass
if model_type == 'topic':
course = Course.objects.get(id=row.pop('course', None))
map_obj = CourseMap.objects.get(course=course)
t_sort += 1
course = Course.objects.get(slug=row.pop('course', None))
Topic.objects.create(
id=pk,
icon=row.pop('icon', None),
course=course,
description=description,
title=title,
sort=t_sort,
)
try:
else:
topic_id = row.pop('topic', None)
last_pivot = PivotVertex.objects.filter(map_course=map_obj).last()
if model_type == 'tutorial':
topic = Topic.objects.get(id=topic_id)
small_vertex = Vertex.objects.create(
id=pk,
video=row.pop('video', None),
materials=materials,
topic=topic,
free=row['free'],
description=description,
title=title,
token=''.join(random.choice(string.ascii_letters) for x in range(15))
)
PivotVertex.objects.create(
map_course=map_obj,
vertex=small_vertex,
sort=last_pivot.sort+1 if last_pivot else 1,
)
if model_type == 'task':
topic = Topic.objects.get(id=topic_id)
small_vertex = Vertex.objects.create(
id=pk,
materials=materials,
topic=topic,
description=description,
title=title,
valid_type=1,
token=''.join(random.choice(string.ascii_letters) for x in range(15))
)
PivotVertex.objects.create(
map_course=map_obj,
vertex=small_vertex,
sort=last_pivot.sort+1 if last_pivot else 1,
)
except Topic.DoesNotExist:
pass
l_sort += 1
topic = Topic.objects.get(id=topic_id)
small_vertex = Lesson.objects.create(
video=row.pop('video', None),
material_tokens=materials,
topic=topic,
free=row['free'],
description=description,
title=title,
sort=l_sort,
old_id=pk,
is_hm=model_type == 'task',
)

@ -6,23 +6,24 @@ sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup()
from achievements.models import Diploma, Achievements
from achievements.models import Diploma, Achievement
if __name__ == '__main__':
Diploma.objects.all().delete()
Achievements.objects.all().delete()
Achievement.objects.all().delete()
with open('./achievement/achievement.csv') as achievements_csv:
achievements_reader = csv.DictReader(achievements_csv)
for row in achievements_reader:
Achievements.objects.create(**row)
Achievement.objects.create(**row)
with open('./achievement/user_achievement.csv') as achievements_csv:
achievements_reader = csv.DictReader(achievements_csv)
for row in achievements_reader:
a = Achievements.objects.get(id=row['id'])
a.users.add(get_user_model().objects.get(id=row['student_id']))
a = Achievement.objects.get(id=row['id'])
a.users.add(get_user_model().objects.get(email=row['user']))
with open('./achievement/diploma.csv') as achievements_csv:
achievements_reader = csv.DictReader(achievements_csv)
for row in achievements_reader:
Diploma.objects.create(**row)
user=get_user_model().objects.get(email=row.pop('user', None))
Diploma.objects.create(user=user, **row)

@ -6,62 +6,53 @@ import json
from datetime import datetime
from django.db import IntegrityError
sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
django.setup()
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
from access.models.other import Progress, PivotProgressVertex
from course_service.courses.models import Vertex, Course
from course_service.maps.api import OutApiRoute
from access.models.progress import ProgressLesson
from access.models import Progress
from courses.models import Lesson, Course
if __name__ == '__main__':
Progress.objects.all().delete()
with open('./access/progress.csv') as progress_csv:
progress_reader = csv.DictReader(progress_csv)
for row in progress_reader:
course = Course.objects.get(id=row['course'])
route = course.route.out_key
api = OutApiRoute
list_vertex = OutApiRoute.get_route_matrix(route)[0]
course = Course.objects.get(slug=row['course'])
try:
user = get_user_model().objects.get(id=row['user'])
teacher = get_user_model().objects.get(email=row['teacher'])
user = get_user_model().objects.get(email=row['user'])
except get_user_model().DoesNotExist:
print(row['user'])
continue
try:
p = Progress.objects.get(
course=course.slug,
user=user,
teacher=get_user_model().objects.get(id=row['teacher']),
)
except Progress.DoesNotExist:
p = Progress.objects.create(
course=course.slug,
course_token=course.token,
user=user,
teacher=get_user_model().objects.get(id=row['teacher']),
teacher=teacher,
)
pivots = json.loads(row['success'])
for pivot in pivots:
try:
pv = PivotProgressVertex.objects.create(
progress=p,
vertex=Vertex.objects.get(id=pivot['id']).token,
teacher=get_user_model().objects.get(id=pivot['teacher']),
status=1,
)
if pivot['date'] and not pivot['date'] == 'None':
pv.date = datetime.strptime(pivot['date'].split('.')[0], '%Y-%m-%d %H:%M:%S')
pv.status = 2
pv.save()
except Vertex.DoesNotExist:
pass
except IntegrityError:
continue
g = Group.objects.get(name='students')
g.user_set.add(user)
pivots = json.loads(row['success'])
for pivot in pivots:
pv = ProgressLesson.objects.create(
progress=p,
lesson_token=Lesson.objects.get(old_id=pivot['id']).token,
teacher=get_user_model().objects.get(email=pivot['teacher']),
)
if pivot['date'] and not pivot['date'] == 'None':
pv.date = datetime.strptime(pivot['date'].split('.')[0], '%Y-%m-%d %H:%M:%S')
pv.status = 2
pv.save()

@ -19,4 +19,4 @@ if __name__ == '__main__':
for row in storage_reader:
if row['original']:
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,4 +1,4 @@
import os, sys, django, csv, json
import os, sys, django, csv
sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
@ -8,6 +8,7 @@ from django.contrib.auth import get_user_model
from access.models.other import Account
if __name__ == '__main__':
get_user_model().objects.all().delete()
with open('./access/users.csv') as user_csv:
user_reader = csv.DictReader(user_csv)
for row in user_reader:
@ -18,6 +19,8 @@ if __name__ == '__main__':
except IndexError:
row['role_list'] = []
row.pop('id')
get_user_model().objects.get_or_create(**row)
except ValueError as e:
if str(e) == 'The given email must be set':
@ -30,7 +33,7 @@ if __name__ == '__main__':
for row in account_reader:
row = dict(row)
try:
acc = Account.objects.get(owner=get_user_model().objects.get(id=row['owner']))
acc = Account.objects.get(owner=get_user_model().objects.get(email=row['owner']))
acc.phone = row['phone'] if row['phone'] and len(row['phone']) < 16 else None
acc.city = row['city'] if row['city'] else None
acc.photo = row['photo']

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
# Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals
from django.conf import settings
@ -12,8 +12,8 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('yandex_money', '0002_auto_20171128_1150'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('yandex_money', '0001_initial'),
]
operations = [
@ -21,7 +21,7 @@ class Migration(migrations.Migration):
name='Bill',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('route', models.CharField(max_length=15, verbose_name='Токен роута')),
('course_token', models.UUIDField(editable=False, verbose_name='Токен курса')),
('comment', models.TextField(blank=True, editable=False, help_text='Будет показано пользователю', verbose_name='Комментарий продавца')),
('description', models.TextField(blank=True, verbose_name='Внутренняя заметка')),
('opener', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Ответственный сотрудник')),
@ -37,7 +37,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.CharField(choices=[('W', 'Ожидание согласия'), ('P', 'На оплате'), ('F', 'Оплачен'), ('C', 'Отклонен')], default='W', max_length=1, verbose_name='Статус')),
('price', models.IntegerField(editable=False, verbose_name='Сумма')),
('price', models.IntegerField(blank=True, editable=False, null=True, verbose_name='Сумма')),
('real_price', models.IntegerField(blank=True, editable=False, help_text='Сумма, минус комиссия', null=True, verbose_name='Полученная сумма')),
('method', models.CharField(choices=[('C', 'Наличные'), ('H', 'JustClick'), ('A', 'Альфа-Банк'), ('S', 'SimplePay'), ('Y', 'YandexKassa')], default='Y', max_length=2, verbose_name='Способ оплаты')),
('key', models.CharField(blank=True, editable=False, max_length=255, unique=True, verbose_name='Ключ платежа')),
@ -54,6 +54,6 @@ class Migration(migrations.Migration):
),
migrations.AlterUniqueTogether(
name='bill',
unique_together=set([('route', 'user')]),
unique_together=set([('course_token', 'user')]),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-25 11:42
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='price',
field=models.IntegerField(blank=True, editable=False, null=True, verbose_name='Сумма'),
),
]

@ -3,11 +3,11 @@ from django.conf import settings
from django.db import models
from yandex_money.models import Payment
from course_service.courses.models import Course, Vertex
from courses.models import Course, Lesson
class Bill(models.Model):
route = models.CharField(max_length=15, verbose_name='Токен роута')
course_token = models.UUIDField(verbose_name="Токен курса", editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='Плательщик', related_name='bill_user')
opener = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='Ответственный сотрудник', null=True)
comment = models.TextField(verbose_name='Комментарий продавца', help_text='Будет показано пользователю',
@ -24,7 +24,7 @@ class Bill(models.Model):
verbose_name = 'Счет'
verbose_name_plural = 'Счета'
unique_together = (
('route', 'user',),
('course_token', 'user',),
)

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

@ -107,8 +107,7 @@ libs = (
apps = (
'access',
'course_service.maps',
'course_service.courses',
'courses',
'storage',
'finance',
'library',

@ -1,3 +1,4 @@
django-model-utils
celery==4.1.0
Django==1.11.6
django-celery-beat==1.0.1

@ -1,13 +1,9 @@
import random
import string
from storage.models import Comment, 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:
new_file = File.objects.create(key=key, original=original)
new_file = File.objects.create(original=original)
else:
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
key = ''.join(random.choice(string.ascii_letters) for _x in range(15))
comment = Comment.objects.create(
text=text,
email=email,
key=key,
)
for file in files:
@ -42,17 +36,17 @@ def add_comment(text: str, email: str, files=None) -> Comment:
def get_comment(key):
comment = Comment.objects.get(key=key)
comment = Comment.objects.get(token=key)
return comment
def update_comment(key, **kwargs):
comment = Comment.objects.get(key=key)
comment = Comment.objects.get(token=key)
comment.__dict__.update(kwargs)
comment.save()
return comment
def delete_comment(key):
comment = Comment.objects.get(key=key).delete()
comment = Comment.objects.get(token=key).delete()
return comment

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-17 18:03
# Generated by Django 1.11.6 on 2018-01-15 17:54
from __future__ import unicode_literals
from django.db import migrations, models
import uuid
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')),
('email', models.CharField(max_length=63, verbose_name='email автора')),
('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='Дата коментария')),
],
options={
@ -31,7 +32,7 @@ class Migration(migrations.Migration):
name='File',
fields=[
('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='Файл')),
('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Видимое имя файла')),
],

@ -2,6 +2,7 @@
import base64
import random
import string
import uuid
from django.core.files.base import ContentFile
from django.db import models
@ -20,7 +21,7 @@ class FileManager(models.Manager):
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)
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)
text = models.TextField(default="", 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="Дата коментария")
def __str__(self):
return '%s' % self.key
return '%s' % self.token
class Meta:
verbose_name = 'Коммент'

@ -17,29 +17,29 @@ class CommentTestCase(TestCase):
Comment.objects.all().delete()
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):
new_text = "Новый текст для коммента"
update_comment(key=self.first_comment.key, text=new_text)
self.assertEqual(get_comment(self.first_comment.key).text, new_text)
def test_comment_create(self):
token = 'fskjfskj'
comment1 = add_comment(text=token, email="artem4000@gmail.com")
self.assertEqual(comment1.text, token)
with tempfile.gettempdir() as dir_path:
file_for_upload = SimpleUploadedFile(dir_path + '/1.txt', 'Я файл!'.encode('utf-8'))
file_name = 'Клёвый файл'
object_for_upload = {'original': file_for_upload, 'name': file_name}
comment2 = add_comment(text=token, email="artem4000@gmail.com", files=[object_for_upload])
self.assertEqual(comment2.files.count(), 1)
self.assertEqual(comment2.files.all()[0].name, file_name)
update_comment(key=self.first_comment.token, text=new_text)
self.assertEqual(get_comment(self.first_comment.token).text, new_text)
# def test_comment_create(self):
# token = 'fskjfskj'
# comment1 = add_comment(text=token, email="artem4000@gmail.com")
# self.assertEqual(comment1.text, token)
# with tempfile.gettempdir() as dir_path:
# file_for_upload = SimpleUploadedFile(dir_path + '/1.txt', 'Я файл!'.encode('utf-8'))
# file_name = 'Клёвый файл'
# object_for_upload = {'original': file_for_upload, 'name': file_name}
# comment2 = add_comment(text=token, email="artem4000@gmail.com", files=[object_for_upload])
# self.assertEqual(comment2.files.count(), 1)
# self.assertEqual(comment2.files.all()[0].name, file_name)
def test_comment_delete(self):
delete_comment(self.first_comment.key)
delete_comment(self.first_comment.token)
try:
comment = get_comment(self.first_comment.id)
comment = get_comment(self.first_comment.token)
except Comment.DoesNotExist:
comment = None
@ -52,12 +52,12 @@ class FileTestCase(TestCase):
self.second_comment = add_comment(text="Привет, отличная работа", email="artem4000@gmail.com")
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):
new_text = "Новый текст для коммента"
update_comment(key=self.first_comment.key, text=new_text)
self.assertEqual(get_comment(self.first_comment.key).text, new_text)
update_comment(key=self.first_comment.token, text=new_text)
self.assertEqual(get_comment(self.first_comment.token).text, new_text)
def test_comment_create(self):
token = 'fskjfskj'
@ -71,9 +71,9 @@ class FileTestCase(TestCase):
self.assertEqual(comment2.files.all()[0].name, file_name)
def test_comment_delete(self):
delete_comment(self.first_comment.key)
delete_comment(self.first_comment.token)
try:
comment = get_comment(self.first_comment.id)
comment = get_comment(self.first_comment.token)
except Comment.DoesNotExist:
comment = None

Loading…
Cancel
Save