o
    aBj£Ú  ã                   @   sP
  d dl Z d dlZd dl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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mZmZmZ eeƒZh d	£Zd
efdd„Zdd„ Zd
e fdd„Z!dededB ded
efdd„Z"de dB de dedededB d
efdd„Z#dedB de dB de dedB ded
edB fdd„Z$dedB d
e%fdd „Z&dedB d
e%fd!d"„Z'd#edB d
edB fd$d%„Z(		&	&�dd'ed(ed)ed*ed+edB d,e%d-e%fd.d/„Z)�dd'ed0edB fd1d2„Z*d'ed3e d4e fd5d6„Z+d'ed3e fd7d8„Z,			9		&				�dd'ede d:ed;ed<edB d=ed>edB d?e%d@edB dAedB dBedB dCe%dB fdDdE„Z-d'ede dFefdGdH„Z.d'ede fdIdJ„Z/d'edKefdLdM„Z0d'ede fdNdO„Z1d'ede d>efdPdQ„Z2d'edRefdSdT„Z3	&				�d	d'ede d>ed;edB d:ed<ed=ed?e%d@edB dAedB dBedB dCe%dB fdUdV„Z4d'ede dWefdXdY„Z5d'ede de fdZd[„Z6d'ed(edB fd\d]„Z7d'ede d@edWed;edB d:ed=ed<edBedB d^edB dCe%dB d_ed`e8fdadb„Z9d'edce de fddde„Z:d'edce dfe%fdgdh„Z;d'edce d_efdidj„Z<d'edce fdkdl„Z=d'ede dWed
e%fdmdn„Z>d'ede doedpefdqdr„Z?d'ede doedpefdsdt„Z@d'ede duedpefdvdw„ZAd'edxe dWefdydz„ZB	�dd'ed{e dxe d@edWed;edB d:ed=ed<ed|edB d^edB de dB fd}d~„ZCd'ed{e dWede fdd€„ZDd'edxe dWed
e%fd�d‚„ZEd'edxe doedpefdƒd„„ZFd'edxe duedpefd…d†„ZGd'edxe de fd‡dˆ„ZHd'edxe dWefd‰dŠ„ZI	�dd'ed{e dxe dWed;edB d:ed=ed<ed|edB d^edB de dB fd‹dŒ„ZJd'ed{e dWede fd�dŽ„ZKd'edxe dWed
e%fd�d�„ZLd'edxe doedpefd‘d’„ZMd'edxe duedpefd“d”„ZNd'ed•efd–d—„ZOd'ed•ed
e%fd˜d™„ZPd'edxe de fdšd›„ZQd'ed•efdœd�„ZRd'ed•ed
e%fdždŸ„ZSd'ede fd d¡„ZTd'ede fd¢d£„ZUd'ede d>ed
e%fd¤d¥„ZVd'ede fd¦d§„ZWd'ed¨efd©dª„ZXd'ede dfe%fd«d¬„ZY	­								�d
d'ede d®ed¯edB d°edB d¨edB d±edB d²edB d³edB d´edB dµedB fd¶d·„ZZd¸d¹hZ[d'ede fdºd»„Z\d'ede fd¼d½„Z]d'ede fd¾d¿„Z^d'ede fdÀdÁ„Z_d'ede fdÂdÃ„Z`d'ede fdÄdÅ„Zad'ede fdÆdÇ„Zbd'ede fdÈdÉ„Zcd'edÊefdËdÌ„Zdd'ede dÍe8fdÎdÏ„Zed'ede dÐe8fdÑdÒ„Zfd'edÓedÐe8fdÔdÕ„Zg	&�dd'ede dÖe8dB d×e%fdØdÙ„Zhd'ede dÚe8fdÛdÜ„Zid'ede dÚe8fdÝdÞ„Zjd'ede dße8fdàdá„Zkd'ede d
e%fdâdã„Zl					�dd'edäedåed`e8dæedB dedB dçedB dèedB déedB fdêdë„Zmd'edìe fdídî„Znd'edæedB fdïdð„Zod'edñefdòdó„Zpd'edñedôefdõdö„Zqd'edÓed÷edB fdødù„Zr�dd'edÓedèedB d`e8dB fdúdû„ZsdedB fdüdý„ZtdÐe8d
efdþdÿ„Zud`e8dB d
edB f�d �d„Zv�ddèedB d`e8dB d
edB f�d�d„Zwd<edB d
ef�d�d„ZxdS (  é    N)ÚdatetimeÚ	timedeltaÚtimezone)ÚPath)Úurlparse)ÚIntegrityError)ÚSession)Ú
get_logger)ÚCalendarSyncStateÚMeetingÚNonRecurringMeetingInviteÚRecallWebhookEventÚ	RecordingÚRecurringMeetingCandidateÚRecurringMeetingInviteÚUser>   ÚliveÚabortÚpendingÚ	completedÚ	scheduledÚ	too_shortÚ
processingÚnot_admittedúbot.doneú	bot.fatalúbot.call_endedúrecording.doneútranscript.doneúbot.joining_callúrecording.failedútranscript.failedúbot.in_waiting_roomúbot.in_call_recordingúbot.in_call_not_recordingÚreturnc                   C   s   t  d¡pd ¡ p
dS )NÚS3_FOLDER_PREFIXÚlocal)ÚosÚgetenvÚstrip© r+   r+   úC/var/www/html/iih-ai-notetaker/iih-ai-notetaker-backend/app/crud.pyÚ_storage_prefix'   s   r-   c                  C   s  zdd l } W n ty   t d¡ Y d S w t d¡pd ¡ }t d¡p%d ¡ }t d¡p.d ¡ }|r7|r7|s9d S t d¡p?d ¡ pCd }t d¡pOt d	¡pOd ¡ pSd }|r…t|ƒ}|jr…|j 	|› d
�¡r…|jt
|› d
�ƒd … }|jr}|› d|j› �}|j|d� ¡ }| jd||||d�S )Nr   z>boto3 is not installed; storage upload/presign is unavailable.ÚAWS_ACCESS_KEY_IDÚ ÚAWS_SECRET_ACCESS_KEYÚAWS_S3_BUCKETÚAWS_S3_ENDPOINT_URLÚAWS_DEFAULT_REGIONÚ
AWS_REGIONÚ.ú:)ÚnetlocÚs3)Úaws_access_key_idÚaws_secret_access_keyÚendpoint_urlÚregion_name)Úboto3ÚImportErrorÚloggerÚwarningr(   r)   r*   r   ÚhostnameÚ
startswithÚlenÚportÚ_replaceÚgeturlÚclient)r=   Úaccess_key_idÚsecret_access_keyÚbucketr;   r<   Úparsedr7   r+   r+   r,   Ú_storage_client+   s6   
þ ûrL   c                  C   s8   t  d¡pd ¡ } ztdt| ƒƒW S  ty   Y dS w )NÚ$AWS_S3_PRESIGNED_URL_EXPIRES_SECONDSÚ3600é<   i  )r(   r)   r*   ÚmaxÚintÚ
ValueError)Ú	raw_valuer+   r+   r,   Ú!_presigned_url_expires_in_secondsL   s   ÿrT   Ú
source_urlÚcontent_typeÚfallback_kindc                 C   sj   t t| ƒjƒj}|r|S |pd dd¡d  ¡  ¡ }|r!t |¡nd }|r'|S |dkr-dS |dkr3dS dS )	Nr/   ú;é   r   Úaudioz.mp3Úvideoz.mp4)	r   r   ÚpathÚsuffixÚsplitr*   ÚlowerÚ	mimetypesÚguess_extension)rU   rV   rW   r]   Únormalized_content_typeÚguessedr+   r+   r,   Ú_guess_extensionT   s   rd   Úuser_idÚ
meeting_idÚkindc                 C   sH   | d urt | ƒnd}t |ƒ}t|||ƒ}tƒ › d|› d|› d|› |› �S )Nzunknown-userú/)Ústrrd   r-   )re   rf   rg   rU   rV   Úuser_segmentÚmeeting_segmentÚ	extensionr+   r+   r,   Ú_build_storage_keya   s    rm   Úrecording_idc             
   C   s   | sd S t  d¡p
d ¡ }tƒ }|r|s| S z\tj| ddd��I}| ¡  d|j_|j	 d¡p/d 
dd¡d	  ¡ }t|||| |d
�}	i }
|rI||
d< |
rV|j|j||	|
d� n| |j||	¡ |	W  d   ƒ W S 1 skw   Y  W d S  ty� } zt d|p€d||¡ W Y d }~d S d }~ww )Nr1   r/   Téx   )ÚstreamÚtimeoutzContent-TyperX   rY   r   )re   rf   rg   rU   rV   ÚContentType)Ú	ExtraArgsz6Storage upload failed for recording %s (%s). Error: %szunknown-recording)r(   r)   r*   rL   ÚrequestsÚgetÚraise_for_statusÚrawÚdecode_contentÚheadersr^   rm   Úupload_fileobjÚ	Exceptionr?   r@   )rU   re   rf   rn   rg   rJ   Ústorage_clientÚresponserV   ÚkeyÚ
extra_argsÚexcr+   r+   r,   Ú!upload_recording_asset_to_storageo   sH    û(íü€ùr�   Úvaluec                 C   s,   | r|   d¡s	dS t| ƒjpd ¡ }d|v S )N)úhttp://úhttps://Fr/   Úrecall)rB   r   rA   r_   )r‚   Úhostr+   r+   r,   Ú_is_recall_download_urlž   s   r‡   c                 C   s   | sdS t | ƒ S ©NF)r‡   ©r‚   r+   r+   r,   Ú_has_bucket_backed_media¥   s   
rŠ   Ústored_valuec              
   C   s–   | sd S |   d¡s|   d¡r| S t d¡pd ¡ }tƒ }|r |s"| S z|jd|| dœtƒ d�W S  tyJ } zt 	d| |¡ | W  Y d }~S d }~ww )	Nrƒ   r„   r1   r/   Ú
get_object)ÚBucketÚKey)ÚParamsÚ	ExpiresInz2Could not generate presigned URL for %s. Error: %s)
rB   r(   r)   r*   rL   Úgenerate_presigned_urlrT   r{   r?   r@   )r‹   rJ   r|   r€   r+   r+   r,   Úresolve_storage_download_url«   s&   ý€þr’   FÚdbÚemailÚnameÚtokenÚrefresh_tokenÚcalendar_scope_grantedÚis_adminc              
   C   sÀ   |   t¡ tj|k¡ ¡ }|r4||_||_|r||_|rdnd|_|r3d|_	d |_
|jp1t tj¡|_n!t|||||r=dnd|rBdnd|rKt tj¡nd |d�}|  |¡ |  ¡  |  |¡ |S )NÚadminÚuserÚapprovedr   )r”   r•   Úaccess_tokenr—   ÚroleÚapproval_statusÚapproved_atÚcalendar_sync_enabled)Úqueryr   Úfilterr”   Úfirstr�   r•   r—   rž   rŸ   Ú	denied_atr    r   Únowr   ÚutcÚaddÚcommitÚrefresh)r“   r”   r•   r–   r—   r˜   r™   r›   r+   r+   r,   Úcreate_or_update_userÖ   s4   	€

ø


r«   rŸ   c                 C   s>   |   t¡ tjdk¡ tj ¡ ¡}|r| tj|k¡}| ¡ S )Nrš   )	r¢   r   r£   rž   Úorder_byÚidÚascrŸ   Úall)r“   rŸ   r¢   r+   r+   r,   Ú
list_usersý   s   "r°   Útarget_user_idÚadmin_user_idc                 C   sf   |   t¡ tj|k¡ ¡ }|sd S |jdkr|S d|_t t	j
¡|_||_d |_|  ¡  |  |¡ |S )Nrš   rœ   )r¢   r   r£   r­   r¤   rž   rŸ   r   r¦   r   r§   r    Úapproved_byr¥   r©   rª   )r“   r±   r²   r›   r+   r+   r,   Úapprove_user  s   

r´   c                 C   sf   |   t¡ tj|k¡ ¡ }|sd S |jdkr|S d|_d |_d |_t	 
tj¡|_|  ¡  |  |¡ |S )Nrš   Údenied)r¢   r   r£   r­   r¤   rž   rŸ   r    r³   r   r¦   r   r§   r¥   r©   rª   )r“   r±   r›   r+   r+   r,   Ú	deny_user  s   

r¶   Úgoogle_meetÚ	meet_linkÚtitleÚscheduled_atÚplatformÚcalendar_event_idÚis_recurringÚrecurring_series_idÚsource_event_idÚhost_rsvp_statusÚapp_toggle_enabledc                 C   sH   t ||||||t|ƒ|||	p||
|d�}|  |¡ |  ¡  |  |¡ |S )N)re   r¼   r¸   r¹   r»   rº   Ústatusr½   r¾   r¿   rÀ   rÁ   )r   Ú_initial_meeting_statusr¨   r©   rª   )r“   re   r¸   r¹   rº   r»   r¼   r½   r¾   r¿   rÀ   rÁ   Úmeetingr+   r+   r,   Úcreate_meeting_record$  s$   ô

rÅ   Ú	file_pathc                 C   s.   t ||dd�}|  |¡ |  ¡  |  |¡ |S )NÚ	recording)rf   rÆ   rÂ   )r   r¨   r©   rª   )r“   rf   rÆ   rÇ   r+   r+   r,   Úcreate_recordingF  s
   

rÈ   c                 C   ó   |   t¡ tj|k¡ ¡ S ©N)r¢   r   r£   rf   r¤   ©r“   rf   r+   r+   r,   Úget_recording_by_meetingN  ó   rÌ   Úrecall_bot_idc                 C   rÉ   rÊ   )r¢   r   r£   rÎ   r¤   )r“   rÎ   r+   r+   r,   Úget_meeting_by_recall_bot_idR  rÍ   rÏ   c                 C   rÉ   rÊ   )r¢   r   r£   r­   r¤   rË   r+   r+   r,   Úget_meeting_by_idV  rÍ   rÐ   c                 C   ó"   |   t¡ tj|ktj|k¡ ¡ S rÊ   )r¢   r   r£   re   r¼   r¤   )r“   re   r¼   r+   r+   r,   Ú get_meeting_by_calendar_event_idZ  ó   
þýrÒ   Úrecall_recording_idc                 C   rÉ   rÊ   )r¢   r   r£   rÔ   r¤   )r“   rÔ   r+   r+   r,   Ú$get_recording_by_recall_recording_ida  rÍ   rÕ   c                 C   s¢   t | ||ƒ}|st| |||||||||	|
|d�S ||_||_||_||_||_||_|	p-||_|
|_	|d ur9||_
|jdv rF|jsFt|ƒ|_|  ¡  |  |¡ |S )N)r“   re   r¸   r¹   rº   r»   r¼   r½   r¾   r¿   rÀ   rÁ   >   Nr   r   )rÒ   rÅ   r¹   r¸   rº   r»   r½   r¾   r¿   rÀ   rÁ   rÂ   rÎ   rÃ   r©   rª   )r“   re   r¼   r¹   r¸   rº   r»   r½   r¾   r¿   rÀ   rÁ   rÄ   r+   r+   r,   Úsave_calendar_meetinge  s>   ô


rÖ   Úgoogle_event_idc                 C   rÑ   rÊ   )r¢   r   r£   re   r×   r¤   )r“   re   r×   r+   r+   r,   Ú#get_recurring_candidate_by_event_id•  rÓ   rØ   c                 C   rÑ   rÊ   )r¢   r   r£   re   Úlinked_meeting_idr¤   )r“   re   rf   r+   r+   r,   Ú,get_recurring_candidate_by_linked_meeting_idœ  rÓ   rÚ   c                 C   s.   |sd S |  ¡  ¡ }|  t¡ tj|k¡ ¡ S rÊ   )r*   r_   r¢   r   r£   r”   r¤   )r“   r”   Únormalized_emailr+   r+   r,   Úget_user_by_email£  s   rÜ   Úorganizer_emailÚbot_permission_statusÚpayloadc                 C   s�   t | ||ƒ}|st|||d�}|  |¡ ||_||_||_||_||_|	|_|
d ur-|
|_	||_
t |¡|_t tj¡|_|  ¡  |  |¡ |S )N)re   r¾   r×   )rØ   r   r¨   r¹   r¸   r»   rº   rÀ   rÝ   rÁ   rÞ   ÚjsonÚdumpsÚpayload_jsonr   r¦   r   r§   Ú
updated_atr©   rª   )r“   re   r¾   r×   r¹   r¸   r»   rº   rÀ   rÝ   rÁ   rÞ   rß   Ú	candidater+   r+   r,   Ú"upsert_recurring_meeting_candidateª  s,   ý

rå   Úcandidate_idc                 C   sD   |   t¡ tj|k¡ ¡ }|sd S ||_d|_|  ¡  |  |¡ |S )NÚbot_created)	r¢   r   r£   r­   r¤   rÙ   rÞ   r©   rª   )r“   ræ   rf   rä   r+   r+   r,   Ú&set_recurring_candidate_linked_meetingÓ  s   
rè   Úenabledc                 C   óL   |   t¡ tj|k¡ ¡ }|sd S ||_t tj	¡|_
|  ¡  |  |¡ |S rÊ   )r¢   r   r£   r­   r¤   rÁ   r   r¦   r   r§   rã   r©   rª   )r“   ræ   ré   rä   r+   r+   r,   Ú!update_recurring_candidate_toggleâ  ó   
rë   c                 C   rê   rÊ   )r¢   r   r£   r­   r¤   rÞ   r   r¦   r   r§   rã   r©   rª   )r“   ræ   rÞ   rä   r+   r+   r,   Úset_recurring_candidate_statusñ  rì   rí   c                 C   sL   |   t¡ tj|k¡ ¡ }|sd S d |_t tj	¡|_
|  ¡  |  |¡ |S rÊ   )r¢   r   r£   r­   r¤   rÙ   r   r¦   r   r§   rã   r©   rª   )r“   ræ   rä   r+   r+   r,   Ú"unlink_recurring_candidate_meeting   s   
rî   c                 C   s*   t | ||ƒ}|s
dS |  |¡ |  ¡  dS )NFT)rØ   Údeleter©   )r“   re   r×   rä   r+   r+   r,   Údelete_recurring_candidate  s   
rð   Úwindow_startÚ
window_endc                 C   sn   |   t¡ tj|ktj|tdd� k tj|kB ¡ ¡ }d}|D ]}|jr%q|  |¡ |d7 }q|r5|  	¡  |S ©NrY   )Údaysr   )
r¢   r   r£   re   rº   r   r¯   rÙ   rï   r©   )r“   re   rñ   rò   Ústale_candidatesÚremovedrä   r+   r+   r,   Úcleanup_recurring_candidates  s"   
ÿýú

r÷   c           
         sÊ   ˆ  t¡ tj|ktjˆktj|k¡ tj ¡ tj ¡ ¡ ¡ }h d£‰ dtdt	f‡ ‡‡fdd„}t
ƒ }d}|D ]%}|j|v rAd}	n||ƒ }	|	sL||ƒrR| |j¡ |j|	kr\|	|_d}q7|rcˆ ¡  |S )N>	   r   r   r   r   r   r"   r#   útranscript.processingr$   rä   r%   c                    sd   | j sdS tˆ| j ƒ}|sdS |jp| j}|r#|jd u r#|jtjd�}|jˆ v r*dS t|o0|ˆkƒS )NF)ÚtzinfoT)	rÙ   rÐ   rº   rù   Úreplacer   r§   rÂ   Úbool)rä   Úlinked_meetingrº   ©Úblocking_statusesr“   rñ   r+   r,   Úcandidate_should_block_seriesH  s   
zMrefresh_recurring_candidate_visibility.<locals>.candidate_should_block_seriesFT)r¢   r   r£   re   rº   r¬   r¾   r®   r¯   rû   Úsetr¨   Údashboard_visibler©   )
r“   re   rñ   rò   Ú
candidatesrÿ   Úfirst_visible_per_seriesÚchangedrä   Úshould_showr+   rý   r,   Ú&refresh_recurring_candidate_visibility0  s0   
ýü


€r  Únow_utcc                 C   s@   |   t¡ tj|ktj d¡tj|ktj|k¡ tj ¡ ¡ 	¡ S ©NT)
r¢   r   r£   re   r  Úis_rº   r¬   r®   r¯   )r“   re   r  rò   r+   r+   r,   Ú!list_visible_recurring_candidatesj  s   

üûr
  Úguest_user_idc                 C   rÑ   rÊ   )r¢   r   r£   r  r×   r¤   ©r“   r  r×   r+   r+   r,   Úget_recurring_meeting_invites  rÓ   r  Úhost_user_idÚguest_rsvp_statusc                 C   sˆ   t | ||ƒ}|st||d�}|  |¡ ||_||_||_||_||_||_|	|_	|
|_
|d ur2||_t tj¡|_|  ¡  |  |¡ |S ©N)r  r×   )r  r   r¨   r  r¾   r¹   r¸   r»   rº   r  rÝ   rf   r   r¦   r   r§   rã   r©   rª   )r“   r  r  r¾   r×   r¹   r¸   r»   rº   r  rÝ   rf   Úinviter+   r+   r,   Úupsert_recurring_meeting_invitez  s*   þ

r  c                 C   óh   |   t¡ tj|ktj|k¡ ¡ }d}|D ]}|j|krq||_t t	j
¡|_|d7 }q|r2|  ¡  |S ©Nr   rY   )r¢   r   r£   r  r×   r¯   rf   r   r¦   r   r§   rã   r©   ©r“   r  r×   rf   ÚinvitesÚupdatedr  r+   r+   r,   Ú)link_recurring_meeting_invites_to_meeting   ó    
þý

r  c                 C   óF   t | ||ƒ}|s
dS t| |ƒrt d|j¡ dS |  |¡ |  ¡  dS )NFzcRecurring meeting invite deletion was skipped for invite %s because meeting history already exists.T)r  Úrecurring_invite_has_historyr?   Úinfor­   rï   r©   ©r“   r  r×   r  r+   r+   r,   Údelete_recurring_meeting_invite¸  ó   
þ
r  c                 C   ór   |   t¡ tj|ktj|tdd� k tj|kB ¡ ¡ }d}|D ]}t| |ƒr'q|  |¡ |d7 }q|r7|  	¡  |S ró   )
r¢   r   r£   r  rº   r   r¯   r  rï   r©   ©r“   r  rñ   rò   Ústale_invitesrö   r  r+   r+   r,   Ú!cleanup_recurring_meeting_invitesÇ  ó"   
ÿýú


r#  c           
      C   s¢   |   t¡ tj|k¡ tj ¡ tj ¡ ¡ ¡ }g }t	ƒ }|D ]0}t
| |ƒ}||j  ko/|kn  }	|r:| |¡ q|	s=q|j|v rCq| |j¡ | |¡ q|S rÊ   )r¢   r   r£   r  r¬   r¾   r®   rº   r¯   r   r  Úappendr¨   )
r“   r  r  rò   r  Úvisibler  r  Úhas_historyÚis_upcomingr+   r+   r,   Ú&list_visible_recurring_meeting_invitesß  s0   
ÿþû


r)  c                 C   s4   |   t¡ tj|ktj|k¡ ¡ }|sd S t| |ƒS rÊ   )r¢   r   r£   r  rf   r¤   rÐ   )r“   r  rf   r  r+   r+   r,   Ú&get_accessible_guest_recurring_meetingø  s   
þý
r*  c                 C   rÑ   rÊ   )r¢   r   r£   r  r×   r¤   r  r+   r+   r,   Ú get_non_recurring_meeting_invite  rÓ   r+  c                 C   s‚   t | ||ƒ}|st||d�}|  |¡ ||_||_||_||_||_||_|	|_	|
d ur/|
|_
t tj¡|_|  ¡  |  |¡ |S r  )r+  r   r¨   r  r¹   r¸   r»   rº   r  rÝ   rf   r   r¦   r   r§   rã   r©   rª   )r“   r  r  r×   r¹   r¸   r»   rº   r  rÝ   rf   r  r+   r+   r,   Ú#upsert_non_recurring_meeting_invite
  s(   þ

r,  c                 C   r  r  )r¢   r   r£   r  r×   r¯   rf   r   r¦   r   r§   rã   r©   r  r+   r+   r,   Ú-link_non_recurring_meeting_invites_to_meeting.  r  r-  c                 C   r  )NFzgNon-recurring meeting invite deletion was skipped for invite %s because meeting history already exists.T)r+  Ú non_recurring_invite_has_historyr?   r  r­   rï   r©   r  r+   r+   r,   Ú#delete_non_recurring_meeting_inviteF  r  r/  c                 C   r   ró   )
r¢   r   r£   r  rº   r   r¯   r.  rï   r©   r!  r+   r+   r,   Ú%cleanup_non_recurring_meeting_invitesU  r$  r0  c           	      C   sv   |   t¡ tj|k¡ tj ¡ tj ¡ ¡ ¡ }g }|D ]}t	| |ƒ}||j  ko,|kn  }|s3|r8| 
|¡ q|S rÊ   )r¢   r   r£   r  r¬   rº   r®   r­   r¯   r.  r%  )	r“   r  r  rò   r  r&  r  r'  r(  r+   r+   r,   Ú*list_visible_non_recurring_meeting_invitesm  s"   
ÿþû

€r1  r  c                 C   s€   |j r	t| |j ƒS |  t¡ tj|jktj|jktj	|jkB ¡ 
¡ }|r>|j |jkr>|j|_ t tj¡|_|  ¡  |  |¡ |S rÊ   )rf   rÐ   r¢   r   r£   re   r  r¼   r×   r¿   r¤   r­   r   r¦   r   r§   rã   r©   rª   ©r“   r  rÄ   r+   r+   r,   Ú)get_host_meeting_for_non_recurring_invite~  s    



ÿýú
r3  c                 C   ó@   t | |ƒ}|s	dS t| |jƒ}t| |jƒ}t|p|p|jtv ƒS rˆ   )r3  rÌ   r­   Úget_transcript_by_meetingrû   rÂ   ÚGUEST_VISIBLE_MEETING_STATUSES©r“   r  rÄ   rÇ   Ú
transcriptr+   r+   r,   r.  ‘  ó   
r.  c                 C   sd   |   t¡ tj|ktj|k¡ ¡ }|rt| |ƒS |   t¡ tj|ktj|k¡ ¡ }|r0t| |ƒS d S rÊ   )r¢   r   r£   r  rf   r¤   rÐ   r   )r“   r  rf   Úrecurring_inviteÚnon_recurring_inviter+   r+   r,   Úget_accessible_guest_meeting›  s"   
þý

þý
r<  c                 C   sŠ   |j r	t| |j ƒS |  t¡ tj|jktj d¡tj	|j
ktj|j
kB ¡ ¡ }|rC|j |jkrC|j|_ t tj¡|_|  ¡  |  |¡ |S r  )rf   rÐ   r¢   r   r£   re   r  r½   r	  r¼   r×   r¿   r¤   r­   r   r¦   r   r§   rã   r©   rª   r2  r+   r+   r,   Ú%get_host_meeting_for_recurring_invite­  s"   




ÿüù
r=  c                 C   r4  rˆ   )r=  rÌ   r­   r5  rû   rÂ   r6  r7  r+   r+   r,   r  Á  r9  r  c                 C   óB   |   t¡ tj|k¡ ¡ }|sdS |D ]}d |_q|  ¡  t|ƒS ©Nr   )r¢   r   r£   rf   r¯   r©   rC   ©r“   rf   r  r  r+   r+   r,   Ú-unlink_recurring_meeting_invites_from_meetingË  ó   ýrA  c                 C   r>  r?  )r¢   r   r£   rf   r¯   r©   rC   r@  r+   r+   r,   Ú1unlink_non_recurring_meeting_invites_from_meetingÛ  rB  rC  c           	      C   s¾   t | ||ƒ}|s
dS t| |jƒ}t| |jƒ}h d£}|s#|s#|j|v r4t d|j|jt|ƒt|ƒ¡ dS t| |jƒ}|rDt d|j|¡ t	| |jƒ}|rTt d|j|¡ |  
|¡ |  ¡  dS )NF>   r   r   r   r   r   r   z�Calendar meeting deletion was skipped for meeting %s because history already exists. Status: %s. Recording exists: %s. Transcript exists: %s.zoRecurring meeting invites were detached from meeting %s before calendar meeting deletion. Detached invites: %s.zsNon-recurring meeting invites were detached from meeting %s before calendar meeting deletion. Detached invites: %s.T)rÒ   rÌ   r­   r5  rÂ   r?   r  rû   rA  rC  rï   r©   )	r“   re   r¼   rÄ   rÇ   r8  Úcompleted_statusesÚdetached_invites_countÚ$detached_non_recurring_invites_countr+   r+   r,   Údelete_calendar_meetingë  s@   	ûýý
rG  c                 C   rÉ   rÊ   )r¢   r
   r£   re   r¤   )r“   re   r+   r+   r,   Úget_calendar_sync_state  rÍ   rH  Ú
channel_idc                 C   rÉ   rÊ   )r¢   r
   r£   rI  r¤   )r“   rI  r+   r+   r,   Ú"get_calendar_sync_state_by_channel  rÍ   rJ  c                 C   s>   |   t¡ tj|k¡ ¡ }|sd S ||_|  ¡  |  |¡ |S rÊ   )r¢   r   r£   r­   r¤   r¡   r©   rª   )r“   re   ré   r›   r+   r+   r,   Úset_calendar_sync_enabled!  s   
rK  ÚprimaryÚcalendar_idÚ
sync_tokenÚwebhook_urlÚchannel_tokenÚresource_idÚresource_uriÚ
expires_atÚlast_message_numberc                 C   s¾   t | |ƒ}|st||d�}|  |¡ ||_|d ur||_|d ur#||_|d ur*||_|d ur1||_|d ur8||_|d ur?||_	|	d urF|	|_
|
d urM|
|_t tj¡|_|  ¡  |  |¡ |S )N)re   rM  )rH  r
   r¨   rM  rN  rO  rI  rP  rQ  rR  rS  rT  r   r¦   r   r§   Úlast_synced_atr©   rª   )r“   re   rM  rN  rO  rI  rP  rQ  rR  rS  rT  Ústater+   r+   r,   Úsave_calendar_sync_state+  s2   


rW  r   r   c                 C   óD   |   t¡ tj|k¡ ¡ }|r |jtvr d|_|  ¡  |  |¡ |S ©Nr   ©	r¢   r   r£   r­   r¤   rÂ   ÚTERMINAL_MEETING_STATUSESr©   rª   ©r“   rf   rÄ   r+   r+   r,   Úmark_meeting_completedX  ó   
r]  c                 C   ó:   |   t¡ tj|k¡ ¡ }|rd|_|  ¡  |  |¡ |S )Nr   ©r¢   r   r£   r­   r¤   rÂ   r©   rª   r\  r+   r+   r,   Úmark_meeting_aborta  ó   
ra  c                 C   sj   t | |ƒ}|rd|_t tj¡|_|  t¡ 	tj
|k¡ ¡ }|r(|jtvr(d|_|  ¡  |r3|  |¡ |S )NÚstoppedr   )rÌ   rÂ   r   r¦   r   r§   Ú
stopped_atr¢   r   r£   r­   r¤   r[  r©   rª   )r“   rf   rÇ   rÄ   r+   r+   r,   Úmark_recording_stoppedj  s   

re  c                 C   r_  )Nr   r`  r\  r+   r+   r,   Úmark_meeting_livez  rb  rf  c                 C   rX  rY  rZ  r\  r+   r+   r,   Úmark_meeting_processingƒ  r^  rg  c                 C   r_  )Nr   r`  r\  r+   r+   r,   Úmark_meeting_not_admittedŒ  rb  rh  c                 C   sZ   ddl m} |  |¡ |j|k¡ ¡ }|r|S ||dd�}|  |¡ |  ¡  |  |¡ |S )Nr   ©Ú
Transcriptr   )rf   rÂ   )	Ú
app.modelsrj  r¢   r£   rf   r¤   r¨   r©   rª   )r“   rf   rj  Úexistingr8  r+   r+   r,   Úcreate_transcript•  s   

rm  c                 C   ó&   ddl m} |  |¡ |j|k¡ ¡ S ©Nr   ri  )rk  rj  r¢   r£   rf   r¤   )r“   rf   rj  r+   r+   r,   r5  £  ó   r5  Úrecall_transcript_idc                 C   rn  ro  )rk  rj  r¢   r£   rq  r¤   )r“   rq  rj  r+   r+   r,   Ú&get_transcript_by_recall_transcript_id¨  rp  rr  Úresultc                 C   sp  ddl m} |  |¡ |j|k¡ ¡ }|sd S | d¡dkr?d|_|d |_| d¡|_	|  t
¡ t
j|k¡ ¡ }|r>d|_nn| d¡rad|_t|d ƒ|_|  t
¡ t
j|k¡ ¡ }|r`d|_nLd	|_| d
¡|_| d¡|_	t | dg ¡¡|_t | di ¡¡|_t | dg ¡¡|_| d¡|_t tj¡|_|  t
¡ t
j|k¡ ¡ }|r­d|_|  ¡  |  |¡ |S )Nr   ri  Úerrorr   ÚmessageÚduration_secondsÚfailedr   ÚdoneÚlanguageÚparticipantsÚspeaker_mapr8  Ú	full_text)rk  rj  r¢   r£   rf   r¤   ru   rÂ   Úerror_messagerv  r   r­   ri   ry  rà   rá   rz  r{  Útranscript_jsonr|  r   r¦   r   r§   Úcompleted_atr©   rª   )r“   rf   rs  rj  r8  rÄ   r+   r+   r,   Úupdate_transcript_result­  sB   
€
€
r€  Úbot_datac                 C   sÊ   |   t¡ tj|k¡ ¡ }|sd S | d¡|_t|ƒ|_t	 
|¡|_| d¡}|r.t|ƒ|_t|jƒ}|r9||_n|jrK|jt tj¡krKd|_d|_|  ¡  |  |¡ t d|j|j|j|j|j¡ |S )Nr­   Újoin_atr   zoRecall bot details were saved for meeting %s. Bot id: %s. Bot status: %s. Meeting status: %s. Bot sub code: %s.)r¢   r   r£   r­   r¤   ru   rÎ   Úextract_recall_bot_statusÚ
bot_statusrà   rá   Úbot_payloadÚparse_iso_datetimeÚrecall_join_atÚ'map_recall_bot_status_to_meeting_statusrÂ   r   r¦   r   r§   r©   rª   r?   r  Úbot_sub_code)r“   rf   r�  rÄ   r‚  Úmapped_statusr+   r+   r,   Úset_meeting_recall_botÓ  s4   




úr‹  rÄ   c                 C   s²   t |ƒ|_t |¡|_| d¡}|rt|ƒ|_t|jƒ}|r-|j	t
v r)|j	|kr)n||_	n|jr?|jt tj¡kr?d|_d|_	|  ¡  |  |¡ t d|j|j|j|j	|j¡ |S )Nr‚  r   zgMeeting %s was synced from Recall AI. Bot id: %s. Bot status: %s. Meeting status: %s. Bot sub code: %s.)rƒ  r„  rà   rá   r…  ru   r†  r‡  rˆ  rÂ   r[  r   r¦   r   r§   r©   rª   r?   r  r­   rÎ   r‰  )r“   rÄ   r�  r‚  rŠ  r+   r+   r,   Úsync_meeting_from_recall_botó  s0   




úrŒ  Úrecording_dataÚmark_links_refreshedc           
   	      sR  ˆs
t  dˆ¡ d S ˆ d¡pi }| d¡pi }| d¡pi }| d¡p%i ‰| d¡p,i ‰| d¡p3i  d¡‰ | d¡p=i  d¡‰t| ˆƒ}|rK|jnd ‰d	td
tf‡ ‡‡‡‡‡‡‡fdd„}t| ˆƒ}	|	sptˆd�}	|  |	¡ ||	ƒ z|  ¡  W n t	y—   |  
¡  t| ˆƒ}	|	s�‚ ||	ƒ |  ¡  Y nw |  |	¡ t  dˆ|	j|	j¡ |	S )NzZRecording sync was skipped for meeting %s because Recall AI did not return recording data.Úmedia_shortcutsÚaudio_mixedÚvideo_mixedr8  Úparticipant_eventsÚdataÚdownload_urlrÇ   r%   c                    s0  ˆ  d¡| _ˆ  d¡pi   d¡p| jpd| _tˆ  d¡ƒp| j| _tˆ  d¡ƒp*| j| _t| jƒs>tˆ ˆˆˆ  d¡dd�| _t| j	ƒsPtˆˆˆˆ  d¡d	d�| _	ˆ  d
¡pVi   d¡| _
ˆ  d
¡pai   d¡| _ˆ  d
¡pli   d¡| _ˆ  d
¡pwi   d¡| _ˆ  d
¡p‚i   d¡| _t ˆ¡| _ˆr–t tj¡| _| S )Nr­   rÂ   Úcoder   Ú
started_atr  rZ   )re   rf   rn   rg   r[   r“  r”  Úprovider_data_download_urlÚparticipant_events_download_urlÚspeaker_timeline_download_urlÚparticipants_download_url)ru   rÔ   rÂ   r†  r–  rd  rŠ   Úaudio_download_urlr�   Úvideo_download_urlÚtranscript_download_urlÚ%transcript_provider_data_download_urlr˜  r™  rš  rà   rá   Úrecording_payloadr   r¦   r   r§   Údownload_urls_refreshed_at)rÇ   ©r›  rŽ  rf   Úmeeting_user_idr’  r�  Útranscript_shortcutrœ  r+   r,   Úapply_recording_fields#  s:    
û
ûz<upsert_recording_from_recall.<locals>.apply_recording_fields©rf   zTRecording details were saved for meeting %s. Recording id: %s. Recording status: %s.)r?   r  ru   rÐ   re   r   rÌ   r¨   r©   r   Úrollbackrª   rÔ   rÂ   )
r“   rf   r�  rŽ  Ú	shortcutsr�  r‘  rÄ   r¤  rÇ   r+   r¡  r,   Úupsert_recording_from_recall  sH   
$



ú
ür¨  Útranscript_datac                 C   sâ   ddl m} t| |ƒ}|s||d�}|  |¡ | d¡|_| d¡p#i  d¡p(d|_| d¡p0i  d	¡|_| d¡p;i  d
¡|_| d¡pFi  d¡pKi  d¡|_	t
 |¡|_d |_d |_|  ¡  |  |¡ t d||j|j¡ |S )Nr   ri  r¥  r­   rÂ   r•  r   r“  r”  r—  ÚproviderÚrecallai_asyncÚlanguage_codezTTranscript creation request was saved for meeting %s. Transcript id: %s. Status: %s.)rk  rj  r5  r¨   ru   rq  rÂ   r”  r—  ry  rà   rá   Útranscript_payloadr}  r  r©   rª   r?   r  )r“   rf   r©  rj  r8  r+   r+   r,   Úsave_recall_transcript_request]  s,   


 
ür®  c                 C   s’  t | |ƒ}|st| ||ƒS | d¡|_| d¡pi  d¡p|j|_| d¡p'i  d¡|_| d¡p2i  d¡|_| d¡p=i  d¡pBi  d	¡|_t 	|¡|_
|jd
krxt| d¡pYi  d¡ƒpct tj¡|_|  t¡ tj|k¡ ¡ }|rwd|_n<|jdv r�| d¡pƒi  d¡pˆd|_|  t¡ tj|k¡ ¡ }|rœd|_n|jdkr´|  t¡ tj|k¡ ¡ }|r´d|_|  ¡  |  |¡ t d||j|j¡ |S )Nr­   rÂ   r•  r“  r”  r—  rª  r«  r¬  rx  rã   r   >   rt  rw  Úsub_codezRecall AI transcript failedr!   r   rø   zMTranscript details were synced for meeting %s. Transcript id: %s. Status: %s.)r5  r®  ru   rq  rÂ   r”  r—  ry  rà   rá   r­  r†  r   r¦   r   r§   r  r¢   r   r£   r­   r¤   r}  r©   rª   r?   r  )r“   rf   r©  r8  rÄ   r+   r+   r,   Úsync_recall_transcript_detailsy  sD   
 
&€
€

ür°  Únormalized_payloadc                 C   sî   t | |ƒ}|st| |ƒ}| d¡pg }| d¡pg }| d¡p i }| d¡p'd}t |¡|_t |¡|_t |¡|_||_d }|D ]}	|	 d¡}
t	|
t
tfƒrXt|pSdt
|
ƒƒ}qA|d ur`||_|  ¡  |  |¡ t d|t|ƒt|ƒ¡ |S )	NÚsegmentsrz  r{  r|  r/   Úendr   zLTranscript content was saved for meeting %s. Segments: %s. Participants: %s.)r5  rm  ru   rà   rá   r~  rz  r{  r|  Ú
isinstancerQ   ÚfloatrP   rv  r©   rª   r?   r  rC   )r“   rf   r±  r8  r²  rz  r{  r|  Úmax_endÚsegmentÚ	end_valuer+   r+   r,   Úsave_recall_transcript_contentŸ  s8   


€
ür¹  c                 C   s&   t | |ƒ}|s	dS |jrdS |jdv S )NFT>   rx  r   )r5  rq  rÂ   )r“   rf   r8  r+   r+   r,   Ú#recall_transcript_already_requestedÅ  s   

rº  Ú
webhook_idÚeventÚbot_idÚtranscript_idÚstatus_codeÚstatus_sub_codec	                 C   sŽ   |   t¡ tj|k¡ ¡ }	|	rt d||¡ |	dfS t|||||||t |¡d�}
|  	|
¡ |  
¡  |  |
¡ t d|||||||¡ |
dfS )NzGRecall webhook %s was ignored because it was already stored. Event: %s.F)r»  r¼  r½  rn   r¾  r¿  rÀ  rß   zxRecall webhook %s was stored. Event: %s. Bot id: %s. Recording id: %s. Transcript id: %s. Status code: %s. Sub code: %s.T)r¢   r   r£   r»  r¤   r?   r  rà   rá   r¨   r©   rª   )r“   r»  r¼  rß   r½  rn   r¾  r¿  rÀ  rl  Úwebhook_eventr+   r+   r,   Úcreate_recall_webhook_eventÎ  s8   ø


ø
rÂ  Úwebhook_event_idc                 C   rÉ   rÊ   )r¢   r   r£   r­   r¤   )r“   rÃ  r+   r+   r,   Úget_recall_webhook_eventø  rÍ   rÄ  c                 C   sJ   |sd S |   t¡ tj|k¡ tj d ¡¡ tj ¡ ¡ 	¡ }|s"d S |jS rÊ   )
r¢   r   r£   r½  rÀ  Úisnotr¬   r­   Údescr¤   )r“   r½  rÁ  r+   r+   r,   Ú!get_latest_recall_status_sub_codeü  s   ûrÇ  rÁ  c                 C   s<   t  tj¡|_d |_|  ¡  |  |¡ t 	d|j
|j¡ |S )Nz1Recall webhook %s finished processing. Event: %s.)r   r¦   r   r§   Úprocessed_atÚprocessing_errorr©   rª   r?   r  r»  r¼  )r“   rÁ  r+   r+   r,   Úmark_recall_webhook_processed  s   
rÊ  r}  c                 C   s0   ||_ |  ¡  |  |¡ t d|j|j|¡ |S )NzARecall webhook %s failed during processing. Event: %s. Error: %s.)rÉ  r©   rª   r?   rt  r»  r¼  )r“   rÁ  r}  r+   r+   r,   Úmark_recall_webhook_failed  s   
ürË  r¯  c                 C   s8   |s|S ||_ |  ¡  |  |¡ t d|j||j ¡ |S )NzcMeeting %s bot sub code was updated from Recall AI. Incoming sub code: %s. Result bot_sub_code: %s.)r‰  r©   rª   r?   r  r­   )r“   rÄ   r¯  r+   r+   r,   Úsave_meeting_bot_sub_code#  s   
ürÌ  c                 C   s^   |d ur
t  |¡|_||_t||d�}|r||_|  ¡  |  |¡ t 	d|j
||j|j¡ |S )N)rß   zfMeeting %s status was updated from Recall AI. Incoming status: %s. Meeting status: %s. Bot status: %s.)rà   rá   r…  r„  rˆ  rÂ   r©   rª   r?   r  r­   )r“   rÄ   r¿  rß   rŠ  r+   r+   r,   Ú#set_meeting_status_from_recall_code2  s    
ûrÍ  c                 C   s2   | sd S z
t  |  dd¡¡W S  ty   Y d S w )NÚZz+00:00)r   Úfromisoformatrú   rR   r‰   r+   r+   r,   r†  E  s   ÿr†  c                 C   s(   |   d¡pg }|r|d   d¡pdS dS )NÚstatus_changeséÿÿÿÿr•  r   )ru   )r�  rÐ  r+   r+   r,   rƒ  N  s   rƒ  c                 C   sb   | sd S |   d¡p
i }t|  d¡tƒr|  d¡pi   d¡S t|  d¡tƒr/|  d¡p+i   d¡S d S )Nr“  r¯  rÂ   )ru   r´  Údict)rß   r“  r+   r+   r,   Ú_extract_recall_bot_sub_codeU  s   rÓ  c                 C   s    | dv rt |ƒ}|dkrdS i dd“dd“dd“dd“dd“d	d
“d
d
“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“ddddddœ¥}| | ¡S )N>   Ú
call_endedr   Úbot_kicked_from_waiting_roomr   r   Újoining_callr   Úin_waiting_roomr"   Úin_call_not_recordingr$   Úin_call_recordingr#   rÔ  r   Úrecording_doner   r    rx  r   Úfatalr   rø   r   r!   )r   rt  rø   r   r!   )rÓ  ru   )r¿  rß   r¯  Úmappingr+   r+   r,   rˆ  `  s\   ÿþýüûúùø	÷
öõôóòñðïê
rˆ  c                 C   s   | r| t  tj¡krdS dS )Nr   r   )r   r¦   r   r§   )rº   r+   r+   r,   rÃ   €  s   rÃ   )NFFrÊ   )	NNr·   NFNNNN)FNNNN)	rL  NNNNNNNN)F)NNNNN)yrà   r`   r(   r   r   r   Úpathlibr   Úurllib.parser   rt   Úsqlalchemy.excr   Úsqlalchemy.ormr   Úapp.logging_utilsr	   rk  r
   r   r   r   r   r   r   r   Ú__name__r?   r6  ri   r-   rL   rQ   rT   rd   rm   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/  r0  r1  r3  r.  r<  r=  r  rA  rC  rG  rH  rJ  rK  rW  r[  r]  ra  re  rf  rg  rh  rm  r5  rr  r€  r‹  rŒ  r¨  r®  r°  r¹  rº  rÂ  rÄ  rÇ  rÊ  rË  rÌ  rÍ  r†  rƒ  rÓ  rˆ  rÃ   r+   r+   r+   r,   Ú<module>   sB   (!þýüûú
ùÿýüûú
ù/0ùÿþýüûú
ù'ôÿþýüûúùø	÷
öõ
ô"ôÿþýüûúùø	÷
öõ
ô0ÿþýüûúùø	÷
öõô
ó)ÿþ
ýÿþ
ýÿþ
ýÿ
þ	ÿþý
üÿþý
ü:	ôÿþýüûúùø	÷
öõ
ô&ÿþý
üÿþý
üõÿþýüûúùø	÷
ö
õ$ÿþý
üÿþý
ü

.õÿþýüûúùø	÷
ö
õ*					&  üÿþý
üN&ÿþ
ý&÷ÿþýüûúùø	
÷*	&	* 