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.
463 lines
19 KiB
463 lines
19 KiB
import csv
|
|
import datetime
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.mail import EmailMessage
|
|
from django.http import HttpResponse, HttpResponseForbidden
|
|
from rest_framework import permissions
|
|
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 access.serializers import UserProgressSearchSerializer
|
|
from courses.models import Course
|
|
from progress.models import ProgressLesson, Progress
|
|
from progress.serializers import ProgressAnalyticSerializer, ProgressLessonSerializer, ProgressSerializer, \
|
|
SecureProgressSerializer
|
|
from courses.api import CourseProgressApi, CourseParamsApi
|
|
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')
|
|
if request.user.is_authenticated() and request.user.groups.filter(name__in=['teachers', 'admin']).exists():
|
|
try:
|
|
if client_status == 'done':
|
|
date_from = datetime.datetime.now() - datetime.timedelta(days=7)
|
|
progress_lessons = ProgressLesson.objects.filter(
|
|
~Q(progress__user__out_key=teacher_token),
|
|
~Q(comment_tokens__len=0),
|
|
status='done',
|
|
checker__out_key=teacher_token,
|
|
finish_date__gte=date_from,
|
|
).order_by('finish_date')
|
|
|
|
else:
|
|
server_status = Q(status='fail') if client_status == 'not_done' else Q(status='wait')
|
|
progress_lessons = ProgressLesson.objects.filter(
|
|
~Q(progress__user__out_key=teacher_token),
|
|
server_status,
|
|
checker__out_key=teacher_token,
|
|
).order_by('-last_update')
|
|
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
|
|
msg = EmailMessage(
|
|
'Ваша работа отправлена на доработку',
|
|
'''Преподаватель "%s" отклонил вашу работу''' % request.user.get_full_name(),
|
|
'robo@skillbox.ru',
|
|
[student.email],
|
|
)
|
|
msg.send()
|
|
|
|
elif action == "yes":
|
|
pv.status = ProgressLesson.STATUSES.done
|
|
pv.finish_date = datetime.datetime.now()
|
|
msg = EmailMessage(
|
|
'Ваша работа принята',
|
|
'''Преподователь "%s" принял вашу работу''' % request.user.get_full_name(),
|
|
'robo@skillbox.ru',
|
|
[student.email],
|
|
)
|
|
msg.send()
|
|
|
|
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):
|
|
permission_classes = (permissions.IsAuthenticated,)
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
lesson_token = request.JSON.get('lesson_token', None)
|
|
comment = request.JSON.get('comment', None)
|
|
|
|
if lesson_token is None:
|
|
return Response('Не передан токен урока', status=400)
|
|
|
|
student = request.user
|
|
|
|
try:
|
|
pv = ProgressLesson.objects.get(
|
|
progress__user=student,
|
|
lesson_token=lesson_token,
|
|
)
|
|
|
|
if pv.status == ProgressLesson.STATUSES.done:
|
|
return Response(SecureProgressSerializer(pv.progress).data, status=200)
|
|
|
|
if not pv.status == ProgressLesson.STATUSES.wait:
|
|
if pv.checker == pv.progress.user:
|
|
pv.status = ProgressLesson.STATUSES.done
|
|
pv.finish_date = datetime.datetime.now()
|
|
|
|
elif not comment is None and\
|
|
not pv.progress.progresslesson_set.filter(status=ProgressLesson.STATUSES.wait).exists():
|
|
pv.status = ProgressLesson.STATUSES.wait
|
|
pv.comment_tokens.append(comment)
|
|
msg = EmailMessage(
|
|
'Студент оставил комментарий',
|
|
'''Студент "%s" оставил вам комментарий.''' % request.user.get_full_name(),
|
|
'robo@skillbox.ru',
|
|
[pv.cheсker.email],
|
|
)
|
|
msg.send()
|
|
|
|
elif comment is None:
|
|
return Response("Не преложен комментарий", status=400)
|
|
|
|
else:
|
|
return Response("В настоящее время, мы уже проверяем одно из ваших домашних заданий. <br> Как "
|
|
"только оно будет успешно сдано - вы сможете продолжить.", status=403)
|
|
|
|
elif not comment is None:
|
|
pv.comment_tokens.append(comment)
|
|
|
|
pv.save()
|
|
|
|
return Response(SecureProgressSerializer(pv.progress).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 FindProgressView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
permission_classes = (IsAuthenticated,)
|
|
|
|
@staticmethod
|
|
def get(request):
|
|
if not request.user.is_staff:
|
|
return Response("Только сотрудники персонала могут запрашивать инфо по прогрессу", status=403)
|
|
key = request.GET.get('key', None)
|
|
count = int(request.GET.get('count', '10'))
|
|
if key:
|
|
res = get_user_model().objects.filter(
|
|
Q(id__contains=key) | Q(email__contains=key.lower()) | Q(first_name__contains=key) |
|
|
Q(last_name__contains=key) | Q(account__phone__contains=key)
|
|
)
|
|
|
|
else:
|
|
res = get_user_model().objects.all()
|
|
|
|
res = res[:(count if len(res) > count else len(res))]
|
|
return Response([UserProgressSearchSerializer(i).data for i in res], status=200)
|
|
|
|
|
|
class FreezeProgressView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
permission_classes = (IsAuthenticated,)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
if not request.user.is_staff:
|
|
return Response("Только сотрудники персонала могут вносить изменение в прогресс", status=403)
|
|
key = request.JSON.get('id', None)
|
|
is_freeze = request.JSON.get('is_freeze', False)
|
|
|
|
try:
|
|
p = Progress.objects.get(id=key)
|
|
p.is_freeze = is_freeze
|
|
p.save()
|
|
except Progress.DoesNotExist:
|
|
return Response("не найден прогресс по заданному id", status=404)
|
|
|
|
return Response(status=204)
|
|
|
|
|
|
class ChangeTeacherView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
permission_classes = (IsAuthenticated,)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
if not request.user.is_staff:
|
|
return Response("Только сотрудники персонала могут вносить изменение в прогресс", status=403)
|
|
key = request.JSON.get('id', None)
|
|
teacher_email = request.JSON.get('teacher_email', False)
|
|
|
|
try:
|
|
p = Progress.objects.get(id=key)
|
|
try:
|
|
teacher = get_user_model().objects.get(email=teacher_email.lower())
|
|
except get_user_model().DoesNotExist:
|
|
return Response("Нет пользователя c таким email", status=404)
|
|
p.teacher = teacher
|
|
p.progresslesson_set.filter(status=ProgressLesson.STATUSES.wait).update(checker=teacher)
|
|
p.save()
|
|
except Progress.DoesNotExist:
|
|
return Response("не найден прогресс по заданному id", status=404)
|
|
|
|
return Response(status=204)
|
|
|
|
|
|
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))
|
|
only_watch = request.JSON.get('only_watch', False)
|
|
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.lower())
|
|
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)
|
|
|
|
progress.only_watch = only_watch
|
|
progress.save()
|
|
|
|
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)
|
|
|
|
|
|
def get_teachers_pay(request):
|
|
if not request.user.is_authenticated and (request.user.groups.filter(name="support") or request.user.is_superuser):
|
|
return HttpResponseForbidden()
|
|
|
|
date_from = request.GET.get('from', None)
|
|
date_to = request.GET.get('to', None)
|
|
email = request.GET.get('email', None)
|
|
|
|
file_name = "teacher_pay_%s" % email
|
|
file_name = file_name + "__from_%s" % date_from if date_from else file_name
|
|
file_name = file_name + "__to_%s" % date_to if date_to else file_name
|
|
|
|
progress_lessons = ProgressLesson.objects.filter(
|
|
~Q(comment_tokens__len=0),
|
|
checker__email=email,
|
|
status='done',
|
|
)
|
|
|
|
progress_lessons = progress_lessons.filter(finish_date__lt=date_to) if date_to else progress_lessons
|
|
progress_lessons = progress_lessons.filter(finish_date__gte=date_from) if date_from else progress_lessons
|
|
|
|
response = HttpResponse(content_type='text/csv')
|
|
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % file_name
|
|
|
|
writer = csv.writer(response)
|
|
writer.writerow(['Почта студента', 'Имя студента', 'Курс', 'Дата', 'Время',])
|
|
|
|
for i in progress_lessons.order_by('-finish_date'):
|
|
course_api = CourseParamsApi(i.progress.course_token)
|
|
writer.writerow([
|
|
i.progress.user.email,
|
|
i.progress.user.get_full_name(),
|
|
course_api.get_slug_and_title()['title'],
|
|
i.finish_date.date(),
|
|
i.finish_date.time(),
|
|
])
|
|
|
|
return response
|
|
|