From 554c1b8c6cdc0dfbd34b9d25ddfdb8504fc24a56 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 27 Nov 2017 10:36:27 +0300 Subject: [PATCH] threads update --- access/models.py | 10 ++--- config_app/management/commands/set_seq.py | 22 +++++++++++ courses/models.py | 4 +- courses/views.py | 11 +++++- csv/load_student_teachers_threads.py | 12 +----- journals/serilizers.py | 8 +++- journals/urls.py | 1 + journals/views.py | 46 ++++++++++++++++++++++- lms/settings.py | 9 ++++- lms/tools.py | 6 ++- storage/models.py | 4 +- storage/serializers.py | 10 +++++ 12 files changed, 117 insertions(+), 26 deletions(-) create mode 100644 config_app/management/commands/set_seq.py create mode 100644 storage/serializers.py diff --git a/access/models.py b/access/models.py index 906c62a..43dad66 100755 --- a/access/models.py +++ b/access/models.py @@ -173,13 +173,13 @@ class User(AbstractBaseUser, PermissionsMixin): class Progress(models.Model): - user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=u'Студент') - course = models.ForeignKey(to=Course, verbose_name=u'Курс') - active_obj = models.ForeignKey(to=Vertex, verbose_name=u'Активный объект', blank=True, null=True) - success = models.BooleanField(default=False, verbose_name=u'Завершён ли курс') + user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='Студент') + course = models.ForeignKey(to=Course, verbose_name='Курс') + active_obj = models.ForeignKey(to=Vertex, verbose_name='Активный объект', blank=True, null=True) + success = models.BooleanField(default=False, verbose_name='Завершён ли курс') def __str__(self): - return u'%s %s %s' % ( + return '%s %s %s' % ( self.user.email, ('завершил курс' if self.success else 'в процессе изучения курса'), self.course.title, diff --git a/config_app/management/commands/set_seq.py b/config_app/management/commands/set_seq.py new file mode 100644 index 0000000..59859e9 --- /dev/null +++ b/config_app/management/commands/set_seq.py @@ -0,0 +1,22 @@ +from django.contrib.contenttypes.models import ContentType +from django.core.management.base import BaseCommand, CommandError +from django.db import connection +from lms.settings import apps + + +class Command(BaseCommand): + help = 'Set seq by last id in table.' + + def handle(self, **_): + with connection.cursor() as cursor: + for i in ContentType.objects.all(): + if i.app_label in apps: + model_name = "%s_%s" % (i.app_label, i.model) + cursor.execute('BEGIN') + cursor.execute('LOCK TABLE %s IN EXCLUSIVE MODE' % model_name) + cursor.execute( + """SELECT setval('%s_id_seq', COALESCE( + (SELECT MAX(id)+1 FROM %s), 1) ,false + )""" % (model_name, model_name) + ) + cursor.execute('COMMIT') \ No newline at end of file diff --git a/courses/models.py b/courses/models.py index d728280..2bdcd15 100755 --- a/courses/models.py +++ b/courses/models.py @@ -131,8 +131,8 @@ class Course(models.Model): return { "topic_count": self.get_vertexes('topic').count(), - "tutorial_count": self.get_vertexes('task').count(), - "task_count": self.get_vertexes('tutorial').count(), + "tutorial_count": self.get_vertexes('tutorial').count(), + "task_count": self.get_vertexes('task').count(), } def get_first(self, vertex_model_list=None): diff --git a/courses/views.py b/courses/views.py index 1aed85a..0d7a716 100644 --- a/courses/views.py +++ b/courses/views.py @@ -6,6 +6,7 @@ from access.serializers import ExtraPrivilegeSerializer from courses.models import Course, Vertex from access.models import Progress, ExtraPrivilege from courses.serializers import CourseDetailSerializer, CourseListSerializer, VertexSerializer, CourseTreeSerializer +from journals.models import Thread class TreeView(APIView): @@ -99,6 +100,14 @@ class VertexDetail(APIView): return Response("permission denied", status=403) res = VertexSerializer(vertex).data - res['is_in_progress'] = vertex.course.progress_set.filter(user=request.user)[0].active_obj == vertex + progress = vertex.course.progress_set.filter(user=request.user) + try: + journals = Thread.objects.get(key="user_%s__vertex_%s" % (request.user.id, vertex.id)).journal_set.all() + res['is_in_progress'] = progress.exists() and progress[0].active_obj == vertex and \ + vertex.content_type.model == 'task' and \ + not journals.filter(action_type__in=['no', 'yes']).count() < \ + journals.filter(action_type='try').count() + except Thread.DoesNotExist: + pass return Response(res, status=200) if status == 200 else Response(status=204) diff --git a/csv/load_student_teachers_threads.py b/csv/load_student_teachers_threads.py index 27eb2da..bf65906 100644 --- a/csv/load_student_teachers_threads.py +++ b/csv/load_student_teachers_threads.py @@ -46,21 +46,11 @@ if __name__ == '__main__': content_type=ct, object_id=vertex.id, action_type=action, + extra_data=row['text'], ) journal.date = row['date'] journal.save() - journal_comment = Journal.objects.create( - thread=child_thread, - user=owner, - content_type=ct, - object_id=vertex.id, - action_type="comment", - extra_data=row['text'], - ) - journal_comment.date = row['date'] - journal_comment.save() - for file_id in row['files'].split("[")[1].split("]")[0].split(", "): if file_id: journal.files.add(Storage.objects.get(id=file_id)) diff --git a/journals/serilizers.py b/journals/serilizers.py index 02962eb..8771c20 100644 --- a/journals/serilizers.py +++ b/journals/serilizers.py @@ -1,15 +1,17 @@ from rest_framework import serializers from journals.models import Thread, Journal +from storage.serializers import StorageSerializer class JournalSerializer(serializers.ModelSerializer): user = serializers.SerializerMethodField() + files = serializers.SerializerMethodField() label = serializers.SerializerMethodField() class Meta: model = Journal - fields = ('label', 'date', 'user', 'files', 'action_type') + fields = ('label', 'date', 'user', 'files', 'action_type', 'object_id', ) @staticmethod def get_user(self): @@ -20,6 +22,10 @@ class JournalSerializer(serializers.ModelSerializer): return self.extra_data if self.extra_data else """%s %s"""\ % (self.user.get_full_name(), self.get_action_type_display()) + @staticmethod + def get_files(self): + return [StorageSerializer(i).data for i in self.files.all()] + class ThreadDetailSerializer(serializers.ModelSerializer): journals = serializers.SerializerMethodField() diff --git a/journals/urls.py b/journals/urls.py index e763d07..4469de0 100644 --- a/journals/urls.py +++ b/journals/urls.py @@ -5,4 +5,5 @@ urlpatterns = [ url(r'thread/$', views.ThreadAdminListView.as_view()), url(r'pay-stat/([0-9]{1,99})/$', views.get_pay_stat), url(r'thread/(?P[-\w]+)/$', views.ThreadDetailView.as_view()), + url(r'journal/$', views.JournalCreateView.as_view()), ] \ No newline at end of file diff --git a/journals/views.py b/journals/views.py index 89964f4..07ddd49 100644 --- a/journals/views.py +++ b/journals/views.py @@ -1,12 +1,16 @@ from django.contrib.auth import get_user_model +from django.contrib.contenttypes.models import ContentType from rest_framework.views import APIView from rest_framework.renderers import JSONRenderer from rest_framework.response import Response import csv from django.http import HttpResponse, HttpResponseForbidden +from access.models import Progress from journals.models import Thread, Journal -from journals.serilizers import ThreadDetailSerializer, ThreadAdminSerializer +from journals.serilizers import ThreadDetailSerializer, ThreadAdminSerializer, JournalSerializer +from lms.tools import decode_base64 +from storage.models import Storage class ThreadAdminListView(APIView): @@ -81,3 +85,43 @@ def get_pay_stat(request, pk): ]) return response + + +class JournalCreateView(APIView): + renderer_classes = (JSONRenderer,) + status_code = 200 + + def post(self, request): + pk = request.JSON.get('thread_id', None) + try: + thread = Thread.objects.get(id=pk) + if request.user.is_authenticated and thread.check_perm(request.user): + action_type = request.JSON.get('action_type', None) + extra_data = request.JSON.get('extra_data', None) + object_id = request.JSON.get('object_id', None) + content_type__model = request.JSON.get('content_type__model', None) + content_type__app_label = request.JSON.get('content_type__app_label', None) + content_type = ContentType.objects.get(model=content_type__model, app_label=content_type__app_label) + + files = request.JSON.get('files', []) + files = [{'data': decode_base64(i['data']), 'name': i['name']} for i in files] + + journal = Journal.objects.create( + action_type=action_type, extra_data=extra_data, thread=thread, + content_type=content_type, object_id=object_id, + user=request.user + ) + + for i in files: + s = Storage.objects.create(original=decode_base64(i['data']), name=i['name']) + journal.files.add(s) + + if journal.action_type == 'yes': + p = Progress.objects.get(course=journal.content_object.course, user=journal.thread.subscribers.all()[0]) + p.active_obj = journal.content_object.get_next(['tutorial', 'task']) + p.save() + + return Response(ThreadDetailSerializer(thread).data, status=200) + return Response("permission denied", status=403) + except Thread.DoesNotExist: + return Response("Thread doesn't exist.", self.status_code,) diff --git a/lms/settings.py b/lms/settings.py index 76ff9b6..400e94c 100644 --- a/lms/settings.py +++ b/lms/settings.py @@ -90,7 +90,7 @@ EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend' SECRET_KEY = env('SECRET_KEY') -INSTALLED_APPS = [ +libs = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -102,6 +102,9 @@ INSTALLED_APPS = [ "djcelery_email", 'yandex_money', 'raven.contrib.django.raven_compat', +) + +apps = ( 'access', 'courses', 'storage', @@ -109,7 +112,9 @@ INSTALLED_APPS = [ 'journals', 'library', 'config_app', -] +) + +INSTALLED_APPS = libs + apps MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', diff --git a/lms/tools.py b/lms/tools.py index 3f920c5..9ae929d 100644 --- a/lms/tools.py +++ b/lms/tools.py @@ -1,10 +1,14 @@ import base64 from django.conf import settings +from django.core.files.base import ContentFile -def decode_base64(my_str, upload_to): +def decode_base64(my_str, upload_to=None): if "data:" in my_str: my_str = my_str[my_str.index("base64,")+7:] + if not upload_to: + ext = my_str.split('/')[-1] + return ContentFile(base64.b64decode(my_str), name='temp.' + ext) path = "%s/%s" % (settings.MEDIA_ROOT, upload_to) url = "%s%s" % (settings.MEDIA_URL, upload_to) with open(path, "wb") as fh: diff --git a/storage/models.py b/storage/models.py index 9672ff9..63cbb14 100755 --- a/storage/models.py +++ b/storage/models.py @@ -3,8 +3,8 @@ from django.db import models class Storage(models.Model): - original = models.FileField(verbose_name='Файл', upload_to="files") - name = models.CharField(max_length=63, null=True, blank=True, verbose_name='Видимое имя файла') + original = models.FileField(max_length=255, verbose_name='Файл', upload_to="files") + name = models.CharField(max_length=255, null=True, blank=True, verbose_name='Видимое имя файла') def __str__(self): return '%s' % self.original diff --git a/storage/serializers.py b/storage/serializers.py new file mode 100644 index 0000000..736f44f --- /dev/null +++ b/storage/serializers.py @@ -0,0 +1,10 @@ +from rest_framework import serializers + +from storage.models import Storage + + +class StorageSerializer(serializers.ModelSerializer): + + class Meta: + model = Storage + exclude = ('id',)