a
    0iWZ                  	   @   s  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 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 e  ed	Zd
Zh dZdZe de de dddZe
eeeeeeedddZe
edddZeedddZ eedddZ!eedddZ"e
ee dd d!Z#eeeed"d#d$Z$ej%edd%d&d'Z&eeeed(d)d*Z'eeeeeed+d,d-Z(ed.d/d0Z)e
eeeeed1d2d3Z*dS )4    N)Path)secure_filename)FileStorage)load_dotenv)Optional)datetime)crear_docs_headcrear_docs_detailobtener_siguiente_doc_lineZdocs_managementi    >   z.jpgz.jpegz.xlsxz.pdfz.docxz.xlsz.pngz.doczhttps://file.sycelephant.comFTP_HOSTFTP_USERFTP_PASSz/public_html/file/)hostuserpassword	base_path)file_objorigenuser_id
created_bytitledescriptionruta_completareturnc                 C   s,  d}zzht d| d|  t| }|d sd|d ddW W |rtj|rzt| t d	|  W S  ty }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S t| }|sFddddW W |rDtj|rDzt| t d	|  W S  tyB }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S t|}
|
d sd|
d ddW W |rtj|rzt| t d	|  W S  ty }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S t|||}|d sr|W W |rptj|rpzt| t d	|  W S  tyn }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S t|||}|d s|W W |rtj|rzt| t d	|  W S  ty  }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S |d }t||||d |d }|d s|W W |rtj|rzt| t d	|  W S  ty }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S dd| d||d |d |d |d |d | jdd}t d|d   |W W |rrtj|rrzt| t d	|  W S  typ }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S  ty8 }	 zdt
|	 }t j|dd ddd|d W  Y d}	~	W |r.tj|r.zt| t d	|  W S  ty, }	 z&t 	d
| dt
|	  W Y d}	~	S d}	~	0 0 S d}	~	0 0 W |r(tj|r(zt| t d	|  W n@ ty }	 z&t 	d
| dt
|	  W Y d}	~	n
d}	~	0 0 nv|r&tj|r&zt| t d	|  W n@ ty$ }	 z&t 	d
| dt
|	  W Y d}	~	n
d}	~	0 0 0 dS )!ux  
    Función REUTILIZABLE para subir UN documento con validación completa
    Puede usarse para: Formularios, Cotizaciones, Oportunidades, etc.
    
    Args:
        file_obj (FileStorage): Objeto archivo de Flask
        origen (str): Módulo origen (ej: "Q_SpQ_FormsHead", "Q_SpQ_Quotations")
        user_id (int): ID del usuario
        created_by (str): Nombre completo del usuario
        title (str): Título del archivo
        description (str): Descripción del archivo
        ruta_completa (str): Ruta completa (ej: "Ventas/Formularios/1001-2/FormPEmx")
    
    Returns:
        dict: Resultado de la operación
    NzIniciando upload de documento: z para validFmessageVALIDATION_ERRORsuccessr   codeArchivo temporal eliminado: %No se pudo eliminar archivo temporal : Error al crear archivo temporalTEMP_FILE_ERRORSECURITY_ERRORr   docs_idremote_path	extensionTDocumento "" subido exitosamentedoc_line_iddownload_url	file_sizer&   r+   r,   r'   r-   	file_typeoriginal_namer   r   datazDocumento subido exitosamente: z%Error inesperado en upload_document: exc_info&Error interno al procesar el documentoINTERNAL_ERRORr   r   r   technical_error)loggerinfovalidar_archivo_basicoospathexistsremovedebug	Exceptionwarningstrcrear_archivo_temporalvalidar_seguridad_archivosubir_archivo_ftpgestionar_docs_headcrear_registro_documentofilenameerror)r   r   r   r   r   r   r   	temp_pathvalidacion_resulteseguridad_resultupload_resultdocs_head_resultr&   docs_detail_resultresultado_final	error_msg rT   8/var/www/html/src/App/Utilities_module/DocsManagement.pyupload_document8   s    J
0A
0
8
0
/
0
*
0
 
0

0	
0	
2
rV   )r   r   c              
   C   s  z| r| j sdddW S t| j }t|j }|tvrPdddt dW S | dtj	 | 
 }| d |tkrtd }dd|d	d
dW S |dkrdddW S d|||dW S  t y } z*tdt|  dddW  Y d}~S d}~0 0 dS )uo   
    Validaciones básicas del archivo (tamaño, extensión, etc.)
    REUTILIZABLE para cualquier módulo
    Fu*   No se proporcionó ningún archivo válidor   r   u4   Tipo de archivo no permitido. Extensiones válidas: z, r      u2   El archivo excede el tamaño máximo permitido de z.1fMBu   El archivo está vacíoT)r   rI   r(   r-   u   Error en validación básica: zError al validar el archivoN)rI   r   r   suffixlowerEXTENSIONES_PERMITIDASjoinseekr<   SEEK_ENDtell   TAMAÑO_MAXIMOrA   r9   rJ   rC   )r   rI   r(   r-   t
   tamaño_mbrM   rT   rT   rU   r;      sB    


r;   )rK   r   c              
   C   s   zHt | }|d s|W S t| }|d s>dd|d  dW S dddW S  ty } z*td	t|  dd
dW  Y d}~S d}~0 0 dS )uX   
    Validación de seguridad usando ClamAV
    REUTILIZABLE para cualquier módulo
    r   cleanFz Archivo infectado o sospechoso: threatrW   TzArchivo segurou#   Error en validación de seguridad: z)Error al validar la seguridad del archivoN)validar_headers_archivoescanear_con_clamavrA   r9   rJ   rC   )rK   Zheader_resultZclamav_resultrM   rT   rT   rU   rE      s"    rE   )	file_pathr   c              
   C   s   znt | d}|d}W d   n1 s,0    Y  g d}|D ] }|| v rBddd  W S qBdd	dW S  ty } z*td
t|  dddW  Y d}~S d}~0 0 dS )uW   
    Validación básica de headers de archivo para detección rápida de amenazas
    rbi   N)s!   X5O!P%@AP[4\PZX54(P^)7CC)7}$EICARs   <scripts   javascript:s	   vbscript:Fz%Archivo contiene patrones sospechososrW   Tu   Headers válidoszError al validar headers: z'Error al validar estructura del archivo)openreadr[   rA   r9   rJ   rC   )rf   fheaderZpatrones_sospechososZpatronrM   rT   rT   rU   rd      s"    (rd   c              
   C   s  zrt jdd| gdddd}|jdkr@td|   ddd	W S |jrP|j nd
}td|  d|d	W S W n t jy   t	d|   ddd	 Y S  t
y   t	d ddd	 Y S  ty } z4t	dt|  ddt| d	W  Y d}~S d}~0 0 dS )z$
    Escanea archivo con ClamAV
    clamscanz--no-summaryTd   )capture_outputtexttimeoutr   zClamAV: Archivo limpio - N)rb   rc   zAmenaza desconocidazClamAV: Amenaza detectada - FzClamAV timeout para archivo: zTimeout en escaneo de virusu3   ClamAV no está instalado o no se encuentra en PATHzSistema antivirus no disponiblezError ejecutando ClamAV: zError en escaneo: )
subprocessrun
returncoder9   r@   stdoutstriprB   TimeoutExpiredrJ   FileNotFoundErrorrA   rC   )rf   resultZthreat_inforM   rT   rT   rU   re   "  s@    



re   c              
   C   s   z~t | j}t|j}tj|d\}}t|d(}| d |	| 
  W d   n1 s`0    Y  td|  |W S  ty } z"tdt|  W Y d}~dS d}~0 0 dS )z4
    Crea un archivo temporal desde FileStorage
    )rZ   wbr   NzArchivo temporal creado: z Error creando archivo temporal: )r   rI   r   rZ   tempfilemkstempr<   fdopenr^   writeri   r9   r@   rA   rJ   rC   )r   rI   r(   Ztemp_fdrK   	temp_filerM   rT   rT   rU   rD   T  s    


,rD   )rK   r   r   r   c                 C   sF  d}zzt |}|s.dtt   }td |dd }| d| }t d| d| }t	td }|
td td  t|| t| d	"}|d
| | W d   n1 s0    Y  td|  td|  d||||dW W |rz|  W S    Y S 0 S  tjy }	 zTdt|	 }
t|
 ddd|
dW  Y d}	~	W |rz|  W S    Y S 0 S d}	~	0  ty }	 zTdt|	 }
t|
 ddd|
dW  Y d}	~	W |rz|  W S    Y S 0 S d}	~	0 0 W |rBz|  W n   Y n0 n"|r@z|  W n   Y n0 0 dS )ub   
    Sube archivo al servidor FTP
    🆕 CORREGIDA: URL de descarga correcta para navegador
    Narchivo_r   \/r   r   r   rg   zSTOR z#Archivo subido exitosamente a FTP: u   URL pública accesible: T)r   r'   r,   rI   Zftp_pathzError de permisos FTP: Fz"Error de permisos al subir archivoZFTP_PERMISSION_ERRORr7   zError subiendo archivo a FTP: z"Error al subir archivo al servidorZ	FTP_ERROR)r   intr   now	timestamp
FTP_CONFIGreplaceBASE_URLftplibFTPlogincrear_directorios_ftprh   
storbinaryr9   r:   quit
error_permrC   rJ   rA   )rK   r   r   Zconn_ftpnombre_archivoZftp_directoryZremote_file_pathZ
public_urlarchivorM   rS   rT   rT   rU   rF   j  s    
0


rF   )ftp_conndirectory_pathr   c                 C   s>  zz"|  | td|  W W dS  tjy8   Y n0 |dd}d}|D ]}|s\qR|d| 7 }z|  | W qR tjy   z| | td|  W n: tjy } z dt|	 vr|W Y d}~n
d}~0 0 Y qR0 qRt
d|  W n> ty8 } z$tdt|  |W Y d}~n
d}~0 0 dS )	z4
    Crea directorios en FTP de forma recursiva
    zDirectorio FTP existe: Nr    zDirectorio FTP creado: r>   z*Estructura de directorios FTP verificada: zError creando directorios FTP: )cwdr9   r@   r   r   ru   splitmkdrC   r[   r:   rA   rJ   )r   r   
path_partsZcurrent_pathpartrM   rT   rT   rU   r     s4    

"r   )r   r   r   r   c              
   C   sX   zt || |W S  tyR } z,tdt|  ddddW  Y d}~S d}~0 0 dS )ux   
    Crea un nuevo DocsHead (cada upload individual genera su propio grupo)
    REUTILIZABLE para cualquier módulo
    zError gestionando DocsHead: Fz1Error interno al gestionar registro de documentosDOCS_HEAD_ERRORr   N)r   rA   r9   rJ   rC   )r   r   r   rM   rT   rT   rU   rG     s    rG   )r&   r   r   rutar/   r   c              
   C   sf   zt | }t| |||||W S  ty` } z,tdt|  ddddW  Y d}~S d}~0 0 dS )uM   
    Crea registro en DocsDetail
    REUTILIZABLE para cualquier módulo
    z%Error creando registro de documento: Fz$Error interno al registrar documentoZDOCS_DETAIL_ERRORr   N)r
   r	   rA   r9   rJ   rC   )r&   r   r   r   r/   Zdoc_linerM   rT   rT   rU   rH     s    rH   )r   c               	   C   s  g } t d s| d t d s(| d t d s:| d z,tjddgd	d
d}|jdkrd| d W n" ttjfy   | d Y n0 zJt }t	|d}|
d W d   n1 s0    Y  t| W n ty   | d Y n0 t| dk| td tttdS )ui   
    Verifica que la configuración del módulo sea correcta
    REUTILIZABLE para cualquier módulo
    r   zFTP_HOST no configurador   zFTP_USER no configurador   zFTP_PASS no configuradorl   z	--versionT   )rn   rp   r   z ClamAV no responde correctamenteu(   ClamAV no está instalado o no accesiblewtestNz&No se pueden crear archivos temporalesrX   )Zconfiguracion_validaerroresu   tamaño_maximo_mbextensiones_permitidasbase_url)r   appendrq   rr   rs   rw   rv   rz   mktemprh   r}   r<   r?   rA   lenra   listr\   r   )r   rx   Z	temp_testrj   rT   rT   rU   verificar_configuracion  s4    



(
r   )r   r&   r   r   r   r   c                 C   s  d}zzt d| d|  t| }|d sd|d ddW W |rtj|rzt| t d	|  W S  ty } z&t 	d
| dt
|  W Y d}~S d}~0 0 S t| }|sFddddW W |rDtj|rDzt| t d	|  W S  tyB } z&t 	d
| dt
|  W Y d}~S d}~0 0 S t|}|d sd|d ddW W |rtj|rzt| t d	|  W S  ty } z&t 	d
| dt
|  W Y d}~S d}~0 0 S t|||}	|	d sr|	W W |rptj|rpzt| t d	|  W S  tyn } z&t 	d
| dt
|  W Y d}~S d}~0 0 S t||||	d |d }
|
d s|
W W |rtj|rzt| t d	|  W S  ty } z&t 	d
| dt
|  W Y d}~S d}~0 0 S dd| d||
d |	d |	d |d |d | jdd}t d| d|
d   |W W |rtj|rzt| t d	|  W S  ty } z&t 	d
| dt
|  W Y d}~S d}~0 0 S  ty } zdt
| }t j|dd ddd|dW  Y d}~W |rtj|rzt| t d	|  W S  ty } z&t 	d
| dt
|  W Y d}~S d}~0 0 S d}~0 0 W |rtj|rzt| t d	|  W n@ ty } z&t 	d
| dt
|  W Y d}~n
d}~0 0 nv|rtj|rzt| t d	|  W n@ ty } z&t 	d
| dt
|  W Y d}~n
d}~0 0 0 dS )u  
    Sube un documento a un DocsHead existente (no crea nuevo DocsHead)
    
    Args:
        file_obj (FileStorage): Objeto archivo de Flask
        docs_id (int): DocsID existente donde agregar el archivo
        title (str): Título del archivo
        description (str): Descripción del archivo
        ruta_completa (str): Ruta completa (ej: "Ventas/Formularios/1001-2/FormPEmx")
    
    Returns:
        dict: Resultado de la operación
    Nz&Subiendo documento a DocsID existente r"   r   Fr   r   r   r    r!   r#   r$   r%   r   r'   r(   Tr)   r*   r+   r,   r-   r.   r1   zDocumento subido a DocsID z6Error inesperado en upload_document_to_existing_docs: r3   r5   r6   r7   )r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rH   rI   rJ   )r   r&   r   r   r   rK   rL   rM   rN   rO   rQ   rR   rS   rT   rT   rU    upload_document_to_existing_docs.  s    C
0:
0
1
0
(
0
 
0

0	
0	
2
r   )+r<   rz   r   rq   loggingpathlibr   Zwerkzeug.utilsr   Zwerkzeug.datastructuresr   dotenvr   typingr   r   )Consultas_SQL.Utilities.DocsManagementSQLr   r	   r
   	getLoggerr9   ra   r\   r   getenvr   rC   r   dictrV   r;   rE   rd   re   rD   rF   r   r   rG   rH   r   r   rT   rT   rT   rU   <module>   sN   
p8#2F-(