You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

348 lines
14 KiB

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 django.db.models import Q
from courses.models import Course
from progress.models import ProgressLesson, Progress
from progress.serializers import ProgressAnalyticSerializer, ProgressLessonSerializer, ProgressSerializer
from courses.api import CourseProgressApi
from progress.tasks import add_next_lesson
class StudentWorkView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, teacher_token):
client_status = request.GET.get('status', 'in_progress')
server_status = Q(status='fail') if \
client_status == 'not_done' else Q(status='wait') if client_status == 'in_progress' else Q(status='done')
if request.user.is_authenticated() and request.user.groups.filter(name__in=['teachers', 'admin']).exists():
try:
progress_lessons = ProgressLesson.objects.filter(
~Q(progress__user__out_key=teacher_token),
server_status,
checker__out_key=teacher_token,
)
return Response([ProgressLessonSerializer(i).data for i in progress_lessons], status=200)
except ValidationError:
return Response("Bad request", status=400)
return Response(status=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() + 1
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 TeacherUpdateProgress(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
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', None)
comment = request.JSON.get('comment', None)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
if student_out_key is None:
return Response('Не передан student_out_key', status=400)
try:
student = get_user_model().objects.get(out_key=student_out_key)
p = Progress.objects.get(
user=student,
teacher=request.user,
course_token=course_token,
)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
if pv.status == ProgressLesson.STATUSES.wait:
if action == "no":
pv.status = ProgressLesson.STATUSES.fail
elif action == "yes":
pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now()
else:
Response("Свойство action должно иметь значение либо done, либо fail", status=400)
else:
return Response("Ошибка прав доступа", status=403)
if not comment is None:
pv.comment_tokens.append(comment)
except ProgressLesson.DoesNotExist:
return Response('Урок не проходится этим пользователем', status=403)
pv.save()
res = {"current": ProgressLessonSerializer(pv).data}
if pv.status == ProgressLesson.STATUSES.done:
# TODO: Ассинхроннаязадача для celery
res['next'] = ProgressLessonSerializer(add_next_lesson(p)).data
return Response(res, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
class StudentUpdateProgress(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
lesson_token = request.JSON.get('lesson_token', None)
course_token = request.JSON.get('course_token', None)
comment = request.JSON.get('comment', None)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
try:
student = request.user
p = Progress.objects.get(user=student, course_token=course_token)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
if not pv.status == ProgressLesson.STATUSES.wait:
if pv.checker == p.teacher:
pv.status = ProgressLesson.STATUSES.wait
if not comment is None:
pv.comment_tokens.append(comment)
elif pv.checker == p.user:
pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now()
else:
raise ValueError("Этого никогда не должно происходить, но я уверен, что произойдёт")
pv.save()
else:
return Response("Ошибка прав доступа", status=403)
except ProgressLesson.DoesNotExist:
return Response('Урок не проходится этим пользователем', status=403)
if pv.status == ProgressLesson.STATUSES.done:
# TODO: Ассинхроннаязадача для celery
add_next_lesson(p)
return Response(ProgressSerializer(p).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
class SetProgress(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,)
@staticmethod
def post(request):
if request.user.is_staff:
email = request.JSON.get('email', None)
course_slug = request.JSON.get('course_slug', None)
topic_sort = int(request.JSON.get('topic', 1))
lesson_sort = int(request.JSON.get('lesson', 1))
force = request.JSON.get('force', False)
if course_slug is None:
return Response('course_slug не передан', status=400)
if email is None:
return Response('email не передан', status=400)
try:
student = get_user_model().objects.get(email=email)
except get_user_model().DoesNotExist:
return Response("User doesn't exist", status=404)
try:
course = Course.objects.get(slug=course_slug)
except get_user_model().DoesNotExist:
return Response("Course doesn't exist", status=404)
try:
progress = Progress.objects.get(course_token=course.token, user=student)
except Progress.DoesNotExist:
if not force:
return Response("Студент не проходит этот курс", status=403)
teacher = get_user_model().objects.get(out_key=course.get_teacher())
progress = Progress.objects.create(course_token=course.token, user=student, teacher=teacher)
token_list = []
lesson_list = []
for topic_idx, topic in enumerate(course.topic_set.all()):
topic_find = topic_idx == (topic_sort - 1)
for lesson_idx, lesson in enumerate(topic.lesson_set.all()):
token_list.append(lesson.token)
lesson_list.append(lesson)
if lesson_idx == (lesson_sort - 1) and topic_find:
break
if topic_find:
break
if progress.progresslesson_set.filter(
~Q(lesson_token__in=token_list)).exists() and not force:
return Response("Пользователь, прошёл дальше по курсу", status=403)
progress.progresslesson_set.filter(~Q(lesson_token__in=token_list)).delete()
for lesson_idx, lesson_token in enumerate(token_list[:-1]):
try:
pl = ProgressLesson.objects.get(progress__user=student, lesson_token=lesson_token)
if pl.finish_date is None:
pl.finish_date = datetime.datetime.now()
pl.status = 'done'
pl.save()
except ProgressLesson.DoesNotExist:
ProgressLesson.objects.create(
progress=progress,
lesson_token=lesson_token,
checker=progress.teacher if lesson_list[lesson_idx].is_hm else student,
status="done",
finish_date=datetime.datetime.now()
)
try:
pl = ProgressLesson.objects.get(progress=progress, lesson_token=token_list[-1:][0])
if pl.status == "done":
pl.status = "start"
pl.finish_date = None
pl.save()
except ProgressLesson.DoesNotExist:
ProgressLesson.objects.create(
progress=progress,
lesson_token=token_list[-1:][0],
checker=progress.teacher if lesson_list[-1:][0].is_hm else student
)
return Response(status=204)
else:
return Response("Эта функция доступна только сотрудникам персонала", status=403)