remotes/origin/feature/test_courses
Dmitriy Shesterkin 8 years ago
commit 41de0175e9
  1. 11
      access/serializers.py
  2. 6
      access/urls.py
  3. 21
      courses/models.py
  4. 5
      courses/serializers.py
  5. 13
      courses/tasks.py
  6. 2
      courses/urls.py
  7. 81
      courses/views.py
  8. 20
      finance/migrations/0003_auto_20180315_1358.py
  9. 2
      finance/models.py
  10. 6
      finance/signals.py
  11. 6
      finance/urls.py
  12. 185
      finance/views.py
  13. 2
      lms/settings.py
  14. 6
      lms/urls.py
  15. 23
      progress/serializers.py
  16. 63
      progress/views.py
  17. 22
      storage/views.py

@ -1,10 +1,9 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.generics import get_object_or_404
from access.models.other import Account
from achievements.serialers import DiplomaSerializer, AchievementsSerializer
from progress.serializers import ProgressSerializer
from progress.serializers import SecureProgressSerializer
class AccountSerializer(serializers.ModelSerializer):
@ -22,13 +21,13 @@ class AccountSerializer(serializers.ModelSerializer):
class UserSelfSerializer(serializers.ModelSerializer):
account = serializers.SerializerMethodField()
groups = serializers.SerializerMethodField()
progress = serializers.SerializerMethodField()
progresses = serializers.SerializerMethodField()
diplomas = serializers.SerializerMethodField()
achievements = serializers.SerializerMethodField()
class Meta:
model = get_user_model()
fields = ('out_key', 'email', 'first_name', 'last_name', 'progress', 'achievements',
fields = ('out_key', 'email', 'first_name', 'last_name', 'progresses', 'achievements',
'account', 'groups', 'is_staff', 'is_superuser', 'diplomas', 'is_active')
@staticmethod
@ -48,8 +47,8 @@ class UserSelfSerializer(serializers.ModelSerializer):
return [group.name for group in self.groups.all()]
@staticmethod
def get_progress(self):
return [ProgressSerializer(i).data for i in self.progress_set.all()]
def get_progresses(self):
return [SecureProgressSerializer(i).data for i in self.progress_set.all()]
class UserProfileSerializer(serializers.ModelSerializer):

@ -18,10 +18,6 @@ urlpatterns = [
url(r'logout/$', views.LogoutView.as_view()),
url(r'reset/$', views.ResetPasswordView.as_view()),
url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.UploadCourseProgressUserView.as_view()),
url(
r'management/password/$',
views.ManagementPassword.as_view(),
name='management-password'
)
url(r'management/password/$', views.ManagementPassword.as_view(), name='management-password')
]

@ -154,19 +154,26 @@ class Course(models.Model):
lesson_list += list(topic.lesson_set.all())
return lesson_list
def get_next(self, lesson: Lesson) -> Lesson:
def get_next(self, lesson: Lesson, f=None) -> Lesson:
lessons = self.get_lesson_list()
try:
return lessons[lessons.index(lesson)]
n = lessons[lessons.index(lesson)+1]
if f is None or f(n):
return n
else:
return self.get_next(n, f)
except IndexError:
pass
def get_previous(self, lesson: Lesson):
def get_previous(self, lesson: Lesson, f=None):
lessons = self.get_lesson_list()
try:
return lessons[lessons.index(lesson) - 2]
except IndexError:
pass
idx = lessons.index(lesson) - 1
if idx > -1:
prev = lessons[idx]
if f is None or f(prev):
return prev
else:
return self.get_previous(prev, f)
def get_first_lesson(self) -> Lesson:
lessons = self.get_lesson_list()

@ -23,11 +23,16 @@ class MiniLessonSerializer(serializers.ModelSerializer):
class LessonSerializer(MiniLessonSerializer):
course_slug = serializers.SerializerMethodField()
class Meta:
model = Lesson
exclude = ('id', 'topic', 'key')
@staticmethod
def get_course_slug(self):
return self.topic.course.slug
class TeacherLessonSerializer(MiniLessonSerializer):
topic_sort = serializers.SerializerMethodField()

@ -0,0 +1,13 @@
from progress.models import ProgressLesson, Progress
from django.contrib.auth import get_user_model
def add_lesson(user_out_key: str, course_token: str, lesson_token: str, teacher_key: str, is_hm: bool):
p = Progress.objects.get(course_token=course_token, user__out_key=user_out_key)
ProgressLesson.objects.get_or_create(
progress=p,
lesson_token=lesson_token,
checker=get_user_model().objects.get(out_key=(teacher_key if is_hm else user_out_key)),
)

@ -3,8 +3,8 @@ from django.conf.urls import url
from courses import views as views
urlpatterns = [
url(r'vertex/(?P<token>.+)/$', views.LessonDetail.as_view()),
url(r'lesson/teacher/(?P<token>.+)/$', views.LessonInfoView.as_view()),
url(r'lesson/(?P<token>.+)/$', views.LessonDetail.as_view()),
url(r'tree/(?P<slug>.+)/$', views.TreeView.as_view()),
url(r'detail/(?P<slug>.+)/$', views.CourseDetailView.as_view()),
url(r'^$', views.CourseListView.as_view()),

@ -1,3 +1,5 @@
from jwt import DecodeError
from courses.models import Course, Lesson
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
@ -5,7 +7,10 @@ from rest_framework.views import APIView
from django.contrib.auth import get_user_model
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer, TeacherLessonSerializer
from progress.models import ProgressLesson
import jwt
from courses.tasks import add_lesson
from lms import settings
class TreeView(APIView):
@ -84,7 +89,7 @@ class LessonInfoView(APIView):
lesson = Lesson.objects.get(token=token)
except Lesson.DoesNotExist:
return Response('Урок не найден', status=404)
if request.user.is_authenticated and request.user.out_key in lesson.topic.course.teacher_tokens:
if request.user.is_authenticated:
return Response(TeacherLessonSerializer(lesson).data, self.status_code)
return Response("Пользователь не является преподователем по курсу", status=403)
@ -93,33 +98,53 @@ class LessonDetail(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request, token):
def post(request, token):
jwt_token = request.JSON.get('jwt_token', None)
try:
lesson = Lesson.objects.get(token=token)
except Lesson.DoesNotExist:
return Response("Lesson doesn't exist", status=404)
if not lesson.free and not ProgressLesson.objects.filter(lesson_token=lesson.token).exists():
previous_lesson = lesson.topic.course.get_previous(lesson)
if not previous_lesson is None or not ProgressLesson.objects.filter(
lesson_token=previous_lesson.token, status=ProgressLesson.STATUSES.done).exists():
return Response("Lesson doesn't access", status=403)
# TODO: Доделать систему прав на курс
res = LessonSerializer(lesson).data
# progress = vertex.course.progress_set.filter(user=request.user)
# try:
# if progress.exists():
# next_vertex = vertex.get_next(progress[0].get_template())
# if next_vertex:
# res['next'] = MiniVertexSerializer(next_vertex).data
# res['is_in_progress'] = vertex in progress[0].get_objects_in_progress()
# else:
# res['next'] = MiniVertexSerializer(vertex.get_next(vertex.course.route)).data
# except Thread.DoesNotExist or Vertex.DoesNotExist:
# res['next'] = MiniVertexSerializer(vertex.get_next(vertex.course.route)).data
return Response(res, status=200)
return Response("Урока не существует", status=404)
l = LessonSerializer(lesson).data
try:
payload = None if jwt_token is None\
else jwt.decode(jwt_token, settings.COURSE_PROGRESS_SECRET_KEY, algorithms=['HS256'])
except DecodeError:
payload = None
course = lesson.topic.course
if payload is None:
if not lesson.free:
return Response("Bad token", status=400)
else:
return Response(l, status=200)
prev_lesson = course.get_previous(lesson, (lambda x: not x.is_hm) if payload['only_watch'] else None)
next_lesson = course.get_next(lesson, (lambda x: not x.is_hm) if payload['only_watch'] else None)
if not prev_lesson is None:
l['prev_token'] = prev_lesson.token
if not next_lesson is None:
l['next_token'] = next_lesson.token
new_lesson = False
for payload_lesson in payload['lessons']:
if payload_lesson['lesson_token'] == str(lesson.token):
return Response(l, status=200)
if not prev_lesson is None and str(prev_lesson.token) == payload_lesson['lesson_token']:
new_lesson = True if prev_lesson is None else \
(payload_lesson['status'] == "done" or payload_lesson['status'] == "wait")
if not new_lesson:
return Response("Permission denied", status=403)
#TODO Задача для селери
add_lesson(request.user.out_key, course.token, lesson.token, course.get_teacher(), lesson.is_hm)
return Response(l, status=200)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-15 13:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0002_auto_20180202_1301'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='real_price',
field=models.FloatField(blank=True, editable=False, help_text='Сумма, минус комиссия', null=True, verbose_name='Полученная сумма'),
),
]

@ -44,7 +44,7 @@ class Invoice(models.Model):
)
status = models.CharField(verbose_name='Статус', max_length=1, default='W', choices=BILL_STATUSES)
price = models.IntegerField(verbose_name='Сумма', editable=False, null=True, blank=True)
real_price = models.IntegerField(verbose_name='Полученная сумма', null=True, blank=True,
real_price = models.FloatField(verbose_name='Полученная сумма', null=True, blank=True,
help_text='Сумма, минус комиссия', editable=False)
method = models.CharField(verbose_name='Способ оплаты', max_length=2, default='Y', choices=BILL_METHOD)
key = models.CharField(verbose_name='Ключ платежа', max_length=255, editable=False, blank=True)

@ -36,7 +36,7 @@ def invoice_signal(instance, **kwargs):
user=instance.bill.user,
)
except Progress.DoesNotExist:
p=Progress.objects.create(
p = Progress.objects.create(
course_token=instance.bill.course_token,
user=instance.bill.user,
teacher=get_user_model().objects.get(out_key=course.get_teacher())
@ -54,7 +54,7 @@ def invoice_signal(instance, **kwargs):
% (course.title, settings.DOMAIN, course.slug),
'robo@skillbox.ru',
[instance.bill.user.email],
cc=[instance.bill.opener.email],
bcc=[instance.bill.opener.email],
reply_to=[instance.bill.opener.email],
)
else:
@ -63,7 +63,7 @@ def invoice_signal(instance, **kwargs):
'''Курс "%s" был забронирован''' % course.title,
'robo@skillbox.ru',
[instance.bill.user.email],
cc=[instance.bill.opener.email],
bcc=[instance.bill.opener.email],
reply_to=[instance.bill.opener.email],
)
msg.send()

@ -2,10 +2,10 @@ from django.conf.urls import url
from finance import views
urlpatterns = [
url(r'bills/([0-9]{1,99})/$', views.BillDetailView.as_view()),
url(r'payment/([0-9]{1,99})/$', views.YandexPay.as_view()),
url(r'bills_find/$', views.FindBillView.as_view()),
url(r'bills/$', views.BillListView.as_view(), name='bills'),
url(r'bills/([0-9]{1,99})/$', views.BillDetailView.as_view()),
url(r'bills_find/$', views.FindBillView.as_view()),
url(r'yandex/fail/$', views.YandexFailView.as_view()),
url(r'invoices/$', views.get_invoices),
]
]

@ -1,10 +1,9 @@
import csv
import logging
import datetime
import dicttoxml
import requests
from django.contrib.auth import get_user_model
from django.core.mail import EmailMessage
from django.db.models import Q
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import redirect
@ -14,11 +13,13 @@ from rest_framework.views import APIView
from yandex_money.models import Payment
from django.conf import settings
from courses.models import Course
from courses.api import CourseParamsApi
from finance.models import Bill, Invoice
from finance.serializers import BillSerializer, InvoiceSerializer
from lms.global_decorators import transaction_decorator
from lms.tools import get_real_name
from django.utils import timezone
logger_yandex = logging.getLogger('yandex_money')
@ -28,11 +29,6 @@ class BillListView(APIView):
@staticmethod
def get(request):
"""
This API endpoint return list of bills.
---
Returns a list of accounts for an authorized user or responsible user
"""
if request.user.is_authenticated:
return Response(
[BillSerializer(i).data for i in Bill.objects.filter(Q(user=request.user) | Q(opener=request.user))],
@ -46,28 +42,49 @@ class BillListView(APIView):
or request.user.is_superuser):
bill = request.JSON.get('bill')
children = request.JSON.get('children', [])
bill_kwarg = dict()
if bill:
bill_kwarg['user'] = get_user_model().objects.get(email=bill['user'])
bill_kwarg['opener'] = get_user_model().objects.get(email=bill['opener'])
bill_kwarg['description'] = bill['description']
bill_kwarg['comment'] = bill['comment']
bill_kwarg['course_token'] = bill['course_token']
bill_obj, is_create = Bill.objects.update_or_create(**bill_kwarg)
invoices = bill_obj.invoice_set.all()
user = get_user_model().objects.get(email=bill['user'])
opener = get_user_model().objects.get(email=bill['opener'])
description = bill['description']
comment = bill['comment']
course_token = bill['course_token']
try:
bill_obj = Bill.objects.get(user=user, course_token=course_token)
except Bill.DoesNotExist:
bill_obj = Bill.objects.create(user=user, course_token=course_token)
bill_obj.opener = opener
bill_obj.description = description
bill_obj.comment = comment
bill_obj.save()
for i in children:
i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD)
i['status'] = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES)
i['bill'] = bill_obj
i['yandex_pay'] = None
invoice, _is_create = Invoice.objects.update_or_create(**i)
if i['method'] == 'Y':
yandex_pay, _is_create = Payment.objects.get_or_create(
status = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES)
try:
invoice_id = i['id']
except KeyError:
invoice_id = None
try:
if not invoice_id is None:
invoice = Invoice.objects.get(id=i['id'])
if invoice.status == "P" or invoice.status == status:
continue
else:
raise Invoice.DoesNotExist
except Invoice.DoesNotExist:
i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD)
i['status'] = status
i['bill'] = bill_obj
i['yandex_pay'] = None
invoice = Invoice.objects.create(**i)
if i['method'] == 'Y' and invoice.yandex_pay is None:
yandex_pay = Payment.objects.create(
order_amount=i['price'],
order_number=invoice.id,
shop_amount=0,
customer_number=bill_obj.user.id,
user=bill_obj.user,
@ -75,9 +92,21 @@ class BillListView(APIView):
)
invoice.yandex_pay = yandex_pay
invoice.save()
invoices = [j for j in invoices if not j.id == invoice.id]
[i.delete() for i in invoices]
msg = EmailMessage(
'Выставлен новый счёт.',
'''Менеджер %s выставил счёт пользователю %s на курс "%s".'''
% (
invoice.bill.opener.get_full_name(),
invoice.bill.user.email,
Course.objects.get(token=invoice.bill.course_token).title,
),
'robo@skillbox.ru',
[invoice.bill.opener.email],
bcc=['dmitry.dolya@skillbox.ru'],
)
msg.send()
res = {
"bill": BillSerializer(bill_obj).data,
@ -163,7 +192,16 @@ class YandexPay(APIView):
'shopFailURL': settings.YANDEX_MONEY_FAIL_URL,
})
logger_yandex.info(r)
msg = EmailMessage(
'Пользователь перешёл на страницу оплаты.',
'''Пользователь "%s" перешёл на страницу оплаты курса "%s".'''
% (pay.invoice.bill.user.email, Course.objects.get(token=pay.invoice.bill.course_token).title),
'robo@skillbox.ru',
[pay.invoice.bill.opener.email],
bcc=['dmitry.dolya@skillbox.ru'],
)
msg.send()
return redirect(r.url)
@ -183,8 +221,8 @@ def get_invoices(request):
file_name = file_name + "__to_%s" % date_to if date_to else file_name
invoices = Invoice.objects.filter(method="Y", status="F")
invoices = invoices.filter(date__lt=date_to) if date_to else invoices
invoices = invoices.filter(date__gte=date_from) if date_from else invoices
invoices = invoices.filter(yandex_pay__performed_datetime__lt=date_to) if date_to else invoices
invoices = invoices.filter(yandex_pay__performed_datetime__gte=date_from) if date_from else invoices
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % file_name
@ -195,8 +233,8 @@ def get_invoices(request):
for i in invoices.order_by('-date'):
course_api = CourseParamsApi(i.bill.course_token)
writer.writerow([
i.date.date(),
i.date.time(),
i.yandex_pay.performed_datetime.date(),
i.yandex_pay.performed_datetime.time(),
i.bill.user.email,
i.bill.user.get_full_name(),
course_api.get_slug_and_title()['title'],
@ -219,38 +257,53 @@ class YandexCheckView(APIView):
val = i.split('=')[1]
data[key] = val
logger_yandex.info(data)
logger_yandex.info('Проверка платежа запрос', exc_info=True, extra={
'request': data,
})
try:
pay = Payment.objects.get(order_number=data['orderNumber'])
except Payment.DoesNotExist:
logger_yandex.error("Payment with id=%s not found" % data['orderNumber'])
logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={
'request': "Payment with id=%s not found" % data['orderNumber'],
})
return Response(status=204)
if not pay.status == Payment.STATUS.PROCESSED:
logger_yandex.error("Payment with id=%s have status %s" % (data['orderNumber'], pay.status))
logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={
'request': "Payment with id=%s have status %s" % (data['orderNumber'], pay.status),
})
return Response(status=204)
if not pay.shop_id == int(data['shopId']):
logger_yandex.error("ShopId=%s not match" % (data['shopId'],))
logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={
'request': "ShopId=%s not match" % (data['shopId'],),
})
return Response(status=204)
if not pay.scid == int(data['scid']):
logger_yandex.error("scid=%s not match" % (data['scid'],))
logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={
'request': "scid=%s not match" % (data['scid'],)
})
return Response(status=204)
if not pay.order_amount == float(data['orderSumAmount']):
logger_yandex.error("Expected amount is %s received amount is %s"
% (pay.order_amount, data['orderSumAmount']))
logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={
'request': "Expected amount is %s received amount is %s"
% (pay.order_amount, data['orderSumAmount']),
})
return Response(status=204)
# TODO Нужно решение
# pay.invoice_id = int(data['invoiceId'])
# pay.save()
now = timezone.now()
pay.performed_datetime = now.isoformat()
pay.save()
xml_res = """<checkOrderResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s" orderSumAmount="%s"/>
""" % (datetime.datetime.now(), str(data['invoiceId']), str(pay.shop_id), str(pay.order_amount))
xml_res = """<checkOrderResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s"/>
""" % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id))
logger_yandex.info(xml_res)
logger_yandex.info('Проверка платежа ответ', exc_info=True, extra={
'response': xml_res,
})
return HttpResponse(xml_res, content_type='application/xml')
@ -269,27 +322,38 @@ class YandexAvisoView(APIView):
try:
pay = Payment.objects.get(order_number=data['orderNumber'])
except Payment.DoesNotExist:
logger_yandex.error("Payment with invoice_id=%s not found" % data['orderNumber'])
logger_yandex.error('Ошибка подтверждения платежа', exc_info=True, extra={
'request': "Payment with invoice_id=%s not found" % data['orderNumber'],
})
return Response(status=204)
logger_yandex.info('Get success pay with invoice_id(yandex) %s' % pay.invoice_id)
logger_yandex.info('Подтверждение платежа запрос', exc_info=True, extra={
'request': 'Get success pay with invoice_id(yandex) %s' % str(data['invoiceId']),
})
pay.shop_amount = data['shopSumAmount']
pay.status = Payment.STATUS.SUCCESS
now = timezone.now()
pay.performed_datetime = now.isoformat()
pay.save()
xml_res = """<paymentAvisoResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s"/>
""" % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id))
xml_res = dicttoxml.dicttoxml({
'code': 0,
'shopId':int(pay.shop_id),
'invoiceId': int(data['invoiceId']),
'orderSumAmount': pay.order_amount,
'performedDatetime': datetime.datetime.now(),
logger_yandex.info('Подтверждение платежа ответ', exc_info=True, extra={
'response': xml_res,
})
"""<paymentAvisoResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s" orderSumAmount="%s"/>
""" % (datetime.datetime.now(), str(data['invoiceId']), str(pay.shop_id), str(pay.order_amount))
logger_yandex.info(xml_res)
msg = EmailMessage(
'Успешная оплата.',
'''Пользователь "%s", перевёл %s рублей. Номер платежа в яндекс кассе %s'''
% (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])),
'robo@skillbox.ru',
[pay.invoice.bill.opener.email],
bcc=['dmitry.dolya@skillbox.ru', 'vera.procenko@skillbox.ru'],
)
msg.send()
return HttpResponse(xml_res, content_type='application/xml')
@ -307,4 +371,13 @@ class YandexFailView(APIView):
logger_yandex.error(data)
return redirect(to=settings.DOMAIN)
return redirect(to=settings.DOMAIN)
class DemoYandexCheckView(YandexCheckView):
"""для тестирования платежей"""
pass
class DemoYandexAvisoView(YandexAvisoView):
pass

@ -70,6 +70,8 @@ DATABASES = {
'default': env.db(),
}
COURSE_PROGRESS_SECRET_KEY = "!gf?s3@4Hr5#J#&%Kfr@56s"
SESSION_ENGINE = 'redis_sessions.session'
CELERY_EMAIL_CHUNK_SIZE = 1

@ -1,7 +1,7 @@
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from finance.views import YandexCheckView, YandexAvisoView
from finance.views import YandexCheckView, YandexAvisoView, DemoYandexCheckView, DemoYandexAvisoView
from django.conf import settings
@ -12,5 +12,7 @@ urlpatterns = [
url(r'^static/(?P<path>.*)/$', serve, {'document_root': settings.STATIC_ROOT}),
url(r'^wallet/pay/check/$', YandexCheckView.as_view(), name='yandex_money_check'),
url(r'^wallet/pay/result/$', YandexAvisoView.as_view(), name='yandex_money_notice'),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^yandex-money/check/$', DemoYandexCheckView.as_view()),
url(r'^yandex-money/aviso/$', DemoYandexAvisoView.as_view())
]

@ -1,6 +1,8 @@
from rest_framework import serializers
from progress.models import Progress, ProgressLesson
import jwt
from django.conf import settings
class ProgressSerializer(serializers.ModelSerializer):
@ -15,6 +17,23 @@ class ProgressSerializer(serializers.ModelSerializer):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class SecureProgressSerializer(serializers.ModelSerializer):
jwt_token = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('jwt_token', )
@staticmethod
def get_jwt_token(self):
payload = {
'lessons': [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()],
'course_token': str(self.course_token),
'only_watch': self.only_watch,
}
return jwt.encode(payload, settings.COURSE_PROGRESS_SECRET_KEY, algorithm='HS256')
class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
@ -47,8 +66,8 @@ class ProgressLessonSerializer(serializers.ModelSerializer):
@staticmethod
def get_student(self):
return {'name': self.progress.user.get_full_name(), "out_key": self.progress.user.out_key}
return {'name': self.progress.user.get_full_name(), "out_key": str(self.progress.user.out_key)}
@staticmethod
def get_course_token(self):
return self.progress.course_token
return str(self.progress.course_token)

@ -14,7 +14,8 @@ 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 progress.serializers import ProgressAnalyticSerializer, ProgressLessonSerializer, ProgressSerializer, \
SecureProgressSerializer
from courses.api import CourseProgressApi, CourseParamsApi
from progress.tasks import add_next_lesson
@ -126,7 +127,7 @@ class TeacherUpdateProgress(APIView):
pv.status = ProgressLesson.STATUSES.fail
msg = EmailMessage(
'Ваша работа отправлена на доработку',
'''Преподователь "%s" отклонил вашу работу''' % request.user.get_full_name(),
'''Преподаватель "%s" отклонил вашу работу''' % request.user.get_full_name(),
'robo@skillbox.ru',
[student.email],
)
@ -175,47 +176,45 @@ class StudentUpdateProgress(APIView):
@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
if lesson_token is None:
return Response('Не передан токен урока', status=400)
p = Progress.objects.get(user=student, course_token=course_token)
student = request.user
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
try:
pv = ProgressLesson.objects.get(
progress__user=student,
lesson_token=lesson_token,
)
if not pv.status == ProgressLesson.STATUSES.wait:
if pv.checker == p.teacher and not comment is None:
pv.status = ProgressLesson.STATUSES.wait
pv.comment_tokens.append(comment)
if pv.status == ProgressLesson.STATUSES.done:
return Response(SecureProgressSerializer(pv.progress).data, status=200)
elif pv.checker == p.user:
pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now()
if not pv.status == ProgressLesson.STATUSES.wait:
if pv.checker == pv.progress.user:
pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now()
else:
raise ValueError("Этого никогда не должно происходить, но я уверен, что произойдёт")
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)
pv.save()
elif comment is None:
return Response("Не преложен комментарий", status=400)
else:
return Response("Ошибка прав доступа", status=403)
return Response("В настоящее время, мы уже проверяем одно из ваших домашних заданий. <br> Как "
"только оно будет успешно сдано - вы сможете продолжить.", status=403)
except ProgressLesson.DoesNotExist:
return Response('Урок не проходится этим пользователем', status=403)
elif not comment is None:
pv.comment_tokens.append(comment)
if pv.status == ProgressLesson.STATUSES.done:
# TODO: Ассинхроннаязадача для celery
add_next_lesson(p)
pv.save()
return Response(ProgressSerializer(p).data, status=200)
return Response(SecureProgressSerializer(pv.progress).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
@ -292,6 +291,7 @@ class SetProgress(APIView):
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:
@ -319,6 +319,9 @@ class SetProgress(APIView):
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()):

@ -1,3 +1,6 @@
import base64
import json
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
@ -44,12 +47,19 @@ class CommentView(APIView):
@staticmethod
def get(request):
token = request.GET.get('token', None)
base64_tokens = request.GET.get('base64_tokens', None)
if not token:
if not base64_tokens:
return Response("Attribute token not set", status=400)
try:
return Response(CommentSerializer(Comment.objects.get(token=token)).data, status=200)
except Comment.DoesNotExist:
return Response("Comment not found", status=404)
tokens = json.loads(base64.b64decode(base64_tokens).decode('utf-8'))
comments = []
for token in tokens:
try:
comment = Comment.objects.get(token=token)
comments.append(comment)
except Comment.DoesNotExist:
pass
return Response([CommentSerializer(comment).data for comment in comments], status=200)

Loading…
Cancel
Save