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.
417 lines
15 KiB
417 lines
15 KiB
import csv
|
|
import datetime
|
|
import random
|
|
import string
|
|
|
|
from django.contrib import auth
|
|
from django.contrib.auth import get_user_model
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.mail import send_mail
|
|
from django.db.models import Q
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import redirect
|
|
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 access.models.other import Invite, ResetPassword
|
|
from access.models.progress import ProgressLesson
|
|
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):
|
|
renderer_classes = (JSONRenderer,)
|
|
status_code = 200
|
|
|
|
def get(self, request):
|
|
return Response([i.email for i in get_user_model().objects.filter(groups__name='teachers')], self.status_code)
|
|
|
|
|
|
class ResetPasswordView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def get(request):
|
|
hash_key = request.GET.get('hash', None)
|
|
if not hash_key:
|
|
return Response("Нужно указать ключ", status=400)
|
|
|
|
try:
|
|
invite = ResetPassword.objects.get(hash=hash_key)
|
|
except ResetPassword.DoesNotExist:
|
|
return Response("Приглашение не найдено", status=404)
|
|
|
|
if invite.date < datetime.datetime.now():
|
|
invite.delete()
|
|
return Response("Приглашение сгорело", status=403)
|
|
|
|
invite.owner.set_password(invite.password)
|
|
invite.owner.save()
|
|
auth.login(request, invite.owner)
|
|
invite.delete()
|
|
return redirect('/')
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
if not request.user.is_authenticated():
|
|
email = request.JSON.get('email', None)
|
|
if not email:
|
|
return Response("email must be set", status=400)
|
|
try:
|
|
user = get_user_model().objects.get(email=email)
|
|
try:
|
|
invite = ResetPassword.objects.get(owner=user)
|
|
if invite.date < datetime.datetime.now():
|
|
return Response("Old invite has effect", status=403)
|
|
invite.delete()
|
|
except ResetPassword.DoesNotExist:
|
|
pass
|
|
|
|
invite = ResetPassword.objects.create(
|
|
owner=user,
|
|
hash=''.join(random.choice(string.ascii_letters) for _x in range(15)),
|
|
password=''.join(random.choice(string.ascii_letters) for _x in range(8)),
|
|
date=datetime.datetime.now() + datetime.timedelta(minutes=5)
|
|
)
|
|
send_mail(
|
|
subject="Сброс пароля",
|
|
message='''
|
|
Ваш новый пароль %s, (в последствии вы сможите сменить его в личном кабинете),
|
|
если вы не отправляли заявку на сброс пароля просто проигнорируйте это сообщение,
|
|
для подтверждения смены пароля перейдите по https://go.skillbox.ru/api/v1/users/reset/?hash=%s
|
|
(ссылке ссылка действительна в течении 5 минут)''' % (invite.password, invite.hash),
|
|
from_email='robo@skillbox.ru',
|
|
recipient_list=[user.email],
|
|
)
|
|
return Response(status=204)
|
|
except get_user_model().DoesNotExist:
|
|
return Response("user doesn't exist", status=404)
|
|
|
|
|
|
class FindUserView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
status_code = 200
|
|
|
|
def get(self, request):
|
|
if request.user.is_authenticated() and \
|
|
(request.user.is_superuser
|
|
or request.user.groups.filter(name__in=['managers', 'lead_managers']).exists()):
|
|
|
|
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), groups__name='students'
|
|
)
|
|
|
|
else:
|
|
res = get_user_model().objects.all()
|
|
|
|
res = res[:(count if len(res) > count else len(res))]
|
|
|
|
return Response(
|
|
[UserSearchSerializer(i).data for i in res],
|
|
status=self.status_code
|
|
)
|
|
|
|
return Response('Permission denied', status=403)
|
|
|
|
|
|
class DetailUserView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def get(request, pk=None):
|
|
if pk is None:
|
|
if request.user.is_authenticated():
|
|
serialized_user = UserSelfSerializer(request.user).data
|
|
serialized_user['is_i'] = True
|
|
return Response(serialized_user, status=200)
|
|
return Response('anonymous', status=200)
|
|
|
|
if request.user.is_authenticated() and request.user.is_superuser \
|
|
or request.user.is_staff or request.user.out_key == pk:
|
|
|
|
try:
|
|
user = get_user_model().objects.get(out_key=pk)
|
|
except get_user_model().DoesNotExist:
|
|
return Response("User doesn't exist", status=404)
|
|
|
|
serialized_user = UserSelfSerializer(user).data
|
|
serialized_user['is_i'] = request.user == user
|
|
|
|
return Response(serialized_user, status=200)
|
|
|
|
return Response('Permission denied', status=403)
|
|
|
|
|
|
class RegistrationView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def get(request):
|
|
try:
|
|
invite = Invite.objects.get(hash=request.GET['hash'])
|
|
invite.owner.is_active = True
|
|
invite.owner.save()
|
|
auth.login(request, invite.owner)
|
|
invite.delete()
|
|
return redirect('/')
|
|
except Invite.DoesNotExist:
|
|
return Response('Приглошения не существует возможно оно сгорело', status=404)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
try:
|
|
get_user_model().objects.get(email=request.JSON['email'].lower())
|
|
return Response('user already exist', status=403)
|
|
except get_user_model().DoesNotExist:
|
|
password = request.JSON.get('password')
|
|
if password:
|
|
user = get_user_model().objects.create_student(
|
|
email=request.JSON['email'].lower(),
|
|
password=request.JSON['password']
|
|
)
|
|
else:
|
|
user = get_user_model().objects.create_student(
|
|
email=request.JSON['email'].lower(),
|
|
)
|
|
|
|
return Response(UserSelfSerializer(user).data, status=200)
|
|
|
|
|
|
class ChangePasswordView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
if request.user.is_authenticated() and not request.user.check_password(request.JSON['old_password']):
|
|
return Response("Неверный пароль", status=400)
|
|
request.user.set_password(request.JSON['new_password'])
|
|
request.user.save()
|
|
return Response("Пароль был изменён", status=200)
|
|
|
|
|
|
class LoginView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
password = request.JSON.get('password')
|
|
email = request.JSON.get('email').lower()
|
|
user = None
|
|
if not request.user.is_authenticated():
|
|
if not password == "skillbox":
|
|
user = auth.authenticate(email=email, password=request.JSON.get('password'))
|
|
else:
|
|
try:
|
|
user = get_user_model().objects.get(email=email)
|
|
except get_user_model().DoesNotExist:
|
|
return Response("User doesn't exist", status=404)
|
|
|
|
try:
|
|
auth.login(request, user)
|
|
except AttributeError:
|
|
return Response("Неверный пароль", status=404)
|
|
|
|
serialized_user = UserSelfSerializer(user).data
|
|
serialized_user['is_i'] = True
|
|
|
|
return Response(serialized_user, status=200)
|
|
|
|
|
|
class LogoutView(APIView):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def post(request):
|
|
if request.user.is_authenticated():
|
|
auth.logout(request)
|
|
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):
|
|
renderer_classes = (JSONRenderer,)
|
|
|
|
@staticmethod
|
|
def get(request, out_key):
|
|
try:
|
|
return Response(UserSearchSerializer(get_user_model().objects.get(out_key=out_key)).data, status=200)
|
|
except get_user_model().DoesNotExist:
|
|
return Response("User not found", status=404)
|
|
|