o
    aeh                     @   s  d Z ddlmZmZmZ ddlmZmZmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZmZmZmZ ddlmZm Z m!Z!m"Z" ddl#m$Z$m%Z% ddl&m'Z' ddl(m)Z) ddlm*Z* ddl+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5 ddl6m7Z7m8Z8m9Z9 ddl:m;Z; ddl<m=Z=m>Z> ddl?m@Z@mAZA ddlBmCZC ddlDmEZE ddlFmGZG ddlHmIZI ddlJmKZK ddlLZLddlMZMd d!lNmOZOmPZPmQZQmRZR d d"lSmTZTmUZUmVZVmWZW e* ZXeMYeZZ[G d#d$ d$eZ\G d%d& d&eZ]G d'd( d(eZ^G d)d* d*eZ_G d+d, d,eZ`G d-d. d.eZaG d/d0 d0eZbe
d1d2 Zce
e3d3gd4d5 ZdG d6d7 d7eIZee=d3ge>e@gd8d9 Zfe=d:ge>e@gd;d< ZgG d=d> d>eZhG d?d@ d@eZidS )Az
Authentication Views Module

This module contains views for handling authentication and authorization
including login, logout, registration, password reset, email verification,
and session management.

Author: Senior Django Developer
Date: 2024
    )renderredirectget_object_or_404)authenticateloginlogout)login_required)LoginRequiredMixin)messages)	send_mail)settings)gettext_lazy)timezone)ViewTemplateViewFormViewListView
DetailView)JsonResponseHttpResponseHttpResponseRedirectHttp404)reverse_lazyreverse)render_to_string)
strip_tags)get_user_model)QCount)	Paginator)csrf_exempt)require_http_methods)method_decorator)AuthenticationFormPasswordResetFormSetPasswordFormstatus)api_viewpermission_classes)IsAuthenticatedAllowAny)Response)APIView)Token)ObtainAuthToken)	timedeltaN   )LoginAttemptPasswordResetTokenEmailVerificationTokenUserSession)get_client_ipget_user_agent_infoget_location_from_ipis_safe_urlc                       T   e Zd ZdZdZeZedZ fddZ	 fddZ
 fdd	Z fd
dZ  ZS )CustomLoginViewz
    Custom login view with enhanced security features.
    
    Features:
    - Login attempt tracking
    - Account lockout protection
    - IP-based suspicious activity detection
    - Session management
    - Device tracking
    zauth/login.htmlcore:dashboardc                    s.   |j jr
t|  S t j|g|R i |S )a$  
        Check if user is already authenticated.
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        N)useris_authenticatedr   get_success_urlsuperdispatchselfrequestargskwargs	__class__ MC:\Users\vibe-look\OneDrive\Desktop\Adtlas_V\src\apps\authentication\views.pyrA   g   s   zCustomLoginView.dispatchc                    .   t  jdi |}td|d< td|d< |S )
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        ZLogintitlezSign in to your accountpage_descriptionNrI   r@   get_context_data_rC   rF   contextrG   rI   rJ   rP   x      
z CustomLoginView.get_context_datac                    s8  |j d}|j d}t| j}| jjdd}t|}t|}tj|dd}|dkrOtj	j
|||dd	|d
d|ddd t| jtd | |S t|rwtj	j
|||dd|d
d|ddd t| jtd | |S t| j||d}	|	dura|	jstj	j
|	|||dd|d
d|ddd t| jtd | |S |	jstj	j
|	|||dd|d
d|ddd t| jtd td|	jdS t| j|	 tj	j
|	|||d|d
d|ddd | jjj}
|
r%tj	j|
|	|||dd|dd|dddt tdd |d
d|ddd 
d! t |	_|	jd"gd# t| jtd$|	  p>|	j! d% | jj"d&}|r[t#|| j$ r[t|S t% &|S z	t'j	j|d'}	W n t'j(yw   d}	Y nw tj	j
|	|||dd(|d
d|ddd t| jtd) | |S )*z
        Handle valid form submission.
        
        Args:
            form: Valid authentication form
            
        Returns:
            HttpResponse: Response object
        usernamepasswordHTTP_USER_AGENT r1   )since_hours   FZaccount_lockedcountrycity)attempted_email
ip_address
user_agentis_successfulfailure_reasonr[   r\   zYAccount temporarily locked due to multiple failed login attempts. Please try again later.Zsuspicious_ipzALogin blocked due to suspicious activity. Please contact support.)rU   rV   NZaccount_inactive)r=   r]   r^   r_   r`   ra   r[   r\   z1Your account is inactive. Please contact support.Zemail_not_verifiedz3Please verify your email address before logging in.auth:resend_verificationuser_idT)r=   r]   r^   r_   r`   r[   r\   device_typebrowseros   )days)
r=   r^   r_   re   rf   operating_system	is_active
expires_atr[   r\   )session_keydefaults
last_login)update_fieldszWelcome back, !next)emailZinvalid_credentialsz,Invalid email or password. Please try again.))cleaned_datagetr6   rD   METAr7   r8   r2   get_failed_attempts_countobjectscreater
   errorrQ   form_invalidis_ip_suspiciousr   rk   is_verifiedr   idr   sessionrm   r5   update_or_creater   nowr0   ro   savesuccessget_full_namers   GETr9   get_hostr@   
form_validUserDoesNotExist)rC   formrs   rV   r^   r_   Zuser_agent_infoZlocation_infofailed_attemptsr=   rm   next_urlrG   rI   rJ   r      s  



























zCustomLoginView.form_validc                    s*   t | jst | jtd t |S )z
        Handle invalid form submission.
        
        Args:
            form: Invalid authentication form
            
        Returns:
            HttpResponse: Response object
         Please correct the errors below.N)r
   get_messagesrD   rz   rQ   r@   r{   rC   r   rG   rI   rJ   r{   =  s   zCustomLoginView.form_invalid)__name__
__module____qualname____doc__template_namer#   
form_classr   success_urlrA   rP   r   r{   __classcell__rI   rI   rG   rJ   r;   W   s     7r;   c                   @   s    e Zd ZdZdd Zdd ZdS )CustomLogoutViewz
    Custom logout view with session cleanup.
    
    Features:
    - Session invalidation
    - Security logging
    - Cleanup of user sessions
    c                 O   s   |j jr?|jj}|r$ztjj||j d}|  W n
 tjy#   Y nw t	
d|j j dt|  t| t|td tdS )a  
        Handle logout POST request.
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        )rm   r=   zUser z logged out from IP z&You have been successfully logged out.
auth:loginN)r=   r>   r   rm   r5   rx   ru   
invalidater   loggerinfors   r6   r   r
   r   rQ   r   )rC   rD   rE   rF   rm   Zuser_sessionrI   rI   rJ   postZ  s*   zCustomLogoutView.postc                 O   s   | j |g|R i |S )a*  
        Handle logout GET request (redirect to POST).
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        N)r   rB   rI   rI   rJ   ru     s   zCustomLogoutView.getN)r   r   r   r   r   ru   rI   rI   rI   rJ   r   P  s    	+r   c                       sX   e Zd ZdZdZedZdd Z fddZ fdd	Z	 fd
dZ
 fddZ  ZS )RegisterViewz
    User registration view.
    
    Features:
    - User account creation
    - Email verification
    - Security logging
    - Input validation
    zauth/register.htmlr   c                    s0   ddl m  ddlm} G  fddd|}|S )z'Return the form class for registration.r   forms)UserCreationFormc                       sT   e Zd ZjddZjdddZjdddZG dd dZd	 fdd	Z	  Z
S )
z;RegisterView.get_form_class.<locals>.CustomUserCreationFormT)requiredrh   )
max_lengthr   c                   @   s   e Zd ZeZdZdS )z@RegisterView.get_form_class.<locals>.CustomUserCreationForm.Meta)rs   
first_name	last_name	password1	password2N)r   r   r   r   modelfieldsrI   rI   rI   rJ   Meta  s    r   c                    sB   t  jdd}| jd |_| jd |_| jd |_|r|  |S )NF)commitrs   r   r   )r@   r   rt   rs   r   r   )rC   r   r=   rG   rI   rJ   r     s   z@RegisterView.get_form_class.<locals>.CustomUserCreationForm.save)T)r   r   r   
EmailFieldrs   	CharFieldr   r   r   r   r   rI   r   rG   rJ   CustomUserCreationForm  s    r   N)djangor   django.contrib.auth.formsr   )rC   r   r   rI   r   rJ   get_form_class  s   zRegisterView.get_form_classc                    s*   |j jrtdS t j|g|R i |S )z'Check if user is already authenticated.r<   N)r=   r>   r   r@   rA   rB   rG   rI   rJ   rA     s   zRegisterView.dispatchc                    rK   )zAdd additional context data.ZRegisterrM   zCreate your accountrN   NrI   rO   rR   rG   rI   rJ   rP     s   zRegisterView.get_context_datac                    sH   |  }t| j}td|j d|  t| jtd t	 
|S )zHandle valid form submission.zNew user registered: 	 from IP z1Account created successfully! You can now log in.N)r   r6   rD   r   r   rs   r
   r   rQ   r@   r   )rC   r   r=   r^   rG   rI   rJ   r     s   
zRegisterView.form_validc                    s   t | jtd t |S )zHandle invalid form submission.r   N)r
   rz   rD   rQ   r@   r{   r   rG   rI   rJ   r{     s
   zRegisterView.form_invalid)r   r   r   r   r   r   r   r   rA   rP   r   r{   r   rI   rI   rG   rJ   r     s    
r   c                       sD   e Zd ZdZdZeZedZ fddZ	 fddZ
dd	 Z  ZS )
PasswordResetRequestViewzj
    Password reset request view.
    
    Handles password reset token generation and email sending.
    z auth/password_reset_request.htmlzauth:password_reset_sentc                    rK   )rL   zReset PasswordrM   z'Enter your email to reset your passwordrN   NrI   rO   rR   rG   rI   rJ   rP     rT   z)PasswordResetRequestView.get_context_datac                    s   |j d }z*tjj|dd}tjj|t| jd}| || t	
d|j dt| j  W n
 tjy9   Y nw t |S )z
        Handle valid form submission.
        
        Args:
            form: Valid password reset form
            
        Returns:
            HttpResponse: Response object
        rs   T)rs   rk   )r=   requested_ipz"Password reset requested for user r   N)rt   r   rx   ru   r3   ry   r6   rD   send_password_reset_emailr   r   rs   r   r@   r   )rC   r   rs   r=   reset_tokenrG   rI   rJ   r     s   

z#PasswordResetRequestView.form_validc                 C   sb   | j tdd|jid}td||ttdd|jd}t|}t	t
d|tj|jg|d	d
 dS )z
        Send password reset email to user.
        
        Args:
            user: User instance
            reset_token: PasswordResetToken instance
        zauth:password_reset_confirmtokenrF   zauth/emails/password_reset.htmlZ	SITE_NAMEzOur Site)r=   	reset_url	site_namerl   zPassword Reset RequestFsubjectmessage
from_emailrecipient_listhtml_messagefail_silentlyN)rD   build_absolute_urir   r   r   getattrr   rl   r   r   rQ   DEFAULT_FROM_EMAILrs   )rC   r=   r   r   r   plain_messagerI   rI   rJ   r     s,   	


z2PasswordResetRequestView.send_password_reset_email)r   r   r   r   r   r$   r   r   r   rP   r   r   r   rI   rI   rG   rJ   r     s    #r   c                       r:   )PasswordResetConfirmViewz\
    Password reset confirmation view.
    
    Handles password reset using the token.
    z auth/password_reset_confirm.htmlzauth:password_reset_completec                    s   | d| _ztjj | jd| _| j s"t|td t	dW S W n tj
y9   t|td t	d Y S w t j|g|R i |S )a&  
        Validate token before processing request.
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        r   r   z3This password reset link is invalid or has expired.zauth:password_reset_requestz$This password reset link is invalid.N)ru   r   r3   rx   r   is_validr
   rz   rQ   r   r   r@   rA   rB   rG   rI   rJ   rA   Q  s(   

z!PasswordResetConfirmView.dispatchc                    s   t   }| jj|d< |S )zb
        Add user to form kwargs.
        
        Returns:
            dict: Form kwargs
        r=   N)r@   get_form_kwargsr   r=   )rC   rF   rG   rI   rJ   r   t  s   
z(PasswordResetConfirmView.get_form_kwargsc                    s:   t  jdi |}td|d< td|d< | jj|d< |S )rL   zSet New PasswordrM   zEnter your new passwordrN   r=   NrI   )r@   rP   rQ   r   r=   rR   rG   rI   rJ   rP     s
   
z)PasswordResetConfirmView.get_context_datac                    sn   |  }| jt| j td|j dt| j  tj	j
|ddjdd t| jtd t |S )	z
        Handle valid form submission.
        
        Args:
            form: Valid set password form
            
        Returns:
            HttpResponse: Response object
        z"Password reset completed for user r   T)r=   rk   F)rk   zPYour password has been reset successfully. Please log in with your new password.N)r   r   	use_tokenr6   rD   r   r   rs   r5   rx   filterupdater
   r   rQ   r@   r   )rC   r   r=   rG   rI   rJ   r     s   z#PasswordResetConfirmView.form_valid)r   r   r   r   r   r%   r   r   r   rA   r   rP   r   r   rI   rI   rG   rJ   r   F  s    #r   c                   @      e Zd ZdZdd ZdS )EmailVerificationViewzT
    Email verification view.
    
    Handles email verification using tokens.
    c                 O   s   zDt jj|d}| r8|t| td|jj	 dt|  t
|td |jjs3tdW S tdW S t
|td W tdS  t jyY   t
|td Y tdS w )
aI  
        Handle email verification GET request.
        
        Args:
            request: HTTP request object
            token: Verification token
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        r   zEmail verified for user r   z*Your email has been verified successfully!r   r<   z7This email verification link is invalid or has expired.z(This email verification link is invalid.N)r4   rx   ru   r   verify_emailr6   r   r   r=   rs   r
   r   rQ   r>   r   rz   r   )rC   rD   r   rE   rF   verification_tokenrI   rI   rJ   ru     s8   

zEmailVerificationView.getN)r   r   r   r   ru   rI   rI   rI   rJ   r         r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ResendVerificationViewz_
    Resend email verification view.
    
    Handles resending email verification tokens.
    c                 O   sv   z$t t|d}|jrt|td tdW S |tdd}t|d|W S  tjy:   t	|td td Y S w )	a\  
        Handle resend verification GET request.
        
        Args:
            request: HTTP request object
            user_id: User ID to resend verification for
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        r~   Your email is already verified.r   zResend Email Verification)r=   rM   zauth/resend_verification.htmlUser not found.N)
r   r   r}   r
   r   rQ   r   r   r   rz   )rC   rD   rd   rE   rF   r=   rS   rI   rI   rJ   ru     s&   
zResendVerificationView.getc              
   O   sN  zgt t|d}|jrt|td tdW S tjj	|dt
 d }|r)|}nddl}|d}	tjj||	|jt
 td	d
 d}| || t|td td|j dt|  td|jdW S  tjy}   t|td td Y S  ty }
 ztdt|
  t|td td|dW  Y d}
~
S d}
~
ww )a]  
        Handle resend verification POST request.
        
        Args:
            request: HTTP request object
            user_id: User ID to resend verification for
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        r   r   r   F)r=   is_usedexpires_at__gtr   N       )hours)r=   r   rs   rl   z7Verification email has been sent to your email address.z#Verification email resent for user r   rb   rc   r   z$Error resending verification email: zIAn error occurred while sending the verification email. Please try again.)r   r   r}   r
   r   rQ   r   r4   rx   r   r   r   firstsecretstoken_urlsafery   rs   r0   send_verification_emailr   r   r6   r~   r   rz   	Exceptionstr)rC   rD   rd   rE   rF   r=   Zexisting_tokenr   r   r   erI   rI   rJ   r     sb   

zResendVerificationView.postc              
   C   s   | j tdd|jid}td}d|jp|j d| d| d}d	|jp'|j d
| d}zt||tj	|jg|dd W dS  t
yU } ztdt|   d}~ww )z
        Send email verification email to user.
        
        Args:
            user: User instance
            verification_token: EmailVerificationToken instance
        zauth:verify_emailr   r   zVerify Your Email Addressz\
        <html>
        <body>
            <h2>Email Verification</h2>
            <p>Hello zk,</p>
            <p>Please click the link below to verify your email address:</p>
            <p><a href="z" style="background-color: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;">Verify Email</a></p>
            <p>Or copy and paste this link in your browser:</p>
            <p>z</p>
            <p>This link will expire in 24 hours.</p>
            <p>If you didn't request this verification, please ignore this email.</p>
        </body>
        </html>
        z3
        Email Verification
        
        Hello zY,
        
        Please visit the following link to verify your email address:
        z
        
        This link will expire in 24 hours.
        
        If you didn't request this verification, please ignore this email.
        Fr   z#Failed to send verification email: N)rD   r   r   r   rQ   r   rs   r   r   r   r   r   rz   r   )rC   r=   r   Zverification_urlr   r   r   r   rI   rI   rJ   r   d  s@   	

z.ResendVerificationView.send_verification_emailN)r   r   r   r   ru   r   r   rI   rI   rI   rJ   r     s
    &Jr   c                 C   s0   t | j}| jj}td||d}t| d|S )z
    View for managing user sessions.
    
    Args:
        request: HTTP request object
        
    Returns:
        HttpResponse: Response object
    zActive Sessions)rM   sessionscurrent_session_keyzauth/user_sessions.htmlN)r5   get_active_sessions_for_userr=   r   rm   rQ   r   )rD   r   r   rS   rI   rI   rJ   user_sessions_view  s   r   POSTc                 C   s   z0t jj|| jdd}|j| jjkrt| td n|	  t
| td W tdS W tdS  t jyE   t| td Y tdS w )z
    View for invalidating a specific user session.
    
    Args:
        request: HTTP request object
        session_id: Session ID to invalidate
        
    Returns:
        HttpResponse: Response object
    T)r~   r=   rk   z+You cannot invalidate your current session.z!Session invalidated successfully.z)Session not found or already invalidated.zauth:user_sessionsN)r5   rx   ru   r=   rm   r   r
   rz   rQ   r   r   r   r   )rD   Z
session_idr   rI   rI   rJ   invalidate_session_view  s4   r   c                   @   r   )CustomAuthTokenViewzu
    Custom API authentication view.
    
    Extends the default token authentication with additional features.
    c           	      O   s   | j |jd|id}| r>|jd }tjj|d\}}tjj||j	t
||jdddd t|j|j|j	|j|jd	S |jd
d}tjj|t
||jddddd t|jtjdS )a  
        Handle token authentication request.
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            Response: API response
        rD   )datarS   r=   )r=   rW   rX   T)r=   r]   r^   r_   r`   )r   rd   rs   r   r   rU   FZinvalid_api_credentials)r]   r^   r_   r`   ra   r&   N)Zserializer_classr   r   Zvalidated_datar.   rx   get_or_creater2   ry   rs   r6   rv   ru   r,   keypkr   r   errorsr'   HTTP_400_BAD_REQUEST)	rC   rD   rE   rF   
serializerr=   r   createdrs   rI   rI   rJ   r     sB   
	zCustomAuthTokenView.postN)r   r   r   r   r   rI   rI   rI   rJ   r     r   r   c              
   C   s`   z| j j  tdtditjdW S  ty/ } ztdtditjdW  Y d}~S d}~ww )z
    API logout view.
    
    Args:
        request: HTTP request object
        
    Returns:
        Response: API response
    r   zSuccessfully logged out.r&   rz   zLogout failed.N)	r=   Z
auth_tokendeleter,   rQ   r'   HTTP_200_OKr   r   )rD   r   rI   rI   rJ   api_logout_view%  s   

r   r   c                 C   sd   t | j}g }|D ]}||j|j|j|j|j|j	|j
|j|j| jjkd	 q
td|itjdS )z
    API view for getting user sessions.
    
    Args:
        request: HTTP request object
        
    Returns:
        Response: API response with user sessions
    )	r~   r^   re   rf   rj   r[   r\   last_activityZ
is_currentr   r&   N)r5   r   r=   appendr~   r^   re   rf   rj   r[   r\   r   rm   r   r,   r'   r   )rD   r   Zsessions_datar   rI   rI   rJ   api_user_sessions_view@  s&   
r   c                       $   e Zd ZdZdZ fddZ  ZS )PasswordResetSentViewz6
    Password reset email sent confirmation view.
    zauth/password_reset_sent.htmlc                    "   t  jdi |}td|d< |S )rL   zPassword Reset Email SentrM   NrI   rO   rR   rG   rI   rJ   rP   i     
z&PasswordResetSentView.get_context_datar   r   r   r   r   rP   r   rI   rI   rG   rJ   r   c      r   c                       r   )PasswordResetCompleteViewz4
    Password reset complete confirmation view.
    z!auth/password_reset_complete.htmlc                    r   )rL   zPassword Reset CompleterM   NrI   rO   rR   rG   rI   rJ   rP   ~  r   z*PasswordResetCompleteView.get_context_datar   rI   rI   rG   rJ   r   x  r   r   )jr   django.shortcutsr   r   r   django.contrib.authr   r   r   django.contrib.auth.decoratorsr   Zdjango.contrib.auth.mixinsr	   django.contribr
   django.core.mailr   django.confr   django.utils.translationr   rQ   django.utilsr   django.views.genericr   r   r   r   r   django.httpr   r   r   r   django.urlsr   r   django.template.loaderr   django.utils.htmlr   r   django.db.modelsr   r   django.core.paginatorr   django.views.decorators.csrfr    Zdjango.views.decorators.httpr!   django.utils.decoratorsr"   r   r#   r$   r%   rest_frameworkr'   Zrest_framework.decoratorsr(   r)   Zrest_framework.permissionsr*   r+   Zrest_framework.responser,   Zrest_framework.viewsr-   Zrest_framework.authtoken.modelsr.   Zrest_framework.authtoken.viewsr/   datetimer0   jsonloggingmodelsr2   r3   r4   r5   utilsr6   r7   r8   r9   r   	getLoggerr   r   r;   r   r   r   r   r   r   r   r   r   r   r   r   r   rI   rI   rI   rJ   <module>   sv   
 zDNdk< 6
*=!