1- from django . shortcuts import render
1+ from rest_framework . decorators import api_view
22
3- # Create your views here.
3+ from django .db .models import Q
4+ from django .conf import settings
5+ from django .utils import timezone
6+ from rest_framework import status
7+ from django .core .mail import send_mail
8+ from rest_framework .response import Response
9+ from core .models import PasswordResetRequest
10+ from django .contrib .auth import get_user_model
11+ from rest_framework .authtoken .models import Token
12+ from django .core .exceptions import ValidationError
13+ from django .contrib .auth import authenticate , login as auth_login
14+ from core .authentication import ExpiringTokenAuthentication
15+ from django .contrib .auth .password_validation import validate_password
16+
17+
18+ def core_login (request , user_type = 'Admin' ):
19+ # get id/email and password
20+ id = request .data .get ('id' )
21+ password = request .data .get ('password' )
22+
23+ errors = {}
24+ if not id : errors ['id' ] = "User id or email is required."
25+ if not password : errors ['password' ] = "Password is required."
26+
27+ if errors : return Response (errors , status = status .HTTP_400_BAD_REQUEST )
28+
29+ # get user
30+ try :
31+ user = get_user_model ().objects .get (Q (id = id ) | Q (email = id ))
32+
33+ except get_user_model ().DoesNotExist :
34+ return Response ({'id' : "User with the given id/email does not exist." }, status = status .HTTP_404_NOT_FOUND )
35+
36+ # validate user type
37+ if user .user_type != user_type :
38+ if user_type == 'Admin' :
39+ return Response ({'id' : f"User with id { id } is not an admin." }, status = status .HTTP_400_BAD_REQUEST )
40+
41+ elif user_type == 'Student' :
42+ return Response ({'id' : f"User with id { id } is not a student." }, status = status .HTTP_400_BAD_REQUEST )
43+
44+ elif user_type == 'Staff' :
45+ return Response ({'id' : f"User with id { id } is not a staff member." }, status = status .HTTP_400_BAD_REQUEST )
46+
47+ # authenticate user
48+ user = authenticate (username = user .id , password = password )
49+
50+ if not user :
51+ return Response ({'password' : "Wrong credentials provided." }, status = status .HTTP_401_UNAUTHORIZED )
52+
53+ # log user in
54+ auth_login (request , user )
55+
56+ # create token
57+ token , created = Token .objects .get_or_create (user = user )
58+
59+ utc_now = timezone .now ()
60+ if not created and token .created < utc_now - ExpiringTokenAuthentication .validity_time :
61+ token .delete ()
62+ token = Token .objects .create (user = user )
63+ token .created = timezone .now ()
64+ token .save ()
65+
66+ # set token as cookie and return response
67+ response = Response ({'token' : token .key }, content_type = "application/json" )
68+ response .set_cookie ('token' , token .key , expires = utc_now + ExpiringTokenAuthentication .validity_time )
69+
70+ return response
71+
72+ def core_logout (request ):
73+ request .user .auth_token .delete ()
74+ return Response ({'success' : "Logged out successfully" }, status = status .HTTP_200_OK )
75+
76+ def core_forgot_password (request , user_type = 'Admin' ):
77+ # get id or email
78+ id = request .data .get ('id' )
79+
80+ if not id :
81+ return Response ({'id' : "User id or email is required" }, status = status .HTTP_400_BAD_REQUEST )
82+
83+ # get user
84+ try :
85+ user = get_user_model ().objects .get (Q (id = id ) | Q (email = id ))
86+
87+ except get_user_model ().DoesNotExist :
88+ return Response ({'id' : "User with the given id/email does not exist." }, status = status .HTTP_404_NOT_FOUND )
89+
90+
91+ # generate password reset request
92+ req , created = PasswordResetRequest .objects .get_or_create (user = user )
93+
94+ first_time = not user .has_usable_password ()
95+ time_limit = timezone .timedelta (hours = 48 ) if first_time else timezone .timedelta (minutes = 30 )
96+
97+ if not created and req .created < timezone .now () - time_limit :
98+ req .delete ()
99+ req = PasswordResetRequest .objects .create (user = user )
100+ req .save ()
101+
102+
103+ # send email
104+ forgot_password_url = settings .FORGOT_PASSWORD_URL .replace ('type' , user .user_type .lower ())
105+ reset_password_url = f"{ settings .RESET_PASSWORD_URL .replace ('type' , user .user_type .lower ())} ?token={ req .key } "
106+
107+ send_mail (
108+ f"BIT Online Portal password account verification" if first_time else f"BIT Online Portal password reset" ,
109+ f'''An account has been created for you in the { user_type } Portal of the BIT website.\n \n
110+ Please click on the following link to verify the account by setting your password: { reset_password_url } \n \n
111+ This link is only valid for the next 48 hours. In order to issue a password-reset request again, visit { forgot_password_url }
112+ If you are not { user .name } , then please ignore this email.''' .replace ('\t \t ' , '' ) if first_time else
113+ f'''We have received a request to reset the password for your account in the { user_type } Portal of the BIT website.
114+ Please click on the following link to reset your password: { reset_password_url } \n \n
115+ This link is only valid for the next 30 minutes. In order to issue a password-reset request again, visit { forgot_password_url }
116+ If you did not request a password reset, please ignore this email.''' .replace ('\t \t ' , '' ),
117+ "superuser.bit@gmail.com" ,
118+ [user .email ]
119+ )
120+
121+ return Response ({'success' : f"{ 'Verification' if first_time else 'Password reset' } email sent to { user .email } ." }, status = status .HTTP_200_OK )
122+
123+ def core_password_reset (request ):
124+ token = request .GET .get ('token' )
125+
126+ try :
127+ req = PasswordResetRequest .objects .get (key = token )
128+
129+ except PasswordResetRequest .DoesNotExist :
130+ return Response ("Invalid password reset request token." , status = status .HTTP_404_NOT_FOUND )
131+
132+ user = req .user
133+ password = request .data .get ('password' )
134+
135+ try :
136+ validate_password (password , user = user )
137+
138+ except ValidationError as e :
139+ return Response ({'password' : e }, status = status .HTTP_400_BAD_REQUEST )
140+
141+ first_time = not user .has_usable_password ()
142+
143+ if settings .TESTING : time_limit = timezone .timedelta (seconds = 15 ) if first_time else timezone .timedelta (seconds = 25 )
144+ else : time_limit = timezone .timedelta (hours = 48 ) if first_time else timezone .timedelta (minutes = 30 )
145+
146+ if req .created < timezone .now () - time_limit :
147+ req .delete ()
148+ return Response ({'token' : "Password reset token expired." }, status = status .HTTP_400_BAD_REQUEST )
149+
150+ else :
151+ user = req .user
152+
153+ user .set_password (password )
154+ user .save ()
155+ req .delete ()
156+
157+ return Response ({'success' : f"Password for user { user } changed successfully." }, status = status .HTTP_200_OK )
158+
159+
160+ @api_view (['POST' ])
161+ def login (request ):
162+ return core_login (request )
163+
164+ @api_view (['POST' ])
165+ def logout (request ):
166+ return core_logout (request )
167+
168+ @api_view (['POST' ])
169+ def forgot_password (request ):
170+ return core_forgot_password (request )
171+
172+ @api_view (['POST' ])
173+ def password_reset (request ):
174+ return core_password_reset (request )
0 commit comments