U
    —âñjØ˜  ã                   @   s¨  d dl mZmZ d dlmZmZ d dlmZmZ d dlm	Z	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 d dlmZ ddlmZmZ ddlmZmZ ddgZdZ dZ!ej"ddgdd�dd„ ƒZ#ej"ddgd�eƒ dd„ ƒƒZ$ej"ddgd�eƒ dd„ ƒƒZ%ej"d dgd�eƒ d!d"„ ƒƒZ&ej"d#dgd�eƒ d$d%„ ƒƒZ'ej"d&ddgd�d'd(„ ƒZ(ej"d)dgd�d*d+„ ƒZ)d,d-„ Z*d.d/„ Z+d0d1„ Z,d2d3„ Z-dS )4é    )ÚrequestÚjsonify)Újwt_requiredÚget_jwt_identity)ÚdatetimeÚ	timedelta)ÚcredentialsÚ	messagingN)Ú
DESCENDING)ÚObjectIdé   )Únotifications_bp)Úget_dbÚSERVICES_DB_MAPÚUSER_DATABASE_NAMEÚinsert_log_in_user_history)Úetiqueta_centro)Úsubscribe_token_to_topicÚsend_topic_notification)Úenviar_alerta_whatsappÚenviar_mensaje_prueba_waZ56976494291Z56935741906ÚITG_CHILE_WHATSAPP_SECUREZevento_centroz8/<SERVICE>/ingest_notifications/<REGION>/<AREA>/<CENTRO>ÚPOSTF)ÚmethodsÚstrict_slashesc           8      C   sF  |   ¡ }t |¡}|s.tdd| › d�iƒdfS �zÊ| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|› d|› d|› �}	tj}
|
sªtddiƒd	fW S t|
t	ƒrÀt
|
 ¡ ƒ}
t|
t
ƒsÜtd
diƒd	fW S tƒ }|| }g }|
D ]L}|	t ¡ d| ¡ › �| dd¡d| dd¡| dd¡dœdœ}| |¡ qò|�sXtd
diƒdfW S |j |¡}dd„ |jD ƒ}|d d }|d d d }|d d d }d}d}|  ¡ }d |k�sØd!|k�sØd"|k�sØd#|k�râd$}d%}nd&|k�söd'|k�rþd(}d)}t|||||ƒ}|› d|› d*| ¡ › �}|› d*|› d+|› d,�}t|	||||d |	d-d.œ|d/d0œd1�}|t }|d2 }|  ¡ }|  ¡ }|  ¡ › d|  ¡ › d|  ¡ › �} |}!d3|› d4|› d4| › d4|!› �}"|"› d5�}#|"› d6�}$| |#d7|$d7d d8œi¡}%g }&|%D ]Þ}'zŽ|' d9i ¡}(|( |i ¡})|) |i ¡}*|* | i ¡}+|+ |!i ¡},|, d:¡}-|-�r†t|-ƒ d;d¡ dd¡ ¡ }.t|.ƒd<k�r†|.|&k�r†|& |.¡ W nH tk
�rÐ }/ z(td=|' d>¡› d?|/› �ƒ W Y ¢�qöW 5 d }/~/X Y nX �qö|&�sðtd@|!› dA| › �ƒ g }0g }1|&�r²|&D ]®}2t|2tdBt|||||	ƒid dC�}3d }4|3 dD¡dEk�rr|3 di ¡}5dF|5k�rrt|5dF ƒdGk�rr|5dF dG d }4|2|4dHt ¡ dIœ}6|1 |6¡ |0 |2|3 dD¡|4|3 d¡dJœ¡ �q|1�rä|�rä|jd }7|j dK|7idL|1dHdMœi¡ tdN|||0dOœƒdfW S  tk
�r@ }/ z&tdP|/› �ƒ tddQiƒdRf W Y ¢S d }/~/X Y nX d S )SNÚmensajez
Servicio 'z' no soportado.é”  Ú Ú Ú-z	Sin datosé�  ÚmsgzSe espera lista o dictzAlerta Údatau   Alerta sin descripciÃ³nÚcriticalÚidZ
unknown_idÚtime)Úlocal_idÚ
local_time)Ú	centro_idÚserver_timestampÚtitleÚmessageZseverityÚraw_datazNo hay alertaséÈ   c                 S   s   g | ]}t |ƒ‘qS © )Ústr)Ú.0Úoidr.   r.   úA/var/www/itgmanager/itgmanager/blueprints/notifications/routes.pyÚ
<listcomp>J   s     z(ingest_notifications.<locals>.<listcomp>éÿÿÿÿr+   r,   r&   r'   u   âš ï¸�z#FFA500ZfalloÚerroru   crÃ­ticou   pÃ©rdidau   ðŸš¨z#FF0000ÚokZrestablecidou   âœ…z#00FF00z - z registrado a las z de hoyZFCM_PLUGIN_ACTIVITY)ÚserviceÚnotification_idr(   Zclick_actionZalerts_channel)ÚcolorZandroid_channel_id)r(   r*   ÚbodyZdata_payloadÚextra_kwargsÚusersz	permisos.Ú.z.statusz.phoneT)z$existsz$neÚpermisosÚphoneú+é   u'    Error extrayendo telÃ©fono de usuario Úusernameú: z5 Info: Nadie tiene configurado recibir WhatsApp para z en Úcentro)Znumero_destinoZnombre_plantillaZheader_varsZ	body_varsÚstatusÚsuccessÚmessagesr   Úsent)r?   ÚwamidrE   Ú	timestamp)ÚnumerorE   rI   r"   Ú_idú$set)Zwhatsapp_logZdelivery_statuszNotificaciones procesadas)r!   Úinserted_idsÚpush_statusZwhatsapp_statuszError: úError internoéô  ) Úlowerr   Úgetr   ÚreplaceÚ
capitalizer   ÚjsonÚ
isinstanceÚdictÚlistÚvaluesr   r   ÚnowÚupperÚappendÚnotificacionesÚinsert_manyrN   r   r   r   Úfindr/   ÚstripÚlenÚ	ExceptionÚprintr   ÚPLANTILLA_NANOOXÚ
update_one)8ÚSERVICEÚREGIONÚAREAÚCENTROÚservice_keyÚtarget_db_nameZr_normZa_normZc_normZcentro_id_unificadoZreceived_dataÚclientÚdbZdocs_to_insertÚitemÚdocÚresultrN   Zultimo_mensajeZid_jaulaZ
event_timeZemoji_statusZ	color_hexZ	msg_lowerZnombre_visibleZtitulo_eleganteZcuerpo_eleganterO   Údb_usersÚ	col_usersÚr_keyÚa_keyÚc_keyZs_keyZpath_to_serviceZpath_statusZ
path_phoneZusuarios_destinatariosZlista_numerosÚusuarior>   Úregion_dataÚ	area_dataZcentro_dataZservicio_dataZtelefonoZtelefono_limpioÚeZwhatsapp_resultsZwhatsapp_log_dbrK   rE   rI   Z	data_respÚ	log_entryZlast_alert_idr.   r.   r2   Úingest_notifications   s   
 




þú(üþõ 

  þ
 ü	ü
ü
þÿþ
üûr|   z/api/notificationsÚGET)r   c               
   C   sÌ  �zzt ƒ } t| ƒ}|s.tg ddidœƒdfW S tj d¡}tj d¡}ttj dd¡ƒ}ttj d	d
¡ƒ}t ¡ }|t	|d� }d|id|idœ}|r¼||kr¨||d< ntg ddœƒdfW S t
ƒ }	g }
|rèt | ¡ ¡}|râ|gng }ntt ¡ ƒ}|D ]V}z6|	| d }| |¡ dt¡ |¡}|
 t|ƒ¡ W qø tk
�rL   Y qøY qøX qø|
jdd„ dd� |
d |… }dd„ |D ƒ}t| ¡ ƒ}tƒ }|D ]Z}z@|	| d  d|i| dœddi¡}|D ]}| |d ¡ �q¾W n   Y �q’Y nX �q’g }|D ]h}|d }t|ƒ|d< | d i ¡}t|tƒ�r8| d!d ¡|d!< nd |d!< |d= ||k|d"< | |¡ �qöt|| t|ƒd#œdœƒdfW S  tk
�rÆ } z*td$|› �ƒ td%t|ƒiƒd&f W Y ¢S d }~X Y nX d S )'NÚcountr   )r"   Z
query_infor-   r(   r7   Úlimité2   Úhoursé   )r�   z$gtez$in)r)   r(   z$Acceso denegado al centro solicitado)r"   r!   é“  r^   r)   c                 S   s   |   dd¡S )Nr)   r   )rS   )Úxr.   r.   r2   Ú<lambda><  ó    z#get_notifications.<locals>.<lambda>T)ÚkeyÚreversec                 S   s   i | ]}|d  |“qS )rL   r.   )r0   rp   r.   r.   r2   Ú
<dictcomp>@  s      z%get_notifications.<locals>.<dictcomp>Únotificaciones_lecturas©r8   Ú
user_emailr8   r   rL   r$   r,   r&   Úread)Úuserr~   zError en GET: r5   rQ   )r   Ú"obtener_centros_permitidos_usuarior   r   ÚargsrS   Úintr   r[   r   r   r   rR   rY   rZ   r`   Úsortr
   r   Úextendrc   ÚkeysÚsetÚaddr/   rW   rX   r]   rb   rd   )Úcurrent_usernameZallowed_centersZreq_centro_idZservice_reqr   Zhours_lookbackZutc_nowZcutoff_timeÚqueryrm   Zraw_resultsZ	target_dbZdbs_to_searchÚdb_nameÚcolÚcursorZfinal_sliceZnotif_ids_mapZlist_of_idsZread_setZreads_cursorÚrÚresponse_datarp   Zdoc_oidr,   rz   r.   r.   r2   Úget_notifications  sŒ    þ
 þû þþúrž   z/api/notifications/subscribec               
   C   sV  �zt ƒ } t ¡ }| d¡}|s2tddiƒdfW S tƒ }|t d  d| idd|ii¡ g }tƒ }|t d  	d| i¡}|D ]}t
||ƒr|| |¡ q|d}|ròz"|D ]}	t|g|	ƒ q¤t|ƒ}W n0 tk
rð }
 ztd	|
› �ƒ W 5 d
}
~
X Y nX tdd| › d|› d�|dœƒdfW S  tk
�rP }
 ztdt|
ƒiƒdf W Y ¢S d
}
~
X Y nX d
S )u/  
    VÃ­a Correcta: 
    1. Recibe un token (que asumimos es NUEVO o VÃ�LIDO para este usuario).
    2. Calcula permisos reales en DB.
    3. Suscribe SOLO a los permisos reales.
    NO intenta desuscribir de lo prohibido, porque confiamos en que el token
    es fresco o exclusivo de este usuario.
    Ú	fcm_tokenr!   zFalta tokenr    r<   rB   rM   r   zError suscribiendo: NrF   úUsuario z suscrito a z	 centros.)rE   r!   Ztopicsr-   r5   rQ   )r   r   Úget_jsonrS   r   r   r   rf   Ú%obtener_todos_los_topicos_del_sistemaÚfind_oneÚverificar_permiso_inversor]   r   rb   rc   rd   r/   )r—   r"   rŸ   rm   Útopicos_permitidosZset_universoÚuser_docZtopicZ	suscritosÚtrz   r.   r.   r2   Úsubscribe_devicep  sD    

þ
 ýür¨   z/api/logout_pushc            	   
   C   s  zÎt ƒ } t ¡ }| d¡}|s0tddiƒdfW S td| › �ƒ tƒ }d}|rˆ|D ]6}z$t |g|¡}|j	dkrv|d7 }W qP   Y qPX qPt
ƒ }|t d  d	| id
ddii¡ td|› d�ƒ tddiƒdfW S  tk
�r } z*td|› �ƒ tdt|ƒiƒdf W Y ¢S d}~X Y nX dS )u‚   
    Ruta de LIMPIEZA: Recibe el token que se va a destruir y
    fuerza la desuscripciÃ³n de todos los tÃ³picos del sistema.
    rŸ   r!   zToken requeridor    u.   ðŸ‘‹ [LOGOUT] Iniciando limpieza para usuario r   r   r<   rB   z$unsetr   u   âœ… [LOGOUT] Token limpiado de z temas y eliminado de DB.zToken limpiador-   zError en logout_push: r5   rQ   N)r   r   r¡   rS   r   rd   r¢   r	   Zunsubscribe_from_topicZsuccess_countr   r   rf   rc   r/   )	r—   r"   rŸ   Ztodos_los_temasr~   ZtemaÚresponserm   rz   r.   r.   r2   Úlogout_push_device±  s6    

 
þrª   z /ack/<SERVICE>/<NOTIFICATION_ID>c              
   C   s  �zÈt  |¡s tddiƒdfW S |  ¡ }t |¡}|sHtddiƒdfW S tƒ }|sdtddiƒdfW S tƒ }|| }|j 	dt |ƒiddd	œ¡}|s¤tdd
iƒdfW S |j
jt |ƒ|dœdt |ƒ|| d¡t ¡ dœidd�}|jrædnd}	td|› d|› d|	› d�ƒ |j�r¶zt|t }
|
d }|
j 	d|iddi¡}|�rNd|k�rN|d n|}| ¡ | dd¡| dd¡dœ}t|||dƒ W n2 tk
�r´ } ztd|› �ƒ W 5 d }~X Y nX td!d"|	d#œƒd$fW S  tk
�r } z,td%|› �ƒ td&t|ƒd'œƒd(f W Y ¢S d }~X Y nX d S ))u…   
    Registra la lectura ('firma') de un usuario sobre una notificaciÃ³n.
    Simula el evento "Usuario hizo clic en la alerta".
    r!   u   ID de notificaciÃ³n invÃ¡lidor    u   Servicio no vÃ¡lidor   u   Falta el parÃ¡metro user_emailrL   r   )r(   r+   u(   La notificaciÃ³n ha expirado o no exister‹   rM   r(   )r8   rŒ   r(   Zread_atT)ÚupsertÚCreatedZUpdatedz[ACK] z
 -> Notif z (ú)Úhistorial_usersÚemailrB   ÚDesconocidor+   zAlerta sin texto)r7   rD   r+   Úread_notificationz%Error escribiendo historial usuario: NrF   z Lectura registrada correctamente)rE   r!   Úactionr-   zError en ACK: zError interno del servidor)r!   r5   rQ   )r   Úis_validr   rR   r   rS   r   r   r^   r£   rŠ   rf   r   r[   Úupserted_idrd   r   r<   r\   r   rc   r/   )rg   ZNOTIFICATION_IDrk   rl   rŒ   rm   rn   Znotif_existsrq   r²   rr   Úcol_historyr¦   Úreal_usernameÚlog_datarz   r.   r.   r2   Úacknowledge_notificationâ  sz    

þüÿóþ

ýü ýür¸   z/whatsapp/webhookc               
      sx  t jdkrltj dd¡} t j d¡}t j d¡}t j d¡}|dkr\|| kr\tdƒ |d	fS td
ƒ dS �nt jdk�rtt j}�z¼| di g¡d }| di g¡d }| di ¡}d|k�r:tƒ }|d D �]l}	|	d }
|	d }|	d }|	 d¡}td|› d|
› �ƒ t	t
 ¡ ƒ}|D ]R}|| }|j}| d|id|
t ¡ dœi¡}|jdk�rtd|› �ƒ  �qj�q|
dkrÊ|t }|d }|d }‡ fdd „‰ | i d!d!d!d"œ¡}d }|D ],}| d#¡}|�r²ˆ ||ƒ�r²|} �qà�q²|�r(| d$d%¡}d&d'd(|d)|› d*�d+œ}t|||d,ƒ td-|› �ƒ qÊtd.|› d/�ƒ qÊW n2 tk
�rn } ztd0|› �ƒ W 5 d }~X Y nX d1S d S )2Nr}   r   Ztu_token_aquizhub.modezhub.verify_tokenzhub.challengeZ	subscribez1[WEBHOOK] Meta ha verificado la URL exitosamente.r-   u+   [WEBHOOK] Intento de verificaciÃ³n fallido.)Ú	Forbiddenrƒ   r   Úentryr   ÚchangesÚvalueZstatusesrE   r$   Zrecipient_idrJ   z [WHATSAPP] z -> Estado: zwhatsapp_log.wamidrM   )zwhatsapp_log.$.statuszwhatsapp_log.$.updated_atz# [DB UPDATE] Alerta actualizada en r�   r<   r®   c                    s¦   t |ƒ ¡ }t| tƒr~|  ¡ D ]\\}}|dkr\|r\t |ƒ dd¡ dd¡ ¡ }||kr\ dS t|ttfƒrˆ ||ƒr dS qn$t| tƒr¢| D ]}ˆ ||ƒrŒ dS qŒdS )Nr?   r@   r   r   TF)r/   ra   rW   rX   ÚitemsrT   rY   )r"   Ztarget_phoneÚkÚvZdb_phonero   ©Úexiste_telefono_en_estructurar.   r2   rÁ   ‰  s    




z7whatsapp_webhook.<locals>.existe_telefono_en_estructurar   )rB   r?   r>   r>   rB   r°   ZWHATSAPPu   NotificaciÃ³n ExternaZmessage_readr    u    leyÃ³ la alerta.)r7   rD   r²   Z
message_idÚdetailsr±   u,   [HISTORIAL] Ã‰XITO: Registrado 'Visto' para u    [HISTORIAL] TelÃ©fono u4    reportÃ³ lectura pero no se encontrÃ³ dueÃ±o en DB.z [WEBHOOK ERROR] Procesando: )ZEVENT_RECEIVEDr-   )r   ÚmethodÚosÚenvironrS   r�   rd   rV   r   rY   r   rZ   r^   rf   r   r[   Úmodified_countr   r`   r   rc   )ZVERIFY_TOKENÚmodeÚtokenÚ	challenger"   rº   r»   r¼   rm   rE   Z
new_statusZwa_idZnumero_metarJ   Z
target_dbsr™   rn   Z	col_notifrq   rr   rs   rµ   Zcursor_usersZusuario_encontradoÚur>   r¶   r·   rz   r.   rÀ   r2   Úwhatsapp_webhookD  sŒ    


þÿþ	



ûü rË   z/test-whatsapp/<numero>c              
   C   s~   z4t | ƒ}|d dkr$t|ƒdfW S t|ƒdfW S W nD tk
rx } z&td|› �ƒ tddiƒdf W Y ¢S d	}~X Y nX d	S )
uÌ   
    Ruta de prueba. Se usa GET para poder ejecutarla fÃ¡cilmente 
    desde la barra de direcciones del navegador.
    Ejemplo: https://test.itgchile.com/itg_7xR9L2m_secure/test-whatsapp/56912345678
    rE   rF   r-   r    zError en ruta de WhatsApp: r!   rP   rQ   N)r   r   rc   rd   )rK   Ú	resultadorz   r.   r.   r2   Útrigger_whatsapp_testÊ  s    rÍ   c              	   C   s  t ƒ }|t j}| d| i¡}|r*d|kr.g S g }| di ¡}| ¡ D ]Ò\}}| ¡ D ]À\}}	|	 ¡ D ]®\}
}d}| ¡ D ](\}}t|tƒrz| d¡dkrzd} q¤qz|rfz^|
 d¡}t	|ƒdk�r|d  
¡ }|d	  
¡ }|d
  
¡ }|› d|› d|› �}| |¡ W qf   Y qfX qfqVqF|S )z—
    Retorna una lista de IDs de centros (formato Topic) permitidos para el usuario.
    Ej: ['Loslagos-Puertomontt-Itg', 'Aysen-Aysen-Puntacola']
    rB   r>   FrE   Tr   é   r   r   r‚   )r   r   r<   r£   rS   r½   rW   rX   Úsplitrb   rU   r]   )rB   rm   Ú	users_colrŽ   Zcentros_permitidosr>   ÚregionÚareasÚareaÚcentros_dictÚ
centro_rawÚ	serviciosÚtiene_accesoÚsrvr"   ÚpartsÚc_nameÚa_nameÚr_nameZformatted_idr.   r.   r2   r�   Þ  s6    

 r�   c              
   C   sp  �z(t ƒ }|t d }| d| i¡}|r0d|kr6g W S g }| di ¡}| ¡ D ]Ö\}}| ¡ D ]Ä\}}	|	 ¡ D ]²\}
}d}| ¡ D ](\}}t|tƒr‚| d¡dkr‚d} q¬q‚|rnz^|
 d¡}t|ƒdk�r|d	  	¡ }|d
  	¡ }|d  	¡ }|› d|› d|› �}| 
|¡ W qn   Y qnY qnX qnq^qN|W S  tk
�rj } z td| › d|› �ƒ g  W Y ¢S d}~X Y nX dS )u¹   
    Consulta la DB y retorna una lista de los tÃ³picos (Centros) 
    a los que el usuario tiene acceso real.
    Retorna ej: ['Loslagos-Puertomontt-Itg', 'Aysen-Aysen-Puntacola']
    r<   rB   r>   FrE   Tr   rÎ   r   r   r‚   zError obteniendo permisos para rC   N)r   r   r£   rS   r½   rW   rX   rÏ   rb   rU   r]   rc   rd   )rB   rm   rÐ   rŽ   r¥   r>   rÑ   rÒ   rÓ   rÔ   rÕ   rÖ   r×   rØ   r"   rÙ   rÚ   rÛ   rÜ   Z	topic_fmtrz   r.   r.   r2   Úobtener_topicos_permitidos  s>    
rÝ   c                  C   sÞ   t ƒ } | t d }tƒ }| i ddi¡}|D ]¬}| di ¡}| ¡ D ]’\}}| ¡ D ]€\}}	|	 ¡ D ]n\}
}zX|
 d¡}t|ƒdkrÂ|d  ¡ }|d  ¡ }|d  ¡ }| 	|› d|› d|› �¡ W qd   Y qdX qdqTqDq,|S )u¤   
    Escanea la colecciÃ³n de usuarios para descubrir TODOS los centros (tÃ³picos) que existen.
    Retorna un SET con strings tipo 'Loslagos-Puertomontt-Itg'.
    r<   r>   r   r   rÎ   r   r‚   )
r   r   r•   r`   rS   r½   rÏ   rb   rU   r–   )rm   rÐ   Ztodos_los_topicosr›   rŽ   r>   rÑ   rÒ   rÓ   ÚcentrosrÕ   Ú_rÙ   ÚcÚarœ   r.   r.   r2   r¢   <  s&    
 r¢   c              
   C   sü   zº|  d¡}t|ƒdkrW dS |\}}}| ¡ }| ¡ }| ¡ }|› d|› d|› �}	|  di ¡}
|
 |i ¡ |i ¡ |	¡}|s„W dS | ¡ D ](\}}t|tƒrŒ| d¡dkrŒ W dS qŒW dS  tk
rö } ztd|› d|› �ƒ W Y ¢dS d	}~X Y nX d	S )
u¾   
    Recibe un TÃ³pico: "Loslagos-Puertomontt-Itg"
    Lo transforma a Key DB: "itg-puertomontt-loslagos" (Al revÃ©s y minÃºsculas)
    Y verifica si existe en los permisos del usuario.
    r   rÎ   Fr>   rE   Tz'Error verificando permiso inverso para rC   N)	rÏ   rb   rR   rS   r½   rW   rX   rc   rd   )r¦   Z	topic_strrÙ   Zr_topicZa_topicZc_topicrt   ru   rv   Zdb_centro_key_reversedr>   Údatos_centroÚservicioÚinforz   r.   r.   r2   r¤   Y  s(    


r¤   ).Úflaskr   r   Úflask_jwt_extendedr   r   r   r   Zfirebase_adminr   r	   ZpytzÚpymongor
   Úbsonr   r   r   Úshared_db_utilsr   r   r   r   Úblueprints.etiquetasr   Zpush_servicer   r   Zwhatsapp_servicer   r   ZPHONE_TO_SENDr   re   Úrouter|   rž   r¨   rª   r¸   rË   rÍ   r�   rÝ   r¢   r¤   r.   r.   r.   r2   Ú<module>   sL   
 kl?/`
 
)5