U
    Pd                     @   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dddZ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dddZe
ddddZ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/d0d1Zeedd2d3d4Zeedd5d6d7Zeedd8d9d:Zddd;d<Ze
eeedd=d>d?ZdJeeeedAdBdCZ e
dKeeeeedDdEdFZ!e
eedGdHdIZ"dS )LCmfPluginConvertMixinuO   
    Используется в классах CmfDocument, CmfAttachment
    )content	extensionc              	   C   s   | j  d| j d| }tj| dd}tj|sBt| tj||}t|d}|	| W 5 Q R X tjd|  d|}t
|S )up  
        Метод сохраняет файл директорию объекта и возвращает путь для скачивания
        :param content: Контент в байт
        :param extension: Расширение файла
        :return: file_path: Строка пути с кодированием символов для URL
        _.TZexportwbfiles)namecodeospathjoinZget_files_direxistsmakedirsopenwriter   Zquote)selfr
   r   	file_nameZfull_export_pathZfile_full_pathfile	file_path r   +./common/models/cmf_plugin_convert_mixin.py_save_export_file   s    
z'CmfPluginConvertMixin._save_export_file)returnc                 O   s<   |   }| t|d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pdf_handle_htmlobj_to_formatbytesr   )r   argskwargshtml
docx_bytes	pdf_bytesurl_file_pathr   r   r   save_to_pdf1   s
    z!CmfPluginConvertMixin.save_to_pdfc                 O   s.   |   }| t|dddd}| |d}|S )uu   
        Сохраняет HTML -> DOCX

        :return: Данные docx в виде строки base64
        r!   r"   r$   r%   docxr'   )r   r+   r,   r-   r.   r0   r   r   r   save_to_docx@   s    z"CmfPluginConvertMixin.save_to_docx)	html_textr    c           	   
   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)r2   r5   Zhtmldocxr6   r   _handle_view_htmlZadd_html_to_documentioBytesIOsaveseekgetvalue)	r   r4   r5   r6   ZdocumentZ
new_parsertmp_dir_namer-   	docx_filer   r   r   html_to_docxM   s    

z"CmfPluginConvertMixin.html_to_docx)r
   r    c                 C   s   t |  S )up   
        Преобразует байты в строку base64

        :return: Строка base64
        )base64Z	b64encodedecode)r
   r   r   r   _get_base64a   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)rC   Zpixelsr   r   r   _get_value_in_pixelsj   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: Ширина ячейки
        widthrG   rF   heightg)\(@N)rJ   attrsgetrK   rL   )imgZ
cell_widthZ	img_widthZ
img_heightproportion_ratior   r   r   _auto_size_img_for_cellw   s    z-CmfPluginConvertMixin._auto_size_img_for_cellc                 C   s   ddl m} | dg || jj}|jddD ]}||d q0|d}|jdd	d
}d|_|j	
| |j	j
| |dD ]"}t|jdk r|
|d q| | | | | | | | | | | | t|S )u   
        Обработка страницы html для сохранения

        :param html_text: Страница html
        :return: Обработанная страница html
        r   BeautifulSouptextzspoiler-iconclass_pheadstyleztext/css)typez@page { size: 21.0cm 29.7cm }   br)bs4rW   Zload_fieldsrX   rC   find_allreplace_withnew_tagstringr-   appendr\   lencontents_handle_html_card_preview_handle_html_svg_to_png_handle_html_img_handle_html_layout_handle_html_table_handle_html_cleanstr)r   rW   soupspanZhead_tag	style_tagr[   r   r   r   r(      s(    






z"CmfPluginConvertMixin._handle_htmlNc                 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-previewrY   rS   Z150pxrO   zapp-tinymce-file-name-viewdivzapp-tinymce-file-create-viewN)rb   findrQ   wraprd   rf   rc   )rp   ZpreviewrS   r   Zfile_creaters   r   r   r   ri      s    





z/CmfPluginConvertMixin._handle_html_card_previewc              	   C   s&  ddl }ddlm} |dD ] }zd}|jdd }rx|jd}dd	d
| jjgdd
| dgg}t	j
j|dgd}|r|jd|jjd}	nT|jt|d}
| |
}|t|
}	|	j\}}|jdd| t|t|d}	||	 W q tk
r   dt| }t| Y qX qdS )ud  
        Метод заменяет тег SVG тегом IMG с изображением в PNG.
        Конвертирует SVG в PNG, если SVG в диаграммах DrawIO, то сначала пытается найти готовый PNG диаграммы
        :param bs4.BeautifulSoup soup: Объект библиотеки
        r   NImagesvgzdrawio-contentrY   zdata-drawio-titleZANDZ	parent_id==r   z.pngurlfilterZfieldsrS   )src)Z
bytestringzdata:image/png;base64,)r}   rO   rP   u3   Не удалось заменить SVG на PNG: )cairosvgPILrw   rb   find_parentrQ   rR   idrC   modelsCmfAttachmentrd   rz   Zsvg2pngro   rB   r   r8   r9   sizerc   	Exceptionlogging	exception)r   rp   r~   rw   rx   
attachmentZdrawioZdrawio_titler|   rS   Zimg_byteZ
img_base64rO   rP   err_msgr   r   r   rj      s.     

 z-CmfPluginConvertMixin._handle_html_svg_to_pngc                 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 }z\||}|j\}}t|d4}| | }|j }d| d| |jd< W 5 Q R X W n8 tk
r   ||j  t!"d| d Y q*Y nX |dr<zt#j|dd}|j$dkr||%dd d }|d krZd!}| |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 |rX|sX|| }|| }|rt|st|| }|| }|s|s|}|}|| }|t- }|| }|t.ks|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   rv   NrS   rO   rP   rD   rE   rF   rG   r}   zhttps:///z%25rz   ry   r   r{   /files/common/static/file-outline.pngrbdata:image/z;base64,u	   Файл u/    не является изображениемhttp)r_      )timeout   r   r_   )ZpngZbmpZgifZtiffZtifZjpegZjpgz/imgz%Y%m%d-%H%M%Szwb+r[   r]   z0color: red; font-style: italic; font-size: 10pt;u?   Не удалось отобразить изображениеuL   Не удалось скачать изображения документаuN   Не удалось скачать изображения документа: )0r   rw   tempfiler   rb   rQ   rR   rH   WEB_PAGE_WIDTH_PXrJ   rK   rL   
startswithconfigZAPP_FQDNr   unquoter   r   r   full_path_file
UPLOAD_DIRr   PROJECT_DIRr   r   rB   readformatlowerr   rc   r   r   r   requestsstatus_coderfindr
   r   Znowr   rd   re   	cmf_alertrM   rI   abs)r   rp   rw   r   tmp_dirZimg_tagrO   rP   r}   url_pathr   Zattach_pathrS   Zwidth_originalZheight_originalZattachment_byteZattach_base64Z	mime_typeresZextension_imgr   fpeZtag_iZscalerT   coefficientr   r   r   rk      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: Объект библиотеки
        tablers   ztableView-content-wraprY   r]   rF   ;:rO   100%Zcellpadding1ZcellspacingZborderNr_   )starttrr   tdcolspanrG   rS   )rQ   )rb   r   rc   rR   splitrK   Zcolgroup	enumeratechildrenrQ   rN   	decomposerangeintrU   )r   rp   r   Zstyle_tableparentparamsr   rC   Z
cols_widthZcol_numcolZwidth_pxr   	nums_colsZtable_widthr   Ztd_styleZtd_widthr   irS   r   r   r   rm   H  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   Tagrs   zdata-layout-sectiontruer   rO   r   r   c                    s   g | ]}t | r|qS r   )
isinstance.0elr   r   r   
<listcomp>  s     
 z=CmfPluginConvertMixin._handle_html_layout.<locals>.<listcomp>rE      r   zdata-column-widthrD   N)
ra   r   rb   r   rd   r   rg   roundrR   rf   )rp   Zlayoutr   columnsr   Zwidth_columncolumnr   r   r   rl     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-buttonrY   N)rb   r   )rp   tagr   r   r   rn     s    z(CmfPluginConvertMixin._handle_html_clean)r4   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   )rw   UnidentifiedImageErrorrV   azcmf-fileclassrF   r   )objr^   ZhrefrS   Zimager]   titler   rO   rP   r}   z
data:image,r   z;base64Zfile_r   r   r   rz   ry   r   r{   i  c                 s   s   | ]}|  r|V  qd S Nisdigitr   r   r   r   	<genexpr>  s      z:CmfPluginConvertMixin._handle_view_html.<locals>.<genexpr>r   r   ?r   Zname_r_   c                 s   s   | ]}|  r|V  qd S r   r   r   r   r   r   r     s      )'r   rw   r   ra   rW   rb   rQ   rR   rf   dictr   r   r   r   rL   r   r   r   r@   Z	b64decodero   r   r   r   r   r   r   r   r   r   r   r   r   r   rg   r   r   Zresolver
   )!r4   r   rw   r   rW   rp   r   r   indexZ_filerO   rP   Zfull_urlZtype_imgZb64dataZ	name_fileZfile_imgr   r   Zattachment_pathrS   Zwidth_defaultZwidth_valueZpath_defaultZend_nameZfile_extensionZresponser   filepathr   Z	width_newr   Zheight_valuer   r   r   r7     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	HTMLMixinrV   	_HTML2PDF)basesz..modulesZappZassetsZfontsz	noto-sanszNotoSans-Regular.ttfr!   ZNotoSansrF   r   r   rO   r   Z100r   r   N)Zfpdfr   r   ra   rW   types	new_classr   r   abspathr   dirname__file__Zcore_fonts_encodingZadd_pageZadd_fontZset_fontZfindAllrQ   r   Z
write_htmlr7   Zprettifyr*   output)r   r4   r   r   rW   r   Z	path_fontr&   rp   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_htmlr   N)Zmammothr   r   r   r   r   rC   )r   r   r   r>   resultr   r   r   docx_to_html3  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   E  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_imgL  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_htmlU  s    z"CmfPluginConvertMixin.xlsx_to_html)r   path_pngr    c                 C   s$   ddl m} ||}|| dS )u<   
        Сохранение в формате PNG
        r   rv   N)r   rw   r   r:   )r   r   r   rw   rS   r   r   r   save_img]  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   r_   )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   )rC   Zctyper   time)cellrC   Zdatetime_tup)r   r   r   r   _get_xlrd_cell_value  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     s   z4CmfPluginConvertMixin.xls_to_xlsx.<locals>.<genexpr>)Zend_colxN)Zopenpyxlr   Zxlrdr   r   r   ZWorkbooksheet_namesr   rg   Zsheet_by_nameZactiver   Zcreate_sheetZmerged_cellsZmerge_cellsZnrowsrf   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_xlsxf  s2    
 
z!CmfPluginConvertMixin.xls_to_xlsx)dataoutput_pathsuffixr    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    s    z CmfPluginConvertMixin.obj_to_pdfrF   )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   NrV   r-   z	file.htmlr   ignore)errors u   �u   rF   r\   r]   TrY   r   r   {r_   })r   ra   rW   r)   r   r   r   r   get_encoding_typero   rA   rL   rt   Zget_textrb   rR   )r   r  r  r	  r   rW   Z
bytes_htmlr   Zfull_path_htmlr   r#   r4   rp   r\   r]   Z
style_textr   rr   Zstyle_classZ	class_tagZstart_pos_classZstyle_startZ	style_endr   r   r   obj_to_html  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   ro   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   )UniversalDetectorr   r#   r!   zwindows-1251zwindows-1250zwindows-1252asciiz
iso-8859-1latin1r   r"   )Zchardet.universaldetectorr  r   ZfeedZdoner   rR   closer8   	readlinesr;   UnicodeDecodeError)r  r  Zdetectorr   liner#   	encodingsZformat_encodingr   r   r   r    s*    

z'CmfPluginConvertMixin.get_encoding_type)rF   )rF   )#__name__
__module____qualname____doc__r*   ro   r   r1   r3   r?   staticmethodrB   rJ   rN   rU   r(   ri   rj   rk   rm   rl   rn   r7   r   r   r   r   r   r   r   r  r  r  r)   r  r   r   r   r   r	      sP   
&hO	[		+	(r	   )r@   Zhashlibr8   pathlibr   r   r   typingr   Zurllibr   r   r   r   Zcmf.includeZrdiskr   r   rI   rM   r	   r   r   r   r   <module>   s   