Corp/backend/api/auth/endpoints/email_verification.py

118 lines
4.0 KiB
Python

from __future__ import annotations
import logging
from datetime import timedelta
from django.utils import timezone
from django.utils.crypto import get_random_string
from drf_spectacular.utils import (
OpenApiResponse,
extend_schema,
inline_serializer,
)
from rest_framework import serializers
from rest_framework.response import Response
from api.v1.employees.serializers import (
EmailSerializer,
EmailVerifySerializer,
)
from api.v1.employees.views._helpers import Employee
from common.emails import send_templated_mail
from ..base import AnonymousAPIView
logger = logging.getLogger(__name__)
class ResendEmailAPIView(AnonymousAPIView):
throttle_scope = "auth_email"
@extend_schema(
tags=["Auth"],
summary="Повторно отправить код подтверждения email",
request=EmailSerializer,
responses={
200: inline_serializer(
"ResendEmailResponse",
{"ok": serializers.BooleanField()},
),
400: OpenApiResponse(description="Email уже подтвержден."),
404: OpenApiResponse(description="Пользователь не найден."),
},
)
def post(self, request):
ser = EmailSerializer(data=request.data)
ser.is_valid(raise_exception=True)
email = ser.validated_data["email"]
user = Employee.objects.filter(email__iexact=email).first()
if not user:
return Response({"ok": False, "error": "user_not_found"}, status=404)
if user.email_verified:
return Response({"ok": False, "error": "already_verified"}, status=400)
user.email_activation_code = get_random_string(6, "0123456789")
user.email_activation_sent_at = timezone.now()
user.save(
update_fields=[
"email_activation_code",
"email_activation_sent_at",
]
)
send_templated_mail(
subject="Подтверждение регистрации",
to=[user.email],
template_base="emails/registration_verify_code",
context={"code": user.email_activation_code, "user": user},
)
return Response({"ok": True}, status=200)
class VerifyEmailAPIView(AnonymousAPIView):
@extend_schema(
tags=["Auth"],
summary="Подтвердить email кодом",
request=EmailVerifySerializer,
responses={
200: inline_serializer(
"VerifyEmailResponse",
{
"ok": serializers.BooleanField(),
"user_id": serializers.IntegerField(),
},
),
400: OpenApiResponse(description="Код пустой, неверный или истек."),
404: OpenApiResponse(description="Пользователь не найден."),
},
)
def post(self, request):
ser = EmailVerifySerializer(data=request.data)
ser.is_valid(raise_exception=True)
email = ser.validated_data["email"].strip().lower()
code = ser.validated_data["code"].strip()
user = Employee.objects.filter(email__iexact=email).first()
if not user:
return Response({"ok": False, "error": "user_not_found"}, status=404)
if not code:
return Response({"ok": False, "error": "empty_code"}, status=400)
code_sent_at = getattr(user, "email_activation_sent_at", None) or getattr(
user, "created_at", None
)
if code_sent_at and not user.email_verified:
if timezone.now() - code_sent_at > timedelta(minutes=5):
user.delete()
return Response({"ok": False, "error": "expired"}, status=400)
if not user.verify_email(code):
return Response({"ok": False, "error": "invalid_code"}, status=400)
user.is_active = True
user._ldap_changes = {"is_active": True}
user.save()
return Response({"ok": True, "user_id": user.id}, status=200)