diff --git a/api/v1/serializers/content.py b/api/v1/serializers/content.py index 5b6d2c1d..4225bcde 100644 --- a/api/v1/serializers/content.py +++ b/api/v1/serializers/content.py @@ -4,7 +4,7 @@ from django.conf import settings from apps.content.models import ( Baner, Content, Image, Text, ImageText, Video, - Gallery, GalleryImage, ImageObject,) + Gallery, GalleryImage, ImageObject, FAQ) from . import Base64ImageField @@ -256,3 +256,9 @@ class ContentSerializer(serializers.ModelSerializer): return GallerySerializer(obj, context=self.context).to_representation(obj) return super(ContentSerializer, self).to_representation(obj) + +class FAQSerializer(serializers.ModelSerializer): + + class Meta: + model = FAQ + fields = '__all__' diff --git a/api/v1/urls.py b/api/v1/urls.py index 6182a682..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, UserGalleryViewSet) + AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet) router = DefaultRouter() router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests') @@ -41,7 +41,7 @@ router.register(r'image-texts', ImageTextViewSet, base_name='image-texts') router.register(r'videos', VideoViewSet, base_name='videos') router.register(r'galleries', GalleryViewSet, base_name='galleries') router.register(r'gallery-images', GalleryImageViewSet, base_name='gallery-images') - +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') diff --git a/api/v1/views.py b/api/v1/views.py index e78a77ed..a7f04cc7 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -28,7 +28,7 @@ from .serializers.content import ( VideoSerializer, VideoCreateSerializer, GallerySerializer, GalleryImageSerializer, GalleryImageCreateSerializer, - ImageObjectSerializer, + ImageObjectSerializer, FAQSerializer, ) from .serializers.school import ( SchoolScheduleSerializer, @@ -63,7 +63,7 @@ from apps.config.models import Config from apps.content.models import ( Baner, Image, Text, ImageText, Video, Gallery, GalleryImage, ImageObject, - Contest, ContestWork) + Contest, ContestWork, FAQ) from apps.payment.models import ( AuthorBalance, Payment, CoursePayment, SchoolPayment, @@ -719,3 +719,8 @@ class CaptureEmail(views.APIView): return Response({'status': 'ok'}) + + +class FAQViewSet(ExtendedModelViewSet): + queryset = FAQ.objects.all() + serializer_class = FAQSerializer diff --git a/apps/content/migrations/0023_faq.py b/apps/content/migrations/0023_faq.py new file mode 100644 index 00000000..28a2adcb --- /dev/null +++ b/apps/content/migrations/0023_faq.py @@ -0,0 +1,21 @@ +# Generated by Django 2.0.7 on 2018-12-04 11:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0022_auto_20180815_2129'), + ] + + operations = [ + migrations.CreateModel( + name='FAQ', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('question', models.TextField(max_length=1000)), + ('answer', models.TextField(max_length=1000)), + ], + ), + ] diff --git a/apps/content/models.py b/apps/content/models.py index 0c445958..d84b4d43 100644 --- a/apps/content/models.py +++ b/apps/content/models.py @@ -210,3 +210,8 @@ class ContestWork(models.Model): def get_absolute_url(self): return reverse_lazy('contest_work', args=[self.id]) + + +class FAQ(models.Model): + question = models.TextField(max_length=1000,) + answer = models.TextField(max_length=1000,) diff --git a/apps/content/templates/content/faq.html b/apps/content/templates/content/faq.html new file mode 100644 index 00000000..4672bab3 --- /dev/null +++ b/apps/content/templates/content/faq.html @@ -0,0 +1,18 @@ +{% extends "templates/lilcity/index.html" %} +{% load static %} +{% load jsonify_queryset %} + +{% block content %} +
+
+
Часто задаваемые вопросы
+ +
+
+{% endblock content %} + +{% block pre_app_js %} + +{% endblock pre_app_js %} diff --git a/apps/content/views.py b/apps/content/views.py index 4d350cca..4bb8e9fa 100644 --- a/apps/content/views.py +++ b/apps/content/views.py @@ -7,7 +7,7 @@ from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods from django.views.generic import TemplateView, DetailView -from apps.content.models import Contest, ContestWork +from apps.content.models import Contest, ContestWork, FAQ from apps.course.models import ContestWorkComment @@ -110,3 +110,17 @@ def contest_work_comment(request, contest_work_id): 'success': True, 'comment': html, }) + + +class FAQView(TemplateView): + template_name = 'content/faq.html' + + def get(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + context['faqs'] = [{ + 'question': f.question, + 'answer': f.answer, + 'opened': 0, + } for f in FAQ.objects.all()] + return self.render_to_response(context) + diff --git a/apps/notification/tasks.py b/apps/notification/tasks.py index 03f3cc9e..243be211 100644 --- a/apps/notification/tasks.py +++ b/apps/notification/tasks.py @@ -84,6 +84,8 @@ def sendgrid_update_recipients(): for user in users: last_course_purchase = course_payments.get(user.id) and course_payments.get(user.id).strftime(date_format) last_school_purchase = school_payments.get(user.id) and school_payments.get(user.id).strftime(date_format) + courses_purchased = CoursePayment.objects.filter(user=user, + status__in=CoursePayment.PW_PAID_STATUSES).values_list('course_id', flat=True) data.append({ 'first_name': user.first_name, 'last_name': user.last_name, @@ -94,6 +96,7 @@ def sendgrid_update_recipients(): # 'gender': {User.NOT_DEFINED: '', User.MALE: 'Мужчина', User.FEMALE: 'Женщина'}[user.gender] if user.gender else '', 'birthday': user.birthday and user.birthday.strftime(date_format), 'date_joined': user.date_joined.strftime(date_format), + 'courses_purchased': ','.join(map(str, courses_purchased)) + ',' if courses_purchased else '', }) sg = get_sendgrid_client() diff --git a/project/settings.py b/project/settings.py index 3bd90b7d..40ac56bb 100644 --- a/project/settings.py +++ b/project/settings.py @@ -252,7 +252,7 @@ CELERY_BEAT_SCHEDULE = { }, 'send_certificates': { 'task': 'apps.notification.tasks.send_certificates', - 'schedule': crontab(hour=19), + 'schedule': crontab(minute=0, hour=19), 'args': (), }, 'sendgrid_update_recipients': { diff --git a/project/templates/blocks/lil_store_js.html b/project/templates/blocks/lil_store_js.html index 6ec010b1..ac8952ff 100644 --- a/project/templates/blocks/lil_store_js.html +++ b/project/templates/blocks/lil_store_js.html @@ -24,6 +24,7 @@ userProfileEdit: "{% url 'user-edit-profile' %}", userProfile: "{% url 'user-profile' %}", userBonuses: "{% url 'user-bonuses' %}", + faq: "{% url 'faq' %}", }, flags: { referrer: '{{ referrer.id|default:'' }}', diff --git a/project/urls.py b/project/urls.py index e122aace..9b0a5b00 100644 --- a/project/urls.py +++ b/project/urls.py @@ -18,7 +18,7 @@ from django.contrib import admin from django.views.generic import TemplateView from django.urls import path, include -from apps.content.views import ContestEditView, ContestView, ContestWorkView, contest_work_comment +from apps.content.views import ContestEditView, ContestView, ContestWorkView, contest_work_comment, FAQView from apps.course.views import ( CoursesView, likes, coursecomment, CourseView, LessonView, SearchView, @@ -97,6 +97,7 @@ urlpatterns = [ path('payments/gift-certificate//success', GiftCertificateBuySuccessView.as_view(), name='gift-certificate-payment-success'), path('gift-certificate//get', GiftCertificateGetView.as_view(), name='gift-certificate-get'), + path('faq', FAQView.as_view(), name='faq'), ] diff --git a/web/src/components/FAQ.vue b/web/src/components/FAQ.vue new file mode 100644 index 00000000..a87ce42b --- /dev/null +++ b/web/src/components/FAQ.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/web/src/components/blocks/BlockImageText.vue b/web/src/components/blocks/BlockImageText.vue index 8d0ec678..11fd9d7e 100644 --- a/web/src/components/blocks/BlockImageText.vue +++ b/web/src/components/blocks/BlockImageText.vue @@ -15,11 +15,7 @@
- +
@@ -29,6 +25,7 @@ diff --git a/web/src/js/app.js b/web/src/js/app.js index 35a9818e..d15518d6 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -15,7 +15,6 @@ import "./modules/courses"; import "./modules/comments"; import "./modules/comments"; import "./modules/password-show"; -import {main as profileMain} from "./modules/profile"; import "./modules/notification"; import "./modules/mixpanel"; @@ -34,42 +33,37 @@ Vue.use(Vuelidate); Vue.use(VueAutosize); if (process.env.NODE_ENV === 'development') { - // Enable vue-devtools - Vue.config.devtools = true; + // Enable vue-devtools + Vue.config.devtools = true; } +window.urlIs = (urlPatternName) => { + return window.location.pathname.search(window.LIL_STORE.urls[urlPatternName]) > -1; +}; + const components = { - UploadContestWork, - ContestWorks, - Likes, - Comments, + UploadContestWork, + ContestWorks, + Likes, + Comments, }; Object.assign(components, window.LIL_STORE.components); +if(urlIs('faq')){ + const FAQ = require('../components/FAQ.vue'); + components['faq'] = FAQ.default; +} +if(urlIs('userProfileEdit') || urlIs('userBonuses')){ + const profile = require("./modules/profile"); + profile.main(); +} + const app = new Vue({ - el: '#lilcity-vue-app', - data() { - return { - store: window.LIL_STORE, - } - }, - mounted(){ - if(this.urlIs('userProfileEdit') || this.urlIs('userBonuses')){ - profileMain(this); - } - if(this.urlIs('userProfile')){ - if(window.location.hash){ - $(document).ready(() => { - $(`[href="${window.location.hash}"]`).click(); - }); - } - } - }, - methods: { - urlIs(urlPatternName){ - return window.location.pathname.search(this.store.urls[urlPatternName]) > -1; - }, - }, - components: components + el: '#lilcity-vue-app', + data() { + return { + store: window.LIL_STORE, + } }, + components: components }); diff --git a/web/src/js/modules/profile.js b/web/src/js/modules/profile.js index 60933c3d..141e5e0e 100644 --- a/web/src/js/modules/profile.js +++ b/web/src/js/modules/profile.js @@ -3,8 +3,8 @@ import slugify from 'slugify'; import ClipboardJS from 'clipboard'; import {showNotification} from './notification'; -export const main = (app) => { - if(app.urlIs('userBonuses')){ +export const main = () => { + if(urlIs('userBonuses')){ $('#referrer-url').select().click(function(){ $(this).select(); });