Merge branch 'master' of gitlab.com:lilschool/site into feature/ecommerce-gtag

remotes/origin/feature/ecommerce-gtag
gzbender 6 years ago
commit d47275ecfb
  1. 67
      api/v1/auth.py
  2. 3
      api/v1/urls.py
  3. 2
      api/v1/views.py
  4. 7
      apps/auth/forms.py
  5. 52
      apps/auth/views.py
  6. 19
      apps/notification/templates/notification/email/landing_registration.html
  7. 5
      apps/payment/views.py
  8. 4
      apps/school/templates/blocks/prolong_btn.html
  9. 8
      apps/school/templates/summer/prolong_btn.html
  10. 2
      project/urls.py

@ -1,21 +1,31 @@
from datetime import timedelta from datetime import timedelta
import string
import logging
from urllib.parse import urlencode
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.timezone import now from django.utils.timezone import now
from django.urls import reverse_lazy
from phonenumber_field.serializerfields import PhoneNumberField
from rest_framework import serializers from rest_framework import serializers
from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.compat import authenticate from rest_framework.compat import authenticate
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.authtoken.models import Token
from rest_framework import status from rest_framework import status
from rest_framework.authentication import BasicAuthentication
from apps.auth.models import TempToken from apps.auth.models import TempToken
from apps.auth.tokens import verification_email_token
from apps.notification.utils import send_email
User = get_user_model() User = get_user_model()
logger = logging.getLogger(__name__)
class AuthTokenSerializer(serializers.Serializer): class AuthTokenSerializer(serializers.Serializer):
@ -56,6 +66,12 @@ class AuthTokenSerializer(serializers.Serializer):
return attrs return attrs
class LandingRegistrationSerializer(serializers.Serializer):
phone = PhoneNumberField(required=True)
email = serializers.EmailField(required=True)
name = serializers.CharField(required=True)
class ObtainToken(ObtainAuthToken): class ObtainToken(ObtainAuthToken):
serializer_class = AuthTokenSerializer serializer_class = AuthTokenSerializer
@ -73,3 +89,52 @@ class ObtainTempToken(APIView):
return Response({'temp_token': token.key}) return Response({'temp_token': token.key})
return Response(status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_400_BAD_REQUEST)
class LandingRegistrationView(APIView):
serializer_class = LandingRegistrationSerializer
authentication_classes = (BasicAuthentication,)
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, context={'request': request})
if not serializer.is_valid():
return Response({
'status': 'error',
'errors': serializer.errors,
}, status=400)
email = serializer.validated_data['email']
phone = serializer.validated_data['phone']
if User.objects.filter(Q(email=email) | Q(phone=phone)).count():
return Response({
'status': 'error',
'errors': ['Возможно вы уже зарегистрированы?'],
'user_exists': True,
}, status=400)
user = User(
username=email,
email=email,
phone=phone,
)
name = serializer.validated_data['name'].split(' ')
user.first_name = name[0]
if len(name) > 1:
user.last_name = name[1]
password = User.objects.make_random_password(8, string.ascii_lowercase + string.digits)
user.set_password(password)
user.save()
verification_token = verification_email_token.make_token(user)
url = 'https://%s%s?%s' % (settings.MAIN_HOST,
reverse_lazy('lilcity:verification-email', args=[verification_token, user.id]),
urlencode({'next': 'https://lil.school/p/free-lesson'}))
try:
send_email('Регистрация в Lil School', email, "notification/email/landing_registration.html", url=url,
user=user, password=password)
except Exception as e:
logger.error(str(e))
return Response({
'status': 'ok',
'url': url,
})

@ -6,7 +6,7 @@ from rest_framework.routers import DefaultRouter
from drf_yasg.views import get_schema_view from drf_yasg.views import get_schema_view
from drf_yasg import openapi from drf_yasg import openapi
from .auth import ObtainToken, ObtainTempToken from .auth import ObtainToken, ObtainTempToken, LandingRegistrationView
from .views import ( from .views import (
AuthorBalanceViewSet, AuthorRequestViewSet, AuthorBalanceViewSet, AuthorRequestViewSet,
BannerViewSet, ConfigViewSet, CategoryViewSet, BannerViewSet, ConfigViewSet, CategoryViewSet,
@ -71,6 +71,7 @@ urlpatterns = [
path('author-balance-users/', AuthorBalanceUsersViewSet.as_view(), name='author-balance-users'), path('author-balance-users/', AuthorBalanceUsersViewSet.as_view(), name='author-balance-users'),
path('api-token-auth/', ObtainToken.as_view(), name='api-token-auth'), path('api-token-auth/', ObtainToken.as_view(), name='api-token-auth'),
path('temp-auth-token/', ObtainTempToken.as_view(), name='temp-auth-token'), path('temp-auth-token/', ObtainTempToken.as_view(), name='temp-auth-token'),
path('landing-registration/', LandingRegistrationView.as_view(), name='landing-registration'),
path('configs/', ConfigViewSet.as_view(), name='configs'), path('configs/', ConfigViewSet.as_view(), name='configs'),
path('swagger(<str:format>.json|.yaml)', schema_view.without_ui(cache_timeout=None), name='schema-json'), path('swagger(<str:format>.json|.yaml)', schema_view.without_ui(cache_timeout=None), name='schema-json'),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'), path('swagger/', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),

@ -774,11 +774,13 @@ class NotifiedAboutBonuses(views.APIView):
b.save() b.save()
return Response({'status': 'ok'}) return Response({'status': 'ok'})
class PackageViewSet(ExtendedModelViewSet): class PackageViewSet(ExtendedModelViewSet):
queryset = Package.objects.all() queryset = Package.objects.all()
serializer_class = PackageSerializer serializer_class = PackageSerializer
permission_classes = (IsAdmin,) permission_classes = (IsAdmin,)
class TagViewSet(ExtendedModelViewSet): class TagViewSet(ExtendedModelViewSet):
queryset = Tag.objects.all() queryset = Tag.objects.all()
serializer_class = TagSerializer serializer_class = TagSerializer

@ -1,4 +1,5 @@
from django import forms from django import forms
from phonenumber_field.formfields import PhoneNumberField
class LearnerRegistrationForm(forms.Form): class LearnerRegistrationForm(forms.Form):
@ -6,3 +7,9 @@ class LearnerRegistrationForm(forms.Form):
last_name = forms.CharField() last_name = forms.CharField()
email = forms.EmailField() email = forms.EmailField()
password = forms.CharField() password = forms.CharField()
class LandingRegistrationForm(forms.Form):
name = forms.CharField(required=True)
email = forms.EmailField(required=True)
phone = PhoneNumberField(required=True)

@ -1,14 +1,17 @@
import string
import os import os
import logging import logging
from uuid import uuid4 from uuid import uuid4
from urllib.parse import urlsplit from urllib.parse import urlsplit, urlencode
from django.db.models import Q
from facepy import GraphAPI from facepy import GraphAPI
from facepy.exceptions import FacepyError from facepy.exceptions import FacepyError
from django.contrib.auth import get_user_model, logout, login, views from django.contrib.auth import get_user_model, logout, login, views
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.http import JsonResponse from django.http import JsonResponse, HttpResponse
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
@ -19,7 +22,7 @@ from django.conf import settings
from apps.notification.utils import send_email from apps.notification.utils import send_email
from apps.config.models import Config from apps.config.models import Config
from apps.user.models import Referral from apps.user.models import Referral
from .forms import LearnerRegistrationForm from .forms import LearnerRegistrationForm, LandingRegistrationForm
from .tokens import verification_email_token from .tokens import verification_email_token
@ -122,13 +125,14 @@ class VerificationEmailView(View):
user = User.objects.get(pk=kwargs.get('uid')) user = User.objects.get(pk=kwargs.get('uid'))
is_valid_token = verification_email_token.check_token( is_valid_token = verification_email_token.check_token(
user, kwargs.get('token')) user, kwargs.get('token'))
next = request.GET.get('next')
if is_valid_token: if is_valid_token:
user.is_email_proved = True user.is_email_proved = True
user.save() user.save()
login(request, user) login(request, user)
self.request.session['referrer'] = None self.request.session['referrer'] = None
return redirect(reverse_lazy('lilcity:success-verification-email')) return redirect(next or reverse_lazy('lilcity:success-verification-email'))
else: else:
return JsonResponse({"success": False}, status=400) return JsonResponse({"success": False}, status=400)
@ -238,3 +242,43 @@ class FacebookLoginOrRegistration(View):
login(requests, user=user) login(requests, user=user)
self.request.session['referrer'] = None self.request.session['referrer'] = None
return JsonResponse({"success": True}) return JsonResponse({"success": True})
@method_decorator(csrf_exempt, name="dispatch")
class LandingRegistrationView(View):
def post(self, request, *args, **kwargs):
form = LandingRegistrationForm(request.POST)
if not form.is_valid():
return HttpResponse(form.errors.as_text())
phone = form.cleaned_data['phone']
name = form.cleaned_data['name'].split()
email = form.cleaned_data['email'].lower()
if User.objects.filter(Q(email=email) | Q(phone=phone)).count():
return redirect('/p/user-exists')
user = User(
username=email,
email=email,
phone=phone,
)
user.first_name = name[0]
if len(name) > 1:
user.last_name = name[1]
password = User.objects.make_random_password(8, string.ascii_lowercase + string.digits)
user.set_password(password)
user.save()
verification_token = verification_email_token.make_token(user)
url = 'https://%s%s?%s' % (settings.MAIN_HOST,
reverse_lazy('lilcity:verification-email', args=[verification_token, user.id]),
urlencode({'next': 'https://lil.school/p/free-lesson'}))
try:
send_email('Регистрация в Lil School', email, "notification/email/landing_registration.html", url=url,
user=user, password=password)
except Exception as e:
logger.error(str(e))
return redirect(url)

@ -0,0 +1,19 @@
<p>Здравствуйте, {{ user.get_full_name }}! Вы только что записались на вводный урок в онлайн-школе Lil School!</p>
<p>Перейдите по ссылке, чтобы пройти вводный урок</p>
<p><a href="{{ url }}"
style="text-decoration: none; position: relative; padding: 13px 24px 12px; background-image: linear-gradient(-225deg, #D1FF7F 0%, #56FFFD 100%);
border-radius: 3px; font-size: 12px; color: #191919; text-transform: uppercase; letter-spacing: 2px; text-align: center; transition: all .2s; z-index: 2;"
>Пройти вводный урок</a>
</p>
<p>Доступ в личный кабинет:<br>
логин<br>
{{ user.email }}<br>
временный пароль<br>
{{ password }}
</p>
<p>Теперь у вас есть личный кабинет. Там хранятся учебные материалы, видео прошлых уроков, актуальное расписание и море вдохновения.</p>
<p>Желаем интересных уроков и свободы в творчестве!</p>

@ -145,6 +145,11 @@ class SchoolBuyView(TemplateView):
payment_id = request.GET.get('payment_id') payment_id = request.GET.get('payment_id')
package = get_object_or_404(Package, duration=duration) package = get_object_or_404(Package, duration=duration)
date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date()
prev_payment = SchoolPayment.objects.paid().filter(
user=self.request.user,
date_end__gte=now().date(),).last()
if prev_payment and prev_payment.date_end > date_start:
date_start = prev_payment.date_end + timedelta(1)
if payment_id: if payment_id:
school_payment = get_object_or_404(SchoolPayment, id=payment_id) school_payment = get_object_or_404(SchoolPayment, id=payment_id)
else: else:

@ -1,9 +1,9 @@
<a <a
{% if not user.is_authenticated %} {% if not user.is_authenticated %}
data-popup=".js-popup-auth" data-popup=".js-popup-auth"
href="#"
{% else %} {% else %}
data-popup=".js-popup-buy" href="{% url 'packages' %}"
{% endif %} {% endif %}
class="casing__btn btn{% if pink %} btn_pink{% endif %}" class="casing__btn btn{% if pink %} btn_pink{% endif %}"
href="#"
>продлить</a> >продлить</a>

@ -1,5 +1,9 @@
<a <a
data-popup=".js-popup-buy" data-prolong="1" data-date-start="{{ prolong_date_start|date:'Y-m-d' }}" {% if not user.is_authenticated %}
class="casing__btn btn{% if pink %} btn_pink{% endif %}" data-popup=".js-popup-auth"
href="#" href="#"
{% else %}
href="{% url 'packages' %}"
{% endif %}
class="casing__btn btn{% if pink %} btn_pink{% endif %}"
>продлить</a> >продлить</a>

@ -18,6 +18,7 @@ from django.contrib import admin
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.urls import path, include from django.urls import path, include
from apps.auth.views import LandingRegistrationView
from apps.content.views import ContestEditView, ContestView, ContestWorkView, contest_work_comment, FAQView from apps.content.views import ContestEditView, ContestView, ContestWorkView, contest_work_comment, FAQView
from apps.course.views import ( from apps.course.views import (
CoursesView, likes, coursecomment, CoursesView, likes, coursecomment,
@ -104,6 +105,7 @@ urlpatterns = [
path('faq', FAQView.as_view(), name='faq'), path('faq', FAQView.as_view(), name='faq'),
path('links', LinksView.as_view(), name='links'), path('links', LinksView.as_view(), name='links'),
path('prices', PackagesView.as_view(), name='packages'), path('prices', PackagesView.as_view(), name='packages'),
path('landing-registration', LandingRegistrationView.as_view(), name='landing-registration'),
] ]

Loading…
Cancel
Save