Reputation: 1
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager, PermissionsMixin)
from rest_framework_simplejwt.tokens import RefreshToken
class UserManager(BaseUserManager):
def create_user(self,username,email, password=None ):
if username is None:
raise TypeError("Users should have a username")
if email is None:
raise TypeError("Users should have an Email")
user =self.model(username=username, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password=None):
if password is None:
raise TypeError("Password should not be none")
user = self.create_user(username, email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=100, unique=True, db_index=True)
email = models.EmailField(max_length=100, unique=True, db_index=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
objects = UserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
"refresh":str(refresh),
"access": str(refresh.access_token)
}
Below is the serializers.py file
from .models import User
from rest_framework import serializers
from django.contrib import auth
from rest_framework.exceptions import AuthenticationFailed
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length=50, min_length=6, write_only =True)
class Meta:
model = User
fields = ["email", "username", "password"]
def validate(self, attrs):
email = attrs.get("email", '')
username = attrs.get("username", '')
if not username.isalnum():
raise serializers.ValidationError("The username should contain only alphanumeric characters")
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class EmailVerificationSerializer(serializers.ModelSerializer):
token = serializers.CharField(max_length=555)
class Meta:
model = User
fields = ["token"]
class LoginSerializer(serializers.ModelSerializer):
email = serializers.EmailField(max_length=255,min_length=3)
password = serializers.CharField(max_length=68, min_length=6, write_only=True)
username = serializers.CharField(max_length=255,min_length=3, read_only=True)
tokens = serializers.CharField(max_length=68, min_length=6,read_only=True)
class Meta:
model = User
fields = ["email", "password","username","tokens"]
def validate(self,attrs):
email = attrs.get("email", "")
password = attrs.get("password", "")
user = auth.authenticate(email=email, password=password)
if not user:
raise AuthenticationFailed("Invalid Credentials, try again")
if not user.is_active:
raise AuthenticationFailed("Account disabled, contact admin")
if not user.is_verified:
raise AuthenticationFailed("Email is not verified")
return super().validate(attrs,{
"email":user.email,
"username": user.username,
"tokens":user.tokens
})
Below is the views.py file
**from django.shortcuts import render from rest_framework import generics, status, views from .serializers import EmailVerificationSerializer, RegisterSerializer, LoginSerializer from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken, AccessToken
from .models import User
from .utils import Util
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
from django.conf import settings
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import jwt**
# Create your views here.
class RegisterView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data= serializer.data
user = User.objects.get(email=user_data["email"])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse("email-verify")
absurl= "http://" + current_site + relativeLink + "?token="+ str(token)
email_body ="Hi "+ user.username + " Use link below to verify your email \n" + absurl
data = {"email_body":email_body,"to_email":user.email, "email_subject":"Verify your email"}
Util.send_email(data)
return Response(user_data, status=status.HTTP_201_CREATED)
class VerifyEmail(views.APIView):
serializer_class = EmailVerificationSerializer
token_param_config = openapi.Parameter(
"token", in_=openapi.IN_QUERY, description="Description",type=openapi.TYPE_STRING)
@swagger_auto_schema(manual_parameters=[token_param_config])
def get(self,request):
token = request.GET.get("token")
try:
payload = jwt.decode(token, settings.SECRET_KEY)
user = User.objects.get(id=payload["user_id"])
if not user.is_verified:
user.is_verified = True
user.save()
return Response({"email":"Successfully activated"}, status=status.HTTP_200_OK)
except jwt.ExpiredSignatureError as identifier:
return Response({"error": "Activation Link Expired"}, status=status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as identifier:
return Response({"error": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST)
class LoginAPIView(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Below is the utils.py for sending a mail
from django.core.mail import EmailMessage
class Util:
@staticmethod #We'll use the class method without instantiating it
def send_email(data):
email =EmailMessage(
subject=data["email_subject"], body=data["email_body"], to=[data["to_email"]])
email.send()
Below is the urls.py
from django.urls import path
from .views import RegisterView, VerifyEmail, LoginAPIView
urlpatterns = [
path("register/", RegisterView.as_view(), name="register"),
path("email-verify/", VerifyEmail.as_view(), name="email-verify"),
path("login/", LoginAPIView.as_view(), name="login")
]
Below is the verification mail sent
Below are the error gotten while trying to verify the token
A screenshot image description
Upvotes: 0
Views: 489
Reputation: 1
at VerifyEmailView class the payload needs the algorithm with which you decode your token.`class VerifyEmail(views.APIView): serializer_class = EmailVerificationSerializer
token_param_config = openapi.Parameter(
"token", in_=openapi.IN_QUERY, description="Description",type=openapi.TYPE_STRING)
@swagger_auto_schema(manual_parameters=[token_param_config])
def get(self,request):
token = request.GET.get("token")
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms='HS256')
user = User.objects.get(id=payload["user_id"])
if not user.is_verified:
user.is_verified = True
user.save()
return Response({"email":"Successfully activated"}, status=status.HTTP_200_OK)
except jwt.ExpiredSignatureError as identifier:
return Response({"error": "Activation Link Expired"}, status=status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as identifier:
return Response({"error": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST)`
Upvotes: 0