diff --git a/api/v1/auth.py b/api/v1/auth.py index e09d27c5..ef959a65 100644 --- a/api/v1/auth.py +++ b/api/v1/auth.py @@ -1,21 +1,31 @@ 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.db.models import Q from django.utils.translation import ugettext_lazy as _ from django.shortcuts import get_object_or_404 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.authtoken.views import ObtainAuthToken from rest_framework.compat import authenticate from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework.authtoken.models import Token from rest_framework import status +from rest_framework.authentication import BasicAuthentication 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() +logger = logging.getLogger(__name__) class AuthTokenSerializer(serializers.Serializer): @@ -56,6 +66,12 @@ class AuthTokenSerializer(serializers.Serializer): return attrs +class LandingRegistrationSerializer(serializers.Serializer): + phone = PhoneNumberField(required=True) + email = serializers.EmailField(required=True) + name = serializers.CharField(required=True) + + class ObtainToken(ObtainAuthToken): serializer_class = AuthTokenSerializer @@ -73,3 +89,52 @@ class ObtainTempToken(APIView): return Response({'temp_token': token.key}) 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, + }) diff --git a/api/v1/urls.py b/api/v1/urls.py index ab6e3525..ee6683f8 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -6,7 +6,7 @@ from rest_framework.routers import DefaultRouter from drf_yasg.views import get_schema_view from drf_yasg import openapi -from .auth import ObtainToken, ObtainTempToken +from .auth import ObtainToken, ObtainTempToken, LandingRegistrationView from .views import ( AuthorBalanceViewSet, AuthorRequestViewSet, BannerViewSet, ConfigViewSet, CategoryViewSet, @@ -71,6 +71,7 @@ urlpatterns = [ path('author-balance-users/', AuthorBalanceUsersViewSet.as_view(), name='author-balance-users'), path('api-token-auth/', ObtainToken.as_view(), name='api-token-auth'), 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('swagger(.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'), diff --git a/api/v1/views.py b/api/v1/views.py index 6972826e..4b4ad44c 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -774,11 +774,13 @@ class NotifiedAboutBonuses(views.APIView): b.save() return Response({'status': 'ok'}) + class PackageViewSet(ExtendedModelViewSet): queryset = Package.objects.all() serializer_class = PackageSerializer permission_classes = (IsAdmin,) + class TagViewSet(ExtendedModelViewSet): queryset = Tag.objects.all() serializer_class = TagSerializer diff --git a/apps/auth/forms.py b/apps/auth/forms.py index e369a8f9..f9017dcb 100644 --- a/apps/auth/forms.py +++ b/apps/auth/forms.py @@ -1,4 +1,5 @@ from django import forms +from phonenumber_field.formfields import PhoneNumberField class LearnerRegistrationForm(forms.Form): @@ -6,3 +7,9 @@ class LearnerRegistrationForm(forms.Form): last_name = forms.CharField() email = forms.EmailField() password = forms.CharField() + + +class LandingRegistrationForm(forms.Form): + name = forms.CharField(required=True) + email = forms.EmailField(required=True) + phone = PhoneNumberField(required=True) diff --git a/apps/auth/views.py b/apps/auth/views.py index 48719b3f..34a6eb3f 100644 --- a/apps/auth/views.py +++ b/apps/auth/views.py @@ -1,14 +1,17 @@ +import string + import os import logging 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.exceptions import FacepyError from django.contrib.auth import get_user_model, logout, login, views from django.contrib.auth.forms import AuthenticationForm 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.utils.decorators import method_decorator 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.config.models import Config from apps.user.models import Referral -from .forms import LearnerRegistrationForm +from .forms import LearnerRegistrationForm, LandingRegistrationForm from .tokens import verification_email_token @@ -122,13 +125,14 @@ class VerificationEmailView(View): user = User.objects.get(pk=kwargs.get('uid')) is_valid_token = verification_email_token.check_token( user, kwargs.get('token')) + next = request.GET.get('next') if is_valid_token: user.is_email_proved = True user.save() login(request, user) self.request.session['referrer'] = None - return redirect(reverse_lazy('lilcity:success-verification-email')) + return redirect(next or reverse_lazy('lilcity:success-verification-email')) else: return JsonResponse({"success": False}, status=400) @@ -238,3 +242,43 @@ class FacebookLoginOrRegistration(View): login(requests, user=user) self.request.session['referrer'] = None 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) + diff --git a/apps/notification/templates/notification/email/landing_registration.html b/apps/notification/templates/notification/email/landing_registration.html new file mode 100644 index 00000000..5fc8db42 --- /dev/null +++ b/apps/notification/templates/notification/email/landing_registration.html @@ -0,0 +1,19 @@ +

Здравствуйте, {{ user.get_full_name }}! Вы только что записались на вводный урок в онлайн-школе Lil School!

+ +

Перейдите по ссылке, чтобы пройти вводный урок

+

Пройти вводный урок +

+ +

Доступ в личный кабинет:
+логин
+{{ user.email }}
+временный пароль
+{{ password }} +

+ +

Теперь у вас есть личный кабинет. Там хранятся учебные материалы, видео прошлых уроков, актуальное расписание и море вдохновения.

+ +

Желаем интересных уроков и свободы в творчестве!

diff --git a/apps/payment/views.py b/apps/payment/views.py index c57c005f..4341e32b 100644 --- a/apps/payment/views.py +++ b/apps/payment/views.py @@ -135,6 +135,11 @@ class SchoolBuyView(TemplateView): payment_id = request.GET.get('payment_id') 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() + 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: school_payment = get_object_or_404(SchoolPayment, id=payment_id) else: diff --git a/apps/school/templates/blocks/prolong_btn.html b/apps/school/templates/blocks/prolong_btn.html index c4026242..648a56da 100644 --- a/apps/school/templates/blocks/prolong_btn.html +++ b/apps/school/templates/blocks/prolong_btn.html @@ -1,9 +1,9 @@ продлить diff --git a/apps/school/templates/summer/prolong_btn.html b/apps/school/templates/summer/prolong_btn.html index 75021093..648a56da 100644 --- a/apps/school/templates/summer/prolong_btn.html +++ b/apps/school/templates/summer/prolong_btn.html @@ -1,5 +1,9 @@ продлить diff --git a/project/urls.py b/project/urls.py index 54415f98..e2bee7b0 100644 --- a/project/urls.py +++ b/project/urls.py @@ -18,6 +18,7 @@ from django.contrib import admin from django.views.generic import TemplateView 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.course.views import ( CoursesView, likes, coursecomment, @@ -104,6 +105,7 @@ urlpatterns = [ path('faq', FAQView.as_view(), name='faq'), path('links', LinksView.as_view(), name='links'), path('prices', PackagesView.as_view(), name='packages'), + path('landing-registration', LandingRegistrationView.as_view(), name='landing-registration'), ]