Merge branch 'current_branch' into 'dev'

Current branch

See merge request !212
remotes/origin/dev2
Andrey 8 years ago
commit 95b9f40a9f
  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. 79
      courses/views.py
  8. 2
      lms/settings.py
  9. 23
      progress/serializers.py
  10. 29
      progress/views.py

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

@ -18,10 +18,6 @@ urlpatterns = [
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_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.UploadCourseProgressUserView.as_view()), url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.UploadCourseProgressUserView.as_view()),
url( url(r'management/password/$', views.ManagementPassword.as_view(), name='management-password')
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()) lesson_list += list(topic.lesson_set.all())
return lesson_list return lesson_list
def get_next(self, lesson: Lesson) -> Lesson: def get_next(self, lesson: Lesson, f=None) -> Lesson:
lessons = self.get_lesson_list() lessons = self.get_lesson_list()
try: try:
return lessons[lessons.index(lesson)] n = lessons[lessons.index(lesson)+1]
if f is None or f(lesson):
return n
else:
return self.get_next(lesson, f)
except IndexError: except IndexError:
pass pass
def get_previous(self, lesson: Lesson): def get_previous(self, lesson: Lesson, f=None):
lessons = self.get_lesson_list() lessons = self.get_lesson_list()
try: idx = lessons.index(lesson) - 1
return lessons[lessons.index(lesson) - 2] if idx > -1:
except IndexError: prev = lessons[idx]
pass if f is None or f(lesson):
return prev
else:
return self.get_previous(prev, f)
def get_first_lesson(self) -> Lesson: def get_first_lesson(self) -> Lesson:
lessons = self.get_lesson_list() lessons = self.get_lesson_list()

@ -23,11 +23,16 @@ class MiniLessonSerializer(serializers.ModelSerializer):
class LessonSerializer(MiniLessonSerializer): class LessonSerializer(MiniLessonSerializer):
course_slug = serializers.SerializerMethodField()
class Meta: class Meta:
model = Lesson model = Lesson
exclude = ('id', 'topic', 'key') exclude = ('id', 'topic', 'key')
@staticmethod
def get_course_slug(self):
return self.topic.course.slug
class TeacherLessonSerializer(MiniLessonSerializer): class TeacherLessonSerializer(MiniLessonSerializer):
topic_sort = serializers.SerializerMethodField() 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 from courses import views as views
urlpatterns = [ urlpatterns = [
url(r'vertex/(?P<token>.+)/$', views.LessonDetail.as_view()),
url(r'lesson/teacher/(?P<token>.+)/$', views.LessonInfoView.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'tree/(?P<slug>.+)/$', views.TreeView.as_view()),
url(r'detail/(?P<slug>.+)/$', views.CourseDetailView.as_view()), url(r'detail/(?P<slug>.+)/$', views.CourseDetailView.as_view()),
url(r'^$', views.CourseListView.as_view()), url(r'^$', views.CourseListView.as_view()),

@ -1,3 +1,5 @@
from jwt import DecodeError
from courses.models import Course, Lesson from courses.models import Course, Lesson
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response 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 django.contrib.auth import get_user_model
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer, TeacherLessonSerializer 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): class TreeView(APIView):
@ -93,33 +98,53 @@ class LessonDetail(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)
@staticmethod @staticmethod
def get(request, token): def post(request, token):
jwt_token = request.JSON.get('jwt_token', None)
try: try:
lesson = Lesson.objects.get(token=token) lesson = Lesson.objects.get(token=token)
except Lesson.DoesNotExist: except Lesson.DoesNotExist:
return Response("Lesson doesn't exist", status=404) return Response("Урока не существует", status=404)
if not lesson.free and not ProgressLesson.objects.filter(lesson_token=lesson.token).exists(): l = LessonSerializer(lesson).data
previous_lesson = lesson.topic.course.get_previous(lesson)
try:
if not previous_lesson is None or not ProgressLesson.objects.filter( payload = None if jwt_token is None\
lesson_token=previous_lesson.token, status=ProgressLesson.STATUSES.done).exists(): else jwt.decode(jwt_token, settings.COURSE_PROGRESS_SECRET_KEY, algorithms=['HS256'])
return Response("Lesson doesn't access", status=403) except DecodeError:
payload = None
# TODO: Доделать систему прав на курс
course = lesson.topic.course
res = LessonSerializer(lesson).data
# progress = vertex.course.progress_set.filter(user=request.user) if payload is None:
# try: if not lesson.free:
# if progress.exists(): return Response("Bad token", status=400)
# next_vertex = vertex.get_next(progress[0].get_template())
# if next_vertex: else:
# res['next'] = MiniVertexSerializer(next_vertex).data return Response(l, status=200)
# res['is_in_progress'] = vertex in progress[0].get_objects_in_progress()
# else: prev_lesson = course.get_previous(lesson, (lambda x: not x.is_hm) if payload['only_watch'] else None)
# res['next'] = MiniVertexSerializer(vertex.get_next(vertex.course.route)).data next_lesson = course.get_next(lesson, (lambda x: not x.is_hm) if payload['only_watch'] else None)
# except Thread.DoesNotExist or Vertex.DoesNotExist:
# res['next'] = MiniVertexSerializer(vertex.get_next(vertex.course.route)).data if not prev_lesson is None:
l['prev_token'] = prev_lesson.token
return Response(res, status=200)
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)

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

@ -1,6 +1,8 @@
from rest_framework import serializers from rest_framework import serializers
from progress.models import Progress, ProgressLesson from progress.models import Progress, ProgressLesson
import jwt
from django.conf import settings
class ProgressSerializer(serializers.ModelSerializer): class ProgressSerializer(serializers.ModelSerializer):
@ -15,6 +17,23 @@ class ProgressSerializer(serializers.ModelSerializer):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()] 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): class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField() name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField() email = serializers.SerializerMethodField()
@ -47,8 +66,8 @@ class ProgressLessonSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_student(self): 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 @staticmethod
def get_course_token(self): 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 courses.models import Course
from progress.models import ProgressLesson, Progress 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 courses.api import CourseProgressApi, CourseParamsApi
from progress.tasks import add_next_lesson from progress.tasks import add_next_lesson
@ -175,28 +176,25 @@ class StudentUpdateProgress(APIView):
@staticmethod @staticmethod
def post(request): def post(request):
lesson_token = request.JSON.get('lesson_token', None) lesson_token = request.JSON.get('lesson_token', None)
course_token = request.JSON.get('course_token', None)
comment = request.JSON.get('comment', None) comment = request.JSON.get('comment', None)
if lesson_token is None or course_token is None: if lesson_token is None:
return Response('Не передан слаг курса или токен урока', status=400) return Response('Не передан токен урока', status=400)
try:
student = request.user
p = Progress.objects.get(user=student, course_token=course_token) student = request.user
try: try:
pv = ProgressLesson.objects.get( pv = ProgressLesson.objects.get(
progress=p, progress__user=student,
lesson_token=lesson_token, lesson_token=lesson_token,
) )
if not pv.status == ProgressLesson.STATUSES.wait: if not pv.status == ProgressLesson.STATUSES.wait:
if pv.checker == p.teacher and not comment is None: if pv.checker == pv.progress.teacher and not comment is None:
pv.status = ProgressLesson.STATUSES.wait pv.status = ProgressLesson.STATUSES.wait
pv.comment_tokens.append(comment) pv.comment_tokens.append(comment)
elif pv.checker == p.user: elif pv.checker == pv.progress.user:
pv.status = ProgressLesson.STATUSES.done pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now() pv.finish_date = datetime.datetime.now()
@ -206,16 +204,9 @@ class StudentUpdateProgress(APIView):
pv.save() pv.save()
else: else:
return Response("Ошибка прав доступа", status=403) pass
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) return Response(SecureProgressSerializer(pv.progress).data, status=200)
except Progress.DoesNotExist: except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404) return Response('Не найден прогресс по заданным параметрам', status=404)

Loading…
Cancel
Save