U
    $-dx                     @   s   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Zd dlZd dlT d dlmZ d	Zd
Zee ZG dd dZdS )    N)Path)TemporaryDirectory)Dict)parse)datetime)*)RFilei  i  c                   @   s  e Zd Z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dddZe	dd ZeedddZe	ddddZddddZddddZe	ddddZe	ddddZe	eeedd d!Zeedd"d#Zeed$d%d&Ze	eedd'd(d)Ze	eedd*d+d,Zeedd-d.d/Zeedd0d1d2Zeedd3d4d5Zddd6d7Ze	eeedd8d9d:ZdEeeeed<d=d>Ze	dFeeeeed?d@dAZe	eedBdCdDZ dS )GCmfPluginConvertMixinuO   
    Используется в классах CmfDocument, CmfAttachment
    )	html_textreturnc                 C   s8   |  |}| t|dddd}| |dd}| |S )u   
        Сохраняет HTML -> PDF
        Используется преобразование через DOCX, из-за этого нет разрыва страниц.

        :return: Данные pdf в виде строки base64
        utf-8encoding.htmldocx:MS Word 2007 XMLz.docxzpdf:writer_pdf_Export_handle_htmlobj_to_formatbytes_get_base64)selfr
   html
docx_bytes	pdf_bytes r   +./common/models/cmf_plugin_convert_mixin.pysave_to_pdf   s    
z!CmfPluginConvertMixin.save_to_pdfc                 C   s*   |  |}| t|dddd}| |S )uu   
        Сохраняет HTML -> DOCX

        :return: Данные docx в виде строки base64
        r   r   r   r   r   )r   r
   r   r   r   r   r   save_to_docx*   s    
z"CmfPluginConvertMixin.save_to_docxc           	   
   C   s~   ddl m} ddlm} | }| }t J}| ||}||| t }|	| |
d | W  5 Q R  S Q R X dS )ud   
        Преобразует HTML -> DOCX

        :return: Данные в байтах
        r   )Document)
HtmlToDocxN)Zdocxr   Zhtmldocxr   r   _handle_view_htmlZadd_html_to_documentioBytesIOsaveseekgetvalue)	r   r
   r   r   ZdocumentZ
new_parsertmp_dir_namer   	docx_filer   r   r   html_to_docx5   s    

z"CmfPluginConvertMixin.html_to_docx)contentr   c                 C   s   t |  S )up   
        Преобразует байты в строку base64

        :return: Строка base64
        )base64Z	b64encodedecode)r)   r   r   r   r   I   s    z!CmfPluginConvertMixin._get_base64)valuer   c                 C   sD   |  dr(td t|  dd }nt|  ddt }|S )u?  
        Метод масштабирует значение ширины под формат А4 и переводит его в пиксели
        :param value: Строка значения ширины в % или пикселях
        :return: pixels: Число с плавающей точкой
        %d    px)endswithA4_PAGE_WIDTH_PXfloatstripreplaceSCALE_A4)r,   Zpixelsr   r   r   _get_value_in_pixelsR   s    
z*CmfPluginConvertMixin._get_value_in_pixelsc                 C   sx   t | jd dd}t | jd dd}||krt|| }|d }| d| jd< ||  d| jd< dS )u   
        Метод масштабирует изображение под ширину ячейки таблицы
        :param img: Тег изображения
        :param cell_width: Ширина ячейки
        widthr0   r/   heightg)\(@N)r3   attrsgetr4   r5   )imgZ
cell_widthZ	img_widthZ
img_heightproportion_ratior   r   r   _auto_size_img_for_cell_   s    z-CmfPluginConvertMixin._auto_size_img_for_cellc              	   C   s  ddl m} ddl}i }ttjdtjd|D ]:}t|	 }|
 }d| d}|||}|||< q0||}	|	d}
|	jd	d
d}d|_|	j|
 |	jj| |	d}|r|  |	dD ]}|jdkr||	d q| |	 | |	 | |	 | |	 | |	 t|	}|D ]|}z6|j|| d}| |}d| d}|||}W n> tk
r   d||  }t| |||| }Y nX q*|S )u   
        Обработка страницы html для сохранения

        :param html_text: Страница html
        :return: Обработанная страница html
        r   BeautifulSoupNz(<svg.*?svg>))flagsz	<div id="z"></div>headstyleztext/css)typez@page { size: 21.0cm 29.7cm }h1pbr)Z
bytestringz <img src="data:image/png;base64,z">u=   Не удалось конвертировать svg в png: )bs4r@   cairosvgrefindallcompileDOTALLhashlibmd5encodeZ	hexdigestr5   new_tagstringr   appendrB   find	decomposefind_all_handle_html_card_preview_handle_html_img_handle_html_layout_handle_html_table_handle_html_cleanstrZsvg2pngr   	Exceptionlogging	exception)r   r
   r@   rI   Zsvg_replaceZsvgrO   Zmd5sumkeysoupZhead_tag	style_tagrE   rF   Zimg_contentattach_base64img_tagerr_msgr   r   r   r   o   sL    










z"CmfPluginConvertMixin._handle_htmlN)r   c                 C   s   | j ddD ]z}|d}d|jd< |jdd| d}|jdd| d}| d}|| || || || qd	S )
u  
        Метод парсит DIV вложения и оставляет в нем только нужные теги: изображение, имя файла и дата

        :param bs4.BeautifulSoup soup: Объект библиотеки
        zapp-tinymce-card-previewclass_r<   Z150pxr8   zapp-tinymce-file-name-viewdivzapp-tinymce-file-create-viewN)rV   rT   r:   wraprQ   rS   replace_with)ra   Zpreviewr<   	file_nameZfile_createrh   r   r   r   rW      s    





z/CmfPluginConvertMixin._handle_html_card_previewc                 C   s  ddl m} ddl}| }|dD ]}|jd}|jd}|r|drttd t	|
 dd	 }nt	|
 d
d	}|r|drtd t	|
 dd	 }nt	|
 d
d	}|jd}|sq*|dtj r|dtj d	}|dr|dd}t|}	tjjdd|	gdgd}
|
rNt|
j}nt|	dtj}| sxttjd }t|d4}| | }d|jdd	 d| |jd< W 5 Q R X ||}|j\}}|drztj|dd}|jdkr||dd d }|dkrd}| |j }d| d| |jd< t| d t!" d!d| }t|d"}|#|j  W 5 Q R X ||}|j\}}W nh t$k
r } zH|%d#}d$d%i|_d&|_&|'| t()d' t*d(|  W Y q*W 5 d}~X Y nX |r|s|| }|| }|r6|s6|| }|| }|sJ|sJ|}|}|| }|t+ }|| }|t,ksv|dkr|rt,| nd}t,}|t-|9 }| d
|jd< | d
|jd< q*W 5 Q R X dS ))u#  
        Метод заменяет адрес картинки на base64 и масштабирует размер изображения под формат А4 относительно исходного

        :param bs4.BeautifulSoup soup: Объект библиотеки
        r   ImageNr<   r8   r9   r-   r.   r/   r0   srczhttps:///z%25url==r   filterZfields/files/common/static/file-outline.pngrbdata:image/.z;base64,http)      )timeout   rz   )ZpngZbmpZgifZtiffZtifZjpegZjpgz/imgz%Y%m%d-%H%M%Szwb+rF   rC   z0color: red; font-style: italic; font-size: 10pt;u?   Не удалось отобразить изображениеuL   Не удалось скачать изображения документаuN   Не удалось скачать изображения документа: ).PILrm   tempfiler   rV   r:   r;   r1   WEB_PAGE_WIDTH_PXr3   r4   r5   
startswithconfigZAPP_FQDNr   unquotemodelsCmfAttachmentr   full_path_file
UPLOAD_DIRexistsPROJECT_DIRopenr   readsuffixsizerequestsstatus_coderfindr)   r   Znowwriter]   rQ   rR   rj   r^   r_   	cmf_alertr6   r2   abs)r   ra   rm   r   tmp_dirrd   r8   r9   rn   url_path
attachmentZattach_pathZattachment_byterc   r<   Zwidth_originalZheight_originalresZextension_imgZ	file_pathfpeZtag_iZscaler=   coefficientr   r   r   rX      s    



*







z&CmfPluginConvertMixin._handle_html_imgc                 C   s  | dD ]}i }|jddd}|r0|| |dddD ]&}|rB|d\}}| || < qB|d	s|d	d
|d	< |dsd|d< |dsd|d< |ds|dd|d< i }|jdk	r8t|jjddD ]J\}	}
|
j	dddD ],}d	|kr|d\}}| 
|}|||	< qq|j  | dD ]}d}	d}| 
|d	}| dD ]}i }|dddD ]*}|r|d\}}| || < q|s|d	p|d	 }r8| 
|}nX||	 }|d }r0t|	d t||	 D ]}||| 7 }q|	t|7 }	n|	d7 }	|rt| d|d	< ||8 }| dD ]}| || q^n|d7 }qj|dkrB|| }|j dd	didD ]2}| d|d	< | dD ]}| || qqqBq
dS )u  
        Функция добавляет стиль для таблиц
        Для конвертирования таблиц в LibreOffice используем inline style

        :param bs4.BeautifulSoup soup: Объект библиотеки
        tablerh   ztableView-content-wraprf   rC   r/   ;:r8   100%Zcellpadding1ZcellspacingZborderNrz   )starttrr   tdcolspanr0   r<   )r:   )rV   Zfind_parentrj   r;   splitr4   Zcolgroup	enumeratechildrenr:   r7   rU   rangeintr>   )r   ra   r   Zstyle_tableparentparamsnamer,   Z
cols_widthZcol_numcolZwidth_pxr   	nums_colsZtable_widthr   Ztd_styleZtd_widthr   ir<   r   r   r   rZ      sr    







z(CmfPluginConvertMixin._handle_html_tablec                    s   ddl m  | dddiD ]}d|d< d|_| d	} fd
d|jD }t|}td| d}|D ]*}d|_|d| d|d< |	| qf|	| qdS )u   
        Функция добавляет стиль для макета, используем table, так как flex не поддерживается в LibreOffice

        :param bs4.BeautifulSoup soup: Объект библиотеки
        r   Tagrh   zdata-layout-sectiontruer   r8   r   r   c                    s   g | ]}t | r|qS r   )
isinstance.0elr   r   r   
<listcomp>}  s     
 z=CmfPluginConvertMixin._handle_html_layout.<locals>.<listcomp>r.      r   zdata-column-widthr-   N)
rH   r   rV   r   rQ   r   lenroundr;   rS   )ra   Zlayoutr   columnsr   Zwidth_columncolumnr   r   r   rY   o  s    
z)CmfPluginConvertMixin._handle_html_layoutc                 C   s"   | j ddgdD ]}|  qdS )u   
        Метод очищает HTML от лишних тегов

        :param bs4.BeautifulSoup soup: Объект библиотеки
        ztable-context-menuzcell-dropbox-buttonrf   N)rV   rU   )ra   tagr   r   r   r[     s    z(CmfPluginConvertMixin._handle_html_clean)r
   tmp_pathr   c           !   
   C   s  ddl m}m} ddlm} || }g }|dD ]>}d|jddkrZ|t	|dd	 |jd
s2d|jd
< q2|dD ]}|t	|dd	 q||dD ]}|
  q|dD ]}|
  qt|D ]\}}	|	d }|jdd}
|jdd}|jd}|dr|d\}}|dd}|dd}t|d| d|  }t|d$}|t| t||jd< W 5 Q R X |dr
t|}tjjddtjgdgd}|rt|j}nt|dtj}| r
t||jd< |
s
||}|j\}
}d}tdd d! t|
D }|d"rBttj d# }|!d$d%kr\t"|n|!d$}||!d| }t#|}|j$d&kr4t|}|d'| |  % }t|d}||j& W 5 Q R X z>||}|j\}
}t||jd< |r|n|
r|
n|}W n$ |k
r0   t||jd< Y nX nt||jd< ||krP|n|}|r|| rj|| nd(}||jd< tdd)d! t|D } t| | |jd< qt|S )*u   
        Функция заменяет адрес картинки, файла на фактический

        :return: HTML с фактическими адресами картинок, файлов
        r   )rm   UnidentifiedImageErrorr?   azcmf-fileclassr/   file)objrD   Zhrefr<   ZimagerC   titler   r8   r9   rn   z
data:image,rw   z;base64Zfile_rx   wbrt   rp   rq   r   rr   i  c                 s   s   | ]}|  r|V  qd S Nisdigitr   r   r   r   	<genexpr>  s      z:CmfPluginConvertMixin._handle_view_html.<locals>.<genexpr>ry   ru   ?r}   Zname_rz   c                 s   s   | ]}|  r|V  qd S r   r   r   r   r   r   r     s      )'r~   rm   r   rH   r@   rV   r:   r;   rS   dictrU   r   r   r   r5   r   r   r   r*   Z	b64decoder\   r   r   r   r   r   r   r   r   r   r   joinr   r   r   r   r   Zresolver)   )!r
   r   rm   r   r@   ra   filesr   indexZ_filer8   r9   Zfull_urlZtype_imgZb64dataZ	name_fileZfile_imgr   r   Zattachment_pathr<   Zwidth_defaultZwidth_valueZpath_defaultZend_nameZfile_extensionZresponser   filepathr   Z	width_newr   Zheight_valuer   r   r   r      s    





"



z'CmfPluginConvertMixin._handle_view_htmlc              
   C   s  ddl m}m} ddlm} tjd||fd}tj	tj
tjtdd}tj
|ddd	d
dd}| }d|_|  |dd| |d ||}|dD ]}	d|	jd< q|dD ]}	d|	jd< d|	jd< qt 0}
|| | |
 t| W  5 Q R  S Q R X dS )uw   
        Конвертирует HTML -> PDF

        :return: Возвращает байты PDF файла
        r   )FPDF	HTMLMixinr?   	_HTML2PDF)basesz..modulesZappZassetsZfontsz	noto-sanszNotoSans-Regular.ttfr   ZNotoSansr/   r   r   r8   r   Z100r   r   N)Zfpdfr   r   rH   r@   types	new_classospathabspathr   dirname__file__Zcore_fonts_encodingZadd_pageZadd_fontZset_fontZfindAllr:   r   Z
write_htmlr    Zprettifyr   output)r   r
   r   r   r@   r   Z	path_fontZpdfra   r   r&   r   r   r   html_to_pdf  s&     

z!CmfPluginConvertMixin.html_to_pdf)	path_docxr   c              
   C   sH   ddl m} tj|rDt|d}||}|jW  5 Q R  S Q R X dS )u7   
        Конвертирует DOCX -> HTML
        r   )convert_to_htmlrv   N)Zmammothr   r   r   r   r   r,   )r   r   r   r'   resultr   r   r   docx_to_html  s
    z"CmfPluginConvertMixin.docx_to_html)path_imgr   r   c                 C   s   t | | dS u5   
        Конвертирует PDF -> PNG
        N)r   pdf_bytes_to_imgr   r   r   r   r   r     s    z&CmfPluginConvertMixin.pdf_bytes_to_img)path_pdfr   r   c                 C   s   t | | dS r   )r   
pdf_to_img)r   r   r   r   r   r     s    z CmfPluginConvertMixin.pdf_to_img)	path_htmlr   r   c              	   C   sB   t j|r>t|d"}| | }| j||d W 5 Q R X dS )u6   
        Конвертирует HTML -> PNG
        rr   N)r   r   r   r   r   r   r   )r   r   r   	file_htmlr   r   r   r   html_to_img$  s    z!CmfPluginConvertMixin.html_to_img)	path_xlsxr   r   c                 C   s   ddl m } ||| dS )u7   
        Конвертирует XLSX -> HTML
        r   	xlsx2htmlNr   )r   r   r   r   r   r   r   xlsx_to_html-  s    z"CmfPluginConvertMixin.xlsx_to_html)r   path_pngr   c                 C   s$   ddl m} ||}|| dS )u<   
        Сохранение в формате PNG
        r   rl   N)r~   rm   r   r#   )r   r   r   rm   r<   r   r   r   save_img5  s    
zCmfPluginConvertMixin.save_imgc              
      s  ddl m} ddlm} ddlm  ddlm ||ddd}| }| }tt	|D ]}|
|| }	|dkr|j}
|| |
_n|j|| d}
|	jD ]*}|\}}}}|
j|d	 ||d	 |d
 q fddt|	jD ],}|
fdd|	j||	|dD  qqZ|| dS )u6   
        Конвертирует XLS -> XLSX
        r   )workbook)open_workbook)XL_CELL_DATE)xldate_as_tupleT)Zformatting_infoZragged_rows)r   rz   )Z	start_rowZend_rowZstart_columnZ
end_columnc                    sJ   | j }| j krF|d}|dd dkr>tj|dd   }nt| }|S )Nr      )r   r   r   )r,   Zctyper   time)cellr,   Zdatetime_tup)r   r   r   r   _get_xlrd_cell_valueX  s    

z?CmfPluginConvertMixin.xls_to_xlsx.<locals>._get_xlrd_cell_valuec                 3   s   | ]} |V  qd S r   r   )r   r   )r   r   r   r   c  s   z4CmfPluginConvertMixin.xls_to_xlsx.<locals>.<genexpr>)Zend_colxN)Zopenpyxlr   Zxlrdr   r   r   ZWorkbooksheet_namesr   r   Zsheet_by_nameZactiver   Zcreate_sheetZmerged_cellsZmerge_cellsZnrowsrS   Z	row_sliceZrow_lenr#   )r   Zpath_xlsr   r   r   Zbook_xlsZ	book_xlsxr   Zsheet_indexZ	sheet_xlsZ
sheet_xlsxZcrangeZrloZrhiZcloZchirowr   )r   r   r   r   xls_to_xlsx>  s2    
 
z!CmfPluginConvertMixin.xls_to_xlsx)dataoutput_pathr   r   c                 C   s   t | || dS )u(  
        Конвертация данных в PDF через libreoffice
        :param data: Данные файла в виде байт
        :param output_path: Путь сохранения итогового pdf файла
        :param suffix: Расширение файла
        N)r   
obj_to_pdf)r   r   r   r   r   r   r   i  s    z CmfPluginConvertMixin.obj_to_pdfr/   )r   r   mimetyper   c              
   C   sZ  ddl }ddlm} | ||d|}| @}t|d }t|d}	|	| | t	|}
W 5 Q R X W 5 Q R X |j
|
ddd	d
}|dd}||}|d}|rR|d}|rR| }|jddD ]}|dd}d}|d D ]T}|d| }|||d d d }|||d d }|||| 7 }q||  |d< qt	|S )u  
        Конвертация данных в HTML через libreoffice

        :param data: Данные файла источника в виде байт
        :param suffix: Расширение файла источника

        :return: Строка HTML
        r   Nr?   r   z	file.htmlr   ignore)errors u   �u   r/   rB   rC   Trf   r   rx   {rz   })r   rH   r@   r   r   r   r   r   get_encoding_typer\   r+   r5   rT   Zget_textrV   r;   )r   r   r   r  r   r@   Z
bytes_htmlr   Zfull_path_htmlr   r   r
   ra   rB   rC   Z
style_textr   rb   Zstyle_classZ	class_tagZstart_pos_classZstyle_startZ	style_endr   r   r   obj_to_htmls  s4    	

"

z!CmfPluginConvertMixin.obj_to_html)r   r   	to_formatr  r   c              
   C   s\   zt | |||}W nB tk
rV } z$t|drBtddd n|W 5 d}~X Y nX |S )u*  
        Конвертация данных в HTML через libreoffice
        :param data: Данные файла в виде байт
        :param suffix: Расширение файла
        :param to_format: Формат файла который хотим получить
        u8   Не удалось конвертировать в htmlua   Импорт документов данного формата не поддерживаетсяT)abortN)r   r   r]   r\   r   r   )r   r   r	  r  Zconverted_dataerrr   r   r   r     s    z#CmfPluginConvertMixin.obj_to_format)	path_filer   c              
   C   s   ddl m} | }t| d8}|D ]$}|| |jr"|jdr" qHq"|  W 5 Q R X |jd}|sddddd	d
dg}|D ]d}zFtj| d|d,}|	  |
d |}W 5 Q R  W  qW 5 Q R X W q tk
r   d}Y qX q|S )u   
        Определяем кодировку файла

        :param path_file: Путь к файлу
        :return: Кодировка файла
        r   )UniversalDetectorrv   r   r   zwindows-1251zwindows-1250zwindows-1252asciiz
iso-8859-1latin1r   r   )Zchardet.universaldetectorr  r   ZfeedZdoner   r;   closer!   	readlinesr$   UnicodeDecodeError)r  r  Zdetectorr   liner   	encodingsZformat_encodingr   r   r   r    s*    

z'CmfPluginConvertMixin.get_encoding_type)r/   )r/   )!__name__
__module____qualname____doc__r\   r   r   r   r(   staticmethodr   r3   r7   r>   r   rW   rX   rZ   rY   r[   r    r   r   r   r   r   r   r   r   r   r  r   r  r   r   r   r   r	      sL   
;bO	[		+	(r	   )r*   rN   r!   pathlibr   r   r   typingr   Zurllibr   r   r   r   Zcmf.includeZrdiskr   r   r2   r6   r	   r   r   r   r   <module>   s   