Commit 73c60411 authored by Ilham Maulana's avatar Ilham Maulana 💻

fix: sifting reset password from token based to pin based

parent 9e3d67d1
import json import random
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth import authenticate, login, logout
from django.core.mail import send_mail from django.core.mail import send_mail
from rest_framework import views, viewsets, status from rest_framework import views, viewsets, status
...@@ -9,6 +8,8 @@ from rest_framework.response import Response ...@@ -9,6 +8,8 @@ from rest_framework.response import Response
from rest_framework.filters import SearchFilter from rest_framework.filters import SearchFilter
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from users.models import ResetPasswordPin
from .serializers import ( from .serializers import (
User, User,
Librarian, Librarian,
...@@ -243,6 +244,14 @@ class MemberChangePasswordView(views.APIView): ...@@ -243,6 +244,14 @@ class MemberChangePasswordView(views.APIView):
class TokenResetPasswordView(views.APIView): class TokenResetPasswordView(views.APIView):
def generate_random_pin(self):
return random.randint(10000000, 99999999)
def store_data_with_pin(self, user):
pin = self.generate_random_pin()
ResetPasswordPin.objects.get_or_create(pin=pin, user=user)
return pin
def post(self, request): def post(self, request):
data = request.data.copy() data = request.data.copy()
email = data.get("email") email = data.get("email")
...@@ -250,14 +259,14 @@ class TokenResetPasswordView(views.APIView): ...@@ -250,14 +259,14 @@ class TokenResetPasswordView(views.APIView):
if user is None: if user is None:
return Response( return Response(
{"message": "Invalid Email, Request token reset password failed"}, {"message": "Invalid Email, Request pin reset password failed"},
status=status.HTTP_403_FORBIDDEN, status=status.HTTP_403_FORBIDDEN,
) )
token = default_token_generator.make_token(user) pin = self.store_data_with_pin(user)
message = f"Here's your reset password token: {token}" message = f"Here's your reset password pin: {pin}"
send_mail( send_mail(
subject="Django Library App Reset password token, dev: Ilham Maulana", subject="Django Library App Reset password pin, dev: Ilham Maulana",
message=message, message=message,
from_email="from@example.com", from_email="from@example.com",
recipient_list=["to@example.com"], recipient_list=["to@example.com"],
...@@ -265,11 +274,9 @@ class TokenResetPasswordView(views.APIView): ...@@ -265,11 +274,9 @@ class TokenResetPasswordView(views.APIView):
) )
data["message"] = ( data["message"] = (
"Your token request was successful! We've sent an email with instructions on how to use it." "Your pin request was successful! We've sent an email with instructions on how to use it."
) )
self.request.session["user_id_reset_pw"] = user.id
return Response(data, status=status.HTTP_200_OK) return Response(data, status=status.HTTP_200_OK)
...@@ -278,11 +285,10 @@ class ResetPasswordConfirmView(views.APIView): ...@@ -278,11 +285,10 @@ class ResetPasswordConfirmView(views.APIView):
def post(self, request): def post(self, request):
data = request.data data = request.data
token = data.get("token") pin = data.get("pin")
password1 = data.get("password1") password1 = data.get("password1")
password2 = data.get("password2") password2 = data.get("password2")
user_id = self.request.session["user_id_reset_pw"] encoded = None
user = User.objects.get(pk=user_id)
is_password_invalid = password1 != password2 is_password_invalid = password1 != password2
if is_password_invalid: if is_password_invalid:
...@@ -291,17 +297,18 @@ class ResetPasswordConfirmView(views.APIView): ...@@ -291,17 +297,18 @@ class ResetPasswordConfirmView(views.APIView):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
is_token_valid = default_token_generator.check_token(user, token) try:
if not is_token_valid: encoded = ResetPasswordPin.objects.get(pin=pin)
except ResetPasswordPin.DoesNotExist:
return Response( return Response(
{"message": "Invalid token reset password"}, {"message": "Invalid pin reset password"},
status=status.HTTP_401_UNAUTHORIZED, status=status.HTTP_401_UNAUTHORIZED,
) )
user.set_password(password1) encoded.user.set_password(password1)
user.save() encoded.user.save()
encoded.delete()
del user_id
return Response( return Response(
{"message": "Reset password success"}, {"message": "Reset password success"},
status=status.HTTP_200_OK, status=status.HTTP_200_OK,
......
# Generated by Django 5.0.7 on 2024-07-31 09:53
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0004_alter_librarianloginhistory_librarian'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='ResetPasswordPin',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('pin', models.IntegerField()),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
...@@ -31,3 +31,8 @@ class LibrarianLoginHistory(models.Model): ...@@ -31,3 +31,8 @@ class LibrarianLoginHistory(models.Model):
Librarian, blank=True, null=True, on_delete=models.CASCADE Librarian, blank=True, null=True, on_delete=models.CASCADE
) )
date = models.DateTimeField(auto_now_add=True) date = models.DateTimeField(auto_now_add=True)
class ResetPasswordPin(models.Model):
pin = models.IntegerField()
user = models.OneToOneField(User, on_delete=models.CASCADE)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment