o
    pjk)                     @  s  d Z ddl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m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mZ edZedZG dd deZd'ddZd'ddZd(ddZ G dd dZ!d)d d!Z"d)d"d#Z#d*d+d%d&Z$dS ),zEMessaging orchestration: policy, idempotency, rendering and delivery.    )annotationsN)datetime	timedelta)	parseaddr)AuditLogger)get_platform_loggerlog_structured)QuotaExceededconsume)SecretsManager   )default_registry)MessagingRepository)TemplateErrorrender_templatemessaging_servicez^\+[1-9][0-9]{7,14}$c                      s&   e Zd Zdddd fddZ  ZS )MessagingErrori  Fstatus	retryablecodestrmessager   intr   boolreturnNonec                  s&   |||| _ | _| _t | d S N)r   r   r   super__init__)selfr   r   r   r   	__class__ !apps/messaging_service/service.pyr      s   zMessagingError.__init__)
r   r   r   r   r   r   r   r   r   r   )__name__
__module____qualname__r   __classcell__r#   r#   r!   r$   r      s    r   valuer   r   c                 C  sh   t ddt| pd}|drt|dkrd|dd   }n	|dr(d| }t|s2td	d
|S )Nz	[\s().-]+ 0
   z+61r   61+invalid_recipientz*Phone number must be a valid E.164 number.)resubr   
startswithlenE164	fullmatchr   )r)   compactr#   r#   r$   normalize_phone   s   


r7   c                 C  s   t t| pd \}}|t| pd ks#|ddks#t|dkr(tdd|dd\}}|r?d|vs?tdd	 |D rDtdd| d|  S )
Nr*   @r   i@  r/   zEmail address is invalid..c                 s  s    | ]}|  V  qd S r   )isspace).0cr#   r#   r$   	<genexpr>-   s    z"normalize_email.<locals>.<genexpr>)	r   r   stripcountr3   r   rsplitanylower)r)   _addresslocaldomainr#   r#   r$   normalize_email(   s   .

rG   channelc                 C  sZ   |dkr| d d dt dt| d   | dd   S | dd\}}|d d d	 | S )
Nsms   *      r8   r   z***@)maxr3   split)r)   rH   rE   rF   r#   r#   r$   mask_recipient2   s   .rQ   c                   @  s>   e Zd ZddddZdd	d
Zdd ZdddZdddZdS )MessagingServiceNr   r   c                 C  s(   |pt  | _|p
t | _|pt | _d S r   )r   
repositoryr   registryr   secrets)r    rS   rT   rU   r#   r#   r$   r   :   s   zMessagingService.__init__contextdictpayloadc                   s*  t |}t|}t|dpd}t|dpd }t|dp#d }t|dp.d }|dvs<|r<|r<|sAtddd	t|  krMd
ksSn tdd| j||}	|	rq||	j	pag vsq||	j
phg vsq||	jpog vrxtdddd|dp~i }
|dkrt|
dnt|
d}| j|||}|stddddzt||dpi }W n ty } ztdt||d }~ww | j||d|}|rt|ddS | ||| zt|dd| ||dd W n ty } ztd d!d"d|d }~ww | j||}|std#d$d%dd&t|d'tr |d'ni  | jj||t|d(p/dp3d d|||t|||j|j|t d)pN|d*pNd fd+d,d-D d.\}}|set|ddS | ||||	j}tt d/|||j!||||j"|j#|j$d0 t% j&||d1|j#|j!|j"|d2 t|S )3NrH   r*   idempotency_keytemplate_keypurpose>   rI   emailinvalid_inputz@channel, template_key, purpose and idempotency_key are required.      z1idempotency_key must contain 8 to 128 characters.permission_deniedz@The requesting application is not allowed to send this template.  r   	recipientrI   phoner\   template_not_foundz Message template is unavailable.  template_datatemplate_invalidsend_template_v1T)replayr   	messages_)rZ   r[   )	tenant_idapp_idmetricmetadatarate_limit_exceededz Tenant messaging limit exceeded.  provider_unavailablez3No healthy provider is configured for this channel.i  r   ro   user_idcorrelation_id
request_idc                   s   i | ]}| v r| | qS r#   r#   )r;   kro   r#   r$   
<dictcomp>i   s    z2MessagingService.send_template.<locals>.<dictcomp>)resource_typeresource_id)rl   requesting_apprequested_by	operationrY   rH   recipient_normalizedrecipient_maskedrZ   template_versionr[   rt   metadata_jsonmessage_delivery_result)	rl   rm   delivery_idrH   rZ   r[   rc   r   rt   zmessaging.send_template)rl   actoractionr   r   rc   rZ   )'
_tenant_id_requesting_appr   getr>   r   r3   rS   
permissionchannels_jsontemplates_jsonpurposes_jsonr7   rG   templater   r   existing_delivery_data_check_recipient_limitsr
   r	   	providers
isinstancerW   create_deliveryrQ   keyversion_deliverallow_fallbackr   LOGGERr   r   r   rt   r   log)r    rV   rX   rl   r{   rH   r   rZ   r[   r   recipient_inputrc   r   renderedexcr   r   deliverycreatedresult_deliveryr#   rw   r$   send_template?   sz   

.$
 




zMessagingService.send_templatec                 C  sR  d}|r|n|d d }|}|D ]}t  }	|jd ur/| jj|j|j|	tdd d|jkr/q|jd urH| jj|j|j|	tdd d|jkrHq|j	rV| j
j|jd|j	dnd }
| j|j}tdt|jd }t|D ]/}|d7 }||jpyi |
|j|d |d	 |d
 d}| j|j|j||}|js|js nqm|jdkr|  S q|S )Nr   r   minutes)rl   provider_idsince)daysr   rl   rm   secret_namesubjecttexthtml)rc   r   r   r   accepted)r   utcnowper_minute_limitrS   count_sincerl   r   r   daily_limit
secret_refrU   
get_secretrT   r   driverrO   r   max_retriesrangesendconfig_jsonr~   complete_attemptr   r   r   r   )r    r   r   r   r   attemptselectedlast_deliveryprovidernowsecretr   triesrC   resultr#   r#   r$   r   w   sH    

zMessagingService._deliverrl   r   rc   r[   c                 C  sh   t  }| jj|||tdd ddkrtdddd| jj|||tdd d	d
kr2tddddd S )Nr   r   )rl   rc   r      rp   zRecipient rate limit exceeded.rq   rb   )rl   r[   r      zPurpose rate limit exceeded.)r   r   rS   r   r   r   )r    rl   rc   r[   r   r#   r#   r$   r      s     z(MessagingService._check_recipient_limitsr   c                 C  s   | j t||}|stdddd|jr | jj|jd|jdnd }| j	|j
|jp-i |}| j |j| |j|j|j|j|jt  d dS )	Nprovider_not_foundzProvider was not found.rf   rb   r   r   Z)r   r   r   	connected
latency_ms
checked_at)rS   r   r   r   r   rU   r   rl   rT   r   r   health_checkr   update_healthr   namer   r   r   r   r   	isoformat)r    rV   r   r   r   r   r#   r#   r$   r      s    zMessagingService.health_check)NNN)r   r   )rV   rW   rX   rW   r   rW   )rl   r   rc   r   r[   r   r   r   )rV   rW   r   r   r   rW   )r%   r&   r'   r   r   r   r   r   r#   r#   r#   r$   rR   9   s    
8
 rR   rV   rW   c                 C  s.   t | dpi dpd}|stdd|S )Ntenantrl   r*   tenant_context_missingz#Trusted tenant context is required.)r   r   r   )rV   rl   r#   r#   r$   r      s   r   c                 C  s,   t | dpd }|stdddd|S )Nr{   r*   caller_context_missingz/Trusted caller application context is required.ra   rb   )r   r   r>   r   )rV   trustedr#   r#   r$   r      s   r   Fc                 C  s(   | j | j| j| j| j d | j|dS )Nr   )r   rH   r   r   
created_atrt   idempotent_replay)r   rH   r   r   r   r   rt   )r   rj   r#   r#   r$   r      s
   r   )r)   r   r   r   )r)   r   rH   r   r   r   )rV   rW   r   r   )F)r   rW   )%__doc__
__future__r   r0   r   r   email.utilsr   $bridge_platform.logging.audit_loggerr   'bridge_platform.logging.platform_loggerr   r   bridge_platform.quotas.servicer	   r
   'bridge_platform.secrets.secrets_managerr   driversr   rS   r   	templatesr   r   r   compiler4   	Exceptionr   r7   rG   rQ   rR   r   r   r   r#   r#   r#   r$   <module>   s,    





p
