ó
    fÁÍjË  ã                   óà   • S SK r S SKrS SKJrJrJr  S SKJr  S SKJr  S SK	J
r
JrJrJrJr  S SKJr  S SKJr  S SKJr  S S	KJrJrJr  \ R2                  " \5      rS
rS rS rS rS r S r!S r"g)é    N)ÚdatetimeÚ	timedeltaÚtimezone©Úwraps)Ú	urlencode)Úcurrent_appÚflashÚredirectÚsessionÚurl_for)Údb)ÚAccount)Ú	Forbidden)Úexchange_codeÚget_user_infoÚrefresh_tokené
   c                  ó¼   • [         R                  " S5      n U [        S'   [        R                  n[        US   SR                  US   5      SUS   U S.5      nS	U 3$ )
zUBuild the TikTok Login authorization URL with a per-flow state stored in the session.é   Úoauth_stateÚTIKTOK_CLIENT_KEYÚ,ÚTIKTOK_SCOPESÚcodeÚTIKTOK_REDIRECT_URI)Ú
client_keyÚscopeÚresponse_typeÚredirect_uriÚstatez*https://www.tiktok.com/v2/auth/authorize/?)ÚsecretsÚ	token_hexr   r	   Úconfigr   Újoin)r!   r$   Úparamss      Ú:F:\Solutions\Thinkera\Publishers\TikTokManager\app\auth.pyÚget_auth_urlr(      sn   € ä×Ò˜bÓ!€EØ"„GˆMÑÜ×Ñ€FÜØÐ0Ñ1Ø—‘˜& Ñ1Ó2ØØÐ4Ñ5Øñó €Fð 8¸°xÐ@Ð@ó    c           
      ó@  • U (       a"  U(       a  U[         R                  " SS5      :w  a  [        S5      e[        R                  n[        XS   US   US   5      nUS   n[        U5      =(       d    0 n[        R                  R                  UR                  S5      =(       d    UR                  S5      S	9R                  5       n[        R                  " [        R                  5      R!                  SS
9[#        [%        UR                  SS5      5      S9-   nU(       a�  UR                  S5      =(       d    UR&                  Ul        UR                  S5      =(       d    UR(                  Ul        XFl        US   Ul        UR                  S5      =(       d    UR.                  Ul        Xvl        [3        Xe5        O¢[        UR                  S5      =(       d    UR                  S5      UR                  S5      =(       d    SUR                  S5      UUS   UR                  S5      =(       d    SUS9n[3        Xe5        [4        R                   R7                  U5        [4        R                   R9                  5         [:        R=                  SUR>                  5        U$ )zoExchange the OAuth code for tokens, fetch the profile, and upsert the account; raises Forbidden on a bad state.r   Nz<Login session expired or the state did not match; try again.r   ÚTIKTOK_CLIENT_SECRETr   Úaccess_tokenÚopen_id)r-   ©ÚtzinfoÚ
expires_iné€Q ©ÚsecondsÚdisplay_nameÚ
avatar_urlr   r   ÚUnknownÚ )r-   r4   r5   r,   r   ÚscopesÚ
expires_atzauth.connect ok open_id=%s) r   Úpopr   r	   r$   r   r   r   ÚqueryÚ	filter_byÚgetÚfirstr   Únowr   ÚutcÚreplacer   Úintr4   r5   r,   r   r8   r9   Ú_apply_statsr   ÚaddÚcommitÚlogÚinfor-   )r   r!   r$   Útokensr,   ÚuserÚaccountr9   s           r'   Úsave_account_from_loginrK   "   sý  € æ–u ¬¯ª°]ÀDÓ)IÓ IÜÐVÓWÐWä×Ñ€FÜØÐ(Ñ)¨6Ð2HÑ+IÈ6ÐRgÑKhó€Fð ˜.Ñ)€LÜ˜Ó&×,¨"€Dä�m‰m×%Ñ%¨f¯j©j¸Ó.C×.ZÀtÇxÁxÐPYÓGZÐ%Ð[×aÑaÓc€GÜ—’œhŸl™lÓ+×3Ñ3¸4Ð3Ð@Ä9ÔUXÐY_×YcÑYcÐdpÐrwÓYxÓUyÑCzÑz€JÞØ#Ÿx™x¨Ó7×O¸7×;OÑ;OˆÔØ!ŸX™X lÓ3×I°w×7IÑ7IˆÔØ+ÔØ & Ñ 7ˆÔØŸ™ GÓ,×>°·±ˆŒØ'ÔÜ�WÕ#äØ—J‘J˜yÓ)×@¨T¯X©X°iÓ-@ØŸ™ .Ó1×>°YØ—x‘x Ó-Ø%Ø  Ñ1Ø—:‘:˜gÓ&×,¨"Ø!ñ
ˆô 	�WÔ#Ü
�
‰
�‰�wÔÜ‡J�J×ÑÔÜ‡H�HÐ)¨7¯?©?Ô;Ø€Nr)   c           	      ól   • S H.  nUR                  U5      c  M  [        X[        X   5      5        M0     g )N)Úfollower_countÚfollowing_countÚlikes_countÚvideo_count)r=   ÚsetattrrB   )rJ   rI   Úfields      r'   rC   rC   I   s,   € ÛTˆØ�8‰8�E‹?Ó&Ü�G¤C¨©Ó$4Ö5ò Ur)   c           	      ó\  • [         R                  " [        R                  5      R	                  SS9nU R
                  (       a.  U R
                  [        [        S9-
  U:”  a  U R                  5       $ [        R                  n[        U R                  5       US   US   5      nUS   U l        US   U l        U[        [        UR                  SS	5      5      S
9-   U l        UR                  S5      (       a
  US   U l        ["        R$                  R'                  5         U R                  5       $ )z­Return a valid access token, refreshing (and persisting the rotated tokens) when the
current one is expired or about to expire. Raises TikTokAPIError when the refresh fails.Nr.   )Úminutesr   r+   r,   r   r0   r1   r2   r   )r   r?   r   r@   rA   r9   r   ÚREFRESH_AHEAD_MINUTESÚaccess_token_plainr	   r$   r   Úrefresh_token_plainr,   rB   r=   r8   r   r   rE   )rJ   r?   r$   rH   s       r'   Úensure_fresh_tokenrX   O   sý   € ô �,Š,”x—|‘|Ó
$×
,Ñ
,°DÐ
,Ð
9€CØ××˜g×0Ñ0´9ÔEZÑ3[Ñ[Ð^aÓaØ×)Ñ)Ó+Ð+ä×Ñ€FÜØ×#Ñ#Ó% vÐ.AÑ'BÀFÐKaÑDbó€Fð " .Ñ1€GÔØ" ?Ñ3€GÔØœy´°V·Z±ZÀÈeÓ5TÓ1UÑVÑV€GÔØ‡z�z�'×ÑØ ™ˆŒÜ‡J�J×ÑÔØ×%Ñ%Ó'Ð'r)   c                  ó†   • [         R                  " S5      n U (       d  g[        R                   R                  [        U 5      $ )zTThe account active in this browser session; None when the visitor has not logged in.Úactive_account_idN)r   r=   r   r   )Ú
account_ids    r'   Úget_active_accountr\   c   s,   € ä—’Ð0Ó1€JÞØÜ�:‰:�>‰>œ' :Ó.Ð.r)   c                 ó0   ^ • [        T 5      U 4S j5       nU$ )z\GUI guard: only a session with an active account passes; there is no first-account fallback.c                  ór   >• [        5       (       d   [        SS5        [        [        S5      5      $ T" U 0 UD6$ )Nz&Please connect a TikTok account first.Úwarningz
auth.login)r\   r
   r   r   )ÚargsÚkwargsÚfs     €r'   Údecorated_functionÚ*login_required.<locals>.decorated_functionm   s7   ø€ ä!×#Ñ#ÜÐ:¸IÔFÜœG LÓ1Ó2Ð2Ù�$Ð!˜&Ñ!Ð!r)   r   )rb   rc   s   ` r'   Úlogin_requiredre   k   s!   ø€ ä
ˆ1ƒXô"ó ð"ð
 Ðr)   )#Úloggingr"   r   r   r   Ú	functoolsr   Úurllib.parser   Úflaskr	   r
   r   r   r   Úappr   Ú
app.modelsr   Úapp.services.errorsr   Úapp.tiktok_apir   r   r   Ú	getLoggerÚ__name__rF   rU   r(   rK   rC   rX   r\   re   © r)   r'   Ú<module>rq      sb   ðÛ Û ß 2Ñ 2Ý Ý "ç @Õ @å Ý Ý )ß FÑ Fà×Ò˜Ó!€àÐ òAò$òN6ò(ò(/ór)   