
    *^:i3                        d 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
mZ ddlmZmZ  ed	       G d
 de             Z G d de      Z G d de      Zy)z4Tests for Telegram authentication and webhook flows.    )annotations)patch)TestCaseoverride_settings)reverse)User)TelegramDataValidationErrorgenerate_signed_init_datatest-bot-token)TELEGRAM_BOT_TOKENc                      e Zd ZddZ ed      d        Zd Z ed      d        Z ed      d        Z ed      d        Z	 ed      d        Z
 ed      d	        Z ed      d
        Zy)AuthenticateTelegramTestsc                    | j                   j                  t        d      |d      }| j                  |j                  d       |j                         S )Ntelegram-authapplication/jsondatacontent_type   )clientpostr   assertEqualstatus_codejsonselfpayloadresponses      T/home/cursorai/projects/telegram-earn/backend/apps/users/tests/test_telegram_auth.py
_post_authz$AuthenticateTelegramTests._post_auth   sM    ;;##O$+ $ 

 	--s3}}    z,apps.users.views.validate_telegram_init_datac                *   ddddddd|_         | j                  dd	i      }| j                  d
|       | j                  d|       t        j                  j                  d      }| j                  |j                  d       | j                  |j                  d       | j                  |j                  d       | j                  |j                  d       | j                  |j                  d       | j                  |d   d   |j                         y)z5Creates a new user and returns JWTs and profile data.i90  aliceAliceTesterenzhttps://img.test/alice.jpg)idusername
first_name	last_namelanguage_code	photo_url	init_datazsigned-init-dataaccessrefreshtelegram_user_iduserreferral_codeN)return_valuer    assertInr   objectsgetr   r(   r)   r*   r+   r,   r3   r   mock_validatebodyr2   s       r   $test_creates_user_and_returns_tokensz>AuthenticateTelegramTests.test_creates_user_and_returns_tokens   s     !!!5&
" -?@Ah%i&||70'22++T2)EFfo68J8JKr!   c                    | j                   j                  t        d      i d      }| j                  |j                  d       | j                  d|j                         d          y)zinit_data must be provided.r   r   r     zinit_data is requirederrorN)r   r   r   r   r   r5   r   r   r   s     r   test_rejects_missing_init_dataz8AuthenticateTelegramTests.test_rejects_missing_init_data1   s[    ;;##O$+ $ 
 	--s3-x}}w/GHr!   c                    t        d      |_        | j                  j                  t	        d      ddid      }| j                  |j                  d       | j                  d|j                         d          y	)
z@Invalid init data returns 401 with the validation error message.zbad signaturer   r-   invalidr   r   i  r>   N)	r	   side_effectr   r   r   r   r   r5   r   r   r9   r   s      r   (test_rejects_invalid_init_data_signaturezBAuthenticateTelegramTests.test_rejects_invalid_init_data_signature<   so     %@$P!;;##O$y)+ $ 
 	--s3ox}}w'?@r!   c                    ddi|_         | j                  j                  t        d      ddid      }| j	                  |j
                  d       | j                  d	|j                         d
          y)z8Validation output without an id is treated as bad input.r(   noidr   r-   signedr   r   r=   zInvalid user datar>   N)r4   r   r   r   r   r   r5   r   rD   s      r   test_rejects_missing_user_idz6AuthenticateTelegramTests.test_rejects_missing_user_idJ   so     '1&%9";;##O$x(+ $ 
 	--s3)8==?7+CDr!   c                l   t         j                  j                  dddd      }dddd	|_        | j	                  d
|j
                  d      }t         j                  j                  d      }| j                  |j                  |j                         | j                  |d   d   |j                         y)z.Links referrer by referral_code when provided.   referrerRefrefcode1234r1   r(   r)   r3   iV  bobBob)r'   r(   r)   rH   r-   start_paramr0   r2   referred_byN)
r   r6   create_userr4   r    r3   r7   r   referred_by_idr'   )r   r9   rL   r:   new_users        r   .test_assigns_referral_when_start_param_presentzHAuthenticateTelegramTests.test_assigns_referral_when_start_param_presentX   s     <<++'	 , 
 &
" "83I3IJ
 <<##U#;00(++>fm4hkkBr!   c                   t         j                  j                  ddd      }t         j                  j                  dddd	      }t         j                  j                  d
dd|      }d
dd|_        | j	                  d|j
                  d      }|j                          | j                  |j                  |j                         | j                  |d   d   |j                         y)zDExisting referred_by is preserved even if a new start_param arrives.
   ref1Ref1)r1   r(   r)      ref2Ref2	OTHERCODErO   i  existingExisting)r1   r(   r)   rT   r'   r(   rH   rR   r2   rT   N)
r   r6   rU   r4   r    r3   refresh_from_dbr   rV   r'   )r   r9   original_referrerother_referrerr2   r:   s         r   )test_does_not_overwrite_existing_referralzCAuthenticateTelegramTests.test_does_not_overwrite_existing_referralo   s     !LL44&V 5 
 11&VS^ 2 
 ||''"!)	 ( 
 -2z%J"XnFbFbcd,,.?.B.BCfm46G6J6JKr!   c                    ddd|_         | j                  ddd      }t        j                  j	                  d      }| j                  |j                         | j                  |d   d	          y
)z8Unknown referral codes are ignored without failing auth.i  nolinkrc   rH   DOESNOTEXISTrR   r0   r2   rT   N)r4   r    r   r6   r7   assertIsNonerV   r8   s       r   "test_ignores_invalid_referral_codez<AuthenticateTelegramTests.test_ignores_invalid_referral_code   sf     -2x%H"XnUV||7$--.$v,}56r!   c                   t         j                  j                  ddddd      }ddddd	d
|_        | j	                  ddi       |j                          | j                  |j                  d       | j                  |j                  d       | j                  |j                  d       | j                  |j                  d	       y)z5Existing user gets profile fields refreshed on login.i5  oldnameOldN)r1   r(   r)   r*   r+   newnameNewNamer'   )r'   r(   r)   r*   r+   r-   rH   )r   r6   rU   r4   r    rd   r   r(   r)   r*   r+   )r   r9   r2   s      r   $test_updates_existing_profile_fieldsz>AuthenticateTelegramTests.test_updates_existing_profile_fields   s     ||''" ( 
 !!&
" 	h/0	2%00++T2r!   N)r   dictreturnrt   )__name__
__module____qualname__r    r   r;   r@   rE   rI   rX   rg   rl   rs    r!   r   r   r      s     9:L ;L.	I 9:A ;A 9:E ;E 9:C ;C, 9:L ;L, 9:7 ;7 9:3 ;3r!   r   c                  (   e Zd Z eddd       ed      d               Z ed      d        Z ed      d	        Z eddd       ed      d
               Z eddd       ed      d               Z	 eddd       ed      d               Z
y)TelegramWebhookTestsr   secret-tokenhttps://example.com/app)r   TELEGRAM_WEBHOOK_SECRETTELEGRAM_WEBAPP_URLz&apps.users.views.send_telegram_messagec                   d|_         dddiddi}| j                  j                  t        d      |dd	
      }| j	                  |j
                  d       |j                          |j                  \  }}| j	                  |d   d       | j                  d|       |d   d   d   d   d   d   }| j	                  |d       y)z<Webhook responds with a WebApp button including start param.Tmessager'   í z/start ABCDEFchattexttelegram-webhookr   r|   r   r   $HTTP_X_TELEGRAM_BOT_API_SECRET_TOKENr   chat_idreply_markupkeyboardr   web_appurlz'https://example.com/app?startapp=ABCDEFN)	r4   r   r   r   r   r   assert_called_once	call_argsr5   r   	mock_sendr   r   argskwargs
button_urls          r   8test_webhook_replies_with_webapp_button_and_valid_secretzMTelegramWebhookTests.test_webhook_replies_with_webapp_button_and_valid_secret   s     "&	u'
 ;;##&'+1?	 $ 
 	--s3$$& **f	*E2nf-N+J7:1=iHO
%NOr!   )r~   c                    dddiddi}| j                   j                  t        d      |dd	      }| j                  |j                  d
       y)z9Webhook returns 403 when the secret token does not match.r   r'   iW  /startr   r   r   zwrong-secretr     Nr   r   r   r   r   r   s      r   #test_webhook_rejects_invalid_secretz8TelegramWebhookTests.test_webhook_rejects_invalid_secret   sb     t 
 ;;##&'+1?	 $ 
 	--s3r!   c                    | j                   j                  t        d      dddiddid      }| j                  |j                  d	       y
)z@Webhook returns 403 when secret is configured but header absent.r   r   r'   i  r   r   r   r   r   Nr   r?   s     r   *test_webhook_rejects_missing_secret_headerz?TelegramWebhookTests.test_webhook_rejects_missing_secret_header   sR     ;;##&'tTlHEF+ $ 
 	--s3r!   c                `   d|_         dddiddi}| j                  j                  t        d      |dd	
      }| j	                  |j
                  d       |j                          |j                  \  }}| j	                  |d   d       |d   d   d   d   d   d   }| j	                  |d       y)zANon-/start messages still reply without appending startapp param.Tr   r'   i  hellor   r   r   r|   r   r   r   r   r   r   r   r   r}   N)r4   r   r   r   r   r   r   r   r   s          r   &test_webhook_handles_non_start_messagez;TelegramWebhookTests.test_webhook_handles_non_start_message   s     "&	c{GDE;;##&'+1?	 $ 
 	--s3$$& **f	*C0N+J7:1=iHO
%>?r!   c                $   d|_         dddddiidi}| j                  j                  t        d      |d	d
      }| j	                  |j
                  d       |j                  j                  d   d   d   d   d   d   }| j	                  |d       y)z)Callback queries use data as start param.Tcallback_queryCALLBACKCODEr   r'   i	  )r   r   r   r   r|   r   r   r   r   r   r   r   z-https://example.com/app?startapp=CALLBACKCODEN)r4   r   r   r   r   r   r   r   )r   r   r   r   r   s        r   "test_webhook_handles_callback_dataz7TelegramWebhookTests.test_webhook_handles_callback_data  s     "&	&"T3K0
 ;;##&'+1?	 $ 
 	--s3((//?
KANqQR[\]bc
%TUr!   c                   d|_         | j                  j                  t        d      di idd      }| j	                  |j
                  d       | j	                  |j                         ddi       |j                          y	)
z:Gracefully ack when chat info is missing to avoid retries.Tr   r   r   r|   r   r   okN)r4   r   r   r   r   r   r   assert_not_called)r   r   r   s      r   6test_webhook_acknowledges_missing_chat_without_sendingzKTelegramWebhookTests.test_webhook_acknowledges_missing_chat_without_sending  sy     "&	;;##&'R+1?	 $ 
 	--s34,7##%r!   N)rv   rw   rx   r   r   r   r   r   r   r   r   ry   r!   r   r{   r{      s    + .5
 34P 5P2 ~>4 ?4$ ~>4 ?4 + .5
 34@ 5@& + .5
 34V 5V* + .5
 34& 5&r!   r{   c                  P    e Zd Z eddd      d        Z eddd      d        Zy)DevAuthenticateTelegramTestsTdev-bot-token)DEBUGENABLE_DEV_TELEGRAM_AUTHr   c                   t        dddddd      }| j                  j                  t        d      d	|d	   id
      }| j	                  |j
                  d       |j                         }| j	                  |d   d   d       | j                  d|       | j	                  |d   d   |d          | j	                  |d   d   |d          | j                  d|d          y)zCDev endpoint returns debug info and authenticates signed init_data.i Devdevuser)r'   r)   r(   r   z	dev-query)r2   	bot_tokenquery_idtelegram-auth-devr-   r   r   r   r2   r1   debugprovided_hashhashcalculated_hashdata_check_stringN)r
   r   r   r   r   r   r   r5   )r   rH   r   r:   s       r   8test_dev_auth_validates_signed_payload_and_returns_debugzUDevAuthenticateTelegramTests.test_dev_auth_validates_signed_payload_and_returns_debug5  s     +U	J% 
 ;;##'(vk23+ $ 
 	--s3}}f&895Agt$g7Hg'896&>J)4=9r!   Fc                    | j                   j                  t        d      ddid      }| j                  |j                  d       y)z,Dev endpoint returns 404 outside DEBUG mode.r   r-   anythingr   r   i  Nr   r?   s     r   %test_dev_auth_disabled_when_not_debugzBDevAuthenticateTelegramTests.test_dev_auth_disabled_when_not_debugP  sI     ;;##'(z*+ $ 
 	--s3r!   N)rv   rw   rx   r   r   r   ry   r!   r   r   r   4  sD    !%*
:
:, !%*
4
4r!   r   N)__doc__
__future__r   unittest.mockr   django.testr   r   django.urlsr   apps.users.modelsr   utils.telegramr	   r
   r   r{   r   ry   r!   r   <module>r      sZ    : "  3  " Q &67Z3 Z3 8Z3zE&8 E&P)48 )4r!   