# Conflicts: # access/views.pyfeature/fix_generate_pass
commit
a541f879c2
21 changed files with 303 additions and 131 deletions
@ -1,12 +1,9 @@ |
||||
from django.contrib import admin |
||||
from access.models.other import Invite, Account, ResetPassword, UserActivity |
||||
from access.models.progress import ProgressLesson, Progress |
||||
from access.models.user import User |
||||
|
||||
admin.site.register(User) |
||||
admin.site.register(Account) |
||||
admin.site.register(Progress) |
||||
admin.site.register(Invite) |
||||
admin.site.register(ResetPassword) |
||||
admin.site.register(ProgressLesson) |
||||
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 |
||||
|
||||
from .other import Account, Invite |
||||
from access.models.progress import Progress |
||||
from .user import User |
||||
|
||||
|
||||
|
||||
@ -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…
Reference in new issue