From 09bcbb399e6441eaedf196ca4a50793196f67941 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 11:49:32 +0300 Subject: [PATCH 01/73] Fix balance calc --- apps/user/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/user/models.py b/apps/user/models.py index 43eac1cd..e0b7afa8 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -1,3 +1,6 @@ +from json import dumps +from rest_framework.authtoken.models import Token + from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver @@ -5,10 +8,8 @@ from django.contrib.auth.models import AbstractUser, UserManager from django.contrib.postgres import fields as pgfields from django.utils.translation import gettext_lazy as _ -from rest_framework.authtoken.models import Token - -from json import dumps from api.v1 import serializers +from apps.payment.models import AuthorBalance class User(AbstractUser): @@ -63,7 +64,7 @@ class User(AbstractUser): @property def balance(self): - aggregate = self.balances.aggregate( + aggregate = self.balances.filter(type=AuthorBalance.IN).aggregate( models.Sum('amount'), models.Sum('commission'), ) From 6c60d411b4223026cf6188c053d375597d3240f5 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 12:08:53 +0300 Subject: [PATCH 02/73] Fix card field --- apps/user/models.py | 3 +-- apps/user/views.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/user/models.py b/apps/user/models.py index e0b7afa8..eb8bf8a3 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -9,7 +9,6 @@ from django.contrib.postgres import fields as pgfields from django.utils.translation import gettext_lazy as _ from api.v1 import serializers -from apps.payment.models import AuthorBalance class User(AbstractUser): @@ -64,7 +63,7 @@ class User(AbstractUser): @property def balance(self): - aggregate = self.balances.filter(type=AuthorBalance.IN).aggregate( + aggregate = self.balances.filter(type=0).aggregate( models.Sum('amount'), models.Sum('commission'), ) diff --git a/apps/user/views.py b/apps/user/views.py index 69e42bef..44d9a486 100644 --- a/apps/user/views.py +++ b/apps/user/views.py @@ -115,7 +115,7 @@ class PaymentHistoryView(FormView): type=AuthorBalance.OUT, amount=form.cleaned_data['amount'], status=AuthorBalance.PENDING, - card=form.cleaned_data['amount'], + card=form.cleaned_data['card'], ) return self.form_valid(form) else: From b8e393f82f1e7826b25f7557b500f9e7ca13c732 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 12:39:05 +0300 Subject: [PATCH 03/73] LIL-284. Add api for moderation of comments --- api/v1/serializers/course.py | 46 ++++++++++++++++++++++++++++++++++-- api/v1/urls.py | 4 +++- api/v1/views.py | 14 ++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index 8139d8fa..52e16a25 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, @@ -368,3 +372,41 @@ class CourseSerializer(serializers.ModelSerializer): 'update_at', 'deactivated_at', ) + + +class CommentSerializer(serializers.ModelSerializer): + + class Meta: + model = Comment + fields = ( + 'id', + 'content', + 'author', + 'parent', + '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): + + class Meta: + model = CourseComment + fields = CommentSerializer.Meta.fields + ( + 'course', + ) + + +class LessonCommentSerializer(serializers.ModelSerializer): + + class Meta: + model = LessonComment + fields = CommentSerializer.Meta.fields + ( + 'lesson', + ) diff --git a/api/v1/urls.py b/api/v1/urls.py index ab852c4d..3f487bd9 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -10,6 +10,7 @@ from .auth import ObtainToken from .views import ( AuthorBalanceViewSet, ConfigViewSet, CategoryViewSet, CourseViewSet, + CommentViewSet, MaterialViewSet, LikeViewSet, ImageViewSet, TextViewSet, ImageTextViewSet, VideoViewSet, @@ -20,8 +21,9 @@ from .views import ( router = DefaultRouter() 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..6ae66284 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, ) @@ -35,7 +36,12 @@ from .serializers.user import ( 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, @@ -329,3 +335,9 @@ 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.all() + serializer_class = CommentSerializer + permission_classes = (IsAdmin,) From 5b95f099497d1269c255a4dc66505d2b64bcf4d8 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 13:06:43 +0300 Subject: [PATCH 04/73] LIL-33. Add DeactivatedMixin to Comment model --- .../migrations/0035_comment_deactivated_at.py | 18 ++++++++++++++++++ apps/course/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 apps/course/migrations/0035_comment_deactivated_at.py 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( From ff8708ea0073743bba6e029ad82636fde17f943a Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 13:11:15 +0300 Subject: [PATCH 05/73] LIL-33. Add deactivated_at field to CommentSerializer --- api/v1/serializers/course.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index 52e16a25..a9679fee 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -383,6 +383,7 @@ class CommentSerializer(serializers.ModelSerializer): 'content', 'author', 'parent', + 'deactivated_at', 'created_at', 'update_at', ) From 7b7ee5230caa4e76a2dd8687d8bd26e8452c099f Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 13:11:41 +0300 Subject: [PATCH 06/73] LIL-33. Don't show deactivated comments. --- apps/course/templates/course/blocks/comment.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/course/templates/course/blocks/comment.html b/apps/course/templates/course/blocks/comment.html index 1f338358..463536af 100644 --- a/apps/course/templates/course/blocks/comment.html +++ b/apps/course/templates/course/blocks/comment.html @@ -1,5 +1,5 @@ {% load static %} - +{% if not node.deactivated_at %}
{% if node.author.photo %}
@@ -24,4 +24,5 @@ {% endif %}
- \ No newline at end of file + +{% endif %} From d10369147e4e269088c6cfca849fb29edd19fd17 Mon Sep 17 00:00:00 2001 From: Sanasol Date: Mon, 12 Mar 2018 17:12:50 +0700 Subject: [PATCH 07/73] fixes, gallery --- apps/course/templates/course/content/gallery.html | 12 ++++++++---- apps/course/templates/course/content/image.html | 8 +++++--- apps/course/templates/course/content/imagetext.html | 6 ++++-- web/package.json | 1 + web/src/components/CourseRedactor.vue | 2 +- web/src/js/modules/common.js | 6 ++++++ web/src/sass/_common.sass | 2 +- web/src/sass/app.sass | 1 + 8 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/course/templates/course/content/gallery.html b/apps/course/templates/course/content/gallery.html index 771df8b6..32a4bf91 100644 --- a/apps/course/templates/course/content/gallery.html +++ b/apps/course/templates/course/content/gallery.html @@ -1,18 +1,22 @@ {% if results %}
Галерея итогов обучения
-
+ {% else %}
{{ content.title }}
-
+ diff --git a/apps/course/templates/course/content/image.html b/apps/course/templates/course/content/image.html index 5daeba4e..1117d434 100644 --- a/apps/course/templates/course/content/image.html +++ b/apps/course/templates/course/content/image.html @@ -1,6 +1,8 @@
{{ content.title }}
-
- -
\ No newline at end of file + diff --git a/apps/course/templates/course/content/imagetext.html b/apps/course/templates/course/content/imagetext.html index 9849e357..0b3301cc 100644 --- a/apps/course/templates/course/content/imagetext.html +++ b/apps/course/templates/course/content/imagetext.html @@ -4,6 +4,8 @@
{{ content.txt | safe }}
-
- + \ No newline at end of file diff --git a/web/package.json b/web/package.json index 96794b84..ba9de0b4 100755 --- a/web/package.json +++ b/web/package.json @@ -55,6 +55,7 @@ "dependencies": { "axios": "^0.17.1", "babel-polyfill": "^6.26.0", + "baguettebox.js": "^1.10.0", "history": "^4.7.2", "ilyabirman-likely": "^2.3.0", "inputmask": "^3.3.11", diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index 0f94eb3e..d173f8cf 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -551,7 +551,7 @@ clearTimeout(this.savingTimeout); document.getElementById('course-redactor__saving-status').innerText = 'СОХРАНЕНИЕ'; const courseObject = this.course; - courseObject.url = slugify(courseObject.url); + courseObject.url = (courseObject.url) ? slugify(courseObject.url):courseObject.url; api.saveCourse(courseObject, this.accessToken) .then((response) => { this.courseSaving = false; diff --git a/web/src/js/modules/common.js b/web/src/js/modules/common.js index ecbd4dee..dea36989 100644 --- a/web/src/js/modules/common.js +++ b/web/src/js/modules/common.js @@ -1,8 +1,14 @@ import $ from 'jquery'; import Inputmask from "inputmask"; import SmoothScroll from 'smooth-scroll/dist/js/smooth-scroll'; +import baguetteBox from 'baguettebox.js' + window.Inputmask = Inputmask; +window.baguetteBox = baguetteBox; + $(document).ready(function () { + + baguetteBox.run('.gallery'); // Добавляем заголовок X-CSRFToken для всех AJAX запросов JQuery. $.ajaxSetup({ headers: { diff --git a/web/src/sass/_common.sass b/web/src/sass/_common.sass index de962138..4d66e5d8 100755 --- a/web/src/sass/_common.sass +++ b/web/src/sass/_common.sass @@ -1857,7 +1857,7 @@ a.grey-link left: -10px right: -10px height: 2px - margin-top: -2px + margin-top: 5px background-image: linear-gradient(-225deg, #FFE2EB 0%, #D8F5F5 100%) &__title display: table diff --git a/web/src/sass/app.sass b/web/src/sass/app.sass index 9272f307..020d748e 100755 --- a/web/src/sass/app.sass +++ b/web/src/sass/app.sass @@ -2,3 +2,4 @@ @import helpers/all @import generated/sprite-svg @import common +@import '../../node_modules/baguettebox.js/src/baguetteBox.scss' From 9e26bc15c5f06e933f618389bea6e3a22ab2a558 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 13:31:39 +0300 Subject: [PATCH 08/73] LIL-284. Comment author as object --- api/v1/serializers/course.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index a9679fee..67516670 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -375,6 +375,7 @@ class CourseSerializer(serializers.ModelSerializer): class CommentSerializer(serializers.ModelSerializer): + author = UserSerializer() class Meta: model = Comment @@ -396,6 +397,7 @@ class CommentSerializer(serializers.ModelSerializer): class CourseCommentSerializer(serializers.ModelSerializer): + author = UserSerializer() class Meta: model = CourseComment @@ -405,6 +407,7 @@ class CourseCommentSerializer(serializers.ModelSerializer): class LessonCommentSerializer(serializers.ModelSerializer): + author = UserSerializer() class Meta: model = LessonComment From f3638fafb0c7f44a64c9e201d7e985a1ad5027a3 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 17:02:05 +0300 Subject: [PATCH 09/73] LIL-290. Add AuthorRequest model --- apps/user/migrations/0009_authorrequest.py | 27 ++++++++++++++++ apps/user/models.py | 37 ++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 apps/user/migrations/0009_authorrequest.py diff --git a/apps/user/migrations/0009_authorrequest.py b/apps/user/migrations/0009_authorrequest.py new file mode 100644 index 00000000..9e10d01c --- /dev/null +++ b/apps/user/migrations/0009_authorrequest.py @@ -0,0 +1,27 @@ +# Generated by Django 2.0.2 on 2018-03-12 14:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0008_auto_20180212_0750'), + ] + + operations = [ + migrations.CreateModel( + name='AuthorRequest', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=30, verbose_name='first name')), + ('last_name', models.CharField(max_length=150, verbose_name='last name')), + ('email', models.EmailField(max_length=254, verbose_name='email address')), + ('about', models.CharField(blank=True, max_length=1000, null=True, verbose_name='О себе')), + ('facebook', models.URLField(blank=True, default='', null=True)), + ('status', models.PositiveSmallIntegerField(choices=[(0, 'pending'), (1, 'accepted'), (2, 'declined')], default=0)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('update_at', models.DateTimeField(auto_now=True)), + ], + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index eb8bf8a3..a543d782 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -85,3 +85,40 @@ def create_auth_token(sender, instance=None, created=False, **kwargs): instance.role not in [User.AUTHOR_ROLE, User.ADMIN_ROLE] ) and hasattr(instance, 'auth_token'): instance.auth_token.delete() + + +class AuthorRequestManager(models.Manager): + def create_by_user(self, user): + obj = self.model( + first_name=user.first_name, + last_name=user.last_name, + email=user.email, + about=user.about, + facebook=user.facebook, + ) + self._for_write = True + obj.save(force_insert=True, using=self.db) + return obj + + +class AuthorRequest(models.Model): + PENDING = 0 + ACCEPTED = 1 + DECLINED = 2 + STATUS_CHOICES = ( + (PENDING, 'pending'), + (ACCEPTED, 'accepted'), + (DECLINED, 'declined'), + ) + + first_name = models.CharField(_('first name'), max_length=30) + last_name = models.CharField(_('last name'), max_length=150) + email = models.EmailField(_('email address')) + about = models.CharField('О себе', max_length=1000, null=True, blank=True) + facebook = models.URLField(default='', null=True, blank=True) + status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, default=PENDING) + + created_at = models.DateTimeField(auto_now_add=True) + update_at = models.DateTimeField(auto_now=True) + + objects = AuthorRequestManager() From 77ca5e3737ae82766e331d7ee038aca59c8f2766 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 17:06:05 +0300 Subject: [PATCH 10/73] LIL-291. Add author reques template & form --- apps/user/forms.py | 8 +++ apps/user/templates/user/become-author.html | 61 +++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 apps/user/templates/user/become-author.html diff --git a/apps/user/forms.py b/apps/user/forms.py index 2f75ef68..f2933c70 100644 --- a/apps/user/forms.py +++ b/apps/user/forms.py @@ -54,3 +54,11 @@ class UserEditForm(forms.ModelForm): class WithdrawalForm(forms.Form): amount = forms.DecimalField(required=True, min_value=2000) card = CreditCardField(required=True) + + +class AuthorRequesForm(forms.Form): + first_name = forms.CharField() + last_name = forms.CharField() + email = forms.CharField() + about = forms.CharField() + facebook = forms.URLField(required=False) diff --git a/apps/user/templates/user/become-author.html b/apps/user/templates/user/become-author.html new file mode 100644 index 00000000..bc08345c --- /dev/null +++ b/apps/user/templates/user/become-author.html @@ -0,0 +1,61 @@ +{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %} +
+
+
{% csrf_token %} +
+
Стать автором
+
+
+
ИМЯ
+
+ +
+ {% if form.first_name.errors %} +
Укажите корректно свои данные
+ {% endif %} +
+
+
ФАМИЛИЯ
+
+ +
+ {% if form.last_name.errors %} +
Укажите корректно свои данные
+ {% endif %} +
+
+
+
Почта
+
+ +
+ {% if form.email.errors %} +
Укажите корректно свои данные
+ {% endif %} +
+
+
О себе
+
+ +
+ {% if form.about.errors %} +
Укажите корректно свои данные
+ {% endif %} +
+
+
FACEBOOK
+
+ +
+ {% if form.facebook.errors %} +
Укажите корректно свои данные
+ {% endif %} +
+
+
+ +
+
+
+
+{% endblock content %} From a93aa10474ecad54c41ab5dc0575d521f67d5a1a Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 18:56:02 +0300 Subject: [PATCH 11/73] LIL-300. Add success page for author request --- apps/user/templates/user/become-author-success.html | 12 ++++++++++++ project/urls.py | 1 + 2 files changed, 13 insertions(+) create mode 100644 apps/user/templates/user/become-author-success.html diff --git a/apps/user/templates/user/become-author-success.html b/apps/user/templates/user/become-author-success.html new file mode 100644 index 00000000..e6e97f7d --- /dev/null +++ b/apps/user/templates/user/become-author-success.html @@ -0,0 +1,12 @@ +{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %} +
+
+
+
Ваша заявка отправлена!
+ +
+
+
+{% endblock content %} diff --git a/project/urls.py b/project/urls.py index 30a14cbd..52755963 100644 --- a/project/urls.py +++ b/project/urls.py @@ -35,6 +35,7 @@ from .views import IndexView urlpatterns = [ path('admin/', admin.site.urls), path('auth/', include(('apps.auth.urls', 'lilcity'))), + path('author-request/success/', TemplateView.as_view(template_name='user/become-author-success.html'), name='author-request-success'), path('courses/', CoursesView.as_view(), name='courses'), path('course/create', CourseEditView.as_view(), name='course_create'), path('course/on-moderation', CourseOnModerationView.as_view(), name='course-on-moderation'), From e68b383d57541a9e2bae458c415dae0a00b8a9e8 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 19:11:25 +0300 Subject: [PATCH 12/73] LIL-290. Add unique to AuthorRequest email field --- .../user/migrations/0010_auto_20180312_1610.py | 18 ++++++++++++++++++ apps/user/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 apps/user/migrations/0010_auto_20180312_1610.py diff --git a/apps/user/migrations/0010_auto_20180312_1610.py b/apps/user/migrations/0010_auto_20180312_1610.py new file mode 100644 index 00000000..b691deea --- /dev/null +++ b/apps/user/migrations/0010_auto_20180312_1610.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-03-12 16:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0009_authorrequest'), + ] + + operations = [ + migrations.AlterField( + model_name='authorrequest', + name='email', + field=models.EmailField(max_length=254, unique=True, verbose_name='email address'), + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index a543d782..9ce0e760 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -113,7 +113,7 @@ class AuthorRequest(models.Model): first_name = models.CharField(_('first name'), max_length=30) last_name = models.CharField(_('last name'), max_length=150) - email = models.EmailField(_('email address')) + email = models.EmailField(_('email address'), unique=True) about = models.CharField('О себе', max_length=1000, null=True, blank=True) facebook = models.URLField(default='', null=True, blank=True) status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, default=PENDING) From d5f65f5b957245c648c86631bfd7eaca39847396 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Mon, 12 Mar 2018 19:12:47 +0300 Subject: [PATCH 13/73] LIL-299. Add AuthorRequest view --- .../user/templates/user/profile-settings.html | 4 +- apps/user/views.py | 46 ++++++++++++++++++- project/templates/lilcity/index.html | 7 ++- project/urls.py | 12 +++-- 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index 68d41375..33baee8e 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -79,7 +79,7 @@ {% if form.email.errors %}
Укажите корректно свои данные
{% endif %} -
+
ГОРОД
@@ -250,4 +250,4 @@ var openFile = function(file) { reader.readAsDataURL(input.files[0]); }; -{% endblock content %} \ No newline at end of file +{% endblock content %} diff --git a/apps/user/views.py b/apps/user/views.py index 44d9a486..53e1d689 100644 --- a/apps/user/views.py +++ b/apps/user/views.py @@ -26,7 +26,8 @@ from apps.notification.utils import send_email from apps.school.models import SchoolSchedule from apps.payment.models import AuthorBalance, CoursePayment, SchoolPayment -from .forms import UserEditForm, WithdrawalForm +from .forms import AuthorRequesForm, UserEditForm, WithdrawalForm +from .models import AuthorRequest User = get_user_model() @@ -182,3 +183,46 @@ class UserEditView(UpdateView): def get_success_url(self): return reverse('user-edit-profile', args=[self.object.id]) + + +class AuthorRequestView(FormView): + template_name = 'user/become-author.html' + form_class = AuthorRequesForm + success_url = reverse_lazy('author-request-success') + + def post(self, request, pk=None): + form = self.get_form() + if form.is_valid(): + if request.user.is_authenticated: + email = request.user.email + if request.user.role in [User.AUTHOR_ROLE, User.ADMIN_ROLE]: + messages.info('Вы уже являетесь автором') + return self.form_invalid(form) + else: + email = form.cleaned_data['email'] + + if AuthorRequest.objects.filter(email=email).exists(): + messages.error('Вы уже отправили заявку на преподавателя') + return self.form_invalid(form) + + AuthorRequest.objects.create( + first_name=form.cleaned_daLILta['first_name'], + last_name=form.cleaned_data['last_name'], + email=email, + about=form.cleaned_data['about'], + facebook=form.cleaned_data['facebook'], + ) + return self.form_valid(form) + else: + return self.form_invalid(form) + + def get_context_data(self): + if self.request.user.is_authenticated: + self.initial = { + 'first_name': self.request.user.first_name, + 'last_name': self.request.user.last_name, + 'email': self.request.user.email, + 'about': self.request.user.about, + 'facebook': self.request.user.facebook, + } + return super().get_context_data() diff --git a/project/templates/lilcity/index.html b/project/templates/lilcity/index.html index 2f28628d..b6bb1808 100644 --- a/project/templates/lilcity/index.html +++ b/project/templates/lilcity/index.html @@ -188,8 +188,11 @@
{% 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 %} + + + + + + + + + + + +
+
+ +
Расписание
+
+
+ {% for school_schedule in school_schedules %} +
+
{{ school_schedule }}
+
+
{{ school_schedule.title }}
+
{{ school_schedule.description }}
+
+ +
{{ school_schedule.materials }}
+
+
+
+ {% endfor %} +
+ {% comment %}
+ Распечатать расписание чтобы не забыть +
{% endcomment %} +
+
+ + + + diff --git a/project/urls.py b/project/urls.py index b7f3dde3..b0c6ddb8 100644 --- a/project/urls.py +++ b/project/urls.py @@ -36,7 +36,7 @@ from apps.payment.views import ( SchoolBuyView, ) -from .views import IndexView +from .views import IndexView, SchoolSchedulesView urlpatterns = [ path('admin/', admin.site.urls), @@ -71,6 +71,7 @@ urlpatterns = [ path('privacy', TemplateView.as_view(template_name='templates/lilcity/privacy_policy.html'), name='privacy'), path('terms', TemplateView.as_view(template_name='templates/lilcity/terms.html'), name='terms'), path('refund-policy', TemplateView.as_view(template_name='templates/lilcity/refund_policy.html'), name='refund_policy'), + path('school-schedules', SchoolSchedulesView.as_view(), name='school_schedules'), path('', IndexView.as_view(), name='index'), path('api/v1/', include(('api.v1.urls', 'api_v1'))), path('test', TemplateView.as_view(template_name='templates/lilcity/test.html'), name='test'), diff --git a/project/views.py b/project/views.py index 9dafb0a4..fcedb726 100644 --- a/project/views.py +++ b/project/views.py @@ -14,3 +14,12 @@ class IndexView(TemplateView): 'school_schedules': SchoolSchedule.objects.all(), }) return context + + +class SchoolSchedulesView(TemplateView): + template_name = 'templates/lilcity/school_schedules.html' + + def get_context_data(self): + context = super().get_context_data() + context['school_schedules'] = SchoolSchedule.objects.all() + return context From 7fa8a6ca4600617c8e4736cca3f9e12d0e60c830 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Thu, 15 Mar 2018 14:06:49 +0300 Subject: [PATCH 48/73] LIL-315. Fix user icon in comment block --- apps/course/templates/course/course.html | 4 ++-- apps/course/templates/course/lesson.html | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/course/templates/course/course.html b/apps/course/templates/course/course.html index 5f7a00c8..a2787322 100644 --- a/apps/course/templates/course/course.html +++ b/apps/course/templates/course/course.html @@ -409,11 +409,11 @@
Задавайте вопросы:
- {% if user.is_authenticated %} + {% if request.user.is_authenticated %}
- +
В ответ на diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index 9286f106..abd108b2 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -33,7 +33,7 @@ {% else %} - {% endif %} + {% endif %} @@ -97,10 +97,10 @@
Задавайте вопросы:
- {% if user.is_authenticated %} + {% if request.user.is_authenticated %}
- +
From 9416e3e978243f12239de345a610d075a193c725 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Thu, 15 Mar 2018 14:24:47 +0300 Subject: [PATCH 49/73] Fix user photo if not found --- apps/course/templates/course/course.html | 9 ++++++++- apps/course/templates/course/lesson.html | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/course/templates/course/course.html b/apps/course/templates/course/course.html index a2787322..4426225e 100644 --- a/apps/course/templates/course/course.html +++ b/apps/course/templates/course/course.html @@ -413,7 +413,14 @@
- +
В ответ на diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index abd108b2..480d7d33 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -100,7 +100,14 @@ {% if request.user.is_authenticated %}
- +
From 8fc40c43d3b6194fcadf954980349eaa3a85c7d6 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Thu, 15 Mar 2018 15:13:46 +0300 Subject: [PATCH 50/73] Fix cource user perms --- apps/course/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/course/views.py b/apps/course/views.py index 68fd1b1a..caa3bd5f 100644 --- a/apps/course/views.py +++ b/apps/course/views.py @@ -185,7 +185,7 @@ class CourseView(DetailView): def get(self, request, *args, **kwargs): response = super().get(request, *args, **kwargs) context = self.get_context_data() - if not request.user.is_authenticated or (not request.user.is_authenticated and self.object.status != Course.PUBLISHED) or\ + if (not request.user.is_authenticated and self.object.status != Course.PUBLISHED) or\ (request.user.is_authenticated and request.user.role not in [User.AUTHOR_ROLE, User.ADMIN_ROLE] and self.object.author != request.user and self.only_lessons and not context['paid']): raise Http404 return response From df7a99168d8f6005073553093a8c8937786ddb6d Mon Sep 17 00:00:00 2001 From: Sanasol Date: Thu, 15 Mar 2018 19:25:41 +0700 Subject: [PATCH 51/73] style import fix --- web/src/sass/app.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/sass/app.sass b/web/src/sass/app.sass index 020d748e..82cdc94a 100755 --- a/web/src/sass/app.sass +++ b/web/src/sass/app.sass @@ -2,4 +2,4 @@ @import helpers/all @import generated/sprite-svg @import common -@import '../../node_modules/baguettebox.js/src/baguetteBox.scss' +@import '~baguettebox.js/dist/baguetteBox.min.css'; \ No newline at end of file From acef8ab30a5b5528584c5ec380d41d72fac9b3b3 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Thu, 15 Mar 2018 20:31:25 +0300 Subject: [PATCH 52/73] LIL-320. Add phone to user model --- api/v1/serializers/user.py | 6 +++++- apps/user/forms.py | 3 +++ apps/user/migrations/0018_user_phone.py | 19 +++++++++++++++++++ apps/user/models.py | 3 +++ apps/user/tasks.py | 3 ++- .../user/templates/user/profile-settings.html | 9 +++++++++ requirements.txt | 1 + 7 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 apps/user/migrations/0018_user_phone.py diff --git a/api/v1/serializers/user.py b/api/v1/serializers/user.py index d548da19..fe316cf5 100644 --- a/api/v1/serializers/user.py +++ b/api/v1/serializers/user.py @@ -1,6 +1,8 @@ -from django.contrib.auth import get_user_model +from phonenumber_field.serializerfields import PhoneNumberField from rest_framework import serializers +from django.contrib.auth import get_user_model + from . import Base64ImageField from apps.user.models import AuthorRequest @@ -8,6 +10,7 @@ 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', diff --git a/apps/user/forms.py b/apps/user/forms.py index f2933c70..2445d522 100644 --- a/apps/user/forms.py +++ b/apps/user/forms.py @@ -1,5 +1,6 @@ from django import forms from django.contrib.auth import get_user_model +from phonenumber_field.formfields import PhoneNumberField from .fields import CreditCardField @@ -10,6 +11,7 @@ class UserEditForm(forms.ModelForm): # first_name = forms.CharField() # last_name = forms.CharField() # email = forms.CharField() + phone = PhoneNumberField() # city = forms.CharField() # country = forms.CharField() birthday = forms.DateField(input_formats=['%d.%m.%Y'], required=False) @@ -33,6 +35,7 @@ class UserEditForm(forms.ModelForm): 'first_name', 'last_name', 'email', + 'phone', 'city', 'country', 'birthday', diff --git a/apps/user/migrations/0018_user_phone.py b/apps/user/migrations/0018_user_phone.py new file mode 100644 index 00000000..d377bcf5 --- /dev/null +++ b/apps/user/migrations/0018_user_phone.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0.3 on 2018-03-15 17:19 + +from django.db import migrations +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0017_subscriptioncategory_auto_add'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='phone', + field=phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, null=True, unique=True), + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index f4c56536..57ec8cd2 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -1,5 +1,6 @@ from json import dumps from rest_framework.authtoken.models import Token +from phonenumber_field.modelfields import PhoneNumberField from django.db import models from django.db.models.signals import post_save @@ -33,6 +34,7 @@ class User(AbstractUser): (FEMALE, 'Женщина'), ) email = models.EmailField(_('email address'), unique=True) + phone = PhoneNumberField(null=True, blank=True, unique=True) role = models.PositiveSmallIntegerField( 'Роль', default=0, choices=ROLE_CHOICES) gender = models.CharField( @@ -96,6 +98,7 @@ def send_user_info_to_mixpanel(sender, instance=None, created=False, **kwargs): user_to_mixpanel.delay( instance.id, instance.email, + str(instance.phone), instance.first_name, instance.last_name, instance.date_joined, diff --git a/apps/user/tasks.py b/apps/user/tasks.py index 702c804e..a95988be 100644 --- a/apps/user/tasks.py +++ b/apps/user/tasks.py @@ -6,12 +6,13 @@ from project.celery import app @app.task -def user_to_mixpanel(user_id, email, first_name, last_name, date_joined, role, subscriptions): +def user_to_mixpanel(user_id, email, phone, first_name, last_name, date_joined, role, subscriptions): mix = Mixpanel(settings.MIX_TOKEN) mix.people_set( user_id, { '$email': email, + '$phone': phone, '$first_name': first_name, '$last_name': last_name, '$created': date_joined, diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index 33baee8e..8eddef8c 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -80,6 +80,15 @@
Укажите корректно свои данные
{% endif %}
+
+
Телефон
+
+ +
+ {% if form.phone.errors %} +
Укажите корректно свои данные
+ {% endif %} +
ГОРОД
diff --git a/requirements.txt b/requirements.txt index 4faab0da..2ca79a88 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ django-constance[database]==2.1.0 django-filter==2.0.0.dev1 django-mptt==0.9.0 django-silk==2.0.0 +django-phonenumber-field==2.0.0 django-polymorphic-tree==1.5 djangorestframework==3.7.7 drf-yasg[validation]==1.5.0 From 5dfed1f73daa68123432029d17517a7462515309 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 12:20:40 +0300 Subject: [PATCH 53/73] Fix course slug --- api/v1/serializers/course.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index 1c9efa96..7f45c7a2 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -88,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, From ed7e888b86041f485e6a46e01db215b35c8c8572 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 12:58:29 +0300 Subject: [PATCH 54/73] LIL-314. Fix gallery images --- apps/course/templates/course/content/gallery.html | 12 ++++++++---- project/settings.py | 1 + requirements.txt | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/course/templates/course/content/gallery.html b/apps/course/templates/course/content/gallery.html index 32a4bf91..fd0d1389 100644 --- a/apps/course/templates/course/content/gallery.html +++ b/apps/course/templates/course/content/gallery.html @@ -1,10 +1,13 @@ +{% load thumbnail %} {% if results %}
Галерея итогов обучения
-{% endif %} \ No newline at end of file +{% endif %} diff --git a/project/settings.py b/project/settings.py index a9e02e83..25bd6e03 100644 --- a/project/settings.py +++ b/project/settings.py @@ -52,6 +52,7 @@ INSTALLED_APPS = [ 'corsheaders', 'constance', 'constance.backends.database', + 'sorl.thumbnail', ] + [ 'apps.auth.apps', 'apps.user', diff --git a/requirements.txt b/requirements.txt index 2ca79a88..cf55c8a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,9 +16,10 @@ drf-yasg[validation]==1.5.0 facepy==1.0.9 gunicorn==19.7.1 mixpanel==4.3.2 -requests==2.18.4 psycopg2-binary==2.7.4 Pillow==5.0.0 +requests==2.18.4 +sorl-thumbnail==12.4.1 twilio==6.10.5 # paymentwall-python==1.0.7 git+https://github.com/ivlevdenis/paymentwall-python.git From f9c96c654c34ce2224c03701cddf56319fd2b3ae Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 13:15:53 +0300 Subject: [PATCH 55/73] Fix gallery template --- apps/course/templates/course/content/gallery.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/course/templates/course/content/gallery.html b/apps/course/templates/course/content/gallery.html index fd0d1389..0d751dc6 100644 --- a/apps/course/templates/course/content/gallery.html +++ b/apps/course/templates/course/content/gallery.html @@ -20,7 +20,8 @@ {% thumbnail image.img.image "140x140" crop="center" as im %} - {% endthumbnail %} + {% endthumbnail %} +
{% endfor %}
From cbfd47c77217b85e12c0da85d630f837c3c359d5 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 13:16:28 +0300 Subject: [PATCH 56/73] LIL-319. Fix course preview img --- apps/course/templates/course/_items.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/course/templates/course/_items.html b/apps/course/templates/course/_items.html index 260a482e..2fd55a31 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 %} @@ -8,9 +9,11 @@ > {% if course.cover %} - + {% thumbnail course.cover.image "300x170" crop="center" as im %} + + {% endthumbnail %} {% else %} - + {% endif %}
Подробнее
{% if course.is_featured %} @@ -86,4 +89,4 @@
-
\ No newline at end of file +
From 4026f04044cd3aa434f0fe1c272f3dc93e23677b Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 13:22:24 +0300 Subject: [PATCH 57/73] Use empty tag for img thumbs --- apps/course/templates/course/_items.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/course/templates/course/_items.html b/apps/course/templates/course/_items.html index 2fd55a31..33312e53 100644 --- a/apps/course/templates/course/_items.html +++ b/apps/course/templates/course/_items.html @@ -8,13 +8,11 @@ {% if course.is_deferred_start %}data-future-course data-future-course-time={{ course.deferred_start_at.timestamp }}{% endif %} > - {% if course.cover %} {% thumbnail course.cover.image "300x170" crop="center" as im %} - {% endthumbnail %} - {% else %} + {% empty %} - {% endif %} + {% endthumbnail %}
Подробнее
{% if course.is_featured %}
From 3fcde043876d6951098ef6f566d89a0b00426838 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 14:07:08 +0300 Subject: [PATCH 58/73] LIL-294. Add uuid field to content block --- api/v1/serializers/content.py | 5 +++++ apps/content/migrations/0015_content_uuid.py | 18 ++++++++++++++++++ apps/content/models.py | 1 + 3 files changed, 24 insertions(+) create mode 100644 apps/content/migrations/0015_content_uuid.py 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/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, From 75954748c20bb705ebc742aee77b80d74811692a Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 14:19:28 +0300 Subject: [PATCH 59/73] LIL-308. Only authors & admins in author balance req --- api/v1/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/v1/views.py b/api/v1/views.py index 4a854b78..8aaf84b8 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -55,7 +55,9 @@ 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, From 1f286028800bd5fd9e34f3309b28eee5b25a8264 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 15:27:02 +0300 Subject: [PATCH 60/73] LIL-312. Use fix school amount calc --- apps/payment/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/payment/models.py b/apps/payment/models.py index 5ec8e1ac..d3b42c8c 100644 --- a/apps/payment/models.py +++ b/apps/payment/models.py @@ -157,7 +157,7 @@ class SchoolPayment(Payment): models.Sum('month_price'), ) month_price_sum = aggregate.get('month_price__sum', 0) - if len(self.weekdays) > 7: + if month_price_sum > config.SERVICE_DISCOUNT_MIN_AMOUNT: discount = config.SERVICE_DISCOUNT else: discount = 0 From e63c7c076a508f14c2889a2d4b8e177e3c16dddc Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 15:38:55 +0300 Subject: [PATCH 61/73] LIL-317. Add SCHOOL_LOGO_IMAGE config field --- api/v1/serializers/config.py | 1 + project/settings.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/api/v1/serializers/config.py b/api/v1/serializers/config.py index e17ce57e..31269d66 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/project/settings.py b/project/settings.py index 25bd6e03..59b1f339 100644 --- a/project/settings.py +++ b/project/settings.py @@ -231,6 +231,9 @@ CELERY_BEAT_SCHEDULE = { # Dynamic settings CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend' +CONSTANCE_ADDITIONAL_FIELDS = { + 'image_field': ['django.forms.ImageField', {}] +} CONSTANCE_CONFIG = OrderedDict(( ('INSTAGRAM_CLIENT_ACCESS_TOKEN', ('7145314808.f6fa114.ce354a5d876041fc9d3db04b0045587d', '')), ('INSTAGRAM_CLIENT_SECRET', ('2334a921425140ccb180d145dcd35b25', '')), @@ -240,6 +243,7 @@ CONSTANCE_CONFIG = OrderedDict(( ('SERVICE_COMMISSION', (10, 'Комиссия сервиса в процентах.')), ('SERVICE_DISCOUNT_MIN_AMOUNT', (3500, 'Минимальная сумма платежа для школы, после которой вычитывается скидка SERVICE_DISCOUNT.')), ('SERVICE_DISCOUNT', (1000, 'Комиссия сервиса при покупке всех дней.')), + ('SCHOOL_LOGO_IMAGE', ('default.png', 'Изображение в диалоге покупки школы', 'image_field')), )) CONSTANCE_CONFIG_FIELDSETS = OrderedDict({ @@ -247,6 +251,7 @@ CONSTANCE_CONFIG_FIELDSETS = OrderedDict({ 'SERVICE_COMMISSION', 'SERVICE_DISCOUNT_MIN_AMOUNT', 'SERVICE_DISCOUNT', + 'SCHOOL_LOGO_IMAGE', ), 'Instagram': ( 'INSTAGRAM_CLIENT_ACCESS_TOKEN', From e7f218bd6b60d36998d4be4b4ad7a8b6154d6f7e Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 16 Mar 2018 15:48:24 +0300 Subject: [PATCH 62/73] Update yarn lock file --- web/yarn.lock | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/yarn.lock b/web/yarn.lock index 06389b2f..0a35d84c 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -887,6 +887,10 @@ backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" +baguettebox.js@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/baguettebox.js/-/baguettebox.js-1.10.0.tgz#f24500b2f02433f52338cf77016ecf00cfe7f974" + balanced-match@^0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" From ae00cb34ede15fee52bf59a5cbc51525a050b33f Mon Sep 17 00:00:00 2001 From: Sanasol Date: Mon, 19 Mar 2018 12:42:55 +0300 Subject: [PATCH 63/73] comments filter, new discount config and conditions --- project/templates/lilcity/index.html | 1 + web/src/js/modules/popup.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/project/templates/lilcity/index.html b/project/templates/lilcity/index.html index ed99dd81..9a6ee2b2 100644 --- a/project/templates/lilcity/index.html +++ b/project/templates/lilcity/index.html @@ -500,6 +500,7 @@ {% block foot %}{% endblock foot %} diff --git a/web/src/js/modules/popup.js b/web/src/js/modules/popup.js index db9824b1..4f39ad08 100644 --- a/web/src/js/modules/popup.js +++ b/web/src/js/modules/popup.js @@ -73,7 +73,7 @@ $(document).ready(function () { } var text = ''; - if(weekdays.length >= 7) { + if(schoolAmountForDiscount >= price) { text = ''+price+' '+(price-schoolDiscount)+'р.'; } else { text = price+'p.'; From a17e472be570207389180045d573521c6ae25b5b Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 20 Mar 2018 09:00:58 +0300 Subject: [PATCH 64/73] Disable SCHOOL_LOGO_IMAGE sretting --- api/v1/serializers/config.py | 2 +- project/settings.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/v1/serializers/config.py b/api/v1/serializers/config.py index 31269d66..f6ae89dd 100644 --- a/api/v1/serializers/config.py +++ b/api/v1/serializers/config.py @@ -19,7 +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) + # SCHOOL_LOGO_IMAGE = serializers.ImageField(required=False) def to_representation(self, instance): ret = OrderedDict() diff --git a/project/settings.py b/project/settings.py index 59b1f339..743fb0fb 100644 --- a/project/settings.py +++ b/project/settings.py @@ -243,7 +243,7 @@ CONSTANCE_CONFIG = OrderedDict(( ('SERVICE_COMMISSION', (10, 'Комиссия сервиса в процентах.')), ('SERVICE_DISCOUNT_MIN_AMOUNT', (3500, 'Минимальная сумма платежа для школы, после которой вычитывается скидка SERVICE_DISCOUNT.')), ('SERVICE_DISCOUNT', (1000, 'Комиссия сервиса при покупке всех дней.')), - ('SCHOOL_LOGO_IMAGE', ('default.png', 'Изображение в диалоге покупки школы', 'image_field')), + # ('SCHOOL_LOGO_IMAGE', ('default.png', 'Изображение в диалоге покупки школы', 'image_field')), )) CONSTANCE_CONFIG_FIELDSETS = OrderedDict({ @@ -251,7 +251,7 @@ CONSTANCE_CONFIG_FIELDSETS = OrderedDict({ 'SERVICE_COMMISSION', 'SERVICE_DISCOUNT_MIN_AMOUNT', 'SERVICE_DISCOUNT', - 'SCHOOL_LOGO_IMAGE', + # 'SCHOOL_LOGO_IMAGE', ), 'Instagram': ( 'INSTAGRAM_CLIENT_ACCESS_TOKEN', From d12ed9ae22e4e540288cf933283c48b5923d212c Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 20 Mar 2018 09:27:18 +0300 Subject: [PATCH 65/73] Add is_deactivated filter for comments --- api/v1/views.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api/v1/views.py b/api/v1/views.py index 8aaf84b8..909195d4 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -346,6 +346,16 @@ class CommentViewSet(ExtendedModelViewSet): 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() From fd855045cfbd238149baecb3d26676239e3c998b Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 20 Mar 2018 10:56:26 +0300 Subject: [PATCH 66/73] LIL-151. Disable cache for ajax request in CoursesView --- apps/course/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/course/views.py b/apps/course/views.py index caa3bd5f..42235e27 100644 --- a/apps/course/views.py +++ b/apps/course/views.py @@ -7,6 +7,7 @@ from django.http import JsonResponse, Http404 from django.shortcuts import get_object_or_404 from django.template import loader, Context, Template from django.views.generic import View, CreateView, DetailView, ListView, TemplateView +from django.utils.cache import add_never_cache_headers from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods @@ -245,12 +246,14 @@ class CoursesView(ListView): else: prev_url = None next_url = None - return JsonResponse({ + response = JsonResponse({ 'success': True, 'content': html, 'prev_url': prev_url, 'next_url': next_url, }) + add_never_cache_headers(response) + return response else: return super().get(request, args, kwargs) From b2c03094a32cf0756eed96020a40a690420332ce Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 20 Mar 2018 11:07:34 +0300 Subject: [PATCH 67/73] LIL-226. Add sentry configs --- project/settings.py | 12 ++++++++++++ requirements.txt | 1 + sentry | 1 + 3 files changed, 14 insertions(+) create mode 160000 sentry diff --git a/project/settings.py b/project/settings.py index 743fb0fb..9785e9ca 100644 --- a/project/settings.py +++ b/project/settings.py @@ -11,10 +11,13 @@ https://docs.djangoproject.com/en/2.0/ref/settings/ """ import os +import raven + from celery.schedules import crontab from collections import OrderedDict from datetime import timedelta + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -53,6 +56,7 @@ INSTALLED_APPS = [ 'constance', 'constance.backends.database', 'sorl.thumbnail', + 'raven.contrib.django.raven_compat', ] + [ 'apps.auth.apps', 'apps.user', @@ -290,3 +294,11 @@ if DEBUG: SWAGGER_SETTINGS = { 'DOC_EXPANSION': 'none', } + +# Raven settings +RAVEN_CONFIG = { + 'dsn': 'https://bff536c4d71c4166afb91f83b9f73d55:ca47ad791a53480b9d40a85a26abf141@sentry.io/306843', + # If you are using git, you can also automatically configure the + # release based on the git info. + 'release': raven.fetch_git_sha(BASE_DIR), +} diff --git a/requirements.txt b/requirements.txt index cf55c8a3..710cf88d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,6 +18,7 @@ gunicorn==19.7.1 mixpanel==4.3.2 psycopg2-binary==2.7.4 Pillow==5.0.0 +raven==6.6.0 requests==2.18.4 sorl-thumbnail==12.4.1 twilio==6.10.5 diff --git a/sentry b/sentry new file mode 160000 index 00000000..a514caf9 --- /dev/null +++ b/sentry @@ -0,0 +1 @@ +Subproject commit a514caf906fa22a66eaf6532a721a9393177d2ff From 8f6b5326e61cf02e67f5a22099fc892c921f0347 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 20 Mar 2018 11:08:04 +0300 Subject: [PATCH 68/73] Fix sentry --- sentry | 1 - 1 file changed, 1 deletion(-) delete mode 160000 sentry diff --git a/sentry b/sentry deleted file mode 160000 index a514caf9..00000000 --- a/sentry +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a514caf906fa22a66eaf6532a721a9393177d2ff From 355a7b00fc4844ddedcebbfe6d720a5db19e9b93 Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Tue, 20 Mar 2018 11:53:23 +0300 Subject: [PATCH 69/73] LIL-325. Show authors in main page --- api/v1/serializers/user.py | 1 + apps/user/admin.py | 2 +- .../migrations/0019_user_show_in_mainpage.py | 18 +++++ apps/user/models.py | 1 + project/templates/lilcity/main.html | 70 ++++--------------- project/views.py | 4 ++ 6 files changed, 38 insertions(+), 58 deletions(-) create mode 100644 apps/user/migrations/0019_user_show_in_mainpage.py diff --git a/api/v1/serializers/user.py b/api/v1/serializers/user.py index fe316cf5..f334e9a5 100644 --- a/api/v1/serializers/user.py +++ b/api/v1/serializers/user.py @@ -40,6 +40,7 @@ class UserSerializer(serializers.ModelSerializer): 'is_email_proved', 'photo', 'balance', + 'show_in_mainpage', ) read_only_fields = ( diff --git a/apps/user/admin.py b/apps/user/admin.py index 77d060dc..df3e01d9 100644 --- a/apps/user/admin.py +++ b/apps/user/admin.py @@ -15,7 +15,7 @@ class UserAdmin(BaseUserAdmin): (_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'gender', 'about', 'photo')}), ('Facebook Auth data', {'fields': ('fb_id', 'fb_data', 'is_email_proved')}), (_('Permissions'), {'fields': ('role', 'is_active', 'is_staff', 'is_superuser', - 'groups', 'user_permissions')}), + 'groups', 'user_permissions', 'show_in_mainpage')}), (_('Important dates'), {'fields': ('last_login', 'date_joined')}), ('Social urls', {'fields': ('instagram', 'facebook', 'twitter', 'pinterest', 'youtube', 'vkontakte', )}), ) diff --git a/apps/user/migrations/0019_user_show_in_mainpage.py b/apps/user/migrations/0019_user_show_in_mainpage.py new file mode 100644 index 00000000..e624bba1 --- /dev/null +++ b/apps/user/migrations/0019_user_show_in_mainpage.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.3 on 2018-03-20 08:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0018_user_phone'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='show_in_mainpage', + field=models.BooleanField(default=False, verbose_name='Показывать на главной странице'), + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index 57ec8cd2..058df6b6 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -55,6 +55,7 @@ class User(AbstractUser): 'Верифицирован по email', default=False ) photo = models.ImageField('Фото', null=True, blank=True, upload_to='users') + show_in_mainpage = models.BooleanField('Показывать на главной странице', default=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] diff --git a/project/templates/lilcity/main.html b/project/templates/lilcity/main.html index f0af1cd6..4b2623fd 100644 --- a/project/templates/lilcity/main.html +++ b/project/templates/lilcity/main.html @@ -270,74 +270,30 @@
+ {% for author in authors %}
+ {% if author.photo %} + + {% else %} + {% endif %}
-
Саша Крю, + -
@sashakru
+ {% if author.instagram %} +
{{ author.instagram }}
+ {% endif %} + {% if author.about %}
-

Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.

-

Участник и победитель международных выставок.

-

Основатель компании "Lil City".

-
-
-
-
-
- -
-
-
Саша Крю, - #lil_персонаж -
-
@sashakru
-
-

Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.

-

Участник и победитель международных выставок.

-

Основатель компании "Lil City".

-
-
-
-
-
- -
-
-
Саша Крю, - #lil_персонаж -
-
@sashakru
-
-

Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.

-

Участник и победитель международных выставок.

-

Основатель компании "Lil City".

-
-
-
-
-
- -
-
-
Саша Крю, - #lil_персонаж -
-
@sashakru
-
-

Закончила ПХУ им К.А.Савицкого художник театра и кино. Работала с крупнейшими российскими и зарубежными - издательствами.

-

Участник и победитель международных выставок.

-

Основатель компании "Lil City".

+ {{ author.about }}
+ {% endif %}
+ {% endfor %}
Если хотите к нам в команду, то отправьте нам заявку
diff --git a/project/views.py b/project/views.py index fcedb726..035a5962 100644 --- a/project/views.py +++ b/project/views.py @@ -1,8 +1,11 @@ from django.views.generic import TemplateView +from django.contrib.auth import get_user_model from apps.course.models import Course from apps.school.models import SchoolSchedule +User = get_user_model() + class IndexView(TemplateView): template_name = 'templates/lilcity/main.html' @@ -12,6 +15,7 @@ class IndexView(TemplateView): context.update({ 'course_items': Course.objects.filter(status=Course.PUBLISHED)[:3], 'school_schedules': SchoolSchedule.objects.all(), + 'authors': User.objects.filter(role=User.AUTHOR_ROLE, show_in_mainpage=True), }) return context From 98de6fcdb0de38886fe754e5ee688689370792f2 Mon Sep 17 00:00:00 2001 From: Sanasol Date: Thu, 22 Mar 2018 11:49:06 +0300 Subject: [PATCH 70/73] comments anchor position --- apps/course/templates/course/blocks/comment.html | 3 ++- web/src/sass/_common.sass | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/course/templates/course/blocks/comment.html b/apps/course/templates/course/blocks/comment.html index 463536af..497c398d 100644 --- a/apps/course/templates/course/blocks/comment.html +++ b/apps/course/templates/course/blocks/comment.html @@ -1,6 +1,7 @@ {% load static %} {% if not node.deactivated_at %} -
+ +
{% if node.author.photo %}
diff --git a/web/src/sass/_common.sass b/web/src/sass/_common.sass index 66166011..e1279091 100755 --- a/web/src/sass/_common.sass +++ b/web/src/sass/_common.sass @@ -2488,6 +2488,11 @@ a.grey-link width: 100% .questions + &__anchor + display: block; + position: relative; + top: -110px; + visibility: hidden; &__form, &__item display: flex From 72cdbcb4f276a7e6caf6ca2f55df8ff700f3192d Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Thu, 22 Mar 2018 12:54:06 +0300 Subject: [PATCH 71/73] LIL-326. Add min school price --- project/templates/lilcity/main.html | 2 +- project/views.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/project/templates/lilcity/main.html b/project/templates/lilcity/main.html index 4b2623fd..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 %} diff --git a/project/views.py b/project/views.py index 035a5962..6f73fff7 100644 --- a/project/views.py +++ b/project/views.py @@ -1,5 +1,6 @@ -from django.views.generic import TemplateView +from django.db.models import Min from django.contrib.auth import get_user_model +from django.views.generic import TemplateView from apps.course.models import Course from apps.school.models import SchoolSchedule @@ -15,6 +16,7 @@ class IndexView(TemplateView): context.update({ 'course_items': Course.objects.filter(status=Course.PUBLISHED)[:3], 'school_schedules': SchoolSchedule.objects.all(), + 'min_school_price': SchoolSchedule.objects.all().aggregate(Min('month_price'))['month_price__min'], 'authors': User.objects.filter(role=User.AUTHOR_ROLE, show_in_mainpage=True), }) return context From d4aed0aead1532ba02b683f28c103b11701ea20a Mon Sep 17 00:00:00 2001 From: Sanasol Date: Thu, 22 Mar 2018 12:57:16 +0300 Subject: [PATCH 72/73] discount min price fix --- web/src/js/modules/popup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/js/modules/popup.js b/web/src/js/modules/popup.js index 4f39ad08..feaa8a8a 100644 --- a/web/src/js/modules/popup.js +++ b/web/src/js/modules/popup.js @@ -73,7 +73,7 @@ $(document).ready(function () { } var text = ''; - if(schoolAmountForDiscount >= price) { + if(schoolAmountForDiscount <= price) { text = ''+price+' '+(price-schoolDiscount)+'р.'; } else { text = price+'p.'; From 30f446331d474fa6d45adfc895be912bb9f27c14 Mon Sep 17 00:00:00 2001 From: Sanasol Date: Thu, 22 Mar 2018 13:42:42 +0300 Subject: [PATCH 73/73] phone mask --- apps/user/templates/user/profile-settings.html | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index 8eddef8c..f5f2e9fe 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -83,7 +83,7 @@
Телефон
- +
{% if form.phone.errors %}
Укажите корректно свои данные
@@ -259,4 +259,11 @@ var openFile = function(file) { reader.readAsDataURL(input.files[0]); }; + {% endblock content %} + +{% block foot %} + +{% endblock foot %} \ No newline at end of file