diff --git a/Dockerfile b/Dockerfile
index c61bc829..18f28383 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,12 +2,8 @@ FROM python:3.6
ENV PYTHONUNBUFFERED 1
RUN mkdir /lilcity
WORKDIR /lilcity
-RUN apt-get update \
- && apt-get install -y postgresql-client-9.4 \
- && rm -rf /var/lib/apt/lists/* \
- && pip install --upgrade pip
ADD requirements.txt /lilcity/
RUN pip install -r requirements.txt
-ADD . /lilcity/
\ No newline at end of file
+ADD . /lilcity/
diff --git a/api/v1/serializers/config.py b/api/v1/serializers/config.py
index e17ce57e..f6ae89dd 100644
--- a/api/v1/serializers/config.py
+++ b/api/v1/serializers/config.py
@@ -19,6 +19,7 @@ class ConfigSerializer(serializers.Serializer):
INSTAGRAM_CLIENT_ACCESS_TOKEN = serializers.CharField(required=False)
INSTAGRAM_CLIENT_SECRET = serializers.CharField(required=False)
INSTAGRAM_PROFILE_URL = serializers.CharField(required=False)
+ # SCHOOL_LOGO_IMAGE = serializers.ImageField(required=False)
def to_representation(self, instance):
ret = OrderedDict()
diff --git a/api/v1/serializers/content.py b/api/v1/serializers/content.py
index c01a2c65..e576912b 100644
--- a/api/v1/serializers/content.py
+++ b/api/v1/serializers/content.py
@@ -61,6 +61,7 @@ class ImageCreateSerializer(serializers.ModelSerializer):
model = Image
fields = (
'id',
+ 'uuid',
'course',
'lesson',
'title',
@@ -93,6 +94,7 @@ class TextCreateSerializer(serializers.ModelSerializer):
model = Text
fields = (
'id',
+ 'uuid',
'course',
'lesson',
'title',
@@ -124,6 +126,7 @@ class ImageTextCreateSerializer(serializers.ModelSerializer):
model = ImageText
fields = (
'id',
+ 'uuid',
'course',
'lesson',
'title',
@@ -157,6 +160,7 @@ class VideoCreateSerializer(serializers.ModelSerializer):
model = Video
fields = (
'id',
+ 'uuid',
'course',
'lesson',
'title',
@@ -212,6 +216,7 @@ class GallerySerializer(serializers.ModelSerializer):
model = Gallery
fields = (
'id',
+ 'uuid',
'course',
'lesson',
'title',
diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py
index 8139d8fa..7f45c7a2 100644
--- a/api/v1/serializers/course.py
+++ b/api/v1/serializers/course.py
@@ -1,7 +1,11 @@
from rest_framework import serializers
-from apps.course.models import Category, Course, Material, Lesson, Like
-
+from apps.course.models import (
+ Category, Course,
+ Comment, CourseComment, LessonComment,
+ Material, Lesson,
+ Like,
+)
from .content import (
ImageObjectSerializer, ContentSerializer, ContentCreateSerializer,
GallerySerializer, GalleryImageSerializer,
@@ -84,7 +88,7 @@ class CourseCreateSerializer(DispatchContentMixin,
):
title = serializers.CharField(allow_blank=True)
short_description = serializers.CharField(allow_blank=True)
- slug = serializers.SlugField(allow_unicode=True, allow_blank=True, required=False)
+ slug = serializers.SlugField(allow_unicode=True, allow_blank=True, allow_null=True, required=False)
content = serializers.ListSerializer(
child=ContentCreateSerializer(),
required=False,
@@ -368,3 +372,64 @@ class CourseSerializer(serializers.ModelSerializer):
'update_at',
'deactivated_at',
)
+
+
+class CommentSerializer(serializers.ModelSerializer):
+ author = UserSerializer()
+
+ class Meta:
+ model = Comment
+ fields = (
+ 'id',
+ 'content',
+ 'author',
+ 'parent',
+ 'deactivated_at',
+ 'created_at',
+ 'update_at',
+ )
+
+ read_only_fields = (
+ 'id',
+ 'deactivated_at',
+ 'created_at',
+ 'update_at',
+ )
+
+ def to_representation(self, instance):
+ if isinstance(instance, CourseComment):
+ return CourseCommentSerializer(instance, context=self.context).to_representation(instance)
+ elif isinstance(instance, LessonComment):
+ return LessonCommentSerializer(instance, context=self.context).to_representation(instance)
+
+
+class CourseCommentSerializer(serializers.ModelSerializer):
+ author = UserSerializer()
+ children = CommentSerializer(many=True)
+
+ class Meta:
+ model = CourseComment
+ fields = CommentSerializer.Meta.fields + (
+ 'course',
+ 'children',
+ )
+
+ read_only_fields = CommentSerializer.Meta.read_only_fields + (
+ 'children',
+ )
+
+
+class LessonCommentSerializer(serializers.ModelSerializer):
+ author = UserSerializer()
+ children = CommentSerializer(many=True)
+
+ class Meta:
+ model = LessonComment
+ fields = CommentSerializer.Meta.fields + (
+ 'lesson',
+ 'children',
+ )
+
+ read_only_fields = CommentSerializer.Meta.read_only_fields + (
+ 'children',
+ )
diff --git a/api/v1/serializers/payment.py b/api/v1/serializers/payment.py
index 9174177d..d005a88d 100644
--- a/api/v1/serializers/payment.py
+++ b/api/v1/serializers/payment.py
@@ -16,6 +16,7 @@ class AuthorBalanceCreateSerializer(serializers.ModelSerializer):
'commission',
'status',
'payment',
+ 'card',
'cause',
)
@@ -43,6 +44,7 @@ class AuthorBalanceSerializer(serializers.ModelSerializer):
'commission',
'status',
'payment',
+ 'card',
'cause',
)
diff --git a/api/v1/serializers/user.py b/api/v1/serializers/user.py
index 8ce068e2..f334e9a5 100644
--- a/api/v1/serializers/user.py
+++ b/api/v1/serializers/user.py
@@ -1,13 +1,16 @@
-from django.contrib.auth import get_user_model
+from phonenumber_field.serializerfields import PhoneNumberField
from rest_framework import serializers
-from . import Base64ImageField
+from django.contrib.auth import get_user_model
+from . import Base64ImageField
+from apps.user.models import AuthorRequest
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
+ phone = PhoneNumberField()
class Meta:
model = User
@@ -15,6 +18,7 @@ class UserSerializer(serializers.ModelSerializer):
'id',
'username',
'email',
+ 'phone',
'first_name',
'last_name',
'is_staff',
@@ -36,6 +40,7 @@ class UserSerializer(serializers.ModelSerializer):
'is_email_proved',
'photo',
'balance',
+ 'show_in_mainpage',
)
read_only_fields = (
@@ -53,3 +58,30 @@ class UserPhotoSerializer(serializers.Serializer):
photo = Base64ImageField(
required=False, allow_empty_file=True, allow_null=True
)
+
+
+class AuthorRequestSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = AuthorRequest
+ fields = (
+ 'id',
+ 'first_name',
+ 'last_name',
+ 'email',
+ 'about',
+ 'facebook',
+ 'status',
+ 'cause',
+ 'accepted_send_at',
+ 'declined_send_at',
+ 'created_at',
+ 'update_at',
+ )
+
+ read_only_fields = (
+ 'id',
+ 'accepted_send_at',
+ 'declined_send_at',
+ 'created_at',
+ 'update_at',
+ )
diff --git a/api/v1/urls.py b/api/v1/urls.py
index ab852c4d..cf52179a 100644
--- a/api/v1/urls.py
+++ b/api/v1/urls.py
@@ -8,8 +8,9 @@ from drf_yasg import openapi
from .auth import ObtainToken
from .views import (
- AuthorBalanceViewSet, ConfigViewSet,
- CategoryViewSet, CourseViewSet,
+ AuthorBalanceViewSet, AuthorRequestViewSet,
+ ConfigViewSet, CategoryViewSet,
+ CourseViewSet, CommentViewSet,
MaterialViewSet, LikeViewSet,
ImageViewSet, TextViewSet,
ImageTextViewSet, VideoViewSet,
@@ -19,9 +20,11 @@ from .views import (
)
router = DefaultRouter()
+router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests')
router.register(r'author-balance', AuthorBalanceViewSet, base_name='author-balance')
-router.register(r'courses', CourseViewSet, base_name='courses')
router.register(r'categories', CategoryViewSet, base_name='categories')
+router.register(r'courses', CourseViewSet, base_name='courses')
+router.register(r'comments', CommentViewSet, base_name='comments')
router.register(r'materials', MaterialViewSet, base_name='materials')
router.register(r'lessons', LessonViewSet, base_name='lessons')
router.register(r'likes', LikeViewSet, base_name='likes')
diff --git a/api/v1/views.py b/api/v1/views.py
index 68f0f428..909195d4 100644
--- a/api/v1/views.py
+++ b/api/v1/views.py
@@ -15,6 +15,7 @@ from .serializers.course import (
CategorySerializer, LikeSerializer,
CourseSerializer, CourseCreateSerializer,
CourseBulkChangeCategorySerializer,
+ CommentSerializer,
MaterialSerializer, MaterialCreateSerializer,
LessonSerializer, LessonCreateSerializer,
)
@@ -30,24 +31,33 @@ from .serializers.content import (
from .serializers.school import SchoolScheduleSerializer
from .serializers.payment import AuthorBalanceSerializer, AuthorBalanceCreateSerializer
from .serializers.user import (
+ AuthorRequestSerializer,
UserSerializer, UserPhotoSerializer,
)
from .permissions import IsAdmin, IsAdminOrIsSelf, IsAuthorOrAdmin, IsAuthorObjectOrAdmin
-from apps.course.models import Category, Course, Material, Lesson, Like
+from apps.course.models import (
+ Category, Course,
+ Comment, CourseComment, LessonComment,
+ Material, Lesson,
+ Like,
+)
from apps.content.models import (
Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject,
)
from apps.payment.models import AuthorBalance
from apps.school.models import SchoolSchedule
+from apps.user.models import AuthorRequest
User = get_user_model()
class AuthorBalanceViewSet(ExtendedModelViewSet):
- queryset = AuthorBalance.objects.all()
+ queryset = AuthorBalance.objects.filter(
+ author__role__in=[User.AUTHOR_ROLE, User.ADMIN_ROLE],
+ )
serializer_class = AuthorBalanceCreateSerializer
serializer_class_map = {
'list': AuthorBalanceSerializer,
@@ -329,3 +339,26 @@ class ConfigViewSet(generics.RetrieveUpdateAPIView):
if serializer.is_valid():
serializer.update(get_values(), serializer.validated_data)
return Response(serializer.data)
+
+
+class CommentViewSet(ExtendedModelViewSet):
+ queryset = Comment.objects.filter(level=0)
+ serializer_class = CommentSerializer
+ permission_classes = (IsAdmin,)
+
+ def get_queryset(self):
+ queryset = self.queryset
+ is_deactivated = self.request.query_params.get('is_deactivated', '0')
+ if is_deactivated == '0':
+ return queryset
+ elif is_deactivated == '1':
+ return queryset.filter(deactivated_at__isnull=True)
+ elif is_deactivated == '2':
+ return queryset.filter(deactivated_at__isnull=False)
+
+
+class AuthorRequestViewSet(ExtendedModelViewSet):
+ queryset = AuthorRequest.objects.all()
+ serializer_class = AuthorRequestSerializer
+ permission_classes = (IsAdmin,)
+ filter_fields = ('status',)
diff --git a/apps/auth/middleware.py b/apps/auth/middleware.py
new file mode 100644
index 00000000..1c737a93
--- /dev/null
+++ b/apps/auth/middleware.py
@@ -0,0 +1,18 @@
+from django.contrib.auth import login
+from django.utils.deprecation import MiddlewareMixin
+
+from rest_framework.authtoken.models import Token
+
+
+class TokenAuthLoginMiddleware(MiddlewareMixin):
+
+ def process_request(self, request):
+ if 'token' in request.GET:
+ token = request.GET.get('token')
+ if token:
+ try:
+ token = Token.objects.get(key=token)
+ user = token.user
+ login(request, user)
+ except Token.DoesNotExist:
+ pass
diff --git a/apps/content/migrations/0015_content_uuid.py b/apps/content/migrations/0015_content_uuid.py
new file mode 100644
index 00000000..54a1997c
--- /dev/null
+++ b/apps/content/migrations/0015_content_uuid.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.3 on 2018-03-16 11:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('content', '0014_auto_20180215_1503'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='content',
+ name='uuid',
+ field=models.UUIDField(blank=True, null=True),
+ ),
+ ]
diff --git a/apps/content/models.py b/apps/content/models.py
index 345221f4..5c0b9b66 100644
--- a/apps/content/models.py
+++ b/apps/content/models.py
@@ -17,6 +17,7 @@ class ImageObject(models.Model):
class Content(PolymorphicModel):
+ uuid = models.UUIDField(null=True, blank=True)
course = models.ForeignKey(
'course.Course', on_delete=models.CASCADE,
null=True, blank=True,
diff --git a/apps/course/migrations/0035_comment_deactivated_at.py b/apps/course/migrations/0035_comment_deactivated_at.py
new file mode 100644
index 00000000..cd5ba08e
--- /dev/null
+++ b/apps/course/migrations/0035_comment_deactivated_at.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.2 on 2018-03-12 10:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('course', '0034_auto_20180215_1503'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='comment',
+ name='deactivated_at',
+ field=models.DateTimeField(blank=True, default=None, null=True),
+ ),
+ ]
diff --git a/apps/course/models.py b/apps/course/models.py
index ad59b1b1..98a64423 100644
--- a/apps/course/models.py
+++ b/apps/course/models.py
@@ -196,7 +196,7 @@ class Material(models.Model):
ordering = ('title',)
-class Comment(PolymorphicMPTTModel):
+class Comment(PolymorphicMPTTModel, DeactivatedMixin):
content = models.TextField('Текст комментария', default='')
author = models.ForeignKey(User, on_delete=models.CASCADE)
parent = PolymorphicTreeForeignKey(
diff --git a/apps/course/templates/course/_items.html b/apps/course/templates/course/_items.html
index 260a482e..33312e53 100644
--- a/apps/course/templates/course/_items.html
+++ b/apps/course/templates/course/_items.html
@@ -1,3 +1,4 @@
+{% load thumbnail %}
{% load static %}
{% load data_liked from data_liked %}
@@ -7,11 +8,11 @@
{% if course.is_deferred_start %}data-future-course data-future-course-time={{ course.deferred_start_at.timestamp }}{% endif %}
>
- {% if course.cover %}
-
- {% else %}
-
- {% endif %}
+ {% thumbnail course.cover.image "300x170" crop="center" as im %}
+
+ {% empty %}
+
+ {% endthumbnail %}
-
+
+
+
+
diff --git a/project/templates/lilcity/main.html b/project/templates/lilcity/main.html
index 817a23f6..61fef12c 100644
--- a/project/templates/lilcity/main.html
+++ b/project/templates/lilcity/main.html
@@ -13,7 +13,7 @@
{% endif %}
class="main__btn btn"
href="#"
- >КУПИТЬ ДОСТУП ОТ 2000р. в мес.
+ >КУПИТЬ ДОСТУП ОТ {{ min_school_price }}р. в мес.
{% if messages %}
@@ -270,74 +270,30 @@
+ {% endif %}
Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.
-Участник и победитель международных выставок.
-Основатель компании "Lil City".
-
- Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.
-Участник и победитель международных выставок.
-Основатель компании "Lil City".
-
- Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.
-Участник и победитель международных выставок.
-Основатель компании "Lil City".
-
- Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.
-Участник и победитель международных выставок.
-Основатель компании "Lil City".
+ {{ author.about }}@@ -367,7 +323,7 @@ {% endfor %}
+ Распечатать расписание чтобы не забыть {% if course_items %} diff --git a/project/templates/lilcity/school_schedules.html b/project/templates/lilcity/school_schedules.html new file mode 100644 index 00000000..88601188 --- /dev/null +++ b/project/templates/lilcity/school_schedules.html @@ -0,0 +1,52 @@ +{% load static %} + + + +
+ + + + + + +
+