ó
    DÁÍj!  ã                   óÂ   • S SK r S SKJrJrJr  S SKJrJr  S SKJr  S SK	J
r
  S SKJr  S\4S jrS	 rS
 r " S S\
R                   5      r " S S\
R                   5      rg)é    N)ÚdatetimeÚ	timedeltaÚtimezone)ÚFernetÚMultiFernet)Úcurrent_app)Údb)Útoken_encryption_keysÚreturnc                  ó¦   • [        [        R                  R                  S5      5      n [	        U  Vs/ s H  n[        U5      PM     sn5      $ s  snf )zdMultiFernet over TOKEN_ENCRYPTION_KEY: the first key encrypts, every listed key decrypts (rotation).ÚTOKEN_ENCRYPTION_KEY)r
   r   ÚconfigÚgetr   r   )ÚkeysÚks     Ú<F:\Solutions\Thinkera\Publishers\TikTokManager\app\models.pyÚ_fernetr      s?   € ä ¤×!3Ñ!3×!7Ñ!7Ð8NÓ!OÓP€DÜ©4Ó0ª4 aœ˜qž	©4Ñ0Ó1Ð1ùÒ0s   ²Ac                 óx   • U c  g[        5       R                  U R                  S5      5      R                  S5      $ )z5Fernet-encrypt a string for storage; None stays None.Núutf-8Úascii)r   ÚencryptÚencodeÚdecode)Úplains    r   Úencrypt_secretr      s1   € à�}ØÜ‹9×Ñ˜UŸ\™\¨'Ó2Ó3×:Ñ:¸7ÓCÐCó    c                 óx   • U c  g[        5       R                  U R                  S5      5      R                  S5      $ )zYDecrypt a stored value; None stays None. Raises InvalidToken when no configured key fits.Nr   r   )r   Údecryptr   r   )Úciphers    r   Údecrypt_secretr       s1   € à�~ØÜ‹9×Ñ˜VŸ]™]¨7Ó3Ó4×;Ñ;¸GÓDÐDr   c                   ó¼  • \ rS rSrSrSr\R                  " \R                  SS9r	\R                  " \R                  " S5      SSSS9r\R                  " \R                  " S	5      SS
9r\R                  " \R                  " S5      SS
9r\R                  " S\R                  SS
9r\R                  " S\R                  SS
9r\R                  " \R                  SS
9r\R                  " \R$                  " 5       SS
9r\R                  " \R                  SS
9r\R                  " \R                  SS
9r\R                  " \R                  SS
9r\R                  " \R                  SS
9r\R                  " \R$                  S S9r\R                  " \R$                  S S S9r\R4                  " SSSS9rS rS r\" S\SS9r\" S\SS9r S r!S r"S r#S r$S  r%S!r&g)"ÚAccounté   zYA TikTok account connected through TikTok Login; holds the OAuth access + refresh tokens.ÚaccountsT©Úprimary_keyé@   F)ÚuniqueÚnullableÚindexé   ©r)   é   Úaccess_tokenÚrefresh_tokenc                  óJ   • [         R                  " [        R                  5      $ ©N©r   Únowr   Úutc© r   r   Ú<lambda>ÚAccount.<lambda>0   ó   € ¼¿ºÄXÇ\Á\Ô8Rr   ©Údefaultc                  óJ   • [         R                  " [        R                  5      $ r1   r2   r5   r   r   r6   r7   3   ó   € œŸš¤X§\¡\Ô2r   c                  óJ   • [         R                  " [        R                  5      $ r1   r2   r5   r   r   r6   r7   4   ó   € œŸš¤h§l¡lÔ3r   ©r:   ÚonupdateÚScheduledPostÚaccountzall, delete-orphan)Úback_populatesÚcascadec                 óH   • U(       d  [        S5      e[        U5      U l        g )Nzaccess token is required)Ú
ValueErrorr   Ú_access_token©ÚselfÚvalues     r   Ú_set_access_tokenÚAccount._set_access_token9   s   € ÞÜÐ7Ó8Ð8Ü+¨EÓ2ˆÕr   c                 óH   • U(       d  [        S5      e[        U5      U l        g )Nzrefresh token is required)rF   r   Ú_refresh_tokenrH   s     r   Ú_set_refresh_tokenÚAccount._set_refresh_token>   s   € ÞÜÐ8Ó9Ð9Ü,¨UÓ3ˆÕr   Nz#write-only: encrypted on assignment)Údocc                 ó,   • [        U R                  5      $ )z/The only decryption point for the access token.)r    rG   ©rI   s    r   Úaccess_token_plainÚAccount.access_token_plainF   s   € ä˜d×0Ñ0Ó1Ð1r   c                 ó,   • [        U R                  5      $ )z0The only decryption point for the refresh token.)r    rN   rS   s    r   Úrefresh_token_plainÚAccount.refresh_token_plainJ   s   € ä˜d×1Ñ1Ó2Ð2r   c                 ó†   • U R                   =(       d    SR                  S5       Vs/ s H  o(       d  M  UPM     sn$ s  snf )NÚ Ú,)ÚscopesÚsplit)rI   Úss     r   Ú
scope_listÚAccount.scope_listN   s2   € Ø ŸK™K×-¨2×4Ñ4°SÔ9Ó?Ò9�a»Q—Ñ9Ñ?Ð?ùÒ?s   §
>µ>c                 ó¢   • U R                   (       d  gU R                   [        R                  " [        R                  5      R                  SS9:*  $ )z’True when the access token is gone or past its expiry. `expires_at` is stored as
naive UTC (engine-neutral), so the comparison uses naive UTC too.TN)Útzinfo)Ú
expires_atr   r3   r   r4   ÚreplacerS   s    r   Útoken_is_expiredÚAccount.token_is_expiredQ   s8   € ð ��ØØ�‰¤(§,¢,¬x¯|©|Ó"<×"DÑ"DÈDÐ"DÐ"QÑQÐQr   c                 ó2  • U R                   U R                  U R                  U R                  U R	                  5       U R
                  U R                  U R                  U R                  U R                  (       a  U R                  R                  5       S.
$ S S.
$ )N)
ÚidÚopen_idÚdisplay_nameÚ
avatar_urlr\   Úfollower_countÚfollowing_countÚlikes_countÚvideo_countÚ
created_at)rh   ri   rj   rk   r_   rl   rm   rn   ro   rp   Ú	isoformatrS   s    r   Úto_dictÚAccount.to_dictX   s   € à—'‘'Ø—|‘|Ø ×-Ñ-ØŸ/™/Ø—o‘oÓ'Ø"×1Ñ1Ø#×3Ñ3Ø×+Ñ+Ø×+Ñ+Ø9=¿¿˜$Ÿ/™/×3Ñ3Ó5ñ
ð 	
ð OSñ
ð 	
r   )rG   rN   )'Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__tablename__r	   ÚColumnÚIntegerrh   ÚStringri   rj   rk   ÚTextrG   rN   r\   ÚDateTimerc   rl   rm   rn   ro   rp   Ú
updated_atÚrelationshipÚscheduled_postsrK   rO   Úpropertyr.   r/   rT   rW   r_   re   rr   Ú__static_attributes__r5   r   r   r"   r"      sœ  † Ùcà€Mà	�Š�2—:‘:¨4Ñ	0€BØ�iŠi˜Ÿ	š	 "›¨d¸UÈ$ÑO€GØ—9’9˜RŸYšY s›^°eÑ<€LØ—’˜2Ÿ9š9 S›>°DÑ9€JØ—I’I˜n¨b¯g©gÀÑF€MØ—Y’Y˜°·±À%ÑH€NØ�YŠY�r—w‘w¨Ñ.€FØ—’˜2Ÿ;š;›=°4Ñ8€JØ—Y’Y˜rŸz™z°DÑ9€NØ—i’i §
¡
°TÑ:€OØ—)’)˜BŸJ™J°Ñ6€KØ—)’)˜BŸJ™J°Ñ6€KØ—’˜2Ÿ;™;Ñ0RÑS€JØ—’Ø
�‰Ù2Ù3ñ€Jð —o’o oÀiÐYmÑn€Oò3ò
4ñ
 ˜DÐ"3Ð9^Ñ_€LÙ˜TÐ#5Ð;`Ña€Mò2ò3ò@òRõ
r   r"   c                   óÊ  • \ rS rSrSrSrSrSrSrSr	\
R                  " \
R                  SS	9r\
R                  " \
R                  \
R                  " S
5      SS9r\
R                  " \
R                   SS9r\
R                  " \
R$                  " S5      SS9r\
R                  " \
R$                  " S5      SSS9r\
R                  " \
R                   SS9r\
R                  " \
R$                  " S5      SS9r\
R                  " \
R.                  " 5       SS9r\
R                  " \
R$                  " S5      S\SS9r\
R                  " \
R$                  " S5      SS9r\
R                  " \
R$                  " S5      SS9r\
R                  " \
R                   SS9r\
R                  " \
R.                  S S9r\
R                  " \
R.                  S S S9r\
R>                  " SSS9r S r!Sr"g)rA   ég   z`A video waiting for its scheduled time; the scheduler container publishes it when due (ADR-005).r�   ÚpendingÚ
publishingÚ	publishedÚfailedTr%   zaccounts.idFr,   é    é   Údirect)r)   r:   r-   )r)   r:   r*   é€   c                  óJ   • [         R                  " [        R                  5      $ r1   r2   r5   r   r   r6   ÚScheduledPost.<lambda>}   r8   r   r9   c                  óJ   • [         R                  " [        R                  5      $ r1   r2   r5   r   r   r6   r�   €   r<   r   c                  óJ   • [         R                  " [        R                  5      $ r1   r2   r5   r   r   r6   r�   �   r>   r   r?   r"   )rC   c                 ó˜  • U R                   U R                  U R                  U R                  U R                  U R
                  U R                  (       a  U R                  R                  5       OS U R                  U R                  U R                  U R                  U R                  (       a  U R                  R                  5       S.$ S S.$ )N)rh   Ú
account_idÚtitleÚprivacy_levelÚmodeÚ	video_urlÚscheduled_atÚstatusÚ
publish_idÚvideo_idÚerrorrp   )rh   r“   r”   r•   r–   r—   r˜   rq   r™   rš   r›   rœ   rp   rS   s    r   rr   ÚScheduledPost.to_dict†   s˜   € à—'‘'ØŸ/™/Ø—Z‘ZØ!×/Ñ/Ø—I‘IØŸ™Ø=A×=N×=N˜D×-Ñ-×7Ñ7Ô9ÐTXØ—k‘kØŸ/™/ØŸ™Ø—Z‘ZØ9=¿¿˜$Ÿ/™/×3Ñ3Ó5ñ
ð 	
ð OSñ
ð 	
r   r5   N)#rt   ru   rv   rw   rx   ry   ÚSTATUS_PENDINGÚSTATUS_PUBLISHINGÚSTATUS_PUBLISHEDÚSTATUS_FAILEDr	   rz   r{   rh   Ú
ForeignKeyr“   r}   r”   r|   r•   r–   Ú
video_pathr—   r~   r˜   r™   rš   r›   rœ   rp   r   r€   rB   rr   rƒ   r5   r   r   rA   rA   g   s„  † Ùjà%€Mà€NØ$ÐØ"ÐØ€Mà	�Š�2—:‘:¨4Ñ	0€BØ—’˜2Ÿ:™: r§}¢}°]Ó'CÈeÑT€JØ�IŠI�b—g‘g¨Ñ-€EØ—I’I˜bŸiši¨›m°dÑ;€MØ�9Š9�R—Y’Y˜r“]¨U¸HÑE€DØ—’˜2Ÿ7™7¨TÑ2€JØ—	’	˜"Ÿ)š) C›.°4Ñ8€IØ—9’9˜RŸ[š[›]°UÑ;€LØ�YŠY�r—y’y “}¨u¸nÐTXÑY€FØ—’˜2Ÿ9š9 S›>°DÑ9€JØ�yŠy˜Ÿš 3›°$Ñ7€HØ�IŠI�b—g‘g¨Ñ-€EØ—’˜2Ÿ;™;Ñ0RÑS€JØ—’Ø
�‰Ù2Ù3ñ€Jð �oŠo˜iÐ8IÑJ€Gõ
r   rA   )Újsonr   r   r   Úcryptography.fernetr   r   Úflaskr   Úappr	   Ú
app.configr
   r   r   r    ÚModelr"   rA   r5   r   r   Ú<module>rª      sU   ðÛ ß 2Ñ 2ç 3Ý å Ý ,ð2�ô 2òDòEôE
ˆb�h‰hô E
ôP-
�B—H‘Hõ -
r   