§
    Lëiî  ã                   ó^  — d Z ddlZddlZddlZddl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mZmZ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 ddlm Z  ddl!m"Z"m#Z#  ej$        e%¦  «        Z& eddg¬¦  «        Z'ej(         )                    ej(         *                    e+¦  «        d¦  «        Z, ej-        e,d¬¦  «         d„ Z.de/de/dz  fd„Z0de/de/de/fd„Z1de/de/de/fd„Z2e' 3                    dd ¬!¦  «         ed"¬#¦  «         ee¦  «        fd$ed%e/d&efd'„¦   «         Z4dS )(u    
Inbound email webhook â€” called by Postfix pipe script.
Parses email, saves attachments, generates AI draft via Gemini,
creates IncomingEmail + Task records.
é    N)ÚdatetimeÚ	timedelta)Úgenai)Útypes)Ú	APIRouterÚDependsÚHTTPExceptionÚHeaderÚRequest)ÚAsyncSession)Úselect)Úsettings)Úget_db)ÚUser)ÚTask)ÚIncomingEmail)Únotify_adminsÚnotify_user_groupz/emailÚemail)ÚprefixÚtagsz../../uploads/incomingT)Úexist_okc                  ó°   — t          j        ¦   «         } | j        dk    r%| t          d¬¦  «        z                        ¦   «         S |                      ¦   «         S )z+Today before 4pm, tomorrow at or after 4pm.é   é   )Údays)r   ÚnowÚhourr   Údate)r   s    úA/var/www/html/jarvis.com/web/backend/app/routers/email_inbound.pyÚ	_due_dater!   !   sH   € å
Œ,‰.Œ.€CØ
„x�2‚~€~Ø•i QÐ'Ñ'Ô'Ñ'×-Ò-Ñ/Ô/Ð/Ø�8Š8‰:Œ:Ðó    Úto_addrÚreturnc                 ó˜   — t          j        d| t           j        ¦  «        }|r'|                     d¦  «                             ¦   «         ndS )u*   task-shella@jarvis.goteku.com â†’ 'shella'ztask-([^@\s<>]+)@r   N)ÚreÚsearchÚ
IGNORECASEÚgroupÚlower)r#   Úmatchs     r    Ú_extract_usernamer,   )   s>   € åŒIÐ*¨GµR´]ÑCÔC€EØ%*Ð4ˆ5�;Š;�q‰>Œ>×ÒÑ!Ô!Ð!°Ð4r"   ÚfilenameÚdata_b64c                 óz  — t          j        dd| ¦  «        }t          j                             t
          |¦  «        }t          j                             |¦  «        \  }}d}t          j                             |¦  «        rPt          j                             t
          |› d|› |› �¦  «        }|dz  }t          j                             |¦  «        °Pt          |d¦  «        5 }| 	                    t          j        |¦  «        ¦  «         ddd¦  «         n# 1 swxY w Y   t          j                             |¦  «        S )z>Decode base64 attachment, save to disk, return saved filename.z[^\w.\-]Ú_r   ÚwbN)r&   ÚsubÚosÚpathÚjoinÚ
UPLOAD_DIRÚsplitextÚexistsÚopenÚwriteÚbase64Ú	b64decodeÚbasename)r-   r.   Úsafer4   ÚbaseÚextÚcounterÚfs           r    Ú_save_attachmentrC   /   s>  € åŒ6�+˜s HÑ-Ô-€DÝŒ7�<Š<�
 DÑ)Ô)€DÝ”× Ò  Ñ&Ô&�I€Dˆ#Ø€GÝ
Œ'�.Š.˜Ñ
Ô
ð ÝŒw�|Š|�J¨4Ð(@Ð(@°'Ð(@¸3Ð(@Ð(@ÑAÔAˆØ�1‰ˆõ Œ'�.Š.˜Ñ
Ô
ð õ 
ˆd�DÑ	Ô	ð ,˜QØ	�Š•Ô  Ñ*Ô*Ñ+Ô+Ð+ð,ð ,ð ,ñ ,ô ,ð ,ð ,ð ,ð ,ð ,ð ,øøøð ,ð ,ð ,ð ,åŒ7×Ò˜DÑ!Ô!Ð!s   Ã(DÄDÄDÚsubjectÚbodyc                 ó.  — t           j        sdS 	 t          j        t           j        ¬¦  «        }d| › d|dd…         › �}|j                             d|¬¦  «        }|j        S # t          $ r(}t           	                    d	|› �¦  «         Y d}~dS d}~ww xY w)
z?Call Gemini Flash to generate a formal Indonesian letter draft.Ú )Úapi_keya  Kamu adalah asisten surat bisnis formal Indonesia. Baca email masuk berikut dan buat draft balasan surat resmi dalam Bahasa Indonesia. Format: paragraf singkat, formal, profesional. Jangan sertakan header/footer surat. Hanya isi badan surat.

Subjek email: z

Isi email:
Ni¸  zgemini-2.5-flash)ÚmodelÚcontentszGemini error: )
r   ÚGEMINI_API_KEYr   ÚClientÚmodelsÚgenerate_contentÚtextÚ	ExceptionÚloggerÚerror)rD   rE   ÚclientÚpromptÚresponseÚes         r    Ú_generate_ai_draftrW   =   sÑ   € åÔ"ð ØˆrðÝ”¥hÔ&=Ð>Ñ>Ô>ˆð)ð %ð	)ð )ð
     œ;ð)ð )ð 	ð ”=×1Ò1Ø$Øð 2ñ 
ô 
ˆð Œ}ÐøÝð ð ð Ý�ŠÐ) aÐ)Ð)Ñ*Ô*Ð*Øˆrˆrˆrˆrˆrøøøøðøøøs   �AA" Á"
BÁ,BÂBz/inboundéÈ   )Ústatus_coderG   )ÚdefaultÚrequestÚx_hook_secretÚdbc           
   ƒ   ó²  K  — |t           j        k    rt          dd¦  «        ‚|                      ¦   «         ƒ d {V —†}|                     dd¦  «        }|                     dd¦  «        }|                     dd¦  «        }|                     dd¦  «        }|                     dg ¦  «        }t          |¦  «        }	|	s"t                               d	|› �¦  «         d
ddœS |                     t          t          ¦  «                             t          j        |	k    ¦  «        ¦  «        ƒ d {V —†}
|
                     ¦   «         }|s't                               d|	› d�¦  «         d
d|	› d�dœS g }|D ]~}	 t          |d         |d         ¦  «        }|                     |¦  «         Œ5# t           $ r=}t                               d|                     d¦  «        › d|› �¦  «         Y d }~Œwd }~ww xY wt%          ||¦  «        }t'          |||||t          j        |¦  «        ¬¦  «        }|                     |¦  «         |                     ¦   «         ƒ d {V —† t/          |pd|› �dt1          ¦   «         |j        |j        ¬¦  «        }|                     |¦  «         |                     ¦   «         ƒ d {V —† |j        |_        d|j        › �}d|› �}d|j        › �}t9          ||||¦  «        ƒ d {V —† t;          ||||d¬¦  «        ƒ d {V —† |                     ¦   «         ƒ d {V —† t                               d|j        › d|	› d|› �¦  «         d |j        |j        d!œS )"Ni“  zInvalid hook secretrD   rG   ÚfromÚtorE   ÚattachmentszNo task-username found in To: Úignoredzno task-username in To address)ÚstatusÚreasonzUser 'z' not foundzuser 'r-   ÚdatazFailed to save attachment z: )rD   Ú
from_emailÚto_emailÚbody_rawÚai_draftra   zEmail from Útodo)Útitlerc   Údue_dateÚassigned_toÚ
created_byu   Email masuk â†’ Task baru: zDari: z/tasks/Útelegram_thread_task)Ú
thread_keyzCreated task #z for 'z': Úok)rc   Útask_idÚincoming_email_id) r   ÚWEBHOOK_SECRETr	   ÚjsonÚgetr,   rQ   ÚwarningÚexecuter   r   ÚwhereÚusernameÚscalar_one_or_nonerC   ÚappendrP   rR   rW   r   ÚdumpsÚaddÚflushr   r!   Úidrr   rk   r   r   ÚcommitÚinfo)r[   r\   r]   ÚpayloadrD   Ú	from_addrr#   rE   Úattachments_rawrz   ÚresultÚuserÚsaved_filesÚattÚfnamerV   ri   ÚincomingÚtaskÚnotif_titleÚ
notif_bodyÚ
notif_links                         r    Úemail_inboundr�   U   sï  è è € ð �Ô/Ò/Ð/Ý˜CÐ!6Ñ7Ô7Ð7à—L’L‘N”NÐ"Ð"Ð"Ð"Ð"Ð"€Gà—k’k )¨RÑ0Ô0€GØ—k’k &¨"Ñ-Ô-€IØ—k’k $¨Ñ+Ô+€GØ—k’k &¨"Ñ-Ô-€DØ—k’k -°Ñ4Ô4€Oå  Ñ)Ô)€HØð QÝ�ŠÐA¸ÐAÐAÑBÔBÐBØ#Ð/OÐPÐPÐPà—:’:�f¥T™lœl×0Ò0µ´À(Ò1JÑKÔKÑLÔLÐLÐLÐLÐLÐLÐL€FØ×$Ò$Ñ&Ô&€DØð OÝ�ŠÐ5 Ð5Ð5Ð5Ñ6Ô6Ð6Ø#Ð/M¸Ð/MÐ/MÐ/MÐNÐNÐNð €KØð Rð Rˆð	RÝ$ S¨¤_°c¸&´kÑBÔBˆEØ×Ò˜uÑ%Ô%Ð%Ð%øÝð 	Rð 	Rð 	RÝ�LŠLÐP°c·g²g¸jÑ6IÔ6IÐPÐPÈQÐPÐPÑQÔQÐQÐQÐQÐQÐQÐQøøøøð	Røøøõ " '¨4Ñ0Ô0€Hõ ØØØØØÝ”J˜{Ñ+Ô+ðñ ô €Hð ‡F‚Fˆ8ÑÔÐØ
�(Š(‰*Œ*ÐÐÐÐÐÐÐõ ØÐ2Ð2 yÐ2Ð2ØÝ‘”Ø”GØ”7ðñ ô €Dð ‡F‚Fˆ4�L„L€LØ
�(Š(‰*Œ*ÐÐÐÐÐÐÐà”w€HÔð =°´
Ð<Ð<€KØ&˜9Ð&Ð&€JØ%˜DœGÐ%Ð%€JÝ
˜˜K¨°ZÑ
@Ô
@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ý
˜B ¨Z¸ÐPfÐ
gÑ
gÔ
gÐgÐgÐgÐgÐgÐgÐgà
�)Š)‰+Œ+ÐÐÐÐÐÐÐå
‡K‚KÐF ¤ÐFÐF°ÐFÐF¸WÐFÐFÑGÔGÐGØ t¤wÀXÄ[ÐQÐQÐQs   Å01F"Æ"
G)Æ,3G$Ç$G))5Ú__doc__ru   r3   r&   r;   Úloggingr   r   Úgoogler   Úgoogle.genair   Úgenai_typesÚfastapir   r   r	   r
   r   Úsqlalchemy.ext.asyncior   Ú
sqlalchemyr   Ú
app.configr   Úapp.databaser   Úapp.models.userr   Úapp.models.taskr   Úapp.models.incoming_emailr   Úapp.services.notifierr   r   Ú	getLoggerÚ__name__rQ   Úrouterr4   r5   ÚdirnameÚ__file__r6   Úmakedirsr!   Ústrr,   rC   rW   Úpostr�   © r"   r    ú<module>r¨      s¯  ððð ð
 €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø €€€Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (à Ð Ð Ð Ð Ð Ø -Ð -Ð -Ð -Ð -Ð -Ø FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FØ /Ð /Ð /Ð /Ð /Ð /Ø Ð Ð Ð Ð Ð à Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø  Ð  Ð  Ð  Ð  Ð  Ø  Ð  Ð  Ð  Ð  Ð  Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ø BÐ BÐ BÐ BÐ BÐ BÐ BÐ Bà	ˆÔ	˜8Ñ	$Ô	$€Ø	ˆ˜(¨'¨Ð	3Ñ	3Ô	3€àŒW�\Š\˜"œ'Ÿ/š/¨(Ñ3Ô3Ð5MÑNÔN€
Ø €„ˆJ Ð &Ñ &Ô &Ð &ðð ð ð5˜sð 5 s¨T¡zð 5ð 5ð 5ð 5ð"˜sð "¨cð "°cð "ð "ð "ð "ð ð ¨3ð °3ð ð ð ð ð0 ‡‚ˆZ S€Ñ)Ô)ð  ˜¨Ð+Ñ+Ô+Ø�w˜v‘”ðJRð JRØðJRàðJRð 	ðJRð JRð JRñ *Ô)ðJRð JRð JRr"   