Merge branch 'new_lms_dev__refactor' into 'new_lms_dev'

Вынес прогресс пользователя в отдельное приложение

See merge request skillbox/go.skillbox.ru!87
feature/fix_generate_pass
Andrey 8 years ago
commit c03d805cd9
  1. 3
      access/admin.py
  2. 45
      access/migrations/0004_auto_20180129_0933.py
  3. 1
      access/models/__init__.py
  4. 46
      access/serializers.py
  5. 4
      access/urls.py
  6. 107
      access/views.py
  7. 1
      api_v1/urls.py
  8. 2
      csv/load_bills.py
  9. 4
      csv/load_comments.py
  10. 3
      csv/load_perm.py
  11. 4
      lms/settings.py
  12. 0
      progress/__init__.py
  13. 8
      progress/admin.py
  14. 6
      progress/apps.py
  15. 58
      progress/migrations/0001_initial.py
  16. 0
      progress/migrations/__init__.py
  17. 0
      progress/models.py
  18. 44
      progress/serializers.py
  19. 3
      progress/tests.py
  20. 11
      progress/urls.py
  21. 117
      progress/views.py

@ -1,12 +1,9 @@
from django.contrib import admin from django.contrib import admin
from access.models.other import Invite, Account, ResetPassword, UserActivity from access.models.other import Invite, Account, ResetPassword, UserActivity
from access.models.progress import ProgressLesson, Progress
from access.models.user import User from access.models.user import User
admin.site.register(User) admin.site.register(User)
admin.site.register(Account) admin.site.register(Account)
admin.site.register(Progress)
admin.site.register(Invite) admin.site.register(Invite)
admin.site.register(ResetPassword) admin.site.register(ResetPassword)
admin.site.register(ProgressLesson)
admin.site.register(UserActivity) admin.site.register(UserActivity)

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-29 09:33
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('access', '0003_useractivity'),
]
operations = [
migrations.AlterUniqueTogether(
name='progress',
unique_together=set([]),
),
migrations.RemoveField(
model_name='progress',
name='teacher',
),
migrations.RemoveField(
model_name='progress',
name='user',
),
migrations.AlterUniqueTogether(
name='progresslesson',
unique_together=set([]),
),
migrations.RemoveField(
model_name='progresslesson',
name='progress',
),
migrations.RemoveField(
model_name='progresslesson',
name='teacher',
),
migrations.DeleteModel(
name='Progress',
),
migrations.DeleteModel(
name='ProgressLesson',
),
]

@ -1,7 +1,6 @@
# encoding=utf-8 # encoding=utf-8
from .other import Account, Invite from .other import Account, Invite
from access.models.progress import Progress
from .user import User from .user import User

@ -2,52 +2,8 @@ from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from access.models.other import Account from access.models.other import Account
from access.models.progress import ProgressLesson
from access.models import Progress
from achievements.serialers import DiplomaSerializer, AchievementsSerializer from achievements.serialers import DiplomaSerializer, AchievementsSerializer
from courses.api import CourseProgressApi from progress.serializers import ProgressSerializer
class ProgressLessonSerializer(serializers.ModelSerializer):
teacher = serializers.SerializerMethodField()
class Meta:
model = ProgressLesson
exclude = ('id', 'progress')
@staticmethod
def get_teacher(self):
return self.teacher.get_full_name()
class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('name', 'email',)
@staticmethod
def get_name(self):
return self.user.get_full_name()
@staticmethod
def get_email(self):
return self.user.email
class ProgressSerializer(serializers.ModelSerializer):
lessons = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('lessons', 'course_token')
@staticmethod
def get_lessons(self):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class AccountSerializer(serializers.ModelSerializer): class AccountSerializer(serializers.ModelSerializer):

@ -13,8 +13,4 @@ urlpatterns = [
url(r'login/$', views.LoginView.as_view()), url(r'login/$', views.LoginView.as_view()),
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/$', views.UpdateProgress.as_view()),
url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', views.UploadCourseProgressUserView.as_view()),
url(r'progress_detail/(?P<token>[0-9A-Fa-f-]+)/$', views.CourseProgressUserView.as_view()),
url(r'progress_dynamic/(?P<token>[0-9A-Fa-f-]+)/$', views.CourseProgressDynamicView.as_view()),
] ]

@ -16,10 +16,7 @@ from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from access.models.other import Invite, ResetPassword from access.models.other import Invite, ResetPassword
from access.models.progress import ProgressLesson from access.serializers import UserSelfSerializer, UserSearchSerializer
from access.models import Progress
from access.serializers import UserSelfSerializer, UserSearchSerializer, ProgressLessonSerializer, \
ProgressAnalyticSerializer
from courses.api import CourseProgressApi from courses.api import CourseProgressApi
@ -236,41 +233,6 @@ class LogoutView(APIView):
return Response(status=204) 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)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
try:
p = Progress.objects.get(user=request.user, course_token=course_token)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
except ProgressLesson.DoesNotExist:
pv = ProgressLesson.objects.create(
date=datetime.datetime.now(),
teacher=p.teacher,
progress=p,
lesson_token=lesson_token,
)
pv.status = ProgressLesson.STATUSES.done
pv.save()
return Response(ProgressLessonSerializer(pv).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
class UserGuardView(APIView): class UserGuardView(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
@ -303,73 +265,6 @@ class UserGuardView(APIView):
return res_403 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): class MinUserView(APIView):
renderer_classes = (JSONRenderer,) renderer_classes = (JSONRenderer,)

@ -6,4 +6,5 @@ urlpatterns = [
url(r'library/', include('library.urls')), url(r'library/', include('library.urls')),
url(r'finance/', include('finance.urls')), url(r'finance/', include('finance.urls')),
url(r'storage/', include('storage.urls')), url(r'storage/', include('storage.urls')),
url(r'progress/', include('progress.urls')),
] ]

@ -15,7 +15,7 @@ django.setup()
from yandex_money.models import Payment from yandex_money.models import Payment
from finance.models import Bill, Invoice from finance.models import Bill, Invoice
from access.models import Progress from progress.models import Progress
from courses.models import Course from courses.models import Course
if __name__ == '__main__': if __name__ == '__main__':

@ -1,6 +1,4 @@
import csv import csv
import random
import string
import django import django
import os import os
@ -15,7 +13,7 @@ django.setup()
from storage.models import Comment, File from storage.models import Comment, File
from courses.models import Lesson from courses.models import Lesson
from access.models.progress import ProgressLesson, Progress from progress.models import ProgressLesson, Progress
if __name__ == '__main__': if __name__ == '__main__':
csv.field_size_limit(500 * 1024 * 1024) csv.field_size_limit(500 * 1024 * 1024)

@ -14,8 +14,7 @@ django.setup()
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from access.models.progress import ProgressLesson from progress.models import ProgressLesson, Progress
from access.models import Progress
from courses.models import Lesson, Course from courses.models import Lesson, Course

@ -113,6 +113,7 @@ apps = (
'library', 'library',
'achievements', 'achievements',
'config_app', 'config_app',
'progress',
) )
INSTALLED_APPS = libs + apps INSTALLED_APPS = libs + apps
@ -185,3 +186,6 @@ STATIC_URL = '/static/'
RAVEN_CONFIG = { RAVEN_CONFIG = {
'dsn': 'http://caaea487274f4e23a9107862484c79f3:3d463ad4717942508536f7a659921950@sentry.skillbox.ru/3' 'dsn': 'http://caaea487274f4e23a9107862484c79f3:3d463ad4717942508536f7a659921950@sentry.skillbox.ru/3'
} }
DEBUG = env('DEBUG')

@ -0,0 +1,8 @@
from django.contrib import admin
# Register your models here.
from progress.models import ProgressLesson, Progress
admin.site.register(Progress)
admin.site.register(ProgressLesson)

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ProgressConfig(AppConfig):
name = 'progress'
verbose_name = 'Прогресс'

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-01-29 09:31
from __future__ import unicode_literals
from django.conf import settings
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Progress',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hidden_lessons', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, unique=True, verbose_name='Токен урока'), default=[], size=None, verbose_name='Список скрытых уроков')),
('course_token', models.UUIDField(editable=False, verbose_name='Токен курса')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teacher_progress', to=settings.AUTH_USER_MODEL, verbose_name='Преподователь по умолчанию')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Студент')),
],
options={
'verbose_name': 'Прогресс пользователя',
'verbose_name_plural': 'Прогресс пользователя',
},
),
migrations.CreateModel(
name='ProgressLesson',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lesson_token', models.UUIDField(editable=False, verbose_name='Токен урока')),
('date', models.DateTimeField(blank=True, null=True, verbose_name='Дата зачтения задания')),
('status', models.CharField(choices=[('done', 'done'), ('wait', 'wait'), ('fail', 'fail')], default='wait', max_length=20)),
('comment_tokens', django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(editable=False, verbose_name='Токен комента'), default=[], size=None)),
('progress', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='progress.Progress')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Преподователь')),
],
options={
'verbose_name': 'Прохождение уроков',
'verbose_name_plural': 'Прохождение урока',
},
),
migrations.AlterUniqueTogether(
name='progresslesson',
unique_together=set([('progress', 'lesson_token')]),
),
migrations.AlterUniqueTogether(
name='progress',
unique_together=set([('user', 'course_token')]),
),
]

@ -0,0 +1,44 @@
from rest_framework import serializers
from progress.models import ProgressLesson, Progress
class ProgressLessonSerializer(serializers.ModelSerializer):
teacher = serializers.SerializerMethodField()
class Meta:
model = ProgressLesson
exclude = ('id', 'progress')
@staticmethod
def get_teacher(self):
return self.teacher.get_full_name()
class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('name', 'email',)
@staticmethod
def get_name(self):
return self.user.get_full_name()
@staticmethod
def get_email(self):
return self.user.email
class ProgressSerializer(serializers.ModelSerializer):
lessons = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('lessons', 'course_token')
@staticmethod
def get_lessons(self):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,11 @@
from django.conf.urls import url
from progress import views
urlpatterns = [
url(r'$', views.UpdateProgress.as_view()),
url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', views.UploadCourseProgressUserView.as_view()),
url(r'progress_detail/(?P<token>[0-9A-Fa-f-]+)/$', views.CourseProgressUserView.as_view()),
url(r'progress_dynamic/(?P<token>[0-9A-Fa-f-]+)/$', views.CourseProgressDynamicView.as_view()),
]

@ -0,0 +1,117 @@
import datetime
import csv
from django.http import HttpResponse
from django.shortcuts import render
# Create your views here.
from rest_framework.exceptions import ValidationError
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from courses.api import CourseProgressApi
from progress.models import Progress, ProgressLesson
from progress.serializers import ProgressLessonSerializer, ProgressAnalyticSerializer
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)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
try:
p = Progress.objects.get(user=request.user, course_token=course_token)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
except ProgressLesson.DoesNotExist:
pv = ProgressLesson.objects.create(
date=datetime.datetime.now(),
teacher=p.teacher,
progress=p,
lesson_token=lesson_token,
)
pv.status = ProgressLesson.STATUSES.done
pv.save()
return Response(ProgressLessonSerializer(pv).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
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)
Loading…
Cancel
Save