U
    sc                     @   sX  d dl Z d dlZd dlZd dl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 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mZ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& d dl'm(Z) d dl*m+Z+m,Z, d dl-m.Z. d dl/m0Z0 d dl1m2Z2 d dl3m4Z4 d dl5m6Z6 d dl7m8Z8m9Z9 d dl:m;Z; ee;Z<eeZ=ee<ej>ddG dd deZ?ee<ej@ddG dd deZAee<ejBddG dd  d eZCee<ejDddG d!d" d"eZEee=d#d$ddG d%d& d&eZFee=d#d$ddee<ejGddG d'd( d(eZHee<ejIddG d)d* d*eZJee=d#d$ddee<ejKddG d+d, d,eZLee=d#d$ddee<ejMddG d-d. d.eZNee=d#d$ddG d/d0 d0eZOee<ejPddG d1d2 d2eZQee<ejRddG d3d4 d4eZSee=d#d$ddG d5d6 d6eZTdS )7    N)settings)make_passwordcheck_password)timezone)#decorator_from_middleware_with_args)method_decorator)requests)id_tokenstatus)APIView)serializersconf)0check_verification_attempts_and_recaptcha_helper6check_wrong_verification_attempts_and_recaptcha_helper2check_wrong_password_attempts_and_recaptcha_helper)AuthorizatorMiddleware)VerificationAttemptUserWrongPasswordAttemptUserJWTWrongVerificationAttempt)get_client_ip)defined_roles)AccessInviteAccess)	Institute)UserBalanceHistory)InstitutePlan)pushers)
MyResponse)compress_image
logs_adder)SerializerValidationMiddlewarepost)namec                   @   s   e Zd ZdZdd ZdS )SendAVerificationCodez
    This API class is responsible for handling incoming requests for registering.
    it takes an email from user and after some checks creates a temp user record
    in database with that email and also add a random verification code for temp user.
    c              	   C   s|  |j d}|r| }|j d}|j d}|jd}t|}tdd }t|||||}|d k	rn|S |rtj	j
|||d t|||}	t|	| n|rtj	j
|||d t|| n|rHztj	j|d	}
W n$   t|d
di dtjd Y S X |
js"t|d
di dtjdS tj	j
||
j||d t|
j| nd
dd}t||tjdS ddd}t||tjdS )Nemailphoneusernameg-recaptcha-responsei i )r'   ipverification_code)r(   r+   r,   r)   errorz%User with this username was not foundr   messagedatar
   z3There is't any known method for verifying this user)r)   recovery_phoner+   r,   Bad requestr   r0   ok
Successful)middleware_serializer_datagetlowerPOSTr   secrets	randbelowr   r   objectscreater   Z0register_verification_code_email_content_builderZsend_html_emailZsend_verification_code_smsr   r    r   HTTP_404_NOT_FOUNDr2   HTTP_400_BAD_REQUESTHTTP_200_OK)selfrequestr'   r(   r)   g_recaptcha_responser+   numberresultZemail_contentuserr1    rH   ./var/www/wikiazma_server/authenticate/views.pyr$   1   st                 

zSendAVerificationCode.postN__name__
__module____qualname____doc__r$   rH   rH   rH   rI   r&   )   s   r&   c                   @   s   e Zd ZdZdd ZdS )LoginOrVerificationCodeCheckz
    This API class is just for checking the code validity which was created in Register API.
    it takes an email and a code from the client and checks if the code belongs to that email or not.
    c              	   C   s  |j d}|j d}|j d}t|}|jd}t||||d}|d k	rT|S |r| }ztjj||d W n6   tjj	||d dd	d
}t
||tjd Y S X ztjj|d}	W n$   t
|ddi dtjd Y S X n|rrztjj||d W n6   tjj	||d dd	d
}t
||tjd Y S X ztjj|d}	W n$   t
|ddi dtjd Y S X nddd
}t
||tjdS t|	}
t|	j}dd|
|dd}t
||tjdS )Nr'   r(   coder*   r'   r(   r'   r,   r+   r'   r.   z
wrong coder4   r
   r'   r5   z,Verification Code is valid. Please register.r/   r(   r,   r+   r(   r(   r3   r6   tokenrG   )r7   r8   r   r:   r   r9   r   r=   r   r>   r    r   r@   r   rA   r   create_recordauthenticate_serializers9UserSerializerForAuthenticateAndCollaboratorsAndInstituter1   )rB   rC   r'   r(   rP   r+   rD   rF   r1   rG   rY   	user_datarH   rH   rI   r$   k   sj     

 



z!LoginOrVerificationCodeCheck.postNrJ   rH   rH   rH   rI   rO   c   s   rO   c                   @   s   e Zd ZdZdd ZdS )RegisterUserz
    This API class is responsible for handling incoming requests for register verifying.
    it takes an email, a password and a code from user and checks if the code belongs to that email
    in temp user and then create a User in database
    c              
   C   sx  |j d}|j d}|j d}|j d}|j d}|j d}|j d}|j d}	t|}
|jd	}t|
|||d
}|d k	r|S |r| }ztjj||d}W n6   tjj	|
|d ddd}t
||tjd Y S X z*tjj|d ddd}t
||tjdW S    Y nX tjj	||||	d}|rB||_|r\tt|j| |_|	rt|	tjd|_t|	tjd|_|  n|rztjj||d}W n6   tjj	|
|d ddd}t
||tjd Y S X z*tjj|d ddd}t
||tjdW S    tjj	||||	d}|r2||_|rLtt|j| |_|	rrt|	tjd|_t|	tjd|_|  Y nX nddd}t
||tjdS t|}t| tjj	d|dd}tjj	|dt ! dddddd t"jj	||t#j$g|j%|j&d  |'  |r,t(jj)|dddd!j*|d" n"|rNt(jj)|dddd#j*|d" t+,|j-}t
|d$d%||d&d'tj.dS )(Nr)   r'   r(   passwordrP   
first_name	last_nameimager*   rQ   rR   rS   r.   #Your verification code is incorrectr4   r
   rT   zduplicate email)r'   ra   r`   rb   max_side_sizerU   rV   rW   r3   )r(   ra   r`   rb   sandboxT)r%   rG   rf   r   F)	instituter%   
start_datemax_collaborators_per_institutemax_examinee_per_instituteassign_examinee_to_examassign_public_link_to_examenable_institute_api_key)rG   rg   rolesinstitute_nameinstitute_created_at)invited_phonecanceledrejectedinvited_user__isnull)invited_user)invited_emailrr   rs   rt   r5   r6   rX   r/   )/r7   r8   r   r:   r   r9   r   r=   r   r>   r    r   r@   r   r)   r   stridr_   r!   r   9maximum_side_size_compress_for_authenticate_profile_imagerb   Cmaximum_side_size_compress_for_authenticate_profile_image_thumbnailimage_thumbnailsaver   rZ   r   create_initial_balance_historyr   r   r   nowr   dr__ROLE_OWNER__r%   
created_atdeleter   filterupdater[   r\   r1   rA   )rB   rC   r)   r'   r(   r_   rP   r`   ra   rb   r+   rD   rF   Zverification_attemptr1   rG   rY   Zsandbox_instituter]   rH   rH   rI   r$      s       

     

    



zRegisterUser.postNrJ   rH   rH   rH   rI   r^      s   r^   c                   @   s   e Zd ZdZdd ZdS )LoginWithPasswordz
    This API class is responsible for handling incoming requests for login.
    it takes an email and a password from user and checks if the code belongs to that email
    in temp user and then create a User in database
    c                 C   sz  |j d}|j d}|j d}|j d}t|}|jd}t|||||d}|d k	rb|S |r | }zTtjj|d}	tt	|	j
| |	jstjj||d d	d
d}
t||
tjdW S W n6   tjj||d d	d
d}
t||
tjd Y S X nF|rzVtjj|d}	tt	|	j
| |	jsZtjj||d d	dd}
t||
tjdW S W n6   tjj||d d	dd}
t||
tjd Y S X n|r,zVtjj|d}	tt	|	j
| |	jstjj||d d	dd}
t||
tjdW S W n6   tjj||d d	dd}
t||
tjd Y S X nd	dd}
t||
tjdS t|	}t|	j}t|dd||ddtjdS )Nr)   r'   r(   r_   r*   )r'   r(   r)   rT   r'   r+   r.   zEmail or password is incorrectr4   r
   rW   r(   r+   zPhone or password is incorrectr-   r)   r+   z!Username or password is incorrectr3   r5   r6   rX   r/   )r7   r8   r   r:   r   r9   r   r=   r   rw   rx   r_   r   r>   r    r   r@   r   rZ   r[   r\   r1   rA   )rB   rC   r)   r'   r(   r_   r+   rD   rF   rG   r1   rY   r]   rH   rH   rI   r$   <  s         

zLoginWithPassword.postNrJ   rH   rH   rH   rI   r   4  s   r   T)Zaccept_user_tokenc                   @   s   e Zd ZdZdd ZdS )
LogoutUserz
    This API class is responsible for handling incoming requests for logout.
    it takes the user token and if valid, deletes it.
    c                 C   s    |j   t|dddtjdS )Nr5   r6   r4   r
   )Zmiddleware_token_recordr   r    r   rA   )rB   rC   rH   rH   rI   r$     s    
zLogoutUser.postNrJ   rH   rH   rH   rI   r     s   r   c                   @   s   e Zd ZdZdd ZdS )ChangeUserPasswordz
    This API class is responsible for handling incoming datas for changing password.
    it takes the password and code from the user and if the code belongs to the user of incoming token,
    then hashes and sets the new password to the user.
    c                 C   s   |j d}|j d}t|}|jd}|j}t|||j|j|j}|d k	rT|S |j	d k	rt
t|j| |j	rtt|j| |_	|  t|dddtjdS tjj|j|j|d t|d	d
dtjdS d S )Nold_passwordnew_passwordr*   r6   zPassword updated successfullyr4   r
   )r(   r'   r+   r.   zWrong Old Password)r7   r8   r   r:   middleware_userr   r'   r(   r)   r_   r   rw   rx   r   r|   r    r   rA   r   r=   r>   r@   )rB   rC   r   r   r+   rD   rG   rF   rH   rH   rI   r$     s8           zChangeUserPassword.postNrJ   rH   rH   rH   rI   r     s   r   c                   @   s   e Zd ZdZdd ZdS )ForgetUserPassworda  
    This API class is responsible for handling incoming datas for forgetting password.
    it takes the email, password and code from the user and if the code belongs to the user of incoming email,
    then hashes and sets the new password to the user.
    c                 C   s  |j d}|j d}|j d}|j d}|j d}t|}|jd}t|||||}	|	d k	rl|	S |r*| }ztjj||d W n6   tjj	||d d	d
d}
t
||
tjd Y S X ztjj|d}W n&   d	dd}
t
||
tjd Y S X tt|j| |_|  t|}n|rztjj||d W n6   tjj	||d d	d
d}
t
||
tjd Y S X ztjj|d}W n.   td d	dd}
t
||
tjd Y S X tt|j| |_|  t|}n|rztjj||d W n6   tjj	||d d	d
d}
t
||
tjd Y S X ztjj|d}W n.   td d	dd}
t
||
tjd Y S X tt|j| |_|  t|}nd	dd}
t
||
tjdS dd|d}
t
||
tjdS )Nr'   r(   r)   r   rP   r*   rR   r   r.   rc   r4   r
   rT   zRegister FirstrU   r   rW   z'CRITICAL: Invalid State #44875265927245)r)   r,   r   r-   r3   r5   r6   )r   r0   rY   )r7   r8   r   r:   r   r9   r   r=   r   r>   r    r   r@   r   r   rw   rx   r_   r|   r   rZ   r"   rA   )rB   rC   r'   r(   r)   r   rP   r+   rD   rF   r1   rG   rY   rH   rH   rI   r$     s         

 

 
 

zForgetUserPassword.postNrJ   rH   rH   rH   rI   r     s   r   c                   @   s   e Zd Zdd ZdS )EditUserc                 C   s6  |j d}|j d}|j d}|j d}|j d}|j d}|j d}|j}	|sf|dkrl||	_|sx|dkr~||	_|s|dkr||	_|r|	j  |	j  |r|	j	  |	j
  |rt|tjd	|	_t|tjd	|	_|r
t|tjd	|	_	t|tjd	|	_
|	  t|	j}
t|d
d|
dtjdS )Nr`   ra   inforb   posterdelete_imagedelete_poster rd   r5   r6   r   r0   rG   r
   )r7   r8   r   r`   ra   r   rb   r   r{   r   poster_thumbnailr!   r   ry   rz   2maximum_side_size_compress_for_authenticate_poster<maximum_side_size_compress_for_authenticate_poster_thumbnailr|   r[   r\   r1   r    r   rA   )rB   rC   r`   ra   r   rb   r   r   r   rG   r]   rH   rH   rI   r$     sX    



   zEditUser.postNrK   rL   rM   r$   rH   rH   rH   rI   r     s   r   c                   @   s   e Zd ZdZdd ZdS )UserProfilez
    This API class is responsible for handling incoming requests for accessing user profile data.
    it takes the user token and if valid, responses informations of the user of incoming token in desired format.
    c                 C   sf   |j d}ztjj|d}W n"   t|dddtjd Y S X t|j	}t|dd|d	tj
dS )
Nuser_id)rx   r.   zUser not foundr4   r
   r5   r6   r   )r7   r8   r   r=   r    r   r?   r[   r\   r1   rA   )rB   rC   r   rG   r]   rH   rH   rI   r$   O  s    zUserProfile.postNrJ   rH   rH   rH   rI   r   F  s   r   c                   @   s   e Zd ZdZdd ZdS )UserAccountz
    This API class is responsible for handling incoming requests for accessing user account data.
    it takes the user token and if valid, responses informations of the user of incoming token in desired format.
    c                 C   s&   t |jj}t|dd|dtjdS )Nr5   r6   r   r
   )r[   r\   r   r1   r    r   rA   )rB   rC   r]   rH   rH   rI   r$   e  s    zUserAccount.postNrJ   rH   rH   rH   rI   r   ]  s   r   c                   @   s   e Zd ZdZdd ZdS )UserGoogleLogina  
    This API class is responsible for handling incoming requests for login via Google.
    it takes a g_id_token and try to decode it. if it was successful, then we create a user with the incoming data,
    otherwise the client faces an 403 forbidden error!
    c              
   C   sz  |j d}zDt|t tj}|d rF|d tjksF|d dkr^t|dddt	j
d	W S ztjj|d
 d}W nf   tjj|d |d |d
 |d d}t|}t|j}t|dd||ddt	jd	 Y W S X |js|d |_|  n(|j|d krt|dddt	j
d	W S t|}t|j}t|dd||ddt	jd	W S    t|dddt	j
d	 Y S X d S )N
g_id_tokenZemail_verifiedaudiss)zaccounts.google.comzhttps://accounts.google.comr.   Something was wrongr4   r
   r'   rT   Z
given_nameZfamily_namesub)r`   ra   r'   	g_subjectr5   r6   rX   r/   )r7   r8   r	   Zverify_oauth2_tokengoogle_requestsRequestr   GOOGLE_CLIENT_IDr    r   HTTP_403_FORBIDDENr   r=   r>   r   rZ   r[   r\   r1   rA   r   r|   )rB   rC   r   ZidinforG   rY   r]   rH   rH   rI   r$   t  sd      "



zUserGoogleLogin.postNrJ   rH   rH   rH   rI   r   l  s   r   c                   @   s   e Zd ZdZdd ZdS )UserFacebookLogina	  
    This API class is responsible for handling incoming requests for login via Facebook.
    it takes a g_id_token and try to decode it. if it was successful, then we create a user with the incoming data,
    otherwise the client faces an 403 forbidden error!
    c           
   
   C   s  |j d}z|tjtjtjd}tjd|d}|jdkrTt|dddt	j
d	W S tjd
d| d id}|jdkrt|dddt	j
d	W S | }ztjj|d d}W nf   tjj|d |d |d |d d}t|}t|j}	t|dd||	ddt	jd	 Y W S X |js2|d |_|  n(|j|d krZt|dddt	j
d	W S t|}t|j}	t|dd||	ddt	jd	W S    t|dddt	j
d	 Y S X d S )Nfb_code)rP   Z	client_idZredirect_uriZclient_secretz2https://graph.facebook.com/v7.0/oauth/access_token)params   r.   r   r4   r
   z?https://graph.facebook.com/me?fields=first_name,last_name,emailZaccess_tokenr'   rT   r`   ra   rx   )r`   ra   r'   fb_idr5   r6   rX   r/   )r7   r8   r   FACEBOOK_CLIENT_IDFACEBOOK_REDIRECT_URIFACEBOOK_CLIENT_SECRETr   status_coder    r   r   jsonr   r=   r>   r   rZ   r[   r\   r1   rA   r   r|   )
rB   rC   r   Zfb_dataZfirst_responseZsecond_responseZclient_datarG   rY   r]   rH   rH   rI   r$     s~     
 





zUserFacebookLogin.postNrJ   rH   rH   rH   rI   r     s   r   c                   @   s   e Zd Zdd ZdS )UserBalancec                 C   s(   |j }|j}t|ddd|idtjdS )Nr5   r6   balancer/   r
   )r   r   r    r   rA   )rB   rC   Zcallerr   rH   rH   rI   r$     s    zUserBalance.postNr   rH   rH   rH   rI   r     s   r   )Urandomr;   r   django.confr   django.contrib.auth.hashersr   r   django.utilsr   django.utils.decoratorsr   r   Zgoogle.auth.transportr   Zgoogle.oauth2r	   rest_frameworkr   rest_framework.viewsr   authenticater   r[   r   Zauthenticate.attemp_recaptchar   r   r   Zauthenticate.middlewarer   authenticate.modelsr   r   r   r   r   Zauthenticate.utilsr   collaboratorsr   r   Zcollaborators.modelsr   r   institute.modelsr   payment.modelsr   plan.modelsr   utilsr   utils.myresponser    utils.utilsr!   r"   Zwikiazma.middlewarer#   Z serializer_validation_middlewareZIuser_token_or_server_token_or_server_API_key_validation_and_authorizationZ$SendAVerificationCodeInputSerializerr&   Z+InputLoginOrVerificationCodeCheckSerializerrO   ZInputRegisterUserSerializerr^   Z InputLoginWithPasswordSerializerr   r   Z!InputChangeUserPasswordSerializerr   Z!InputForgetUserPasswordSerializerr   ZInputEditUserSerializerr   ZInputUserProfileSerializerr   r   ZInputUserGoogleLoginSerializerr   Z InputUserFacebookLoginSerializerr   r   rH   rH   rH   rI   <module>   s   9
? N

!]
1

2<
