+
    j~                     ,   R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt	^ RI
t	^ RIt	^ RItRtR t^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt]! ]P.                  P1                  RR4      4      t]P.                  P1                  RR4      tRtRtR!t0 R"mtR	tR
t Rt!R]! 2t"R] R2t#RR.t$R t%R#R lt&R t'R t(R t)R#R lt*R$R lt+R t,R t-R t. ! R R]P^                  P`                  4      t1 ! R R]Pd                  4      t3R t4]5R 8X  d
   ]4! 4        R# R# )%u  
Clinic Content Studio — servidor local

Endpoints:
  Packs (existente):
    POST /api/save-pack            — persiste pack JSON em ./packs/
    GET  /api/list-packs           — lista packs salvos
    GET  /api/load-pack/{f}        — carrega um pack específico

  Meta integration (Fase 3+4):
    GET  /api/meta/config          — retorna app_id (sem secret) + redirect_uri
    POST /api/meta/config          — salva app_id + app_secret em meta_config.json
    GET  /api/meta/auth/start      — redireciona para OAuth Facebook
    GET  /api/meta/auth/callback   — recebe code, troca por token, salva
    POST /api/meta/disconnect      — limpa tokens
    GET  /api/meta/status          — info da conexão (páginas, contas IG)
    POST /api/meta/post            — publica post no Instagram (image/reel/story)
    GET  /api/meta/insights/{id}   — métricas de um media específico
    GET  /api/meta/leads/{form_id} — leads de um form específico

Arquivos sensíveis (não-commitados):
    meta_config.json   — { app_id, app_secret, redirect_uri }
    meta_tokens.json   — { user_token, expires_at, pages: [{...}] }

Uso:
    python3 server.py
    Acesse: http://localhost:8080/clinic_content_studio%20(5).html
Nc                B   ^ RI p^ RIpVP                  RR4      p\        VP                  R^ 4      4      pV P	                  V4      pRV,           R,           P                  4       V,           pVP                  P                  VP                  P                  R7      P                  V4      p/ pVP                  4        F  p	V	P                  RR4      p
V
'       g   K  / pV
P                  R	4      R
,           F_  pVP                  4       pRV9   g   K  VP                  R^4      w  rVP                  4       P                  R4      WP                  4       &   Ka  	  VP                  RR4      pVP                  RR4      pV	P                  RR7      pVf   K  VV3W&   K  	  V# )u3   Parser multipart/form-data sem dependência de cgi.NContent-Type Content-LengthzContent-Type: z

)policyzContent-Disposition;:   NN="namefilenameT)decode)email.parseremail.policygetintreadencodeparserBytesParserr   compat32
parsebyteswalksplitstripget_payload)fpheadersemailctypecontent_lengthbodyrawmsgfieldspartdisppdictsegkvr   fnamepayloads   &&                /opt/apps/studio-api/server.py_parse_multipartr.   ,   s\   %KK+E%5q9:N77>"De#j0
8
8
:T
AC
,,
"
"%,,*?*?
"
@
K
KC
PCF
xx-r2::c?2&&C))+Cczyya(#$779??3#7ggi 	 '
 yy$		*b)""$"/!7+FL  M    STUDIO_PORT8080STUDIO_BINDr   packsuploadszmeta_config.jsonzmeta_tokens.jsonzv21.0zhttps://graph.facebook.com/http://localhost:/api/meta/auth/callbackpages_show_listpages_read_engagementc                     \         P                  P                  \        4      '       g   R #  \	        \        RR7      ;_uu_ 4       p \
        P                  ! V 4      uuR R R 4       #   + '       g   i     R # ; i  \         d     R # i ; iNutf-8encoding)ospathexistsMETA_CONFIG_FILEopenjsonload	Exceptionfs    r-   meta_load_configrH   g   Y    77>>*++"W5599Q< 6555 /   A; A'
A; 'A8	2A; 8A; ;B
	B
c                 $   R V P                  4       RVP                  4       RT;'       g    \        P                  4       /p\        \        RRR7      ;_uu_ 4       p\        P
                  ! W4^R7       RRR4       V#   + '       g   i     T# ; i)app_id
app_secretredirect_uriwr;   r<   indentN)r   DEFAULT_REDIRECT_URIrB   rA   rC   dump)rL   rM   rN   cfgrG   s   &&&  r-   meta_save_configrU   q   ss    &,,.j&&(==)=DDFC
 
g	6	6!		## 
7J 
7	6Js   A>>B	c                     \         P                  P                  \        4      '       g   R #  \	        \        RR7      ;_uu_ 4       p \
        P                  ! V 4      uuR R R 4       #   + '       g   i     R # ; i  \         d     R # i ; ir:   )r>   r?   r@   META_TOKENS_FILErB   rC   rD   rE   rF   s    r-   meta_load_tokensrX   |   rI   rJ   c                     \        \        R RR7      ;_uu_ 4       p\        P                  ! W^R7       RRR4       R#   + '       g   i     R# ; i)rO   r;   r<   rP   N)rB   rW   rC   rS   )tokensrG   s   & r-   meta_save_tokensr[      s1    	g	6	6!		&A& 
7	6	6	6s	   >A	c                      \         P                  P                  \        4      '       d   \         P                  ! \        4       R # R # N)r>   r?   r@   rW   remove r/   r-   meta_clear_tokensr`      s(    	ww~~&''
		"# (r/   c                    \          V  2pV'       d.   VR \        P                  P                  V4      ,           ,          p\        P                  P                  VRR/R7      p\        P                  P                  V^R7      ;_uu_ 4       p\        P                  ! VP                  4       P                  R4      4      uuRRR4       #   + '       g   i     R# ; i)?Acceptapplication/json)r   timeoutr;   N)META_GRAPH_BASEurllibparse	urlencoderequestRequesturlopenrC   loadsr   r   )r?   paramsurlreqrs   &&   r-   meta_graph_getrs      s    dV
$CsV\\++F333
..
 
 x9K.L
 
MC			R		0	0Azz!&&(//'23 
1	0	0	0s   3C

C	c                 0   \          V  2pV'       d.   VR \        P                  P                  V4      ,           ,          p\        P                  P                  T;'       g    / 4      P	                  4       p\        P
                  P                  VVRRRR/R7      p\        P
                  P                  V^R7      ;_uu_ 4       p\        P                  ! VP                  4       P                  R4      4      uuRRR4       #   + '       g   i     R# ; i)	rb   rc   rd   r   z!application/x-www-form-urlencoded)datar   re   r;   N)rg   rh   ri   rj   r   rk   rl   rm   rC   rn   r   r   )r?   ro   ru   rp   r!   rq   rr   s   &&&    r-   meta_graph_postrv      s    dV
$CsV\\++F333<<!!$**"-446D
..
 
 (?
 ! C 
		R		0	0Azz!&&(//'23 
1	0	0	0s   3DD	c                *    \        RRV RVRVRV/4      # )z;Troca o code do OAuth por um short-lived user access token./oauth/access_token	client_idclient_secretrN   coders   )rL   rM   rN   r{   s   &&&&r-   meta_exchange_short_tokenr}      s+    ZLD		
 r/   c                *    \        RRRRV RVRV/4      # )z+Troca short-lived por long-lived (60 dias).rx   
grant_typefb_exchange_tokenry   rz   r|   )rL   rM   short_tokens   &&&r-   meta_exchange_long_livedr      s,    -Z		
 r/   c                   \        RRRRV /4      p. pVP                  R. 4       F  pVP                  R4      ;'       g    / pVP                  RVP                  R4      RVP                  R4      RVP                  R4      R	VP                  R4      R
VP                  R4      RVP                  R4      /4       K  	  V# )uF   Lista páginas do usuário + tokens de página + contas IG vinculadas.z/me/accountsr$   zPid,name,access_token,instagram_business_account{id,username,profile_picture_url}access_tokenru   instagram_business_accountidr   
ig_user_idig_usernameusernameig_profile_picture_urlprofile_picture_url)rs   r   append)
user_token
pages_respoutpigs   &    r-   meta_fetch_pages_with_igr      s    hJ	
J C^^FB'UU/066B

aeeDkfn 5bffTlrvvj1("&&1F*G		
 ( Jr/   c                   @  a a ] tR t^t oR tR tV 3R ltR tR tR t	R t
R tR	 tR
 tR tR tR tR tR tR tR tR tR tR tR tR tRtR tR tR tR tR tR t R t!R t"R  t#R! t$R" t%R# t&R$ t'R% t(R& t)R' t*R( t+R/R) lt,R* t-R+ t.R0R, lt/R- t0R.t1Vt2V ;t3# )1StudioHandlerc                    V P                   P                  R 4      '       d7   \        RV P                    R\        V4      ^8  d
   V^,          MR 24       R# R# )z/api/z  [API] u    — r   N)r?   
startswithprintlen)selffmtargss   &&*r-   log_messageStudioHandler.log_message   sF    99((HTYYKuD	AT!W2,NOP )r/   c                h    V P                  ^4       V P                  4        V P                  4        R# )   N)send_response_cors_headersend_headersr   s   &r-   
do_OPTIONSStudioHandler.do_OPTIONS   s(    3r/   c                  < V P                   R 8X  d   V P                  4        R# V P                   P                  R4      '       d7   V P                   P                  R^4      ^,          pV P	                  V4       R# V P                   P                  R4      '       d*   V P                  V P                   \        R4      R 4       R# V P                   R8X  d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   P                  R4      '       d   V P                  4        R# V P                   P                  R4      '       d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   P                  R	4      '       dM   V P                   P                  R	^4      ^,          P                  R
4      ^ ,          pV P                  V4       R# V P                   P                  R4      '       dM   V P                   P                  R^4      ^,          P                  R
4      ^ ,          pV P                  V4       R# V P                   P                  R4      '       d   R
V P                   9   d+   R
V P                   P                  R
^4      ^,          ,           MRpV P                   P                  RR^4      P                  R
4      ^ ,          pV P                  RWT,           4       R# V P                   R8X  d   V P!                  4        R# V P                   P                  R4      '       d   V P#                  4        R# V P                   P                  R4      '       d   V P%                  4        R# V P                   R8X  d   V P'                  4        R# V P                   R8X  d   V P)                  4        R# \*        SV `Y  4        R# )z/api/list-packsz/api/load-pack/	/uploads/Nz/api/list-uploads/api/meta/configz/api/meta/auth/startr6   z/api/meta/statusz/api/meta/insights/rb   z/api/meta/leads//api/social/r   /api/socialGETz/api/auth/mez/api/insights/z/api/catalogoz/api/sync/statusz/api/sync/pull)r?   _list_packsr   r   
_load_pack_serve_uploadr   _list_uploads_meta_get_config_meta_auth_start_meta_auth_callback_meta_status_meta_insights_meta_leadsreplace_social_hub_proxy_auth_me_handle_insights_handle_catalogo_handle_sync_status_handle_sync_pullsuperdo_GET)r   r   media_idform_idqshub_path	__class__s   &     r-   r   StudioHandler.do_GET   s   99))YY!!"344yy'8!<Q?HOOH%YY!!+..tyy[)9):;<YY-- YY,,!!#YY!!"899!!#YY!!";<<$$&YY,,YY!!"788yy'<a@CII#NqQH)YY!!"455iioo&8!<Q?EEcJ1MGW%YY!!.117:dii7G#		Q/22RByy((A>DDSI!LH""5(-8YY.(MMOYY!!"233!!#YY!!/22!!#YY,,$$&YY**""$GNr/   c                   V P                   R 8X  d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   R8X  d   V P	                  4        R# V P                   R8X  d   V P                  4        R# V P                   P                  R4      '       d7   V P                   P                  R^4      ^,          pV P                  V4       R# V P                   R8X  d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   R	8X  d   V P                  4        R# V P                   R
8X  d   V P                  4        R# V P                   R8X  d   V P                  4        R# V P                   P                  R4      '       dB   V P                  4       pV P                   P!                  RR^4      pV P#                  RW24       R# V P%                  RR4       R# )z/api/save-packr   z/api/meta/disconnectz/api/meta/postz/api/uploadz/api/uploads/delete/z/api/sync/pushz/api/notify/reviewerz/api/auth/request-linkz/api/auth/verifyz/api/auth/onboardingz/api/auth/logoutr   r   r   POST  u   Endpoint não encontradoN)r?   
_save_pack_meta_set_config_meta_disconnect
_meta_post_upload_mediar   r   _delete_upload_handle_sync_push_handle_notify_reviewer_auth_request_link_auth_verify_auth_onboarding_auth_logout	_read_rawr   r   
send_error)r   r   r!   r   s   &   r-   do_POSTStudioHandler.do_POST  s   99((OOYY,,!!#YY00!!#YY**OOYY-' YY!!"899yy'=qA!DH)YY**""$YY00((*YY22##%YY,,YY00!!#YY,,YY!!.11>>#Dyy((A>H""68:OOC!;<r/   c           	         V P                  4       p\        P                  ! \        R R7       \        P                  P                  4       P                  R4      pVP                  RR4      pRV RV R2p\        P                  P                  \        V4      p\        VRR	R
7      ;_uu_ 4       p\        P                  ! WR^R7       RRR4       \        P                  P                  V4      R,          pV P                  ^RVRV/4       R#   + '       g   i     LN; i  \         d)   pT P                  RR\!        T4      /4        Rp?R# Rp?ii ; i)Texist_okz%Y-%m-%d_%H-%M-%Sweekr   pack__.jsonrO   r;   r<   F)ensure_asciirQ   N   r   size_kb  error)
_read_jsonr>   makedirs	PACKS_DIRdatetimenowstrftimer   r?   joinrB   rC   rS   getsize_json_responserE   str)	r   ru   tsr   r   filepathrG   r   es	   &        r-   r   StudioHandler._save_pack@  s   	8??$DKK	D1""&&(112EFB88FB'DtfAbT/Hww||Ix8Hhg66!		$a@ 7ggooh/47Gj(Iw%OP 76  	8gs1v%677	8s1   B.D# 0D
AD# D 	D# #E.EEc                    \         P                  ! \        R R7       \        \         P                  ! \        4       Uu. uF  qP                  R4      '       g   K  VNK  	  upR R7      p. pV EF  p\         P                  P                  \        V4      p\         P                  P                  V4      R,          p \        VRR7      ;_uu_ 4       p\        P                  ! V4      pRRR4       XP                  R. 4      pV U	u. uF=  p	\        V	\        4      '       g   K  V	P                  R	/ 4      P                  R
R4      NK?  	  p
p	V
'       d
   V
^ ,          MRpVP                  RVRVRVP                  RR4      RVP                  RR4      RVP                  RR4      RVP                  R. 4      RVP                  RR4      RVP                  RR4      RVP                  RR4      RV/
4       EK  	  V P#                  ^RV/4       R# u upi   + '       g   i     EL4; iu up	i   \          d    TP                  RTRT/4        EK  i ; i  \          d)   pT P#                  RR\%        T4      /4        Rp?R# Rp?ii ; i)Tr   r   reverser   r;   r<   Npackworkflowstatusrascunhor   r   r   r   yeardatethemesbriefingFocus	profileIdprofileNameworkflowStatusr3   r   r   )r>   r   r   sortedlistdirendswithr?   r   r   rB   rC   rD   r   
isinstancedictr   rE   r   r   )r   rG   filesr3   r   r   fhmeta
pack_itemspiworkflow_statusesworkflow_summaryr   s   &            r-   r   StudioHandler._list_packsO  s0   &	8KK	D1JJy1I1qZZ5H1IE EWW\\)Q/''//"-5Fb733r#yy} 4!%&"!5J #-)",B%b$/ Iz2.228ZH", & )
 @Q'8';VX$LL&%w"DHHVR$8"DHHVR$8"DHHVR$8$dhhx&<+TXXor-J'+r)B)488M2+F,.> : gu%56C J 433)( ! FLL*aG!DEEF  	8gs1v%677	8s~   =I HH"AI >H.H*H.H)%&H)B*H.5I I H& H.. II II J	!JJ	c                "    \         P                  P                  V4      p\         P                  P                  \        V4      p\         P                  P                  V4      '       g   V P                  R RR/4       R# \        VRR7      ;_uu_ 4       p\        P                  ! V4      pRRR4       V P                  ^X4       R#   + '       g   i     L$; i  \         d)   pT P                  RR\        T4      /4        Rp?R# Rp?ii ; i)r   r   u   Pack não encontradoNr;   r<   r   )r>   r?   basenamer   r   r@   r   rB   rC   rD   rE   r   )r   r   r   rG   ru   r   s   &&    r-   r   StudioHandler._load_packx  s    
	8ww''1Hww||Ix8H77>>(++##C'3I)JKh11Qyy| 2T* 21  	8gs1v%677	8s<   A'C *C  C C,C C	C D&D		Dc                $   \        4       pV'       g#   V P                  ^RRR\        R\        /4       R# V P                  ^RRRVP	                  R4      RVP	                  R\        4      R\        VP	                  R	4      4      R\        /4       R# )
r   
configuredFrN   scopesNTrL   
has_secretrM   )rH   r   rR   META_SCOPESr   bool)r   rT   s   & r-   r   StudioHandler._meta_get_config  s      %"$8k d#''(+8L Md377<#89+		
r/   c           
         V P                  4       pVP                  R 4      ;'       g    RP                  4       pVP                  R4      ;'       g    RP                  4       pV'       d	   V'       g   V P                  RRR/4       R# \	        W#VP                  R4      4      pV P                  ^RR	R VR ,          RVR,          /4       R#   \
         d)   pT P                  R
R\        T4      /4        Rp?R# Rp?ii ; i)rL   r   rM     r   u&   app_id e app_secret são obrigatóriosNrN   r  Tr   )r   r   r   r   rU   rE   r   )r   ru   rL   rM   rT   r   s   &     r-   r   StudioHandler._meta_set_config  s    	8??$Dhhx(..B557F((<066B==?J##C'3[)\]"6txx7OPC $c(m"C$7  	8gs1v%677	8s5   'C (C C ,C 4C 
AC D C;;D c           
        \        4       pV'       g   V P                  R RR/4       R# RVR,          RVR,          RRP                  \        4      R	R
RR/pR\        ,           R,           \
        P                  P                  V4      ,           pV P                  R4       V P                  RV4       V P                  4        V P                  4        R# )r  r   z$Configure app_id/app_secret primeiroNry   rL   rN   scope,response_typer{   statestudio_meta_oauthzhttps://www.facebook.com/z/dialog/oauth?i.  Location)rH   r   r   r  META_GRAPH_VERSIONrh   ri   rj   r   send_headerr   r   )r   rT   ro   rp   s   &   r-   r   StudioHandler._meta_auth_start  s     g/U%VWXC/SXXk*V(
 *,>>AQQTZT`T`TjTjkqTrr3S)r/   c           	         \         P                  P                  V P                  4      P                  p\         P                  P                  V4      pVP                  R R.4      ^ ,          pV'       d3   V P                  RV RVP                  RR.4      ^ ,           R24       R# VP                  RR.4      ^ ,          pV'       g   V P                  R4       R# \        4       pV'       g   V P                  R	4       R# \        VR
,          VR,          VR,          V4      pVP                  R4      pV'       g,   V P                  R\        P                  ! V4       R24       R# \        VR
,          VR,          V4      pVP                  R4      ;'       g    Tp	VP                  RR4      p
\        P                  P                  4       \        P                  ! \!        V
4      R7      ,           P#                  4       R,           p\%        V	4      pRV	RVRVR\        P                  P                  4       P#                  4       R,           /p\'        V4       V P                  R4       R#   \         P(                  P*                   dO   pTP-                  4       P/                  RRR7      pT P                  RTP0                   RT R24        Rp?R# Rp?i\2         d!   pT P                  RT R24        Rp?R# Rp?ii ; i)r   Nz<h1>Falha no OAuth</h1><p>z: error_descriptionr   z</p>r{   z<h1>OAuth sem code</h1>z<h1>Config Meta ausente</h1>rL   rM   rN   r   z<h1>Sem short token</h1><pre>z</pre>
expires_in)secondsZr   
expires_atpagessaved_atu   <h1>✓ Conectado ao Meta</h1><p>Você já pode fechar esta janela.</p><script>setTimeout(function(){window.close()},800);</script>r;   r   errorsz<h1>Erro Meta z
</h1><pre>z<h1>Erro</h1><pre>i O )rh   ri   urlparser?   queryparse_qsr   _send_html_closerH   r}   rC   dumpsr   r   utcnow	timedeltar   	isoformatr   r[   r   	HTTPErrorr   r   r{   rE   )r   r   ro   r   r{   rT   shortr   	long_resp
long_tokenr&  r)  r*  rZ   r   r!   s   &               r-   r   !StudioHandler._meta_auth_callback  s   2	B&&tyy177B\\**2.FJJw/2E%%0r&**EX[]Z^:_`a:b9ccgh ::ftf-a0D%%&?@"$C%%&DE-Hs<0#n2EtE  ))N3K%%(EdjjQVFWEXX^&_`0XL@QS^_I"~6EE+J"|^DJ!!((*X-?-?J-XXikC J -Z8EjjH--446@@BSH	F V$!!O ||%% 	S668??79?=D!!N166(*TF&"QRR 	B!!$6qc"@AA	BsW   A3I- 60I- (!I- 
I- #I- A%I- )2I- CI- -LAKL"L#K>>Lc                B    \        4        V P                  ^RR/4       R# )r   disconnectedTN)r`   r   r   s   &r-   r   StudioHandler._meta_disconnect  s    C.$!78r/   c                   \        4       pV'       g   V P                  ^RR/4       R# . pVP                  R. 4       F  pVP                  RVP                  R4      RVP                  R4      RVP                  R4      RVP                  R4      R	VP                  R	4      R
\	        VP                  R4      4      /4       K  	  V P                  ^RRRVP                  R4      RVP                  R4      RV/4       R# )r   	connectedFNr*  r   r   r   r   r   	has_tokenr   Tr)  r+  )rX   r   r   r   r  )r   rZ   
safe_pagesr   s   &   r-   r   StudioHandler._meta_status  s    !#k5%9:
GR(A!%%+AEE&M !%%"5!155#7,aee4L.MaeeN&;!<	 ) 	Tfjj6FJJz2		
r/   c                  aa  V P                  4       pVP                  R 4      ;'       g    RP                  4       oVP                  R4      ;'       g    RP                  4       oVP                  R4      ;'       g    RpVP                  R4      ;'       g    RP                  4       pVP                  R4      ;'       g    RP                  4       p\	        4       pV'       g   V P                  RRR	/4       R
# VP                  R. 4      p\        VV3R lV 4       R
4      pV'       g   V P                  RRR/4       R
# VP                  R4      pVP                  R 4      oV'       d	   S'       g   V P                  RRR/4       R
# V'       g   V P                  RRR/4       R
# RVRV/p	VR8X  d   RV	R&   W9R&   M?VR8X  d5   RV	R&   VP                  4       P                  R(4      '       d   W9R&   M	W9R&   MW9R&   \        RS R2V	R7      p
V
P                  R4      pV'       g   V P                  RRRRV
/4       R
# \        RS R2RVRV/R7      pV P                  ^RVRVP                  R4      R \        P                  P                  4       P                  4       R!,           R"VP                  R"4      /4       R
#   \        P                  P                   dz   pTP!                  4       P#                  R#R$R%7      p \$        P&                  ! T4      pM  \(         d    R&T/p Mi ; iT P                  TP*                  RR'RT/4        R
p?R
# R
p?i\(         d)   pT P                  RR\-        T4      /4        R
p?R
# R
p?ii ; i))r   r   page_idcaption	media_url
media_typeIMAGEr  r      Não conectado ao MetaNr*  c              3      <"   T F4  qP                  R 4      S8X  g   VP                  R4      S8X  g   K0  Vx  K6  	  R# 5i)r   r   N)r   ).0r   r   rD  s   & r-   	<genexpr>+StudioHandler._meta_post.<locals>.<genexpr>*  s1     iEqUU4[G-Cquu\GZ^hGhEs   -?
?u(   Página/IG não encontrada nas conexõesr   u5   Página sem token ou sem Instagram Business vinculadou9   media_url é obrigatório (URL pública da imagem/vídeo)REELS	video_urlSTORIES	image_url/z/media)ru   r   r   u   Container não criadodetailz/media_publishcreation_idcontainer_idr   published_atr(  r   r;   r   r,  r"   zMeta API error).mp4.mov)r   r   r   upperrX   r   nextlowerr  rv   r   r3  r5  rh   r   r6  r   r   rC   rn   rE   r{   r   )r   ru   rE  rF  rG  rZ   r*  page
page_tokencontainer_params	containerrU  publishr   r!   errr   rD  s   &               @@r-   r   StudioHandler._meta_post  s:   D	8??$D((<066B==?Jxx	*00b779Ghhy)//RG+.44";;=I((<0;;GBBDJ%'F##C'3K)LMJJw+EiEikopD##C'3])^_.1J,/JZ##C'3j)kl##C'3n)op !*7NJOW$18 .09-y(1: .??$--.>??4=[14=[109-'!J<v(>EUVI$==.L##C'3JHV_)`a &J<~.#\>:NG "LD 1"H$5$5$<$<$>$H$H$JS$P!488M#:	 ||%% 	T668??79?=D$jj& $dm$2BHc(RSS 	8gs1v%677	8s   'K  (K  (K  >K  (K  7K  ;AK  )K  ,K  4K  
K  K  (BK   A>K   N	!MLML*'M)L**#MN	 N	!NN	c                L    \        4       pV'       g   V P                  R RR/4       R# RpRpVP                  R. 4       FF  pVP                  R4      pV'       g   K   \        RV R2R	VRV/4      pV P                  ^V4        R# 	  V P                  RRRRV/4       R#   \        P
                  P                   d-   pTP                  4       P                  R
RR7      p Rp?K  Rp?ii ; i  \         d)   pT P                  RR\        T4      /4        Rp?R# Rp?ii ; i)r  r   rI  Nz@impressions,reach,saved,likes,comments,shares,total_interactionsr*  r   rR  z	/insightsmetricr;   r   r,  r   u   Insights não disponíveisrS  r   rX   r   r   rs   rh   r   r6  r   r   rE   r   )	r   r   rZ   metricslast_errr   trespr   s	   &&       r-   r   StudioHandler._meta_insightsd  s   	8%'F##C'3K)LMXGHZZ,EE.)	)H:Y/!7NA>D ''T2 - g/KXW_%`a ||--  vvxwyIH  	8gs1v%677	8sL   &C0 4C0 &B"C0 C0 "C-!C("C0 (C--C0 0D#;DD#c                H    \        4       pV'       g   V P                  R RR/4       R# RpVP                  R. 4       FF  pVP                  R4      pV'       g   K   \        RV R2RVR^2/4      pV P                  ^V4        R# 	  V P                  RRRRV/4       R#   \        P
                  P                   d-   pTP                  4       P                  R	R
R7      p Rp?K  Rp?ii ; i  \         d)   pT P                  RR\        T4      /4        Rp?R# Rp?ii ; i)r  r   rI  Nr*  r   rR  z/leadslimitr;   r   r,  r   u   Leads não disponíveisrS  r   re  )r   r   rZ   rg  r   rh  ri  r   s   &&      r-   r   StudioHandler._meta_leads  s   	8%'F##C'3K)LMHZZ,EE.)	)G9F+'GR8D ''T2 - g/H(T\%]^ ||--  vvxwyIH  	8gs1v%677	8sL   &C. 2C. &B C. C.  C+?!C& C. &C++C. .D!9DD!c                    \        V P                  P                  R^ 4      4      pV\        8  d&   V P	                  RRR\        R#,           R2/4       R# V P                  P                  RR	4      pVP                  R
4      '       g   V P	                  RRR/4       R# \        V P                  V P                  4      pRV9  d   V P	                  RRR/4       R# VR,          w  rEV'       g   V P	                  RRR/4       R# \        P                  P                  V4      p\        P                  P                  V4      ^,          P                  4       pV\        9  d*   V P	                  RRRV R\        \        4       2/4       R# \        P                  ! \         RR7       \"        P"                  P%                  4       P'                  R4      p\(        P*                  ! 4       P,                  R,          p\.        P0                  ! RR\        P                  P                  V4      ^ ,          4      R,          ;'       g    Rp	V RV RV	 V 2p
\        P                  P3                  \         V
4      p\5        VR4      ;_uu_ 4       pVP7                  V4       RRR4       \        P                  P9                  V4      R,          pV P	                  ^RV
RVRVRRV
 2R R!\:         RV
 2/4       R#   + '       g   i     La; i  \<         d)   pT P	                  R"R\?        T4      /4        Rp?R# Rp?ii ; i)$u   Recebe multipart/form-data com campo 'file'. Salva em ./uploads/ com nome UUID + extensão original.
Retorna {filename, url, size_kb}.
r   i  r   z
Arquivo > r   z MBNr   r   zmultipart/form-datar  zEsperado multipart/form-datafilezCampo 'file' obrigatoriozArquivo sem nomeu   Extensão não permitida: z. Aceitas: Tr   z%Y%m%d-%H%M%S:N   Nz[^a-zA-Z0-9_-]r   :N(   Nmediawbr   originalr   rp   r   absolute_url_hintr5   r   i   ) r   r   r   MAX_UPLOAD_BYTESr   r   r.   rfiler>   r?   r  splitextr[  ALLOWED_UPLOAD_EXTr   r   UPLOADS_DIRr   r   r   uuiduuid4hexresubr   rB   writer   PORTrE   r   )r   r    r   r$   original_name
file_bytesextr   short_idbasestored_namestored_pathr   r   r   s   &              r-   r   StudioHandler._upload_media  s   ,	8 !1!12BA!FGN 00##C'Z@PU^@_?``c3d)efLL$$^R8E##$9::##C'3Q)RS%djj$,,?FV###C'3M)NO(.v%M ##C'3E)FGGG,,];M''""=1!4::<C,,##C'5OPSuT_`fgy`z_{3|)}~KKd3""&&(11/BBzz|''+H66+S"''2B2B=2QRS2TUVYZee^eDD(1TF3%8K'',,{K@Kk4((C		*% )ggook2d:GwY{m4'+<TF)K=)Y	 )(  	8gs1v%677	8s^   AL 2L 
L  ;L 'L BL B8L AL K8AL 8L	L L>L99L>c                t    \         P                  P                  \        P                  P                  V4      4      p\         P                  P                  \        V4      p\         P                  P                  V4      '       d&   \         P                  P                  V4      '       g   V P                  R R4       R# \        P                  ! V4      w  r4V'       g   Rp\         P                  P                  V4      pV P                  ^4       V P                  RV4       V P                  R\!        V4      4       V P                  RR4       V P#                  4        V P%                  4        \'        VR4      ;_uu_ 4       p VP)                  R
4      pV'       g   MV P*                  P-                  V4       K8  RRR4       R#   + '       g   i     R# ; i  \.        \0        3 d     R# \2         d>   p T P                  R	\!        T4      4        Rp?R#   \2         d	      Rp?R# i ; iRp?ii ; i)r      Arquivo não encontradoNzapplication/octet-streamr   r   zCache-Controlzpublic, max-age=86400rbr   i   )r>   r?   r  rh   ri   unquoter   rz  r@   isfiler   	mimetypes
guess_typer   r   r"  r   r   r   rB   r   wfiler  BrokenPipeErrorConnectionResetErrorrE   )	r   r   r   r   r   sizerG   chunkr   s	   &&       r-   r   StudioHandler._serve_upload  s   	ww''(<(<X(FGHww||K:H77>>(++277>>(3K3K%>? ++H5HE277??8,Ds#^U3-s4y9_.EF h%%FF9-E JJ$$U+ &%%%  !56 	 	SV,, 	sm   BG $G ,G  CG 9G>G G	G G H70H79H7;HH/'H2.H//H22H7c                    \         P                  ! \        R R7       . p\        \         P                  ! \        4      R R7       EF\  pVP                  R4      '       gH   \         P                  P                  \         P                  P                  \        V4      4      '       g   Kd  \         P                  P                  V4      ^,          P                  4       pV\        9  d   K  \         P                  P                  \        V4      pTP                  RTR\         P                  P                  V4      R,          RRV 2R	VR9   d   R
MRR\        P                  P                  \         P                  P!                  V4      4      P#                  4       /4       EK_  	  V P%                  ^RV/4       R#   \&         d)   pT P%                  RR\)        T4      /4        Rp?R# Rp?ii ; i)Tr   r   .r   r   r   rp   r   kindvideoimagemodified_atr4   r   r   N>   .m4vrX  rW  .webm)r>   r   rz  r   r  r   r?   r  r   rx  r[  ry  r   r   r   fromtimestampgetmtimer5  r   rE   r   )r   r  rG   r  r   r   s   &     r-   r   StudioHandler._list_uploads  sh   	8KKd3EBJJ{3TBB<<$$BGGNN277<<UV;W,X,Xgg&&q)!,22400WW\\+q1"A!277??2#6$#>1#32S+SY`%x'8'8'F'FrwwGWGWXZG['\'f'f'h C  i%78 	8gs1v%677	8s   B$F< 'DF< <G/G**G/c                    \         P                  P                  \        P                  P                  V4      4      p\         P                  P                  \        V4      p\         P                  P                  V4      '       g   V P                  R RR/4       R# \         P                  ! V4       V P                  ^RV/4       R#   \         d)   pT P                  RR\        T4      /4        Rp?R# Rp?ii ; i)r   r   r  Ndeletedr   )r>   r?   r  rh   ri   r  r   rz  r@   r   r^   rE   r   )r   r   r   r   s   &&  r-   r   StudioHandler._delete_upload  s    		8ww''(<(<X(FGHww||K:H77>>(++##C'3L)MNIIhi%:; 	8gs1v%677	8s$   BC	 C	 *C	 	C<C77C<c                   V P                  4       '       g   V P                  RRR/4       R# \        P                  ! 4       '       g   V P                  RRRRR/4       R# V P                  P                  R	4      ^ ,          p\        P                  P                  R	V P                  9   d#   V P                  P                  R	4      ^,          MR
4      pVR8X  d)    V P                  ^\        P                  ! 4       4       R# VP                  RR.4      ^ ,          pVP                  RR
.4      ^ ,          pVP                  RR.4      ^ ,          P                  4       R9   p \        VP                  RR.4      ^ ,          4      p \        P                  ! VVVVR7      pV P                  ^V4       R#   \         d#   pT P                  RRRT 2/4        Rp?R# Rp?ii ; i  \         d    ^2p Lni ; i  \        P                    d)   pT P                  RR\#        T4      /4        Rp?R# Rp?i\         d#   pT P                  RRRT 2/4        Rp?R# Rp?ii ; i)u   Roteia /api/catalogo?tipo=X&busca=Y&apenas_ativos=Z&limit=N
e /api/catalogo/sync-status (status do último sync CE).

Tipos: procedimento, consulta, experiencia, protocolo,
       profissional, pacote, produto, todos.
Requer sessão autenticada.  r      Não autenticado.N  uD   Catálogo desabilitado (SUPABASE_URL/SERVICE_ROLE não configurado).hintzEDefina UNI_DATA_SUPABASE_URL e UNI_DATA_SUPABASE_SERVICE_ROLE no .envrb   r   z/api/catalogo/sync-statusr   zErro lendo sync_status: tipotodosbuscaapenas_ativostruerl  50)r  r  r  rl  r  u   Erro lendo catálogo: )1r  yes)_current_userr   catalogo_module
is_enabledr?   r   rh   ri   r0  sync_statusrE   r   r[  r   
ValueErrorlistarCatalogoErrorr   )	r   r?   ro   r   r  r  r  rl  ru   s	   &        r-   r   StudioHandler._handle_catalogo  s0    !!##g/B%CD))++__&  yys#A&&&#BRtyys';A'>XZ[ ..T##C)D)D)FG  zz&7),Q/

7RD)!,

?VH=a@FFHL``	

7TF3A67E	N"))+	D T*)  T##C'5MaS3Q)RSST  	E	 ,, 	8gs1v%677 	Ng1Gs/K%LMM	NsT   %F5 ##G% ,G8 5G" GG"%G54G58I H00I =I >II c                l   V P                  4       '       g   V P                  RRR/4       R# \        P                  ! 4       '       g   V P                  RRR/4       R# V P                  P                  R4      ^ ,          p\        P                  P                  RV P                  9   d#   V P                  P                  R4      ^,          MR4      pVP                  R	4      P                  R	4      p\        V4      ^8  g   V^,          R
8w  d   V P                  RRR/4       R# V^,          pV^,          p\        VP                  RR.4      ^ ,          4      p VR8X  d   \        P                  ! WFR7      pMuVR8X  d   \        P                  ! V4      pMWVR8X  d   \        P                  ! WFR7      pM8VR8X  d   \        P                   ! V4      pMV P                  RRRV R2/4       R# V P                  ^RV/4       R#   \"         d#   pT P                  RRRT 2/4        Rp?R# Rp?ii ; i)u   Roteia /api/insights/{persona_id}/{tipo}?limit=N.
Tipos: top-posts, by-format, topics-demanded, heatmap.
Requer sessão autenticada.r  r   r  Nr  u9   Insights desabilitado (INSIGHTS_DB_DSN não configurado).rb   r   rR  personar   z%Use /api/insights/persona/{id}/{kind}rl  10z	top-posts)rl  z	by-formatztopics-demandedheatmapzTipo 'u   ' não suportado.ru   r   zErro lendo insights: )r  r   insights_moduler  r?   r   rh   ri   r0  r   r   r   r   	top_posts	by_formattopics_demandedr  rE   )	r   r?   ro   parts
persona_idr  rl  ru   r   s	   &        r-   r   StudioHandler._handle_insightsB  s    !!##g/B%CD))++g/j%kl yys#A&&&#BRtyys';A'>XZ[

3%%c*u:>U1X2g/V%WX1X
QxFJJw/23	M{"&00I$&00<**&66zO"&..z:##C'VD6AR3S)TUfd^4 	Mg1Fqc/J%KLL	Ms   BH 0H H3H..H3studio_sessionc                    V P                  4       pVP                  R 4      ;'       g    RP                  4       P                  4       pV'       d   RV9  d   V P	                  RRR/4       R# \
        P                  ! V4      '       g   V P	                  RRR/4       R#  \
        P                  ! V4      pT P+                  4       p\
        P,                  ! Y#R,          T4       RRRR/p\
        P.                  '       d   TR,          TR&   T RTR,           2TR&   T P	                  ^T4       R#   \
        P                   d   p\        P                  ! RR	TP                   R
2RTP                  /RR7      P                  R4      pT P                  R4       T P                  RR4       T P                  R\        TP                  4      4       T P                  R\!        T4      4       T P#                  RR7       T P%                  4        T P&                  P)                  T4        Rp?R# Rp?ii ; i  \0         d)   pT P	                  RR\        T4      /4        Rp?R# Rp?ii ; i)r   r   @r  r   u   Email inválido.Ni  u3   Acesso ao beta ainda não liberado para este email.z&Muitas tentativas. Tente novamente em zs.retry_afterFr   r;   i  r   application/json; charset=utf-8zRetry-Afterr   Tallow_credentialstokenokmessageu7   Link enviado. Verifique seu email (válido por 15 min).	dev_tokenz/?token=dev_linkr   )r   r   r   r[  r   auth_moduleis_email_whitelistedcreate_magic_linkRateLimitExceededrC   r2  retry_after_secondsr   r   r"  r   r   r   r   r  r  _public_base_urlsend_magic_link_emailDEV_MODErE   )	r   ru   r   linkrlr,   base_urlresponser   s	   &        r-   r    StudioHandler._auth_request_linkm  s#   !	8??$DXXg&,,"335;;=ECu,##C'3E)FG33E::##C'3h)ij"44U; ,,.H--e']HMdI/hiH###(,W%*28DM?'K$X.) 00 **EbF\F\E]]_`!2#9#9& !&' (.vg  ""3'  1RS  B4J4J0KL  !13w<@""T":  "

  )*  	8gs1v%677	8sZ   'H8 &H8 H8 .H8 
H8 !D2 7A9H8 2H5C#H0*H8 0H55H8 8I+I&&I+c                    V P                  4       pVP                  R 4      ;'       g    RP                  4       pV'       g   V P                  RRR/4       R# \        P
                  ! V4      pV'       g   V P                  RRR/4       R# \        P                  ! V4      p\        P                  ! VR,          V P                  P                  R	R4      V P                  ^ ,          R
7      pV P                  ^4       V P                  V4       V P                  RRRV/4       R#   \         d)   pT P                  RR\        T4      /4        Rp?R# Rp?ii ; i)r  r   r  r   zToken ausente.Nr  u   Token inválido ou expirado.r   z
User-Agent)user_id
user_agentipr  Tuserr   )r   r   r   r   r  verify_magic_linkget_or_create_usercreate_sessionr   client_addressr   _set_session_cookie_send_json_bodyrE   r   )r   ru   r  r   r  	jwt_tokenr   s   &      r-   r   StudioHandler._auth_verify  s$   	8??$DXXg&,,"335E##C'3C)DE11%8E##C'3Q)RS11%8D#22T
<<++L"=&&q)I
 s#$$Y/  $fd!;< 	8gs1v%677	8s5   'D' D' D' D' 7D' BD' 'E2EEc                    V P                  4       pV'       g   V P                  R RR/4       R# V P                  ^RV/4       R# )r  r   r  Nr  )r  r   )r   r  s   & r-   r   StudioHandler._auth_me  s@    !!#g/B%CDC&$0r/   c                J    V P                  4       pV'       g   V P                  R RR/4       R# V P                  4       pVP                  R4      ;'       g    RP	                  4       pVP                  R4      ;'       g    RP	                  4       pV'       d	   V'       g   V P                  RRR/4       R# \
        P                  ! VR	,          W4R
7      pV P                  ^RRRV/4       R#   \         d)   pT P                  RR\        T4      /4        Rp?R# Rp?ii ; i)r  r   r  Nr   r   roler  u    Nome e papel são obrigatórios.r   )r   r  r  Tr  r   )	r  r   r   r   r   r  update_userrE   r   )r   r  ru   r   r  updatedr   s   &      r-   r   StudioHandler._auth_onboarding  s    	8%%'D##C'3F)GH??$DHHV$**113DHHV$**113Dt##C'3U)VW!--d4jtOGdD&'%BC 	8gs1v%677	8s?   C/ C/ 'C/ (C/ C/ C/ "C/ 85C/ /D":DD"c                    V P                  4       p\        P                  ! V4       V P                  ^4       V P	                  4        V P                  RR7       V P                  4        R# )   Tr  N)_get_session_cookier  revoke_sessionr   _clear_session_cookier   r   )r   r  s   & r-   r   StudioHandler._auth_logout  sU    ,,.	""9-3""$T2r/   c                     V P                  ^\        P                  ! 4       4       R#   \         d)   pT P                  RR\	        T4      /4        Rp?R# Rp?ii ; i)uz   GET /api/sync/status — devolve {enabled, schema, config_present}.
Não exige auth (cliente decide se mostra UI de sync).r   r   N)r   sync_moduler   rE   r   )r   r   s   & r-   r   !StudioHandler._handle_sync_status  sL    	8[%7%7%9: 	8gs1v%677	8s   %) AAAc                6   V P                  4       pV'       g   V P                  RRR/4       R# \        P                  ! 4       '       g   V P                  RRRRR/4       R#  \	        V P
                  P                  R	R
4      4      pV^ 8  d+   V P                  P                  V4      P                  R4      MRp\        P                  ! V4      p \        P                  ! Y4      pT P                  ^RR/TC4       R#   \         d#   pT P                  RRRT 2/4        Rp?R# Rp?ii ; i  \        P                   d)   pT P                  RR\        T4      /4        Rp?R# Rp?i\         d#   pT P                  RRRT 2/4        Rp?R# Rp?ii ; i)u   POST /api/sync/push — body { operators?, personagens?, campanhas?, generatedPacks? }.
Faz upsert em six_hype.* com owner_user_id = sessão atual.r  r   r  Nr  Sync remoto desabilitado.r  zNDefina SIX_HYPE_SYNC_ENABLED=true + UNI_DATA_SUPABASE_URL/SERVICE_ROLE no .envr   0r;   {}r     Body inválido: r  T  r   zFalha no push: )r  r   r  r  r   r   r   rw  r   r   rC   rn   rE   push	SyncErrorr   )r   r  lengthr"   r,   r   results   &      r-   r   StudioHandler._handle_sync_push  su    !!#g/B%CD%%''4h&  	))*:C@AF=CaZ$**//&)009TCjjoG	G %%d4FdD%;F%;<  	g1A!/E%FG	 $$ 	8gs1v%677 	Gg/D%EFF	GsC   #A.D  ,D0  D-D((D-0FE((F5F6FFc                   V P                  4       pV'       g   V P                  RRR/4       R# \        P                  ! 4       '       g   V P                  RRR/4       R#  \        P                  ! V4      pV P                  ^V4       R#   \        P
                   d)   pT P                  RR\        T4      /4        Rp?R# Rp?i\         d#   pT P                  RRR	T 2/4        Rp?R# Rp?ii ; i)
uD   GET /api/sync/pull — devolve estado remoto do owner pra restaurar.r  r   r  Nr  r  r  r   zFalha no pull: )r  r   r  r  pullr  r   rE   )r   r  ru   r   s   &   r-   r   StudioHandler._handle_sync_pull  s    !!#g/B%CD%%''g/J%KL	G##D)DT*$$ 	8gs1v%677 	Gg/D%EFF	Gs*   !(B C3 CC3C3C..C3c                   V P                  4       pV'       g   V P                  RRR/4       R# \        P                  ! 4       '       g   V P                  RRRRR/4       R#  \	        V P
                  P                  R	R
4      4      pV^ 8  d+   V P                  P                  V4      P                  R4      MRp\        P                  ! V4      pTP                  R4      ;'       g    RP                  4       pTP                  R4      ;'       g    RP                  4       pTP                  R4      ;'       g    RP                  4       pT'       d	   T'       g   T P                  RRR/4       R# \        P                  ! YgTR7      w  rT	'       d   T P                  ^RRRT
/4       R# T P                  RRT
/4       R#   \         d#   pT P                  RRRT 2/4        Rp?R# Rp?ii ; i)u   POST /api/notify/reviewer
body { phone, message, reviewerName? }
Envia mensagem WhatsApp via Evolution (BETA_MODE força redirect pra Caue).
Não exige sync remoto — só Evolution configurado.
r  r   r  Nr  u   Evolution não configurado.r  zISetar EVOLUTION_BASE_URL + EVOLUTION_INSTANCE + EVOLUTION_API_KEY no .envr   r  r;   r  r  r   phoner   r  reviewerNameu   phone e message obrigatórios)real_recipientr  Tinfor  )r  r   whatsapp_senderis_configuredr   r   r   rw  r   r   rC   rn   rE   r   send_whatsapp)r   r  r  r"   r,   r   r  r  reviewer_namer  r  s   &          r-   r   %StudioHandler._handle_notify_reviewer  s    !!#g/B%CD,,..6c&  	))*:C@AF=CaZ$**//&)009TCjjoG W%++224;;y)//R668 ^4::AACGg/N%OP"00P]^dD&$%?@gt_5  	g1A!/E%FG	s   #A.G G/G**G/c                   V P                   P                  R R4      pVP                  R4       FV  pVP                  4       P	                  R4      w  r4pW0P
                  8X  g   K7  \        P                  P                  V4      u # 	  R# )Cookier   r   r	   N)	r   r   r   r   	partitionAUTH_COOKIE_NAMErh   ri   r  )r   cookie_headerr%   r)   r   r*   s   &     r-   r  !StudioHandler._get_session_cookie%  sm    ((26!'',Djjl,,S1GA!)))||++A.. - r/   c                J    \         P                  ! V P                  4       4      # r]   )r  verify_sessionr  r   s   &r-   r  StudioHandler._current_user-  s    ))$*B*B*DEEr/   c                ~    \         P                  '       d   R# \        P                  P	                  RR4      pRV R2# )u   Atributos de cookie sensíveis ao ambiente.
Em prod: SameSite=None + Secure + Domain=.uniatacado.com (cross-subdomain).
Em dev: SameSite=Lax + sem Secure (localhost http://).z SameSite=Lax;COOKIE_DOMAINz.uniatacado.comz SameSite=None; Secure; Domain=r   )r  r  r>   environr   )r   cookie_domains   & r-   _cookie_attrsStudioHandler._cookie_attrs0  s7     #

8IJ0qAAr/   c                    \         P                  ^,          ^<,          ^<,          pV P                   R\        P                  P                  V4       RV RV P                  4        2pV P                  RV4       R# )   r	   z; Path=/; HttpOnly; Max-Age=r   
Set-CookieN)r  SESSION_TTL_DAYSr  rh   ri   quoter!  r"  )r   r  max_agecookies   &&  r-   r  !StudioHandler._set_session_cookie:  sv    ..3b82=$$%Qv||'9'9)'D&E F**1!D4F4F4H3IK 	 	v.r/   c                h    V P                    R V P                  4        2pV P                  RV4       R# )z=; Path=/; HttpOnly; Max-Age=0;r%  N)r  r!  r"  )r   r)  s   & r-   r  #StudioHandler._clear_session_cookieB  s>    $$% &,,./1 	 	v.r/   c                    V P                   P                  R R\         24      pV P                   P                  R4      R8X  d   RMRpV RV 2# )Hostz
localhost:zX-Forwarded-Protohttpshttpz://)r   r   r  )r   hostschemes   &  r-   r  StudioHandler._public_base_urlI  sO    ||*TF(;< LL,,-@AWLRXTF##r/   c                (   \         P                  ! VRR7      P                  R4      pV P                  RR4       V P                  R\	        V4      4       V P                  RR7       V P                  4        V P                  P                  V4       R	# )
uA   Após self.send_response() + cookies, envia headers e corpo JSON.Fr  r;   r   r  r   Tr  N)	rC   r2  r   r"  r   r   r   r  r  )r   r!   r,   s   && r-   r  StudioHandler._send_json_bodyN  sr    **T6==gF)JK)3w<8T2

!r/   c                    \        V P                  P                  R ^ 4      4      p\        P                  ! V P
                  P                  V4      4      # )r   )r   r   r   rC   rn   rw  r   r   r  s   & r-   r   StudioHandler._read_jsonX  s:    T\\%%&6:;zz$**//&122r/   c                T   V P                   P                  R 4      p\        P                  P                  RR4      P	                  R4       Uu0 uF*  q3P                  4       '       g   K  VP                  4       kK,  	  ppV'       dB   \        P                  '       g   W$9   d&   V P                  RV4       V P                  RR 4       MV'       d   MV P                  RR4       V P                  RR4       V P                  R	R
4       V'       d   V P                  RR4       R# R# u upi )OriginCORS_ORIGINSr   r  Access-Control-Allow-OriginVary*zAccess-Control-Allow-MethodszGET, POST, OPTIONSzAccess-Control-Allow-Headersr   z Access-Control-Allow-Credentialsr  N)	r   r   r>   r  r   r   r  r  r"  )r   r  originocors_originss   &&   r-   r   StudioHandler._cors_headers\  s    !!(+ ,.::>>."+M+S+STW+Xf+Xa\c\c\e		+Xf{+++v/E:FCVX. :C@79MN7H?H  gs   D%)D%c                D   \         P                  ! VR R7      P                  4       pV P                  V4       V P	                  RR4       V P	                  R\        V4      4       V P                  4        V P                  4        V P                  P                  V4       R# )Fr  r   r  r   N)
rC   r2  r   r   r"  r   r   r   r  r  )r   r{   r!   r,   s   &&& r-   r   StudioHandler._json_responseo  sy    **T6==?4 )JK)3w<8

!r/   c                (   R V,           P                  R4      pV P                  ^4       V P                  RR4       V P                  R\        V4      4       V P	                  4        V P                  4        V P                  P                  V4       R# )z<!doctype html><meta charset='utf-8'><style>body{font-family:system-ui;padding:40px;color:#1a1614;background:#faf6ef;}h1{font-family:Georgia,serif;color:#b8913d;}pre{background:#f3ede0;padding:14px;border-radius:6px;font-size:12px;overflow:auto;}</style>r;   r   ztext/html; charset=utf-8r   N)r   r   r"  r   r   r   r  r  )r   htmlr!   s   && r-   r1  StudioHandler._send_html_closex  s    k 	
 &/ 	 	3)CD)3t95

r/   c                   ^ RI p^ RIHp ^ RIHp VP
                  P                  RR4      pVP
                  P                  RR4      pV'       g   V P                  RR4       R# VP                  R4      V,           p	VP                  WR	7      p
V
P                  R
RV 24       V
P                  RR4       V'       d.   \        V\        4      '       d   TMVP                  4       V
n         VP                  V
^R7      ;_uu_ 4       pVP!                  4       pRRR4       V P#                  ^4       V P%                  RR4       V P%                  RR4       V P'                  4        V P(                  P+                  X4       R#   + '       g   i     Lr; i  TP,                   d   pTP!                  4       pT P#                  TP.                  4       T P%                  RR4       T P%                  RR4       T P'                  4        T P(                  P+                  T4        Rp?R# Rp?i\0         d'   pT P                  R\3        T4      4        Rp?R# Rp?ii ; i)u   Proxy seguro: encaminha /api/social/* para social-hub (localhost:8092).
SOCIAL_HUB_SECRET fica só no .env do servidor, nunca exposto no frontend.
NSOCIAL_HUB_URLzhttp://127.0.0.1:8092SOCIAL_HUB_SECRETr   r  z!SOCIAL_HUB_SECRET nao configuradorR  )methodAuthorizationzBearer r   rd   re   r<  r>  r  )r>   urllib.requestrk   urllib.errorr   r  r   r   rstriprl   
add_headerr  bytesr   ru   rm   r   r   r"  r   r  r  r6  r{   rE   r   )r   rK  r   r!   _os_ur_uehub_url
hub_secretrp   rq   ri  ru   r   err_bodyexs   &&&&            r-   r   StudioHandler._social_hub_proxy  s    	$"++//"24KL[[__%8"=
OOC!DEnnS!H,kk#k-'*(>?~'9:)$66tDKKMCH	*S"--yy{ .s#^-?@:C@JJT" .- }} 	'vvxHqvv&^-?@:C@JJX&& 	*OOCR))	*sD   ,F FA(F F	F I&A:H&&I3I4IIc                    \        V P                  P                  R ^ 4      4      pV'       d   V P                  P	                  V4      # R# )r   r/   )r   r   r   rw  r   r7  s   & r-   r   StudioHandler._read_raw  s8    T\\%%&6:;*0tzzv&9c9r/   r_   )Fr]   )4__name__
__module____qualname____firstlineno__r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r   r   r   r   r   r   r   r   r  r  r!  r  r  r  r  r   r   r   r1  r   r   __static_attributes____classdictcell____classcell__)r   __classdict__s   @@r-   r   r      s    Q
.`"=J8'8R8
08*&3Bj9
:E8P888408d>80
80Nd&MR ("8H8.18"8G8G&!6HFB//$
"3I&""%*N: :r/   r   c                       ] tR tRtRtRtR# )ReusableTCPServeri  Tr_   N)r\  r]  r^  r_  allow_reuse_addressr`  r_   r/   r-   re  re    s    r/   re  c                  B   \         P                  ! \         P                  P                  \         P                  P	                  \
        4      4      4       \        P                  ! 4        \        \        \        3\        4      ;_uu_ 4       p R \         R2p\        \        P                  4      p\        P                  '       d   RMRp\        RV R24       \        R4       \        R\         24       \        RV 24       \        R	\        P                    24       \        R
V R24       V^ 8X  d   \        R4       \        R4       \        R4       \        R\        P                  '       d   RMR 24       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R4       \        R\         R24       \        R4       \        R 4        V P#                  4        R"R"R"4       R"#   \$         d%    \        R!4       \&        P(                  ! ^ 4        L8i ; i  + '       g   i     R"# ; i)#r5   z!/clinic_content_studio%20(5).htmlDEVPRODz
  Clinic Content Studio  []uq     ─────────────────────────────────────z  Servidor:  http://localhost:z  Acesse:    z  Auth DB:   z  Beta whitelist: z email(s) liberado(s)u;     ⚠ Defina BETA_EMAILS=email1,email2 para liberar acesso.z  Endpoints Auth:z"    POST  /api/auth/request-link  z(retorna dev_token)r   z    POST  /api/auth/verifyz    GET   /api/auth/mez    POST  /api/auth/onboardingz    POST  /api/auth/logoutz  Endpoints Meta:z    Config:    /api/meta/configz#    OAuth:     /api/meta/auth/startz    Status:    /api/meta/statusz"    Publicar:  POST /api/meta/postz  Endpoints Upload:zC    Upload:    POST /api/upload (multipart/form-data, campo 'file')z%    Listar:    GET  /api/list-uploadsz'    Servir:    GET  /uploads/{filename}u&     ⚠ Para Meta API: rode 'ngrok http u.   ' em outro terminal e use a URL HTTPS públicaz  Ctrl+C para parar
z
  Servidor encerrado.N)r>   chdirr?   dirnameabspath__file__r  init_dbre  BINDr  r   r   BETA_EMAILSr  r   AUTH_DB_PATHserve_foreverKeyboardInterruptsysexit)httpdrp   whitelist_count	dev_labels       r-   mainrz    s)   HHRWW__RWW__X678 	D$<	7	75!$'HIk556(111Ev	,YKq9:  B  	D.tf56cU#$k66789"?"33HIJaOQ  B  	D!#2KL`L`L`3Hfh2ijk*,&(.0*,!#/135/124#%SU579;  B  	D6tf<jkl  B  	D%'	!C 
8	7D ! 	+,HHQK	E 
8	7	7s+   F4JI,J
J	J

JJ	__main__i  @>	   .gif.jpgr  rX  rW  .png.jpegr  .webpr]   )NN)6__doc__http.serverr0  rC   r>   r   socketserverru  urllib.parserh   rM  rN  r~  cgir.   r  r{  r  r  r  r  r  r   r  r   r  rp  r   rz  rv  ry  rA   rW   r!  rg   rR   r  rH   rU   rX   r[   r`   rs   rv   r}   r   r   serverSimpleHTTPRequestHandlerr   	TCPServerre  rz  r\  r_   r/   r-   <module>r     sH  :   	   
    	
2       
2::>>-01	zz~~mR(	$   & %  /0B/CD*4&0GH '
$
44"

8R:DKK88 R:j.. *Z zF r/   