
    ҷhJ              	          d dl mZmZmZmZ d dlmZ d dlmZmZm	Z	 d dl
Z
d dlmZmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZmZmZ d dlmZ d dlmZ d dlZd dl Z d dlm!Z! d dl"m#Z# d dlm$Z$m%Z% d dl&Z&d dl'Z' e'jP                  d      Z) e'jP                  d      Z*de	dee   de+defdZ,dede-fdZ.de/e   de-fdZ0de+de+fdZ1dZ2d e3d!e3fd"Z4d-defd#Z5d$Z6de+de+fd%Z7d&e+de-fd'Z8d(e+d)e+d*e/e+   de/e+   fd+Z9d-defd,Z:y).    )timezoneUTCAmbiguousTimeErrorNonExistentTimeError)UnknownTimeZoneError)datetimetimedateN)schema
controller)get_db)get_db_session)Session)PostTypeConfig)MasterAccount)HTTPExceptionDependsstatus)func)Optional)ConnectedAccount)BeautifulSoup)CalendarPostType	PostImage	FB_APP_IDFB_APP_SECRETschedule_dateschedule_timetz_strreturnc                    	 t        |xs dj                               }t	        j
                  | |xs t        dd            }	 |j                  |d       }|j                  t              S # t        $ r t        dd|       w xY w# t        $ r |j                  |d      }Y Pt        $ r t        dd      w xY w)	Nr   i  zInvalid timezone: )status_codedetailr   )is_dstFz4Scheduled time does not exist due to DST transition.)r   stripr   r   r   combiner	   localizer   r   
astimezoner   )r   r   r   user_tzlocal_dtlocal_dt_with_tzs         </var/www/html/hubwallet-dev/src/marketing/apps/post/utils.pyconvert_to_utcr-      s    SFOe2245 }/JQ
KHl"++HT+B &&s++   S6H4QRRS  D"++HU+C l4jkkls   A, B	 ,B	B='B=dbconfig_datac                    |j                  dg       D ]  }|j                  dd      }| j                  t              j                  |      j	                         }|st        d| d       [|j                  dg       }|D ]^  }|j                  dd      }| j                  t              j                  |j                  ||	      j	                         }|rt        d
| d| d       jt        |j                  |||j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd            }	| j                  |	       a  | j                          y )N	platformsplatform_display_name )social_media_namezMaster account for platform 'z' not found. Skipping.
post_types	post_type)master_account_idplatformr6   zPost type 'z' for platform 'z' already exists. Skipping.supports_textFsupports_imagesupports_multiple_imagessupports_videosupports_linktext_max_limitr   text_optimum_limitimage_ratioimage_best_resolution_pxvideo_max_size_mbvideo_max_length_secnote)r7   r8   r6   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   additional_notes)
getqueryr   	filter_byfirstprintr   idaddcommit)
r.   r/   platform_infoplatform_namemaster_accountr5   post_type_specpost_type_nameexisting	post_specs
             r,   save_social_config_to_dbrU   5   s   $b9 (%))*A2F -0::]:[aac1-@VWX"&&|R8
( 	N+//R@N xx/99"0"3"3&( :  eg	 
 N#33CM?Rmno&"0"3"3&(,00%H-112BEJ)7););<VX])^-112BEJ,00%H-112BAF#1#5#56JA#N*..}bA)7););<VXZ)["0"4"45H!"L%3%7%78NPQ%R!/!3!3FB!?I" FF9=	(R IIK    configsc                    dg i}i }| D ]  }|j                   }|j                  }||vr|g d||<   ||j                  |j                  |j                  |j
                  |j                  |j                  |j                  |j                  |j                  |j                  |j                  |j                  d}||   d   j                  |        t        |j!                               |d<   |S )Nr1   )r2   r5   )r6   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   r5   )r8   r6   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rE   appendlistvalues)rW   resultplatform_dictconfigr8   r6   post_type_datas          r,   format_post_type_configsr`   d   s   2FM E??$$	=()1 'M(# ##11$33(.(G(G$33#11$33"(";";!--(.(G(G!'!9!9$*$?$?++
  	h-44^D5E: }3356F;MrV   htmlc                     t        | d      }d }g d}|j                  |      D ]  } ||j                               |_         |j                         S )z0Convert HTML to styled Unicode text for Twitter.zhtml.parserc                    i t        t        d      t        d      dz         D ci c]&  }t        |      t        d|t        d      z
  z         ( c}t        t        d      t        d      dz         D ci c]&  }t        |      t        d|t        d      z
  z         ( c}dj                  fd	| D              S c c}w c c}w )
NAZ   i  azi r3   c              3   B   K   | ]  }j                  ||        y wN)rF   ).0c
bold_charss     r,   	<genexpr>z=html_to_unicode_styled.<locals>.style_bold.<locals>.<genexpr>   s     :z~~a+:s   )rangeordchrjoin)textirm   s     @r,   
style_boldz*html_to_unicode_styled.<locals>.style_bold   s    
>CCHcRUhWXj>YZs1vs7a#c(l344Z
>CCHcRUhWXj>YZs1vs7a#c(l344Z

 ww:T::: [Zs   +C 7+C)strongbemrt   upbrh1h2h3olulli
blockquote)r   find_allget_textstring)ra   soupru   tags_to_handletags        r,   html_to_unicode_styledr      sT    }-D;
N
 }}^, 0/
0 ==?rV   z!https://ap.bestbrain.ai/x/refresh	branch_idconnected_account_idc                    	 t               }t        j                  d|         dt        |       i}ddd}t	        d|       t        j                  dt        ||      }t	        d	|j                          t	        d
|j                          t	        |       |j                  dk(  r|j                         }|j                  di       j                  d      }|s't        j                  d       	 |j                          y |j                  t              j!                  t        j"                  |k(        j%                         }|s*t        j                  d|        	 |j                          y ||_        |j)                          |j+                  |       t        j                  d|        ||j                          S t        j                  d|j                   d|j                          	 |j                          y # t,        $ r2}	t        j                  d|	        Y d }	~	j                          y d }	~	ww xY w# j                          w xY w)Nu
   ❌❌❌ app_idapplication/jsonzinsomnia/11.2.0)Content-Typez
User-AgentREFRESH_BODYPOSTjsonheaderszStatus: z
Response:    	tokenDataaccess_tokenu(   ❌ Refresh API returned no access tokenu&   ❌ ConnectedAccount not found for ID u?   🔄 Successfully refreshed Twitter token for ConnectedAccount u   ❌ Failed to refresh token:  - u%   ❌ Error calling token refresh API: )r   logginginfostrrJ   requestsrequestREFRESH_URLr"   rs   r   rF   errorcloserG   r   filterrK   rI   tokenrM   refresh	Exception)
r   r   r.   r   r   respdata	new_tokenconnected_accountes
             r,   refresh_twitter_tokenr      s   +$&z)-/ #i.1.+
 	nl+{wW))*+,
499+&'ds"99;Db155nEIHI2 	
- )*(++/CCD  % FG[F\]^ 	
 '0#IIKJJ()LLZ[oZpqr 	
 MM9$:J:J9K3tyykZ[
 	
	  =aSAB

	 	
s>   C0H AH 3AH /H 	IH<'I <II Ic                 >   |
t               }	 | j                  j                  }|st        d      t	        | dd       }|st        d      d}d| dd}t        |      }d|i}t        j                  |||	      }|j                  d
v rIt        j                  d|j                   d| j                   d       t        | j                  | j                  j                        }	|	rd|	 |d<   t        j                  |||	      }
|
j                  rt        j                  d| j                          |
j!                         j#                  di       j#                  dd       }|| _        |j'                          |j)                  |        d|dS t        j*                  d|
j                   d|
j,                          dd|j                   dS |j                  sAt        j*                  d|j                   d|j,                          dd|j                   dS t        j                  d| j                          |j!                         j#                  di       j#                  dd       }d|dS # t        j.                  j0                  $ r@}t        j*                  d| j                   d|        ddt3        |       dcY d }~S d }~wt4        $ r@}t        j*                  d| j                   d|        dd t3        |       dcY d }~S d }~ww xY w)!Nz(Missing access token for Twitter accountcontentzNo content to post for Twitterz https://api.twitter.com/2/tweetszBearer r   )Authorizationr   rs   r   i  i  u   ⚠ Twitter  for PostType z, refreshing token...)r   r   r   u:   ✅ Posted to Twitter after token refresh for PostType ID r   rK   Tsuccesspost_idu-   ❌ Twitter post failed after token refresh: r   Fz Twitter post failed with status r   r   u   ❌ Twitter API error : u&   ✅ Posted to Twitter for PostType ID u%   ❌ HTTP request failed for PostType HTTP request failed: u5   ❌ Unexpected error posting to Twitter for PostType Unexpected error: )r   r   r   
ValueErrorgetattrr   r   postr"   r   warningrK   r   r   okr   r   rF   external_post_idrM   r   r   rs   
exceptionsRequestExceptionr   r   )r6   r.   r   r   urlr   twitter_text_html_boldpayloadresponser   
retry_respr   r   s                r,   post_to_twitterr      s   	z$&N
 2288GHH)Y5=>>0&|n5.
 "8!@12==7GD :-OOl8+?+?*@y||n\qrs-#--%.%@%@%C%CI -4YK+@(%]]3WgN
==LL#]^g^j^j]k!lm(oo/33FB?CCD$OG18I.IIKJJy)#'#* 
 MM$QR\RhRhQiilmwm|m|l}"~ ;H<P<P;QR  {{MM283G3G2H8==/Z[ ;H<P<P;QR 
 	=ill^LM--/%%fb155dDA
 
 	

 // 
=ill^2aSQR,SVH5
 	
  
Mill^[]^_]`ab)#a&2
 	

sE   FI8 A I8 AI8 !AI8 8L5K
LL5LLLz https://graph.facebook.com/v20.0c                     t        |       }dj                  d |j                         D              j                         S )z
    Reuse your html_to_unicode_styled, but ensure newlines are preserved.
    Facebook supports Unicode characters; styled bold via math bold works.
    
c              3   <   K   | ]  }|j                           y wrj   )rstrip)rk   lines     r,   rn   z(html_to_facebook_text.<locals>.<genexpr>D  s     AtT[[]As   )r   rr   
splitlinesr%   )ra   rs   s     r,   html_to_facebook_textr   =  s3    
 "$'D99At/@AAGGIIrV   
user_tokenc           	      B  K   t        j                  d      4 d{   }t         d}|j                  |dt        t
        | d       d{   }|j                          |j                         cddd      d{    S 7 f7 77 	# 1 d{  7  sw Y   yxY ww)z
    Refresh a Facebook access token to get a new long-lived token.
   
    Args:
        user_token: The current user access token to refresh
       
    Returns:
        dict: Contains new access_token and expires_in
       )timeoutNz/oauth/access_tokenfb_exchange_token)
grant_type	client_idclient_secretr   )params)httpxAsyncClientGRAPHrF   APP_ID
APP_SECRETraise_for_statusr   )r   client	token_urlrs       r,   refresh_facebook_tokenr   K  s        , 	 	g01	**Y-'!+	0
*   	
vvx	 	 		 	 	 	sV   BBB-B
B#B
2B>B?BB
B
BBBBpage_id
page_token
image_urlsc           	         g }t        j                         5 }|D ]  }|j                  t         d|  d|d|dd      }|j                  dk(  r4|j                         j                  d      }|sV|j                  |       ht        j                  d	|j                   d
|j                           	 ddd       |S # 1 sw Y   |S xY w)z|
    Upload images as unpublished photos to get media IDs.
    Later attach them via attached_media on /{page_id}/feed.
    /z/photosfalse)r   	publishedr      r   r   r   rK   u   ❌ FB photo upload failed: r   N)r   r   r   r   r"   r   rF   rY   r   r   rs   )r   r   r   	media_idssr   r   mids           r,   _collect_fb_media_idsr   a  s    
 I				 Yq 	YC'7)7+!($.
   A }}#ffhll4($$S) <Q]]O3qvvhWX	YY" #Y" s   AB>0AB>>Cc                    |
t               }	 t        | dd      }t        |dd      t        |dd      }st        d      |st        d      t        | dd      }|st        d      t        |      t        | d	d      g t	        | d
      rM| j
                  rA| j
                  D ]2  }t        |dd      xs t        |dd      }|s"j                  |       4 dt        ffd} ||      }|j                  dv r^t        j                  d|j                   d| j                   d       t        |      }	|	d   }
|	j                  dd      }t        t        j                               t        |      z   }|
r|
|_        ||_        |j%                          |j'                  |        ||
      }|j(                  r8|j+                         xs i j                  d      }d|d|j-                          S t        j.                  d|j                   d|j0                          dd|j                   d|j-                          S ddd|j-                          S |j(                  sQt        j.                  d|j                   d |j0                          dd|j                   d|j-                          S |j+                         xs i j                  d      }d|d|j-                          S # t2        j4                  j6                  $ rP}t        j.                  d!| j                   d |        dd"t        |       dcY d}~|j-                          S d}~wt8        $ rP}t        j.                  d#| j                   d |        dd$t        |       dcY d}~|j-                          S d}~ww xY w# |j-                          w xY w)%z
    Mirrors post_to_twitter:
    - Formats HTML into styled Unicode text
    - Posts to /{page_id}/feed (text + link) or text + images via attached_media
    - On 401/403, refresh the Page Access Token using the stored long-lived user token
    Nr   external_account_idr   z,Missing Facebook page_id on ConnectedAccountz;Missing Facebook page Page Access Token on ConnectedAccountr   zNo content to post for Facebooklinkimagesr   	image_urlcurrent_page_tokenc                 `   di}rWt        	|       }|st        j                  d       |r1t        |      D ]#  \  }}t	        j
                  d|i      |d| d<   % r%t        d |j                         D              s|d<   t        j                  t         d	 d	i |d
| id      }|S )Nmessageu8   ⚠ No media IDs created; falling back to text/link only
media_fbidzattached_media[]c              3   >   K   | ]  }|j                  d         yw)attached_mediaN)
startswith)rk   ks     r,   rn   z5post_to_facebook.<locals>._do_post.<locals>.<genexpr>  s     W1-= >Ws   r   r   z/feedr   r   r   )r   r   r   	enumerater   dumpsanykeysr   r   r   )
r   r   r   idxr   r   r   r   r   r   s
         r,   _do_postz"post_to_facebook.<locals>._do_post  s     '*G1';MzZ	 OO$^_$-i$8 \S<@JJVYGZ<[/#a 89\ CWWW"& '7)5)DD1CDA HrV   r   u   ⚠ FB r   z; attempting token refresh...r   
expires_ini O rK   Tr   u"   ❌ FB post failed after refresh: r   FzFacebook post failed: r   z%Failed to refresh Facebook Page tokenu   ❌ Facebook API error r   u(   ❌ HTTP request failed for FB PostType r   u6   ❌ Unexpected error posting to Facebook for PostType r   )r   r   r   r   hasattrr   rY   r   r"   r   r   rK   r   rF   intr	   r   
expires_atrM   r   r   r   r   r   rs   r   r   r   r   )r6   r.   car   content_htmlimgry   r   r   refresh_resultr   r   r2r   r   r   r   r   r   s                  @@@@r,   post_to_facebookr	  {  s    
z$&mY 3T:"3T:R$/
KLLZ[[y)T:>??'5 y&$/
 9h'I,<,< '' )C-Pk41P%%a()
	 	 	6 Z  ==J&OOgamm_N9<<.Pmno3Z@N&~6I'++L+FJTYY[)C
O;J$ *		

2i(55!wwyB33D9G'+@4 	
1 MM$Fr~~FVVYZ\ZaZaYb"cd',9OPRP^P^O_7`a. 	
+ $)3Z[* 	
' ttMM3AMM?"QVVHMN$1G/WX" 	
 668>r&&t,
  "$ 	
 // M@bQRPSTU -B3q6(+KLL
 	
	  JNy||n\^_`^abc -?Ax+HII

	J 	
si   B:K9 D K9 >A K9 K9 $AK9 'K9 9N=5M!N=O  !N=-5N8"N=#O  8N==O   Orj   );pytzr   r   r   r   pytz.exceptionsr   r   r	   r
   r   src.marketing.apps.postr   r   src.utils.dbr   r   sqlalchemy.ormr   src.marketing.apps.post.modelr    src.marketing.apps.Account.modelr   fastapir   r   r   
sqlalchemyr   typingr   r   r   r   bs4r   r   r   r   osgetenvr   r   r   r-   dictrU   rZ   r`   r   r   r  r   r   r   r   r   r   r	   rV   r,   <module>r     sd   H H 0 ( (  6  ' " 8 : 2 2     =  E  		;	RYY'
,$ ,x~ ,s ,W_ ,2* *t *^"d>&: "t "R  < 2,S , ,dQ
' Q
v 	+J J JS T ,3 C T#Y SWX[S\ 4v7 vrV   