diff --git a/apps/auth/backend.py b/apps/auth/backend.py new file mode 100644 index 00000000..41568b52 --- /dev/null +++ b/apps/auth/backend.py @@ -0,0 +1,17 @@ +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth import get_user_model + +User = get_user_model() + + +class CaseInsensitiveModelBackend(ModelBackend): + + def authenticate(self, request, username=None, password=None, **kwargs): + if username is None: + username = kwargs.get(User.USERNAME_FIELD) + try: + user = User.objects.get(**{f'{User.USERNAME_FIELD}__iexact': username}) + if user.check_password(password) and self.user_can_authenticate(user): + return user + except User.DoesNotExist: + return None diff --git a/apps/auth/forms.py b/apps/auth/forms.py index 0baea362..e369a8f9 100644 --- a/apps/auth/forms.py +++ b/apps/auth/forms.py @@ -6,8 +6,3 @@ class LearnerRegistrationForm(forms.Form): last_name = forms.CharField() email = forms.EmailField() password = forms.CharField() - - -class LoginForm(forms.Form): - email = forms.CharField() - password = forms.CharField() diff --git a/apps/auth/views.py b/apps/auth/views.py index f6105e75..379ab0a5 100644 --- a/apps/auth/views.py +++ b/apps/auth/views.py @@ -33,7 +33,7 @@ class LearnerRegistrationView(FormView): def form_valid(self, form): first_name = form.cleaned_data['first_name'] last_name = form.cleaned_data['last_name'] - email = form.cleaned_data['email'] + email = form.cleaned_data['email'].lower() password = form.cleaned_data['password'] user, created = User.objects.get_or_create( @@ -170,8 +170,9 @@ class FacebookLoginOrRegistration(View): "errors": {"email": 'is field required'} }) else: + email = email.lower() try: - user = User.objects.get(email=email) + user = User.objects.get(email__iexact=email) except User.DoesNotExist: first_name = data.get('first_name', '') last_name = data.get('last_name', '') diff --git a/apps/course/filters.py b/apps/course/filters.py index 827079e6..6e4e873e 100644 --- a/apps/course/filters.py +++ b/apps/course/filters.py @@ -4,7 +4,7 @@ from .models import Course class CourseFilter(django_filters.FilterSet): - category = django_filters.CharFilter(field_name='category__title', lookup_expr='iexact') + category = django_filters.CharFilter(field_name='category') class Meta: model = Course diff --git a/apps/course/models.py b/apps/course/models.py index 942a0593..d4966b3c 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -1,4 +1,5 @@ import arrow +from random import shuffle from uuid import uuid4 from django.db import models from django.core.exceptions import ValidationError @@ -7,6 +8,7 @@ from django.utils.text import slugify from django.utils.timezone import now from django.contrib.auth import get_user_model from django.urls import reverse_lazy +from django.conf import settings from polymorphic_tree.models import PolymorphicMPTTModel, PolymorphicTreeForeignKey from project.mixins import BaseModel, DeactivatedMixin @@ -97,7 +99,7 @@ class Course(BaseModel, DeactivatedMixin): class Meta: verbose_name = 'Курс' verbose_name_plural = 'Курсы' - ordering = ['-created_at'] + ordering = ['-is_featured', ] def __str__(self): return str(self.id) + ' ' + self.title @@ -129,11 +131,11 @@ class Course(BaseModel, DeactivatedMixin): @property def deferred_start_at_humanize(self): - return arrow.get(self.deferred_start_at).humanize(locale='ru') + return arrow.get(self.deferred_start_at, settings.TIME_ZONE).humanize(locale='ru') @property def created_at_humanize(self): - return arrow.get(self.created_at).humanize(locale='ru') + return arrow.get(self.created_at, settings.TIME_ZONE).humanize(locale='ru') @property def is_deferred_start(self): @@ -148,6 +150,24 @@ class Course(BaseModel, DeactivatedMixin): def count_videos_in_lessons(self): return Video.objects.filter(lesson__in=self.lessons.all()).count() + @classmethod + def shuffle(cls, qs, order_is_featured = True): + if order_is_featured: + featured = [] + other = [] + for c in list(qs): + if c.is_featured: + featured.append(c) + else: + other.append(c) + shuffle(featured) + shuffle(other) + return featured + other + else: + all = list(qs) + shuffle(all) + return all + class Category(models.Model): title = models.CharField('Название категории', max_length=100) @@ -234,7 +254,7 @@ class Comment(PolymorphicMPTTModel, DeactivatedMixin): @property def created_at_humanize(self): - return arrow.get(self.created_at).humanize(locale='ru') + return arrow.get(self.created_at, settings.TIME_ZONE).humanize(locale='ru') def __str__(self): return self.content diff --git a/apps/course/templates/course/content/imagetext.html b/apps/course/templates/course/content/imagetext.html index 6385391e..80c6797a 100644 --- a/apps/course/templates/course/content/imagetext.html +++ b/apps/course/templates/course/content/imagetext.html @@ -9,7 +9,7 @@ -
{{ content.txt | safe }}
+
{{ content.txt | safe | linebreaks }}
diff --git a/apps/course/templates/course/course.html b/apps/course/templates/course/course.html index f5ba90af..53a56abc 100644 --- a/apps/course/templates/course/course.html +++ b/apps/course/templates/course/course.html @@ -70,7 +70,7 @@
{{ course.title }}
-
{{ course.short_description }}
+
{{ course.short_description | linebreaks }}
{% if course.author.photo %} @@ -158,13 +158,13 @@ {% else %} УРОКИ - {% if not paid %} + {% if not paid and course.price %} @@ -270,7 +270,7 @@
{{ course.title }}
-
{{ course.short_description }}
+
{{ course.short_description | linebreaks }}
{% if course.author.photo %} diff --git a/apps/course/templates/course/course_only_lessons.html b/apps/course/templates/course/course_only_lessons.html index f0217bcf..b987475c 100644 --- a/apps/course/templates/course/course_only_lessons.html +++ b/apps/course/templates/course/course_only_lessons.html @@ -25,7 +25,7 @@
Вернуться
- {% if not paid and course.price %} + {% if not paid and course.price and not has_full_access %} {% else %} УРОКИ - {% if not paid %} + {% if not paid and course.price %} @@ -180,19 +180,18 @@ {% endif %}
-
{{ forloop.counter }}. {{ lesson.title }}
- {% if lesson.cover %}
- +
- {% endif %} -
{{ lesson.short_description | truncatechars_html:800 | safe }}
-
-
- Перейти к уроку +
+
{{ forloop.counter }}. {{ lesson.title }}
+
{{ lesson.short_description | truncatechars_html:800 | safe }}
+ Перейти к уроку +
diff --git a/apps/course/templates/course/courses.html b/apps/course/templates/course/courses.html index a3277174..8f6f57d2 100644 --- a/apps/course/templates/course/courses.html +++ b/apps/course/templates/course/courses.html @@ -20,8 +20,8 @@
-
-
{% if category %}{{ category.0 }}{% else %}Категории{% endif %}
+
+
Категории
diff --git a/apps/course/templates/course/inclusion/category_items.html b/apps/course/templates/course/inclusion/category_items.html index 5e6aeef5..5549ffa4 100644 --- a/apps/course/templates/course/inclusion/category_items.html +++ b/apps/course/templates/course/inclusion/category_items.html @@ -1,5 +1,6 @@ {% for cat in category_items %} -
+
{{ cat.title }}
{% endfor %} \ No newline at end of file diff --git a/apps/course/templates/course/inclusion/category_menu_items.html b/apps/course/templates/course/inclusion/category_menu_items.html index a01342a9..ecb83298 100644 --- a/apps/course/templates/course/inclusion/category_menu_items.html +++ b/apps/course/templates/course/inclusion/category_menu_items.html @@ -2,7 +2,7 @@
Все курсы
{% for cat in category_items %} - +
{{ cat.title }}
{% endfor %} diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index dd3c178d..73b70f0a 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -27,37 +27,37 @@ {% endif %}
-
{{ lesson.title }}
-
{{ lesson.short_description }}
- - @@ -117,6 +117,7 @@
{% if request.user.is_authenticated %}
+
+
diff --git a/apps/course/templatetags/lilcity_category.py b/apps/course/templatetags/lilcity_category.py index 957e50c2..956bbab4 100644 --- a/apps/course/templatetags/lilcity_category.py +++ b/apps/course/templatetags/lilcity_category.py @@ -9,7 +9,7 @@ register = template.Library() def category_items(category=None): return { 'category_items': Category.objects.filter(courses__status=Course.PUBLISHED).exclude(courses=None).distinct(), - 'category': category, + 'category': int(category[0]) if category and category[0] else None, } @@ -17,5 +17,5 @@ def category_items(category=None): def category_menu_items(category=None): return { 'category_items': Category.objects.filter(courses__status=Course.PUBLISHED).exclude(courses=None).distinct(), - 'category': category, + 'category': int(category[0]) if category and category[0] else None, } diff --git a/apps/course/views.py b/apps/course/views.py index 8cff720a..857a57d0 100644 --- a/apps/course/views.py +++ b/apps/course/views.py @@ -189,9 +189,13 @@ 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 and self.object.status != Course.PUBLISHED) or\ - (request.user.is_authenticated and request.user.role < User.AUTHOR_ROLE and self.object.author != request.user and self.only_lessons and not context['paid']): - raise Http404 + + # если это не админ или автор + if not context.get('has_full_access'): + # если это не опубл курс или это страница уроков, курс платный, а юзер не оплатил курс - 404 + if (self.object.status != Course.PUBLISHED) or \ + (self.only_lessons and self.object.price and not context.get('paid')): + raise Http404 return response # ((self.object.status != Course.PUBLISHED and request.user.role != User.ADMIN_ROLE) or @@ -216,6 +220,9 @@ class CourseView(DetailView): context['only_lessons'] = self.only_lessons if self.only_lessons: context['lessons'] = self.object.lessons.order_by('position') + context['is_owner'] = self.object.author == self.request.user + context['is_admin'] = self.request.user.role == User.ADMIN_ROLE + context['has_full_access'] = context['is_owner'] or context['is_admin'] return context def get_queryset(self): @@ -234,7 +241,6 @@ class CoursesView(ListView): def get(self, request, *args, **kwargs): self.object_list = self.get_queryset() - allow_empty = self.get_allow_empty() if request.is_ajax(): context = self.get_context_data() template_name = self.get_template_names() @@ -276,6 +282,7 @@ class CoursesView(ListView): context = super().get_context_data() filtered = CourseFilter(self.request.GET) context.update(filtered.data) + context['course_items'] = Course.shuffle(context.get('course_items')) return context def get_template_names(self): @@ -292,10 +299,20 @@ class LessonView(DetailView): def get(self, request, *args, **kwargs): response = super().get(request, *args, **kwargs) - if (self.object.course.status != Course.PUBLISHED and not - (request.user.role == User.ADMIN_ROLE or - self.object.course.author == request.user)): - raise Http404 + paid = request.user.is_authenticated and self.object.course.payments.filter( + user=self.request.user, + status__in=[ + Pingback.PINGBACK_TYPE_REGULAR, + Pingback.PINGBACK_TYPE_GOODWILL, + Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, + ], + ).exists() + # если это не автор или админ + if not (request.user.is_authenticated and + (request.user.role == User.ADMIN_ROLE or self.object.course.author == request.user)): + # если курс не опубликован или он платный и не оплачен - 404 + if self.object.course.status != Course.PUBLISHED or (self.object.course.price and not paid): + raise Http404 return response def get_context_data(self, **kwargs): diff --git a/apps/payment/models.py b/apps/payment/models.py index 32d7a0e9..415ad98e 100644 --- a/apps/payment/models.py +++ b/apps/payment/models.py @@ -9,6 +9,7 @@ from django.contrib.auth import get_user_model from django.contrib.postgres.fields import ArrayField, JSONField from django.core.validators import RegexValidator from django.utils.timezone import now +from django.conf import settings from project.utils import weekday_in_date_range @@ -198,4 +199,4 @@ class SchoolPayment(Payment): @property def date_end_humanize(self): - return arrow.get(self.date_end).humanize(locale='ru') + return arrow.get(self.date_end, settings.TIME_ZONE).humanize(locale='ru') diff --git a/apps/payment/views.py b/apps/payment/views.py index 2f70df36..40fccca0 100644 --- a/apps/payment/views.py +++ b/apps/payment/views.py @@ -17,6 +17,7 @@ from django.views.decorators.csrf import csrf_exempt from django.urls import reverse_lazy from django.utils.decorators import method_decorator from django.utils.timezone import now +from django.conf import settings from paymentwall import Pingback, Product, Widget @@ -219,14 +220,14 @@ class PaymentwallCallbackView(View): date_start = self.add_months(sourcedate=now().replace(hour=0, minute=0, day=1), months=1) date_end = school_payment.date_end else: - date_start = arrow.get(school_payment.date_end).shift(days=1).datetime - date_end = arrow.get(date_start).shift(months=1).datetime + date_start = arrow.get(school_payment.date_end, settings.TIME_ZONE).shift(days=1).datetime + date_end = arrow.get(date_start, settings.TIME_ZONE).shift(months=1).datetime else: #month = 0 if now().day >= 1 and now().day <= 10 else 1 # Логика июльского лагеря: до конца июля приобретаем только на текущий месяц month = 0 date_start = self.add_months(sourcedate=now().replace(hour=0, minute=0, day=1), months=month) - date_end = arrow.get(date_start).shift(months=1, minutes=-1).datetime + date_end = arrow.get(date_start, settings.TIME_ZONE).shift(months=1, minutes=-1).datetime payment.date_start = date_start payment.date_end = date_end if product_type_name == 'course': diff --git a/apps/school/templates/blocks/_schedule_purchased_item.html b/apps/school/templates/blocks/_schedule_purchased_item.html deleted file mode 100644 index b9d1db1f..00000000 --- a/apps/school/templates/blocks/_schedule_purchased_item.html +++ /dev/null @@ -1,78 +0,0 @@ -{% load static %} {% load thumbnail %} -
-
-
-
- {{ school_schedule }} -
- {% if live_lesson %} -
{{ live_lesson.date }}
- {% endif %} -
-
-
{{ school_schedule.start_at }} (МСК)
- {% if school_schedule.weekday in school_schedules_purchased %} - {% if live_lesson and live_lesson.title %} - {% include './open_lesson.html' %} - {% endif %} - {% else %} - {% include './day_pay_btn.html' %} - {% endif %} -
- {% comment %} - - {% endcomment %} - {% if school_schedule.weekday in school_schedules_purchased %} - - {% endif %} -
-
-
- {% thumbnail live_lesson.cover.image "70x70" crop="center" as im %} - - {% empty %} - - {% endthumbnail %} -
-
-
-
{{ school_schedule.title }}{% if live_lesson and live_lesson.title %}, - {{ live_lesson.title }} - {% endif %} -
-
- {% if live_lesson and live_lesson.short_description %} - {{ live_lesson.short_description }} - {% else %} - {{ school_schedule.description }} - {% endif %} -
-
-
Материалы
-
-
- {{ school_schedule.materials }} -
-
- {% if school_schedule.schoolschedule_images.exists %} -
Результаты прошлых уроков
- - {% endif %} -
-
-
- -
-
diff --git a/apps/school/templates/blocks/open_lesson.html b/apps/school/templates/blocks/open_lesson.html index 46999c7f..abb8a9a2 100644 --- a/apps/school/templates/blocks/open_lesson.html +++ b/apps/school/templates/blocks/open_lesson.html @@ -1,4 +1,4 @@ смотреть урок +>подробнее diff --git a/apps/school/templates/blocks/schedule.html b/apps/school/templates/blocks/schedule.html index 89ce9222..5f088511 100644 --- a/apps/school/templates/blocks/schedule.html +++ b/apps/school/templates/blocks/schedule.html @@ -6,78 +6,7 @@
{% for school_schedule in school_schedules %} - {% with current_live_lesson=school_schedule.current_live_lesson %} -
-
-
-
- {{ school_schedule }} -
- {% comment %} - {% if current_live_lesson %} -
{{ current_live_lesson.date }}
- {% endif %} - {% endcomment %} -
-
-
{{ school_schedule.start_at }} (МСК)
- {% comment %} - {% include './pay_btn.html' %} - {% endcomment %} -
-
-
-
- {% thumbnail current_live_lesson.cover.image "70x70" crop="center" as im %} - - {% empty %} - - {% endthumbnail %} -
-
-
-
{{ school_schedule.title }} - {% if current_live_lesson and current_live_lesson.title %} - , {{ current_live_lesson.title }} - {% endif %} -
-
- {% if live_lesson %} - {{ live_lesson.short_description }} - {% else %} - {{ school_schedule.description }} - {% endif %} -
-
-
Материалы
-
-
- {{ school_schedule.materials }} -
-
- {% if school_schedule.schoolschedule_images.exists %} -
Результаты прошлых уроков
- - {% endif %} -
-
-
- -
-
- {% endwith %} + {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson purchased=True %} {% endfor %}
diff --git a/apps/school/templates/summer/_schedule_purchased_item.html b/apps/school/templates/blocks/schedule_item.html similarity index 69% rename from apps/school/templates/summer/_schedule_purchased_item.html rename to apps/school/templates/blocks/schedule_item.html index 0e86ccba..3895f575 100644 --- a/apps/school/templates/summer/_schedule_purchased_item.html +++ b/apps/school/templates/blocks/schedule_item.html @@ -1,21 +1,23 @@ {% load static %} {% load thumbnail %} -
+
{{ school_schedule }}
- {% if live_lesson %} + {% if purchased and live_lesson %}
{{ live_lesson.date }}
{% endif %} +
{{ school_schedule.start_at }} (МСК)
-
{{ school_schedule.start_at }} (МСК)
- {% if school_schedule.weekday in school_schedules_purchased %} - {% if live_lesson and live_lesson.title %} - {% include './open_lesson.html' %} + {% if purchased %} + {% if school_schedule.weekday in school_schedules_purchased %} + {% if live_lesson and live_lesson.title %} + {% include './open_lesson.html' %} + {% endif %} + {% else %} + {% include './day_pay_btn.html' %} {% endif %} - {% else %} - {% include './day_pay_btn.html' %} {% endif %}
@@ -26,7 +28,7 @@ {% endif %}
-
+
{% thumbnail live_lesson.cover.image "70x70" crop="center" as im %} @@ -36,7 +38,7 @@ {% endthumbnail %}
-
+
{{ school_schedule.title }}{% if live_lesson and live_lesson.title %}, {{ live_lesson.title }} {% endif %} @@ -51,11 +53,19 @@
Материалы
-
- {{ school_schedule.materials }} -
+ {% if print %} +
+
+ {{ school_schedule.materials }} +
+
+ {% else %} +
+ {{ school_schedule.materials }} +
+ {% endif %}
- {% if school_schedule.schoolschedule_images.exists %} + {% if not print and school_schedule.schoolschedule_images.exists %}
Результаты прошлых уроков
+ {% if not print %}
+ {% endif %}
diff --git a/apps/school/templates/blocks/schedule_purchased.html b/apps/school/templates/blocks/schedule_purchased.html index 7f8f035d..5d1a5827 100644 --- a/apps/school/templates/blocks/schedule_purchased.html +++ b/apps/school/templates/blocks/schedule_purchased.html @@ -41,10 +41,10 @@ {% for school_schedule in school_schedules %} {% if is_previous %} {% if school_schedule.previous_live_lesson in live_lessons %} - {% include './_schedule_purchased_item.html' with school_schedule=school_schedule live_lesson=school_schedule.previous_live_lesson %} + {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.previous_live_lesson purchased=True %} {% endif %} {% else %} - {% include './_schedule_purchased_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson %} + {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson purchased=True %} {% endif %} {% endfor %} {% endif %} diff --git a/apps/school/templates/school/livelesson_detail.html b/apps/school/templates/school/livelesson_detail.html index 2637da2c..74a6eb4e 100644 --- a/apps/school/templates/school/livelesson_detail.html +++ b/apps/school/templates/school/livelesson_detail.html @@ -8,42 +8,20 @@
{{ livelesson.title }}
{{ livelesson.short_description }}
- {% comment %} - -
- {% if livelesson.author.photo %} -
- -
- {% else %} -
- -
- {% endif %} -
-
{{ livelesson.author.get_full_name }}
-
-
{{ livelesson.created_at_humanize }}
-
-
-
-
- {% endcomment %} {% if livelesson.stream_index %} - - Если видео не загрузилось обновите страницу + + + + Если видео не загрузилось, уменьшите качество видео или обновите страницу {% else %} - {% if livelesson.cover %} - - {% else %} - - {% endif %} + {% if livelesson.cover %} + + {% endif %} {% endif %} -
diff --git a/apps/school/templates/school/livelessons_list.html b/apps/school/templates/school/livelessons_list.html index b02e4f8d..b2099cbe 100644 --- a/apps/school/templates/school/livelessons_list.html +++ b/apps/school/templates/school/livelessons_list.html @@ -24,7 +24,7 @@
{{ livelesson.date }} // {{ livelesson.title }}
-
{{ livelesson.short_description }}
+
{{ livelesson.short_description | linebreaks }}
{% endfor %} diff --git a/apps/school/templates/school/schedules_print.html b/apps/school/templates/school/schedules_print.html index 25aca06e..66c936cb 100644 --- a/apps/school/templates/school/schedules_print.html +++ b/apps/school/templates/school/schedules_print.html @@ -11,70 +11,16 @@ - +
Расписание
- {% for school_schedule in school_schedules %} {% with current_live_lesson=school_schedule.current_live_lesson %} -
-
-
-
- {{ school_schedule }} -
- {% if current_live_lesson %} - - {% endif %} -
-
-
{{ school_schedule.start_at }} (МСК)
-
-
-
-
- {% thumbnail current_live_lesson.cover.image "70x70" crop="center" as im %} - {% empty %} - {% endthumbnail %} -
-
-
-
{{ school_schedule.title }}{% if current_live_lesson %}, - {{ current_live_lesson.title }} - {% endif %} -
-
- {% if live_lesson %} - {{ live_lesson.short_description }} - {% else %} - {{ school_schedule.description }} - {% endif %} -
-
-
Материалы
-
-
-
- {{ school_schedule.materials }} -
-
-
- - - - - - - - - - -
-
-
- {% endwith %} {% endfor %} + {% for school_schedule in school_schedules %} + {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson print=True %} + {% endfor %}
diff --git a/apps/school/templates/summer/schedule_purchased.html b/apps/school/templates/summer/schedule_purchased.html index 63e963fd..b6e183a1 100644 --- a/apps/school/templates/summer/schedule_purchased.html +++ b/apps/school/templates/summer/schedule_purchased.html @@ -25,12 +25,15 @@ {% else %}
Новые уроки
{% endif %} + + {% comment %} + {% endcomment %}
{% endif %}
@@ -38,15 +41,17 @@ {% if is_previous and not live_lessons_exists %} Записей уроков пока нет {% else %} - {% for school_schedule in school_schedules %} - {% if is_previous %} - {% if school_schedule.previous_live_lesson in live_lessons %} - {% include './_schedule_purchased_item.html' with school_schedule=school_schedule live_lesson=school_schedule.previous_live_lesson %} - {% endif %} - {% else %} - {% include './_schedule_purchased_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson %} - {% endif %} - {% endfor %} + {% if is_previous %} + {% for live_lesson in live_lessons %} + {% if live_lesson.school_schedule and live_lesson.title %} + {% include 'blocks/schedule_item.html' with school_schedule=live_lesson.school_schedule live_lesson=live_lesson purchased=True %} + {% endif %} + {% endfor %} + {% else %} + {% for school_schedule in school_schedules %} + {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson purchased=True %} + {% endfor %} + {% endif %} {% endif %}
diff --git a/apps/school/views.py b/apps/school/views.py index 7f4ab734..3f269067 100644 --- a/apps/school/views.py +++ b/apps/school/views.py @@ -4,9 +4,9 @@ from paymentwall import Pingback from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required, user_passes_test from django.db.utils import IntegrityError -from django.db.models import Min, F, Func, Q +from django.db.models import Min, F, Func, Q, Value from django.http import Http404 -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, redirect from django.utils.decorators import method_decorator from django.utils.timezone import now from django.views.generic import ListView, UpdateView, TemplateView, DetailView @@ -170,10 +170,19 @@ class SchoolView(TemplateView): class SummerSchoolView(TemplateView): template_name = 'school/summer_school.html' + def get(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + if not context.get('is_purchased'): + return redirect('/') + return self.render_to_response(context) + def get_context_data(self): context = super().get_context_data() is_previous = 'is_previous' in self.request.GET date_now = now().date() + yesterday = date_now - timedelta(days=1) + # month_start = date_now.replace(day=1) + month_start = datetime(2018, 7, 1).date() now_time = now() try: school_schedule = SchoolSchedule.objects.get(weekday=now_time.isoweekday()) @@ -186,7 +195,25 @@ class SummerSchoolView(TemplateView): (end_at + timedelta(hours=1)).time() >= now_time.time() and school_schedule.current_live_lesson() ) + + school_schedules = SchoolSchedule.objects.all() + school_schedules_dict = {ss.weekday: ss for ss in school_schedules} + school_schedules_dict[0] = school_schedules_dict.get(7) + all_schedules_purchased = [] if self.request.user.is_authenticated: + all_schedules_purchased = SchoolPayment.objects.filter( + user=self.request.user, + status__in=[ + Pingback.PINGBACK_TYPE_REGULAR, + Pingback.PINGBACK_TYPE_GOODWILL, + Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, + ], + date_start__range=[month_start, date_now], + ).annotate( + joined_weekdays=Func(F('weekdays'), function='unnest',) + ).distinct().values_list('joined_weekdays', flat=True) + all_schedules_purchased = list(map(lambda x: 1 if x == 7 else x+1, all_schedules_purchased)) + school_payment = SchoolPayment.objects.filter( user=self.request.user, status__in=[ @@ -221,12 +248,14 @@ class SummerSchoolView(TemplateView): school_payment_exists_future = False school_purchased_future = False school_schedules_purchased = [] - if school_payment_exists and is_previous: + if all_schedules_purchased and is_previous: live_lessons = LiveLesson.objects.filter( - date__gte=school_payment.last().date_start, - date__range=[(now_time - timedelta(days=8)).date(), (now_time - timedelta(days=1)).date()], + date__range=[month_start, yesterday], deactivated_at__isnull=True, - ) + date__week_day__in=all_schedules_purchased, + ).order_by('-date') + for ll in live_lessons: + ll.school_schedule = school_schedules_dict.get(ll.date.isoweekday()) live_lessons_exists = live_lessons.exists() else: live_lessons = None @@ -240,7 +269,7 @@ class SummerSchoolView(TemplateView): 'is_purchased': school_payment_exists, 'is_purchased_future': school_payment_exists_future, 'min_school_price': SchoolSchedule.objects.aggregate(Min('month_price'))['month_price__min'], - 'school_schedules': SchoolSchedule.objects.all(), + 'school_schedules': school_schedules, 'school_schedules_purchased': school_schedules_purchased, 'school_purchased_future': school_purchased_future, 'subscription_ends': school_payment.filter(add_days=False).first().date_end if school_payment_exists else None, diff --git a/apps/user/templates/user/author_profile.html b/apps/user/templates/user/author_profile.html new file mode 100644 index 00000000..da09c579 --- /dev/null +++ b/apps/user/templates/user/author_profile.html @@ -0,0 +1,87 @@ +{% extends "templates/lilcity/index.html" %} {% load static %} {% load thumbnail %} {% block content %} +
+
+
+
+ {% thumbnail user.photo "120x120" crop="center" as im %} + + {% empty %} + + {% endthumbnail %} +
+
+
{{ user.get_full_name }}
+ +
+
+ {% if user.about %} + {{ user.about }} + {% endif %} +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ {% if published.exists %} + {% include "course/course_items.html" with course_items=published %} + {% else %} +
+
+
Нет опубликованных курсов!
+
+
+ {% endif %} +
+
+
+
+
+
+
+{% endblock content %} diff --git a/apps/user/templates/user/notification-settings.html b/apps/user/templates/user/notification-settings.html index f2688060..40c679e5 100644 --- a/apps/user/templates/user/notification-settings.html +++ b/apps/user/templates/user/notification-settings.html @@ -2,7 +2,7 @@
diff --git a/apps/user/templates/user/payment-history.html b/apps/user/templates/user/payment-history.html index 5643dfa5..c27a3faa 100644 --- a/apps/user/templates/user/payment-history.html +++ b/apps/user/templates/user/payment-history.html @@ -2,7 +2,7 @@
diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index f590c7f9..5502c21d 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -2,7 +2,7 @@
diff --git a/apps/user/templates/user/profile.html b/apps/user/templates/user/profile.html index 6b0f0b07..fd279635 100644 --- a/apps/user/templates/user/profile.html +++ b/apps/user/templates/user/profile.html @@ -2,9 +2,7 @@
- {% if not guest %} - Редактировать - {% endif %} + Редактировать
{% thumbnail user.photo "120x120" crop="center" as im %} @@ -56,7 +54,7 @@ {% endif %}
@@ -66,18 +64,18 @@
- {% if owner %} - + {# #} - {% endif %} - + {% endif %}
- {% if owner %} + {% comment %}
{% if is_purchased_future %}
@@ -108,7 +106,8 @@ {% endif %} {% endif %}
-
+ {% endcomment %} +
{% if paid.exists %} @@ -126,8 +125,8 @@
- {% endif %} -
+ {% if is_author %} +
{% if published.exists %} @@ -145,6 +144,7 @@
+ {% endif %}
diff --git a/apps/user/views.py b/apps/user/views.py index 500d8404..309fb0e0 100644 --- a/apps/user/views.py +++ b/apps/user/views.py @@ -1,5 +1,3 @@ -import arrow - from io import BytesIO from PIL import Image from uuid import uuid4 @@ -41,25 +39,23 @@ def resend_email_verify(request): url = request.scheme + '://' + request.get_host() + str(reverse_lazy('lilcity:verification-email', args=[token, request.user.id])) send_email('Вы успешно прошли регистрацию', request.user.email, "notification/email/verification_email.html", url=url) messages.info(request, 'Письмо подтверждения отправлено.') - return redirect('user-edit-profile', request.user.id) + return redirect('user-edit-profile') -class UserView(DetailView): +@method_decorator(login_required, name='dispatch') +class ProfileView(TemplateView): model = User template_name = 'user/profile.html' + def get(self, request, *args, **kwargs): + self.object = self.request.user + context = self.get_context_data(object=self.object) + return self.render_to_response(context) + def get_context_data(self, object): context = super().get_context_data() - if not self.request.user.is_anonymous: - context['simple_user'] = self.request.user.role == User.USER_ROLE - context['guest'] = self.request.user.id != self.object.id and self.request.user.role <= User.USER_ROLE - else: - context['simple_user'] = True - context['guest'] = True - context['owner'] = self.request.user.id == self.object.id - - if context['guest'] and self.object.role <= User.USER_ROLE: - raise Http404() + context['user'] = self.request.user + context['is_author'] = self.request.user.role == User.AUTHOR_ROLE context['published'] = Course.objects.filter( author=self.object, @@ -110,6 +106,18 @@ class UserView(DetailView): return context +class UserView(DetailView): + model = User + template_name = 'user/author_profile.html' + + def get_context_data(self, object): + context = super().get_context_data() + context['published'] = Course.objects.filter( + author=self.object, + ) + return context + + class SubscribeView(View): def post(self, request, pk=None, **kwargs): @@ -190,16 +198,16 @@ class PaymentHistoryView(FormView): @method_decorator(login_required, name='dispatch') -class UserEditView(UpdateView): +class ProfileEditView(UpdateView): model = User template_name = 'user/profile-settings.html' form_class = UserEditForm - @method_decorator(login_required) + def get_object(self, queryset=None): + return self.request.user + def dispatch(self, request, *args, **kwargs): self.object = self.get_object() - if request.user != self.object: - raise Http404() return super().dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): @@ -245,7 +253,7 @@ class UserEditView(UpdateView): return super().post(request, *args, **kwargs) def get_success_url(self): - return reverse('user-edit-profile', args=[self.object.id]) + return reverse('user-edit-profile') class AuthorRequestView(FormView): diff --git a/project/context_processors.py b/project/context_processors.py index 0e7e9d32..e4788dc4 100644 --- a/project/context_processors.py +++ b/project/context_processors.py @@ -1,5 +1,9 @@ +from django.utils.timezone import now +from paymentwall.pingback import Pingback + from apps.config.models import Config from apps.content.models import Baner +from apps.payment.models import SchoolPayment def config(request): @@ -8,3 +12,20 @@ def config(request): def baner(request): return {'baner': Baner.objects.filter(use=True).first()} + + +def is_summer_school_purchased(request): + if request.user.is_authenticated: + n = now().date() + school_payment = SchoolPayment.objects.filter( + user=request.user, + status__in=[ + Pingback.PINGBACK_TYPE_REGULAR, + Pingback.PINGBACK_TYPE_GOODWILL, + Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, + ], + date_start__lte=n, + date_end__gte=n + ) + return {'is_summer_school_purchased': school_payment.exists()} + return {'is_summer_school_purchased': False} diff --git a/project/settings.py b/project/settings.py index 9323745c..646c94ed 100644 --- a/project/settings.py +++ b/project/settings.py @@ -93,6 +93,7 @@ TEMPLATES = [ 'context_processors': [ 'project.context_processors.config', 'project.context_processors.baner', + 'project.context_processors.is_summer_school_purchased', 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', @@ -141,6 +142,7 @@ AUTH_PASSWORD_VALIDATORS = [ AUTH_USER_MODEL = 'user.User' +AUTHENTICATION_BACKENDS = ['apps.auth.backend.CaseInsensitiveModelBackend'] # Internationalization # https://docs.djangoproject.com/en/2.0/topics/i18n/ diff --git a/project/templates/blocks/about.html b/project/templates/blocks/about.html index 8deec906..5fefa4ca 100644 --- a/project/templates/blocks/about.html +++ b/project/templates/blocks/about.html @@ -44,6 +44,7 @@
+ {% comment %} {% if not is_purchased and not is_purchased_future %} {% endif %} + {% endcomment %}
diff --git a/project/templates/blocks/header.html b/project/templates/blocks/header.html index ae4107d1..5be001d8 100644 --- a/project/templates/blocks/header.html +++ b/project/templates/blocks/header.html @@ -25,13 +25,15 @@
diff --git a/project/templates/blocks/popup_course_lock.html b/project/templates/blocks/popup_course_lock.html index 75053862..45f87ae0 100644 --- a/project/templates/blocks/popup_course_lock.html +++ b/project/templates/blocks/popup_course_lock.html @@ -5,8 +5,8 @@ diff --git a/project/templates/blocks/promo.html b/project/templates/blocks/promo.html index 4e49ee7a..e05a1e88 100644 --- a/project/templates/blocks/promo.html +++ b/project/templates/blocks/promo.html @@ -11,44 +11,46 @@
Lil School — первая образовательная онлайн-платформа креативного мышления для детей
- {% if user.is_authenticated and online %} -
- Сейчас идёт прямой эфир урока «{{ school_schedule.title }}, {{ school_schedule.current_live_lesson.title }}» -
- - {% elif user.is_authenticated and online_coming_soon and school_schedule and school_schedule.start_at_humanize %} -
- Урок «{{ school_schedule.title }}, {{ school_schedule.current_live_lesson.title }}» начнётся -
-
- {{ school_schedule.start_at_humanize }} -
- + {% if False and user.is_authenticated and online %} +
+ Сейчас идёт прямой эфир урока «{{ school_schedule.title }}, {{ school_schedule.current_live_lesson.title }}» +
+ + {% elif False and user.is_authenticated and online_coming_soon and school_schedule and school_schedule.start_at_humanize %} +
+ Урок «{{ school_schedule.title }}, {{ school_schedule.current_live_lesson.title }}» начнётся +
+
+ {{ school_schedule.start_at_humanize }} +
+ {% else %}
- Присоединяйтесь в Рисовальный лагерь + {# Присоединяйтесь в Рисовальный лагерь #} + Приглашаем вас на месяц открытых дверей в Lil School
+ {% comment %} {% if not is_purchased and not is_purchased_future %} {% endif %} - О лагере + {% endcomment %} + {# О лагере #} + Подробнее
{% endif %}
diff --git a/project/templates/blocks/user_menu.html b/project/templates/blocks/user_menu.html index 13f4fbdf..95e2b7d3 100644 --- a/project/templates/blocks/user_menu.html +++ b/project/templates/blocks/user_menu.html @@ -1,7 +1,7 @@ {% load static %} {% load thumbnail %} {% if request.user.is_authenticated %}
{{ lesson.title }}
-
{{ lesson.short_description }}
+
{{ lesson.short_description | linebreaks }}
@@ -992,28 +992,28 @@ }); } - // let user = api.getCurrentUser(this.accessToken); - // promises.push(user); - // - // user.then((response) => { - // if (response.data) { - // this.me = response.data; - // - // if(this.me.role == ROLE_ADMIN) { - // api.getUsers({role: [ROLE_AUTHOR,ROLE_ADMIN], page_size: 1000}, this.accessToken) - // .then((usersResponse) => { - // if (usersResponse.data) { - // this.users = usersResponse.data.results.map((user) => { - // return { - // title: `${user.first_name} ${user.last_name}`, - // value: user.id - // } - // }); - // } - // }); - // } - // } - // }); + let user = api.getCurrentUser(this.accessToken); + promises.push(user); + + user.then((response) => { + if (response.data) { + this.me = response.data; + + /* if(this.me.role == ROLE_ADMIN) { + api.getUser(this.me.id, {role: [ROLE_AUTHOR, ROLE_ADMIN], page_size: 1000}, this.accessToken) + .then((usersResponse) => { + if (usersResponse.data) { + this.users = usersResponse.data.results.map((user) => { + return { + title: `${user.first_name} ${user.last_name}`, + value: user.id + } + }); + } + }); + } */ + } + }); // if (this.courseId) { // this.loadCourse().then(()=>{this.updateViewSection(window.location, 'load')}).catch(()=>{ diff --git a/web/src/img/pinkbus.jpg b/web/src/img/pinkbus.jpg new file mode 100644 index 00000000..6661d849 Binary files /dev/null and b/web/src/img/pinkbus.jpg differ diff --git a/web/src/js/modules/courses.js b/web/src/js/modules/courses.js index 2581df46..1353ae43 100644 --- a/web/src/js/modules/courses.js +++ b/web/src/js/modules/courses.js @@ -12,6 +12,10 @@ moment.locale('ru'); const history = createHistory(); $(document).ready(function () { + const currentCategory = $('div.js-select-option.active[data-category-option]').attr('data-category-name'); + if(currentCategory) { + $('.js-select[data-category-select] .js-select-head').text(currentCategory); + } // Обработчик отложенных курсов setInterval(() => { $('div[data-future-course]').each((_, element) => { @@ -129,4 +133,4 @@ function load_courses(coursesUrl, fromStart) { buttonElement.removeClass('loading'); } }); -} \ No newline at end of file +} diff --git a/web/src/sass/_common.sass b/web/src/sass/_common.sass index 174fd777..4dfc3acb 100755 --- a/web/src/sass/_common.sass +++ b/web/src/sass/_common.sass @@ -175,7 +175,7 @@ button top: 1px left: 1px right: 1px - bottom: 1px + bottom: 2px background: white border-radius: 2px transition: opacity .2s @@ -2654,10 +2654,9 @@ a.grey-link border-radius: 50%; overflow: hidden; &__pic - top: 50%; - position: relative; - transform: translateY(-50%); + object-fit: cover width: 100% + height: 100% &__content flex: 0 0 calc(100% - 165px) &__actions @@ -2700,7 +2699,7 @@ a.grey-link margin-bottom: 10px color: #191919 &__content - margin-bottom: 30px + margin-bottom: 15px color: #191919 &__video_frame width: 100% @@ -2708,8 +2707,26 @@ a.grey-link &__chat_frame width: 100% height: 600px + &__row + display: flex + +m + display: block + &__preview + margin-right: 25px + flex: 0 0 140px + +m + display: none + &__pic-wrapper + width: 130px; + height: 130px; + border-radius: 50%; + overflow: hidden; + &__pic + object-fit: cover + width: 100% + height: 100% &__user - margin-bottom: 40px + margin-bottom: 30px .lessons @@ -3784,6 +3801,7 @@ a.grey-link +m display: flex flex-direction: row + width: 100% &__day position: relative margin: 10px 0 5px @@ -3809,20 +3827,22 @@ a.grey-link margin: -3px 0 0 auto &__buy +m - display: flex - margin-left: 20px + flex: 1 0 0 + text-align: right &__time margin: 15px 0 opacity: .5 +m - width: 90px - margin: 0 + margin: -1px 15px + font-size: 12px; &__btn margin-right: -60px padding-left: 20px padding-right: 20px white-space: nowrap letter-spacing: 1px + +m + margin-right: 0 &__pic display: block width: 100%