diff --git a/api/v1/serializers/mixins.py b/api/v1/serializers/mixins.py index 50e7d19d..a79ff8e5 100644 --- a/api/v1/serializers/mixins.py +++ b/api/v1/serializers/mixins.py @@ -131,7 +131,7 @@ class DispatchMaterialMixin(object): class DispatchGalleryMixin(object): - def dispatch_gallery(self, course, gallery): + def dispatch_gallery(self, obj, gallery): if gallery: if 'id' in gallery and gallery['id']: g = Gallery.objects.get(id=gallery['id']) @@ -145,15 +145,19 @@ class DispatchGalleryMixin(object): ) if 'images' in gallery: for image in gallery['images']: + if isinstance(image['img'], ImageObject): + img = image['img'] + else: + img = ImageObject.objects.get(id=image['img']) if 'id' in image and image['id']: gi = GalleryImage.objects.get(id=image['id']) gi.gallery = g - gi.img = image['img'] + gi.img = img gi.save() else: gi = GalleryImage.objects.create( gallery=g, - img=image['img'], + img=img, ) - course.gallery = g - course.save() + obj.gallery = g + obj.save() diff --git a/api/v1/serializers/user.py b/api/v1/serializers/user.py index bbb5e6b5..79f17d32 100644 --- a/api/v1/serializers/user.py +++ b/api/v1/serializers/user.py @@ -3,8 +3,10 @@ from rest_framework import serializers from django.contrib.auth import get_user_model +from api.v1.serializers.content import GallerySerializer, GalleryImageSerializer, GalleryImageCreateSerializer from . import Base64ImageField from apps.user.models import AuthorRequest +from .mixins import DispatchGalleryMixin User = get_user_model() @@ -104,3 +106,32 @@ class AuthorRequestSerializer(serializers.ModelSerializer): 'created_at', 'update_at', ) + + +class UserGallerySerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ( + 'gallery', + ) + + +class UserGalleryUpdateSerializer(DispatchGalleryMixin, serializers.ModelSerializer): + images = serializers.ListField() + + class Meta: + model = User + fields = ( + 'images', + ) + + def update(self, instance, validated_data): + images = validated_data.pop('images', {}) + self.dispatch_gallery(instance, { + 'id': instance.gallery_id, + 'images': images, + }) + return instance + + def to_representation(self, instance): + return UserGallerySerializer(instance=instance, context=self.context).to_representation(instance) diff --git a/api/v1/urls.py b/api/v1/urls.py index 500c51c8..b86acbbc 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -19,7 +19,7 @@ from .views import ( SchoolScheduleViewSet, LiveLessonViewSet, PaymentViewSet, ObjectCommentsViewSet, ContestViewSet, ContestWorkViewSet, - AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet) + AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet) router = DefaultRouter() router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests') @@ -45,6 +45,7 @@ router.register(r'faq', FAQViewSet, base_name='faq') router.register(r'school-schedules', SchoolScheduleViewSet, base_name='school-schedules') router.register(r'users', UserViewSet, base_name='users') +router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery') router.register(r'contests', ContestViewSet, base_name='contests') router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works') diff --git a/api/v1/views.py b/api/v1/views.py index a567a7cc..a7f04cc7 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -4,7 +4,7 @@ from decimal import Decimal from django.contrib.auth import get_user_model from django.db.models import Q -from rest_framework import status, views, viewsets, generics +from rest_framework import status, views, viewsets, generics, mixins from rest_framework.decorators import detail_route, list_route, action, permission_classes, authentication_classes from rest_framework.response import Response @@ -42,7 +42,7 @@ from .serializers.payment import ( from .serializers.user import ( AuthorRequestSerializer, UserSerializer, UserPhotoSerializer, -) + UserGallerySerializer, UserGalleryUpdateSerializer) from .serializers.contest import ( ContestCreateSerializer, ContestSerializer, ContestWorkSerializer, ContestWorkCreateSerializer ) @@ -475,6 +475,13 @@ class UserViewSet(ExtendedModelViewSet): return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) +class UserGalleryViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet): + queryset = User.objects.all() + serializer_class = UserGalleryUpdateSerializer + # FIXME + authentication_classes = [] + + class SchoolScheduleViewSet(ExtendedModelViewSet): queryset = SchoolSchedule.objects.all() serializer_class = SchoolScheduleSerializer diff --git a/apps/school/templates/blocks/schedule.html b/apps/school/templates/blocks/schedule.html index 15b129fb..1a021d31 100644 --- a/apps/school/templates/blocks/schedule.html +++ b/apps/school/templates/blocks/schedule.html @@ -10,7 +10,9 @@ {% endfor %}
- {# include './pay_btn.html' #} + {% if not is_purchased and not is_purchased_future %} + Получить доступ на месяц + {% endif %} Распечатать расписание чтобы не забыть diff --git a/apps/school/templates/school/livelessons_list.html b/apps/school/templates/school/livelessons_list.html index 1c0a1778..237072b0 100644 --- a/apps/school/templates/school/livelessons_list.html +++ b/apps/school/templates/school/livelessons_list.html @@ -1,4 +1,4 @@ -{% extends "templates/lilcity/index.html" %} {% load jsonify from jsonify_queryset %} {% load static %} {% block content %} +{% extends "templates/lilcity/index.html" %}{% load static %} {% block content %}
Уроки онлайн-школы LilCity
diff --git a/apps/school/templates/summer/schedule_purchased.html b/apps/school/templates/summer/schedule_purchased.html index 8463fc51..4acc2f49 100644 --- a/apps/school/templates/summer/schedule_purchased.html +++ b/apps/school/templates/summer/schedule_purchased.html @@ -20,38 +20,19 @@
- {% if not profile %} - - {% endif %}
- {% if is_previous and not live_lessons_exists %} - Записей уроков пока нет - {% else %} - {% 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 %} - {% endif %} - {% endfor %} - {% else %} - {% for school_schedule in school_schedules_sorted %} - {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson %} - {% endfor %} - {% endif %} +
Новые уроки
+ {% for school_schedule in school_schedules_sorted %} + {% include 'blocks/schedule_item.html' with school_schedule=school_schedule live_lesson=school_schedule.current_live_lesson %} + {% endfor %} + {% if prev_live_lessons_exists %} +
Прошедшие уроки
+ {% for live_lesson in prev_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 %} + {% endif %} + {% endfor %} {% endif %}
diff --git a/apps/school/views.py b/apps/school/views.py index a3cc379b..71029683 100644 --- a/apps/school/views.py +++ b/apps/school/views.py @@ -110,9 +110,7 @@ class SchoolView(TemplateView): 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) now_time = now() try: school_schedule = SchoolSchedule.objects.get(weekday=now_time.isoweekday()) @@ -132,8 +130,8 @@ class SchoolView(TemplateView): key=lambda ss: ss.current_live_lesson and ss.current_live_lesson.date) except Exception: school_schedules_sorted = school_schedules - live_lessons = [] - live_lessons_exists = False + prev_live_lessons = [] + prev_live_lessons_exists = False subscription_ends = None school_payment_exists = False school_schedules_purchased = [] @@ -178,31 +176,29 @@ class SchoolView(TemplateView): weekdays__len__gt=0, ) - if is_previous: - # берем все подписки, которые были в периоде - for sp in prev_school_payments: - # берем все уроки в оплаченном промежутке - date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])] - live_lessons += LiveLesson.objects.filter( - date__range=date_range, - deactivated_at__isnull=True, - date__week_day__in=list(map(lambda x: 1 if x == 7 else x+1, sp.weekdays)), - ).values_list('id', flat=True) - live_lessons = LiveLesson.objects.filter(id__in=set(live_lessons)).order_by('-date') - live_lessons_exists = live_lessons.exists() - if live_lessons_exists: - school_schedules_dict = {ss.weekday: ss for ss in school_schedules} - school_schedules_dict[0] = school_schedules_dict.get(7) - for ll in live_lessons: - ll.school_schedule = school_schedules_dict.get(ll.date.isoweekday()) - else: - live_lessons = [] + # берем все подписки, которые были в периоде + for sp in prev_school_payments: + # берем все уроки в оплаченном промежутке + date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])] + prev_live_lessons = LiveLesson.objects.filter( + date__range=date_range, + deactivated_at__isnull=True, + date__week_day__in=list(map(lambda x: 1 if x == 7 else x+1, sp.weekdays)), + ).values_list('id', flat=True) + prev_live_lessons = LiveLesson.objects.filter(id__in=set(prev_live_lessons)).order_by('-date') + prev_live_lessons_exists = prev_live_lessons.exists() + if prev_live_lessons_exists: + school_schedules_dict = {ss.weekday: ss for ss in school_schedules} + school_schedules_dict[0] = school_schedules_dict.get(7) + for ll in prev_live_lessons: + ll.school_schedule = school_schedules_dict.get(ll.date.isoweekday()) + else: + prev_live_lessons = [] context.update({ 'online': online, - 'live_lessons': live_lessons, - 'live_lessons_exists': live_lessons_exists, - 'is_previous': is_previous, + 'prev_live_lessons': prev_live_lessons, + 'prev_live_lessons_exists': prev_live_lessons_exists, 'course_items': Course.objects.filter(status=Course.PUBLISHED)[:6], 'is_purchased': school_payment_exists, 'is_purchased_future': False, diff --git a/apps/user/forms.py b/apps/user/forms.py index 4a0ccf0e..6066c132 100644 --- a/apps/user/forms.py +++ b/apps/user/forms.py @@ -28,6 +28,7 @@ class UserEditForm(forms.ModelForm): pinterest = forms.URLField(required=False) youtube = forms.URLField(required=False) vkontakte = forms.URLField(required=False) + site = forms.URLField(required=False) photo = forms.ImageField(required=False) class Meta: @@ -53,6 +54,7 @@ class UserEditForm(forms.ModelForm): 'pinterest', 'youtube', 'vkontakte', + 'site', 'photo', ) diff --git a/apps/user/migrations/0026_user_site.py b/apps/user/migrations/0026_user_site.py new file mode 100644 index 00000000..2e9aa105 --- /dev/null +++ b/apps/user/migrations/0026_user_site.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.6 on 2018-11-15 09:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0025_merge_20180927_2353'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='site', + field=models.URLField(blank=True, default='', null=True), + ), + ] diff --git a/apps/user/migrations/0027_user_gallery.py b/apps/user/migrations/0027_user_gallery.py new file mode 100644 index 00000000..eb33301a --- /dev/null +++ b/apps/user/migrations/0027_user_gallery.py @@ -0,0 +1,20 @@ +# Generated by Django 2.0.6 on 2018-11-16 16:36 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0022_auto_20180815_2129'), + ('user', '0026_user_site'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='gallery', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='content.Gallery', verbose_name='Галерея'), + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index f9bac9dc..adb40b55 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -71,6 +71,7 @@ class User(AbstractUser): pinterest = models.URLField(default='', null=True, blank=True) youtube = models.URLField(default='', null=True, blank=True) vkontakte = models.URLField('ВКонтакте', default='', null=True, blank=True) + site = models.URLField(default='', null=True, blank=True) fb_id = models.BigIntegerField(null=True, blank=True, unique=True) fb_data = pgfields.JSONField(default={}, null=True, blank=True) is_email_proved = models.BooleanField( @@ -83,6 +84,10 @@ class User(AbstractUser): allow_unicode=True, null=True, blank=True, max_length=100, unique=True, db_index=True, ) + gallery = models.ForeignKey( + 'content.Gallery', on_delete=models.CASCADE, + verbose_name='Галерея', null=True, blank=True, + ) objects = UserManager() diff --git a/apps/user/templates/user/edit-gallery.html b/apps/user/templates/user/edit-gallery.html new file mode 100644 index 00000000..e3fbf2d8 --- /dev/null +++ b/apps/user/templates/user/edit-gallery.html @@ -0,0 +1,35 @@ +{% extends "templates/lilcity/index.html" %} +{% load static %} + +{% block head %} + {{ block.super }} + +{% endblock head %} + +{% block pre_app_js %} + + +{% endblock pre_app_js %} + +{% block content %} +
+
+
Редактировать работы
+
+ +
+ Сохранить +
+
+{% endblock %} diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index 436cb374..04eecdec 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -255,7 +255,16 @@ {% for error in form.vkontakte.errors %}
{{ error }}
{% endfor %} -
+
+
+
САЙТ
+
+ +
+ {% for error in form.site.errors %} +
{{ error }}
+ {% endfor %} +
diff --git a/apps/user/templates/user/profile.html b/apps/user/templates/user/profile.html index b8e19a19..bb3b909a 100644 --- a/apps/user/templates/user/profile.html +++ b/apps/user/templates/user/profile.html @@ -67,12 +67,13 @@
- + МОИ ПОКУПКИ {% if is_author %} - + {% endif %} + МОИ РАБОТЫ
@@ -138,6 +139,24 @@
{% endif %} +
+
+ + + +
diff --git a/apps/user/views.py b/apps/user/views.py index d1a6f02b..1c244b01 100644 --- a/apps/user/views.py +++ b/apps/user/views.py @@ -313,3 +313,8 @@ class BonusHistoryView(TemplateView): 'Перейдите по ссылке и получите скидку %d%% на первую покупку' \ % (request.user.get_full_name(), config.REFERRAL_BONUS) return self.render_to_response(context) + + +@method_decorator(login_required, name='dispatch') +class UserGalleryEditView(TemplateView): + template_name = 'user/edit-gallery.html' diff --git a/project/templates/blocks/lil_store_js.html b/project/templates/blocks/lil_store_js.html index 1cb5e329..ac8952ff 100644 --- a/project/templates/blocks/lil_store_js.html +++ b/project/templates/blocks/lil_store_js.html @@ -22,6 +22,7 @@ urls: { courses: "{% url 'courses' %}", userProfileEdit: "{% url 'user-edit-profile' %}", + userProfile: "{% url 'user-profile' %}", userBonuses: "{% url 'user-bonuses' %}", faq: "{% url 'faq' %}", }, diff --git a/project/templates/blocks/mobile_apps.html b/project/templates/blocks/mobile_apps.html index cb9e085a..50be50db 100644 --- a/project/templates/blocks/mobile_apps.html +++ b/project/templates/blocks/mobile_apps.html @@ -7,10 +7,10 @@
Lil World – это арт-фото редактор многократно отмеченный AppStore по всему миру как лучшее приложение с огромной коллекцией иллюстраций стикеров. Украшайте ваши фото и превращайте их в волшебные миры.
diff --git a/project/templates/lilcity/index.html b/project/templates/lilcity/index.html index 6e994250..48c85a01 100644 --- a/project/templates/lilcity/index.html +++ b/project/templates/lilcity/index.html @@ -165,6 +165,6 @@ (function(w, d, s, h, id) { w.roistatProjectId = id; w.roistatHost = h; var p = d.location.protocol == "https:" ? "https://" : "http://"; var u = /^.*roistat_visit=[^;]+(.*)?$/.test(d.cookie) ? "/dist/module.js" : "/api/site/1.0/"+id+"/init"; var js = d.createElement(s); js.charset="UTF-8"; js.async = 1; js.src = p+h+u; var js2 = d.getElementsByTagName(s)[0]; js2.parentNode.insertBefore(js, js2);})(window, document, 'script', 'cloud.roistat.com', '{% setting "ROISTAT_COUNTER_ID" %}'); {% block foot %}{% endblock foot %} - {% block body_js %}{% endblock body_js %} + {% block foot_js %}{% endblock foot_js %} diff --git a/project/urls.py b/project/urls.py index 2458b43e..9b0a5b00 100644 --- a/project/urls.py +++ b/project/urls.py @@ -30,7 +30,7 @@ from apps.user.views import ( ProfileEditView, NotificationEditView, PaymentHistoryView, resend_email_verify, SubscribeView, ProfileView, - BonusHistoryView) + BonusHistoryView, UserGalleryEditView) from apps.payment.views import ( CourseBuySuccessView, CourseBuyView, PaymentwallCallbackView, SchoolBuySuccessView, @@ -75,6 +75,7 @@ urlpatterns = [ path('user/notifications', NotificationEditView.as_view(), name='user-edit-notifications'), path('user/payments', PaymentHistoryView.as_view(), name='user-edit-payments'), path('user/bonuses', BonusHistoryView.as_view(), name='user-bonuses'), + path('user/gallery-edit', UserGalleryEditView.as_view(), name='user-gallery-edit'), path('user/resend-email-verify', resend_email_verify, name='resend-email-verify'), path('subscribe', SubscribeView.as_view(), name='subscribe'), path('subscribe/success', TemplateView.as_view(template_name='templates/lilcity/subscribe_success.html'), name='subscribe-success'), diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index cd684536..3f3a4ba8 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -3,63 +3,38 @@
-
-
-
-
-
- Аватар -
-
-
АВТОР
-
{{ authorName }}
-
-
-
- Загрузить фон +
+
+
+ +
+
Загрузить превью
+ + + + +
-
-
-
{{titles.courseTitle}}
-
- -
-
-
-
{{titles.shortDescription}}
-
- -
-
-
-
-
-
КАТЕГОРИЯ
-
- +
+ -
-
-
-
ПРОДОЛЖИТЕЛЬНОСТЬ
-
- - -
+
{{ course.price }}₽
+
+
+ +
+
+
@@ -90,6 +65,16 @@
--> +
+
ПРОДОЛЖИТЕЛЬНОСТЬ
+
+ + +
+
+
ДОСТУП
@@ -155,7 +140,7 @@
-
+