feature/fix_generate_pass
Andrey 8 years ago
parent deb0c6142c
commit 5c2a9d33cc
  1. 2
      access/admin.py
  2. 41
      access/migrations/0001_initial.py
  3. 2
      access/models/__init__.py
  4. 46
      access/serializers.py
  5. 12
      access/urls.py
  6. 180
      access/views.py
  7. 2
      achievements/migrations/0001_initial.py
  8. 2
      courses/migrations/0001_initial.py
  9. 2
      csv/load_bills.py
  10. 2
      csv/load_comments.py
  11. 8
      csv/load_perm.py
  12. 2
      finance/migrations/0001_initial.py
  13. 2
      library/migrations/0001_initial.py
  14. 1
      lms/settings.py
  15. 1
      progress/__init__.py
  16. 7
      progress/apps.py
  17. 60
      progress/migrations/0001_initial.py
  18. 0
      progress/migrations/__init__.py
  19. 30
      progress/models.py
  20. 44
      progress/serializers.py
  21. 0
      progress/tasks.py
  22. 0
      progress/urls.py
  23. 184
      progress/views.py
  24. 2
      storage/migrations/0001_initial.py

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

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-29 16:48 # Generated by Django 1.11.6 on 2018-01-31 18:55
from __future__ import unicode_literals from __future__ import unicode_literals
import access.models.user import access.models.user
@ -75,37 +75,6 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Приглошения в систему', 'verbose_name_plural': 'Приглошения в систему',
}, },
), ),
migrations.CreateModel(
name='Progress',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('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='Токен курса')),
('active_lesson', models.UUIDField(blank=True, null=True, 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='Студент')),
],
options={
'verbose_name': 'Прогресс пользователя',
'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( migrations.CreateModel(
name='UserActivity', name='UserActivity',
fields=[ fields=[
@ -136,12 +105,4 @@ 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.AlterUniqueTogether(
name='progresslesson',
unique_together=set([('progress', 'lesson_token')]),
),
migrations.AlterUniqueTogether(
name='progress',
unique_together=set([('user', 'course_token')]),
),
] ]

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

@ -2,52 +2,8 @@ from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from access.models.other import Account from access.models.other import Account
from access.models.progress import ProgressLesson
from access.models import Progress
from achievements.serialers import DiplomaSerializer, AchievementsSerializer from achievements.serialers import DiplomaSerializer, AchievementsSerializer
from courses.api import CourseProgressApi from progress.serializers import ProgressSerializer
class ProgressLessonSerializer(serializers.ModelSerializer):
teacher = serializers.SerializerMethodField()
class Meta:
model = ProgressLesson
exclude = ('id', 'progress')
@staticmethod
def get_teacher(self):
return self.teacher.get_full_name()
class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('name', 'email',)
@staticmethod
def get_name(self):
return self.user.get_full_name()
@staticmethod
def get_email(self):
return self.user.email
class ProgressSerializer(serializers.ModelSerializer):
lessons = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('lessons', 'course_token')
@staticmethod
def get_lessons(self):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class AccountSerializer(serializers.ModelSerializer): class AccountSerializer(serializers.ModelSerializer):

@ -1,4 +1,6 @@
from django.conf.urls import url from django.conf.urls import url
import progress.views
from access import views from access import views
urlpatterns = [ urlpatterns = [
@ -6,15 +8,15 @@ urlpatterns = [
url(r'detail/$', views.DetailUserView.as_view()), url(r'detail/$', views.DetailUserView.as_view()),
url(r'detail/([0-9]{1,99})/$', views.DetailUserView.as_view()), url(r'detail/([0-9]{1,99})/$', views.DetailUserView.as_view()),
url(r'info/(?P<out_key>[0-9A-Fa-f-]+)/$', views.MinUserView.as_view()), url(r'info/(?P<out_key>[0-9A-Fa-f-]+)/$', views.MinUserView.as_view()),
url(r'guard/(?P<pk>[0-9]{1,99})/(?P<page>.+)/$', views.UserGuardView.as_view()), url(r'guard/(?P<pk>[0-9]{1,99})/(?P<page>.+)/$', progress.views.UserGuardView.as_view()),
url(r'find/$', views.FindUserView.as_view()), url(r'find/$', views.FindUserView.as_view()),
url(r'registration/$', views.RegistrationView.as_view()), url(r'registration/$', views.RegistrationView.as_view()),
url(r'change_password/$', views.ChangePasswordView.as_view()), url(r'change_password/$', views.ChangePasswordView.as_view()),
url(r'login/$', views.LoginView.as_view()), url(r'login/$', views.LoginView.as_view()),
url(r'logout/$', views.LogoutView.as_view()), url(r'logout/$', views.LogoutView.as_view()),
url(r'reset/$', views.ResetPasswordView.as_view()), url(r'reset/$', views.ResetPasswordView.as_view()),
url(r'progress/$', views.UpdateProgress.as_view()), url(r'progress/$', progress.views.UpdateProgress.as_view()),
url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', views.UploadCourseProgressUserView.as_view()), url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.UploadCourseProgressUserView.as_view()),
url(r'progress_detail/(?P<token>[0-9A-Fa-f-]+)/$', views.CourseProgressUserView.as_view()), url(r'progress_detail/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.CourseProgressUserView.as_view()),
url(r'progress_dynamic/(?P<token>[0-9A-Fa-f-]+)/$', views.CourseProgressDynamicView.as_view()), url(r'progress_dynamic/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.CourseProgressDynamicView.as_view()),
] ]

@ -1,27 +1,18 @@
import csv
import datetime import datetime
import random import random
import string import string
from django.contrib import auth from django.contrib import auth
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.core.mail import send_mail from django.core.mail import send_mail
from django.db.models import Q from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView 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.serializers import UserSelfSerializer, UserSearchSerializer
from access.models import Progress
from access.serializers import UserSelfSerializer, UserSearchSerializer, ProgressLessonSerializer, \
ProgressAnalyticSerializer
from access.tasks import add_next_lesson
from courses.api import CourseProgressApi
class TeacherListView(APIView): class TeacherListView(APIView):
@ -237,175 +228,6 @@ class LogoutView(APIView):
return Response(status=204) return Response(status=204)
class UpdateProgress(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
"""
На вход обязательно передаётся параметр id (id узла).
"""
lesson_token = request.JSON.get('lesson_token', None)
course_token = request.JSON.get('course_token', None)
student_out_key = request.JSON.get('student_out_key', None)
action = request.JSON.get('action', 'wait')
comment = request.JSON.get('comment', None)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
try:
is_student = student_out_key is None
student = request.user if is_student else get_user_model().objects.get(out_key=student_out_key)
if is_student:
p = Progress.objects.get(user=student, course_token=course_token)
else:
p = Progress.objects.get(
user=student,
teacher=request.user,
course_token=course_token,
)
if p.active_lesson == lesson_token:
return Response("Ошибка доступа", status=403)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
if is_student and pv.status == ProgressLesson.STATUSES.fail and action == "wait":
pv.status = ProgressLesson.STATUSES.wait
elif not is_student and pv.status == ProgressLesson.STATUSES.wait:
pv.status = action
else:
return Response("Ошибка прав доступа", status=403)
pv.comment_tokens.append(comment)
except ProgressLesson.DoesNotExist:
pv = ProgressLesson.objects.create(
date=datetime.datetime.now(),
teacher=p.teacher,
progress=p,
lesson_token=lesson_token,
status=ProgressLesson.STATUSES.done
)
pv.save()
if pv.status == ProgressLesson.STATUSES.done:
#TODO: Ассинхроннаязадача для celery
add_next_lesson(p)
return Response(ProgressLessonSerializer(pv).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
class UserGuardView(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,)
@staticmethod
def get(request, pk, page):
try:
user = get_user_model().objects.get(out_key=pk)
except get_user_model().DoesNotExist:
return Response("User doesn't exist", status=404)
is_i = request.user == user
res_403 = Response('Permission denied', status=403)
res_204 = Response(status=204)
if is_i and not request.user.groups.filter(name='teachers').exists() and page == 'homeworks':
return res_403
if is_i and not \
request.user.groups.filter(name__in=['students', 'managers', 'lead_managers']).exists() \
and page == 'payment':
return res_403
if is_i:
return res_204
if page == 'profile' and (request.user.is_superuser or request.user.is_staff):
return res_204
return res_403
class CourseProgressDynamicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
try:
progresses = Progress.objects.filter(course_token=token)
res = {}
for i in progresses:
key = i.progresslesson_set.filter(status="done").count()
res[key] = 1 if not key in res.keys() else res[key] + 1
return Response(res, status=200)
except ValidationError:
return Response("Bad request", status=400)
return Response(status=403)
class CourseProgressUserView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
try:
res = []
sorted_token_list = CourseProgressApi.get_topic_lesson(token)
for p in Progress.objects.filter(course_token=token):
progress = ProgressAnalyticSerializer(p).data
progress['progress_course'] = p.progress_status(sorted_token_list)
res.append(progress)
return Response(res, status=200)
except ValidationError:
return Response("Bad request", status=400)
return Response(status=403)
class UploadCourseProgressUserView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
try:
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % token
sorted_token_list = CourseProgressApi.get_topic_lesson(token)
writer = csv.writer(response)
writer.writerow(['Имя', 'Почта', 'Последняя тема', 'Последний урок'])
for p in Progress.objects.filter(course_token=token):
progress = ProgressAnalyticSerializer(p).data
progress['progress_course'] = p.progress_status(sorted_token_list)
writer.writerow([
progress['name'],
progress['email'],
progress['progress_course'] and progress['progress_course'][0],
progress['progress_course'] and progress['progress_course'][1],
])
return response
except ValidationError:
return Response("Bad request", status=400)
return Response(status=403)
class MinUserView(APIView): class MinUserView(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-29 16:48 # Generated by Django 1.11.6 on 2018-01-31 18:55
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-29 16:48 # Generated by Django 1.11.6 on 2018-01-31 18:55
from __future__ import unicode_literals from __future__ import unicode_literals
import django.contrib.postgres.fields import django.contrib.postgres.fields

@ -15,7 +15,7 @@ django.setup()
from yandex_money.models import Payment from yandex_money.models import Payment
from finance.models import Bill, Invoice from finance.models import Bill, Invoice
from access.models import Progress from progress.models import Progress
from courses.models import Course from courses.models import Course
if __name__ == '__main__': if __name__ == '__main__':

@ -15,7 +15,7 @@ django.setup()
from storage.models import Comment, File from storage.models import Comment, File
from courses.models import Lesson from courses.models import Lesson
from access.models.progress import ProgressLesson, Progress from progress.models import ProgressLesson, Progress
if __name__ == '__main__': if __name__ == '__main__':
csv.field_size_limit(500 * 1024 * 1024) csv.field_size_limit(500 * 1024 * 1024)

@ -15,8 +15,7 @@ django.setup()
from courses.api import CourseProgressApi from courses.api import CourseProgressApi
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from access.models.progress import ProgressLesson from progress.models import ProgressLesson, Progress
from access.models import Progress
from courses.models import Lesson, Course from courses.models import Lesson, Course
@ -55,7 +54,7 @@ if __name__ == '__main__':
) )
if pivot['date'] and not pivot['date'] == 'None': if pivot['date'] and not pivot['date'] == 'None':
pv.date = datetime.strptime(pivot['date'].split('.')[0], '%Y-%m-%d %H:%M:%S') pv.start_date = datetime.strptime(pivot['date'].split('.')[0], '%Y-%m-%d %H:%M:%S')
pv.status = ProgressLesson.STATUSES.done pv.status = ProgressLesson.STATUSES.done
pv.save() pv.save()
@ -68,4 +67,5 @@ if __name__ == '__main__':
last_progress_lesson = p.progresslesson_set.filter(status=ProgressLesson.STATUSES.done).last() last_progress_lesson = p.progresslesson_set.filter(status=ProgressLesson.STATUSES.done).last()
is_next = True if last_progress_lesson is None else last_progress_lesson.lesson_token == lesson_token is_next = True if last_progress_lesson is None else \
last_progress_lesson.lesson_token == lesson_token

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-29 16:48 # Generated by Django 1.11.6 on 2018-01-31 18:55
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-29 16:48 # Generated by Django 1.11.6 on 2018-01-31 11:24
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime

@ -107,6 +107,7 @@ libs = (
apps = ( apps = (
'access', 'access',
'progress',
'courses', 'courses',
'storage', 'storage',
'finance', 'finance',

@ -0,0 +1 @@
default_app_config = "progress.apps.ProgressAppConfig"

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
from django.apps import AppConfig
class ProgressAppConfig(AppConfig):
name = "progress"
verbose_name = "Прогрес"

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-31 18:55
from __future__ import unicode_literals
from django.conf import settings
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Progress',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('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='Токен курса')),
('active_lesson', models.UUIDField(blank=True, null=True, 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='Студент')),
],
options={
'verbose_name': 'Прогресс пользователя',
'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='Токен урока')),
('finish_date', models.DateTimeField(blank=True, null=True, verbose_name='Дата зачтения задания')),
('start_date', models.DateTimeField(auto_now_add=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)),
('checker', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Преподователь')),
('progress', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='progress.Progress')),
],
options={
'verbose_name': 'Прохождение уроков',
'verbose_name_plural': 'Прохождение урока',
},
),
migrations.AlterUniqueTogether(
name='progresslesson',
unique_together=set([('progress', 'lesson_token')]),
),
migrations.AlterUniqueTogether(
name='progress',
unique_together=set([('user', 'course_token')]),
),
]

@ -2,7 +2,6 @@ from django.conf import settings
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from model_utils import Choices from model_utils import Choices
from courses.api import CourseProgressApi
class Progress(models.Model): class Progress(models.Model):
@ -50,8 +49,9 @@ class Progress(models.Model):
class ProgressLesson(models.Model): 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="Преподователь",) checker = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name="Преподователь", )
date = models.DateTimeField(verbose_name='Дата зачтения задания', blank=True, null=True) finish_date = models.DateTimeField(verbose_name='Дата зачтения задания', blank=True, null=True)
start_date = models.DateTimeField(verbose_name='Дата начала прохождения задания', auto_now_add=True)
STATUSES = Choices('done', 'wait', 'fail') STATUSES = Choices('done', 'wait', 'fail')
status = models.CharField(choices=STATUSES, default=STATUSES.wait, max_length=20) status = models.CharField(choices=STATUSES, default=STATUSES.wait, max_length=20)
comment_tokens = ArrayField(models.UUIDField(verbose_name="Токен комента", editable=False), default=[]) comment_tokens = ArrayField(models.UUIDField(verbose_name="Токен комента", editable=False), default=[])
@ -63,27 +63,3 @@ class ProgressLesson(models.Model):
verbose_name = 'Прохождение уроков' verbose_name = 'Прохождение уроков'
verbose_name_plural = 'Прохождение урока' verbose_name_plural = 'Прохождение урока'
unique_together = ('progress', 'lesson_token') 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 = 'Ответы пользователя'

@ -0,0 +1,44 @@
from rest_framework import serializers
from progress.models import Progress, ProgressLesson
class ProgressSerializer(serializers.ModelSerializer):
lessons = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('lessons', 'course_token')
@staticmethod
def get_lessons(self):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('name', 'email',)
@staticmethod
def get_name(self):
return self.user.get_full_name()
@staticmethod
def get_email(self):
return self.user.email
class ProgressLessonSerializer(serializers.ModelSerializer):
teacher = serializers.SerializerMethodField()
class Meta:
model = ProgressLesson
exclude = ('id', 'progress')
@staticmethod
def get_teacher(self):
return self.teacher.get_full_name()

@ -0,0 +1,184 @@
import csv
import datetime
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.http import HttpResponse
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from progress.models import ProgressLesson, Progress
from progress.serializers import ProgressAnalyticSerializer, ProgressLessonSerializer
from courses.api import CourseProgressApi
from progress.tasks import add_next_lesson
class CourseProgressDynamicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
try:
progresses = Progress.objects.filter(course_token=token)
res = {}
for i in progresses:
key = i.progresslesson_set.filter(status="done").count()
res[key] = 1 if not key in res.keys() else res[key] + 1
return Response(res, status=200)
except ValidationError:
return Response("Bad request", status=400)
return Response(status=403)
class CourseProgressUserView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
try:
res = []
sorted_token_list = CourseProgressApi.get_topic_lesson(token)
for p in Progress.objects.filter(course_token=token):
progress = ProgressAnalyticSerializer(p).data
progress['progress_course'] = p.progress_status(sorted_token_list)
res.append(progress)
return Response(res, status=200)
except ValidationError:
return Response("Bad request", status=400)
return Response(status=403)
class UpdateProgress(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
"""
На вход обязательно передаётся параметр id (id узла).
"""
lesson_token = request.JSON.get('lesson_token', None)
course_token = request.JSON.get('course_token', None)
student_out_key = request.JSON.get('student_out_key', None)
action = request.JSON.get('action', 'wait')
comment = request.JSON.get('comment', None)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
try:
is_student = student_out_key is None
student = request.user if is_student else get_user_model().objects.get(out_key=student_out_key)
if is_student:
p = Progress.objects.get(user=student, course_token=course_token)
else:
p = Progress.objects.get(
user=student,
teacher=request.user,
course_token=course_token,
)
if p.active_lesson == lesson_token:
return Response("Ошибка доступа", status=403)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=p.active_lesson,
)
if is_student and pv.status == ProgressLesson.STATUSES.fail and action == "wait":
pv.status = ProgressLesson.STATUSES.wait
elif not is_student and pv.status == ProgressLesson.STATUSES.wait:
pv.status = action
else:
return Response("Ошибка прав доступа", status=403)
pv.comment_tokens.append(comment)
except ProgressLesson.DoesNotExist:
pv = ProgressLesson.objects.create(
date=datetime.datetime.now(),
teacher=p.teacher,
progress=p,
lesson_token=p.active_lesson,
status=ProgressLesson.STATUSES.done
)
pv.save()
if pv.status == ProgressLesson.STATUSES.done:
#TODO: Ассинхроннаязадача для celery
add_next_lesson(p)
return Response(ProgressLessonSerializer(pv).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
class UploadCourseProgressUserView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
try:
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % token
sorted_token_list = CourseProgressApi.get_topic_lesson(token)
writer = csv.writer(response)
writer.writerow(['Имя', 'Почта', 'Последняя тема', 'Последний урок'])
for p in Progress.objects.filter(course_token=token):
progress = ProgressAnalyticSerializer(p).data
progress['progress_course'] = p.progress_status(sorted_token_list)
writer.writerow([
progress['name'],
progress['email'],
progress['progress_course'] and progress['progress_course'][0],
progress['progress_course'] and progress['progress_course'][1],
])
return response
except ValidationError:
return Response("Bad request", status=400)
return Response(status=403)
class UserGuardView(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,)
@staticmethod
def get(request, pk, page):
try:
user = get_user_model().objects.get(out_key=pk)
except get_user_model().DoesNotExist:
return Response("User doesn't exist", status=404)
is_i = request.user == user
res_403 = Response('Permission denied', status=403)
res_204 = Response(status=204)
if is_i and not request.user.groups.filter(name='teachers').exists() and page == 'homeworks':
return res_403
if is_i and not \
request.user.groups.filter(name__in=['students', 'managers', 'lead_managers']).exists() \
and page == 'payment':
return res_403
if is_i:
return res_204
if page == 'profile' and (request.user.is_superuser or request.user.is_staff):
return res_204
return res_403

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-29 16:48 # Generated by Django 1.11.6 on 2018-01-31 18:55
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

Loading…
Cancel
Save