U
    ~i                    @   sF  d dl m Z  d dlmZ d dlmZmZ d dlmZ d dlZd dlm	Z	 d dl
Z
d dlZd dlmZ d dlmZ d dlZd dlZd dlZd dlZd d	lT 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mZ e Ze  Z!G dd dej"Z#G dd dZ$G dd dZ%G dd de$e%ej&Z&dd Z'G dd dZ(dS )    )copy)Decimal)datetimetimezone)LoggerNPath)BeautifulSoup)cached_property)*fields
cmf_import
log_configwrapsc                   @   s   e Zd Zdd ZdS )AnonymousFilterc                 C   s   t |ddS )N	anonymousF)getattr)selfrecord r   ./common/models/cmf_import.pyfilter#   s    zAnonymousFilter.filterN)__name__
__module____qualname__r   r   r   r   r   r   "   s   r   c                   @   s   e Zd ZeedddZejdddfee	dddZ
deeeeeedddZedddZdd ZedddZdd Zdd Zdd Zd
S )LoggingMixinreturnc           	      C   s  t jrtjntj}tjjd| d}|sRtjd| d}|  |jsR|j	dddd tjjd| d}|stjd| d}|  |js|j	dddd t
j|jddt jt jd	}|| |tt
j t
j|jddt jt jd	}|| |tt
j |t  t }|| |t
  tjt|||}|  td
| j }|| d|_|js|tjt |S )uE    Журнал логирования процесса импорта data.lognameparent    F)Zmake_previewZ
mark_dirtyzanonymous_data.logutf-8D)filenameencodingZwhenZmaxBytesZbackupCountimport_) configDEBUGloggingINFOmodelsCmfAttachmentgetsavefile_existsZupload_filer   ZMyLogsHandlerfull_path_fileZIMPORT_LOG_MAX_BYTESZIMPORT_LOG_BACKUP_COUNTsetLevelZsetFormatterZ	FormatterZ	FORMATTERZ	addFilterr   ZStreamHandlerZCustomFormatterhandlersZQueueListener	log_queuestart	getLoggeridZ	propagateZ
addHandlerZQueueHandler)	r   levelattachment_logZattachment_log_anonZfile_handlerZanonymous_handlerZconsole_handlerZlistenerloggerr   r   r   r>   (   s`    



zLoggingMixin.loggerF   )msgr<   c                 K   s&   | j j||fd|i||d| dS )uI  Логируем как обычные лог для веб так и со скрытыми данными для возможности отправки в СТП

        Args:
            msg (str): сообщение
            level (int, optional): уровень логирования. Defaults to logging.INFO.
        r   )Zextraexc_info
stacklevelN)r>   log)r   r@   r<   r   rA   rB   kwargsr   r   r   rC   h   s    zLoggingMixin.logERR-0001Nprocess)r@   
error_codeobj_typeext_href	dump_path
error_typec           
   
   C   s   | j |tjdd tj||| |||t |d}|rt|j|_|j	|_
|dg |jj}	|	rt|	||_|	||_|  t  dS )u7  Логируем ошибки и записываем их в базу

        Args:
            msg (str): текст ошибки
            error_code (int, optional): Код ошибки для нахождения возможного решения или группировки. Defaults to 1.
           )r@   r<   rB   )textcoder   rJ   rK   rH   	tracebackrI   cmf_import.pluginN)rC   r.   ERRORr0   CmfImportErrorrO   
format_excr$   title
class_namerH   load_fieldsr   pluginZcalc_ext_hrefrI   Zcalc_dump_pathrJ   r3   
cmf_commit)
r   r@   rG   objrH   rI   rJ   rK   Zimport_errorrW   r   r   r   	log_error   s(    	zLoggingMixin.log_error c                 C   s4   d|  d d} td|  d|  t|  d S )Nu1   Ошибка при импорте данных. .ue   . Проверьте загружаемый файл и повторите попытку снова.zCmfImportError: : )stripr.   error	cmf_alert)r@   er   r   r   
_log_error   s    zLoggingMixin._log_errorc                 O   sF   t jjd| dgd}|s.t jd| d}|  |js@| jd |jS )uK   
        Возвращает путь текущему файлу
        r"   url)r$   r%   r   r#   u   Начало)r0   r1   r2   r3   r4   r>   inforc   )r   argsrD   r=   r   r   r   get_log_filename   s    zLoggingMixin.get_log_filenamec                    s:   t d  jddd  fddt D }|S )u   
        Список файлов после logrotate, чтобы можно было загрузить историю
        T)parentsexist_okc                    sB   g | ]:}t jt j |rtd |rt jd |qS )z%(?:data|anonymous_data)\.log(\.\d+)?$files)ospathisfilejoinrematchget_files_dir).0fdir_pathr   r   r   
<listcomp>   s    z2LoggingMixin.get_log_filenames.<locals>.<listcomp>)r   rp   mkdirrj   listdir)r   re   rD   Z	file_listr   rs   r   get_log_filenames   s    zLoggingMixin.get_log_filenamesc              	   O   s   dd l }t| d}|d}tj|r6t| ||d,}| 	 D ]}|
dtj}|| qLW 5 Q R X tjd|  dS )Nr   Tall_logs.zipw/filesri   )zipfiler   rp   joinpathrj   rk   existsremoveZipFilerx   replacer,   
UPLOAD_DIRwriterm   )r   re   rD   r|   rt   zip_pathmyzip	file_pathr   r   r   get_all_logs_by_zip   s    

z LoggingMixin.get_all_logs_by_zipc           	   	   O   s   dd l }t| d}|t d d}|  }|r||d6}|  D ]&}|	dt
j}|| t| qRW 5 Q R X tjd|  dS d S )	Nr   Tz
%Y%m%d%H%Mz_all_logs.ziprz   r{   ri   ry   )r|   r   rp   r}   r   nowstrftimerx   r   r   r,   r   r   rj   r   rk   rm   )	r   re   rD   r|   rt   r   Zlog_file_pathsr   r   r   r   r   zip_all_logs   s    
zLoggingMixin.zip_all_logsc           	      C   s   dd l }dd l}|jdddgd}| jdtjd |D ]0}| jd|jd |jd |jd tjd q6| jd	tjd |d
dg}|	d}|
 }|D ]}| j|tjd qd S )Nr   pidr$   usernameattrsz==============ps auxr<   z{:<10d} {:<20s} {:<10s}z==============netstat -panZnetstatz-panr'   )psutil
subprocessZprocess_iterrC   r.   r-   formatrd   Zcheck_outputdecode
splitlines)	r   r   r   Z	processesrF   outputZ
output_strlinesliner   r   r   
log_detail   s    
zLoggingMixin.log_detail)rE   NNNNrF   )r[   )r   r   r   r
   r   r>   r.   r/   strintrC   rZ   staticmethodrb   rf   listrx   r   r   r   r   r   r   r   r   '   s>   B      &r   c                   @   s   e Zd Zdd Zedd Zdd Zdd Zd	d
 Zdd Z	dd Z
dd Zdd ZddddZddddZddddZddddZddddZdd  Zeed!d"d#Zd$d% Zd&d' Zedd(d)Zd0d*d+Zd1d,d-Zd2d.d/ZdS )3CrossLinkMixinc              	   C   sV   g }t jjddddddddggd	gd
}|D ]$}|js8q,|tj|jjj	 q,|S )u   
        Собирает URL из всех плагинов импорта
        для поиска и конвертации абсолютных ссылок
        на уже импортированные объекты
        typeINCmfPluginConfluenceCmfPluginJiraZCmfPluginTrackerApiZCmfPluginYouTrackZCmfPluginKaitenZCmfPluginZephyrScaleext_urlr   r   )
r0   Z	CmfPluginr   r   appendurllibparseurlparsevaluehostname)r   ZurlsZpluginsrW   r   r   r   _get_plugin_urls   s&     zCrossLinkMixin._get_plugin_urlsc                 C   s    t | jds|  | j_| jjS )N	_api_urls)hasattr	__class__r   r   r   r   r   r   api_urls  s    zCrossLinkMixin.api_urlsc                 C   s   | dd D ]z}|d}|s6| jtj d qtj d| }tjj|dd}|sv| jtj d| d	 q|	tj
| qd
S )u=   Заменяет макросы задач YouTrack и Kaitenc                 S   s
   |  dS )Ndata-issue-id)Zhas_attr)tagr   r   r   <lambda>  r&   z6CrossLinkMixin._replace_issue_macros.<locals>.<lambda>r   uS    Не удалось найти id задачи в атрибуте 'data-issue-id'::Text_idinclude_archivedu:    Не удалось найти задачу по ext_id ''N)find_allr2   r>   warning
thread_ctxlog_objsource_hashr0   CmfTaskreplace_withCmfPluginCsvcreate_tag_link)r   soupr   Zissue_idZissue_ext_idZtaskr   r   r   _replace_issue_macros  s    

z$CrossLinkMixin._replace_issue_macrosc                 C   s   |j ddidD ]}d}|d}|s<| jtj d qtjjddd	d
| dgdd|ggdgdd}|s| jtj d| d q|tj	
| qdS )u/   Заменяет макросы задач Jirazdata-macro-nameZjirar   Nzdata-jira-keyuW    Не удалось найти код задачи в атрибуте 'data-jira-key'ORimport_raw_jsonLIKE%"key":""%rN   =Tr   r   r   <    Не удалось найти задачу по коду 'r   )r   r2   r>   r   r   r   r0   r   r   r   r   )r   r   r   rY   task_keyr   r   r   _replace_jira_macros0  s,    

	z#CrossLinkMixin._replace_jira_macrosc              
   C   sZ   zt j|W S  tk
rT } z(| jtj d| d|  W Y dS d}~X Y nX dS )uf   Безопасно парсит URL и возвращает parsed_url или None при ошибкеu-    Не удалось разобрать URL 'z': N)r   r   r   	Exceptionr>   r   r   r   )r   rc   excr   r   r   _parse_url_safelyM  s    z CrossLinkMixin._parse_url_safelyc                 C   s@   |j r|j | jkrdS |jr,|jds,dS |js<|j r<dS dS )uO   Определяет, нужно ли обрабатывать данный URLFhttpT)r   r   scheme
startswith)r   
parsed_urlr   r   r   _should_process_urlW  s    z"CrossLinkMixin._should_process_urlc           #   
   C   s  | d}| d}|j}tj|j}d}d}	d}
|dkr|dkrtj d| }tj	j |dgdd	}|stj
j d
ddtj dgddd| dggd}|s| jdtj d|  dS | dr|d d}
n|dkr4|dkr4tj
j d
dd| dgdgd}|s| jtj d|  dS nP|drd}td|D ]>}tj d|dd  }tj	j |dgdd	}|rP qqP|s| jtj d| d dS |s| jtj d| d dS |j}
n|drtd|}|s| jtj d | d dS |d!dd }tjj d"ddd#| dgd$d%|ggdgdd&}|s| jtj d'| d dS n|d(rtd)|}|sdS |d}tj|d*}|rrtj	jd+d|gd,d-dggddd.gdd&}|D ]x}d}|jr$|jjr$t|jjj d/}|sX|jrXt|jj d0i  dd1d2d3 }||kr|} qqn&tj
j d4d%d5gdd6d#| dggd}|s| jtj d7|rd8nd9 d:| d dS |jr|jd;d1d<dd3 }
n|d=r| d>r|d> d! }tj	jd
dd| gd
gdd&}|D ]*}t|jtj dr:|} qtq:|rt|d! }|s| jtj d?| d dS |jr|jd;d1d<dd3 }
n|d@rP|d2dA}tj	jdddB| dgdgdd&}|D ]*}|jj dCi  dD}||kr|}q|s| jtj d?| d dS n4|dEr| dFr|dF d! }tjj d
dd| gd}|s| jtj dG| dH| d dS n|dIr8| dJr8|dJ d! }tj j d
dd| gd}|s$| jtj dK| dH| d dS |j!dLdJd}	nL|dMrdN|krt"dO|}|sddS |d}tj
j d4d-d5gdd6d#| dggd}|s| jtj dP| dQ| d dS tj#j ||dRdSddT}|s| jtj dU| dH| d dS dVdWdXdYdZd[d\d]}| dJdgd! }|r4|d^kr:|}n~| |}|st| jtj d_| d`| da| d dS tj j ||db} | s| jtj dc| d`| dd| d dS | }n|j$rde|j$krt"df|rtdg|}|sdS |d}!tjjd
dd|! gdddh|! diggdgdd&}"|"D ](}t|jdj t|!kr2|} q\q2|s| jtj dk|!  dS ndS ||	|
dlS )mu   
        Определяет объект, на который ведет ссылка, и возвращает информацию о ссылке.
        Возвращает словарь с ключами: obj, href, anchor.
        zdata-linked-resource-typezdata-linked-resource-idNpage)NZnullr   hrefT)r   r   r   r   r   %::::%r   %"homepage":{"id":"r   r   r   u9    Не удалось найти документ по id zdata-anchor#spacer   uA    Не удалось найти пространство по id z/wiki/z\/\d+   u:    Не удалось найти id документа в 'u:    Не удалось найти документ по id 'z/browse/z	\/\w+-\d+u8    Не удалось найти код задачи в 'r   r   r   rN   r   r   r   z	/display/z+/display/([~]?[A-Za-z0-9]+)+(?:/)?([^?#]*)?r?   r$   r   !=zparent.import_raw_jsonkeyZ_expandabler[   /logic_prefixproject.wikiILIKEu     Не удалось найти u   документu   проектu    по ссылке 'zid--z/pages/viewpage.actionZpageIdu7    Не удалось найти документ по 'z/x/z\\/z%"tinyui":"Z_linkstinyuiz/secure/RapidBoard.jspaZ	rapidViewu+    Не удалось найти доску u    по 'z/issues/r   u8    Не удалось найти фильтр задач projectz
/projects/z/issuesz"^/projects/([^/]+)/issues(?:/.*)?$u.    Не удалось найти проект 'u   ' по 'u   Задачиr   )tree_parentr%   r$   r   systemuG    Не удалось найти реестр задач проекта u$   Мои открытые задачиu   Сообщено мнойu   Открытые задачиu#   Выполненные задачиu!   Недавно созданныеu   Недавно решенныеu%   Недавно обновленные)ZmyopenissuesZreportedbymeZallopenissuesZ
doneissuesZaddedrecentlyZresolvedrecentlyZupdatedrecentlyZ	allissuesu    Фильтр задач 'u   ' проекта u3    не поддерживается. Ссылка: ')r   r$   u9    Не удалось найти фильтр задач 'u   . Ссылка: 'Zkaitenz%^(?:/\d+|/space/\d+/boards/card/\d+)$z(\d+)$z%"id":z,%r;   u<    Не удалось найти задачу Kaiten по id )rY   r   anchor)%r2   rk   r   r   parse_qsqueryr   r   r0   CmfDocument
CmfProjectr>   r   r   lstripr   rn   findallfragmentsearchgroupr   unquote_plusr   r%   r   r   r   splitr   r   ZCmfKanbanBoardZCmfBqlFilterr   ro   ZCmfRegistryr   )#r   r   r   original_urlZresource_typeZresource_idZurl_pathZ
url_paramsrY   r   r   r   Zext_coder   ro   	space_key	page_nameZdocsdocZ	doc_spacepage_idrowZtinyui_liker   Zboard_idZ	filter_idproject_keyr   Ztask_registryZfilter_type_mapZfilter_typeZfilter_nameZtask_filterZtask_idobjsr   r   r   _resolve_link_infog  s   




	
  
 





	
z!CrossLinkMixin._resolve_link_infoc                    s   |d |d }|d  d}|j ddd}|tjtjfkrd}|j|jrZd	|j nd
 |jrnd|j nd
 d}|rt	|}d| d}	 fdd}
t
|	|
|}tjj|| |d||dd
dS )ui   Создает новый тег ссылки на основе полученной информацииrY   r   r   rM    T)r^   rc   ?r[   r   r   z(https?://[^/]+)?(/?\bz\b)c                    s@    rj  d  nj }| d}tjtt|d|}|S )Nz##r   Zfull_url)r   r   r   r   urljoinapp_base_hrefbool)ro   Z	link_textdomainr   rY   r   r   replacer  s    
z1CrossLinkMixin._create_link_tag.<locals>.replacertarget)rM   r   r   r  	view_moder   )Zget_textr   r$   rN   rk   r   r   r   rn   escapesubr0   r   r   r2   )r   r   r   	link_infor   r	  Ztag_textZrelative_urlZescaped_urlpatternr  r   r  r   _create_link_tag  s:    

zCrossLinkMixin._create_link_tagc                 C   s   | dD ]p}|jdrq
|dd }|s2q
| |}|sBq
| |sNq
| |||}|sbq
| |||}|| q
dS )u1   Заменяет обычные HTML-ссылкиacmf_convertedr   r[   N)	r   r   r2   r^   r   r   r   r  r   )r   r   r   rc   r   r  Znew_tagr   r   r   _replace_regular_links  s     

z%CrossLinkMixin._replace_regular_linksNr    c                 C   s"   |  | | | | | dS )uU   Заменяет макросы задач и ссылки в HTML-документеN)r   r   r  )r   r   r   r   r   _replace_links  s    

zCrossLinkMixin._replace_linksc                 C   s  |j ddidD ]}|jdr"q|jd}|sL| jtj d|  q|jd}tj d| }tj	j|d	d
}|stj
jdddtj dgddd| dggd}|rt|}|jj|d< |jj|d< t||d< d|d< |d= q| jtj d|  qdS )ut   
        Заменяет ссылку на корневую страницу в макросе 'Page Tree'
        data-macrosz	page-treer   r  data-macro-parametersu7    Макрос 'Page Tree' без параметров: Zroot_page_originalr   Tr   r   r   r   r   r   r   r   r   rootZ
rootLocaletrueuh    В макросе 'Page Tree' не удалось найти корневую страницу по id N)r   r   r2   r>   r   r   r   r   r0   r   r   jsonloadsr;   r   r$   dumps)r   r   r   Zdata_macro_parametersZroot_page_idZroot_page_ext_idZ	root_pageZmacro_paramsr   r   r   _replace_page_tree_root_links  s8    
z,CrossLinkMixin._replace_page_tree_root_linksc                 C   s   |j ddidD ]}|dd dkr*q|d}|dd	}t|}|d
}tjjdddt	j
 dgddd| dggdgd}|s| jt	j d| d q|j|d
< tj|ddd|d< d|d< qd S )Nr  Zwikilivesearchr   r  Zfalser  zdata-macros-parametersz&quot;"ZcurrentSpaceKeyr   r   r   r   r   r   r   r   --r   u    При конвертации макроса 'Livesearch' (Динамический поиск) не найдено пространство с ключом 'A   '. Возможно оно еще не импортированоF,:Zensure_asciiZ
separators)r   r2   lowerr   r  r  r0   r   sgetr   r   r>   r   r   r;   r  )r   r   r   Zmacros_parametersparamsr   r   r   r   r   _replace_livesearch_space_links  s2    




z.CrossLinkMixin._replace_livesearch_space_linksc                 C   s   |j dddgidD ]}|d}|dp4|d}tjjdd	d
tj dgddd| dggd}|s| jtj d| d qtj	j||dd}|rt
|j|d< q| jtj d| d qdS )uT   
        Добавляет ID документа в макрос 'Include'
        r  zinclude-excerptzinclude-pager   zdata-param-projectkeyzdata-param-pagenamezdata-param-page-labelr   r   r   r   r   r   r   r   r   u_    В макросе 'Include' не удалось найти пространство по key 'r  Tr$   r%   r   zdata-param-pageidu^    В макросе 'Include' не удалось найти страницу по имени 'uA   '. Возможно она еще не импортированаN)r   r2   r0   r   r   r   r>   r   r   r   r   r;   )r   r   r   r   r   r   Zexcerpt_pager   r   r   _replace_include_page_links-  s.    
z*CrossLinkMixin._replace_include_page_linksc                 C   s  |j ddidD ]}|ddkr&qd}d}d}d}|d}|rtdd	 |d
D }|dr|d }	|	dkr||}n"d|	kr|	dd\}}n|}|	}|rtjjdddtj dgddd| dggd}|s| j	tj
 d| d q|r,tjj||dd}|s,| j	tj
 d| d q|p4|}
|
r|jdd}d |
j |_|d!}t|}t|
j|d"< tj|d#d$d%|d!< d|d< qdS )&u   
        Добавляет ID документа в параметр 'Родительская страница' макроса 'Отображение дочерних'
        r  zchildren-docsr   r  r  Nzoriginal-data-macro-parametersc                 s   s.   | ]&}t |d ddkr|d dV  qdS )r   r   r?   N)lenr   )rq   Zparamr   r   r   	<genexpr>`  s   z@CrossLinkMixin._replace_childpages_page_links.<locals>.<genexpr>|r   r   r   r   r   r   r   r   r   r   r   r   r   u    При конвертации макроса 'Отображение дочерних' не найдено пространство с ключом 'r  Tr&  u~    При конвертации макроса 'Отображение дочерних' не найдена страница 'u9   '.Возможно она не импортированаzextension-object-name)class_z | r  Z
documentIdFr  r!  )r   r2   dictr   r0   r   r   r   r>   r   r   r   findr$   stringr  r  r   r;   r  )r   r   Zcurrent_projectr   r   Zdocumentr   ZpagenameZoriginal_macro_parametersr   Zparent_pageZspan_object_nameZmacro_parametersr$  r   r   r   _replace_childpages_page_linksQ  sn    





z-CrossLinkMixin._replace_childpages_page_linksc                 C   s|   |  D ]n}|sq| D ]Z\}}|s(qtjdtjd}||sDqt|d}| | ddd |j	j
D ||< qq|S )u   
        Конвертирует ссылки, которые могут быть в макросе "Свойства страницы"
        z
<a .+?</a>)flagslxmlr[   c                 S   s   g | ]}t |qS r   r   rq   xr   r   r   ru     s     z9CrossLinkMixin._replace_details_links.<locals>.<listcomp>)valuesitemsrn   compileIr   r	   r  rm   bodychildren)r   detailsZdetailr   r   r  Z
value_soupr   r   r   _replace_details_links  s    


 z%CrossLinkMixin._replace_details_links)task_raw_datalocal_linksc           	      C   s   |pg }| dg D ]}|d }|d }| ddks| ddks| dd	rRqtd
|d }|r|d}tjj ddd| gdd}|sq||kr|| d|d< q|S )NZremotelinksobjectZapplicationr   zcom.atlassian.confluenceZrelationshipz	Wiki Page	processedFz$/pages/viewpage.action\?pageId=(\d+)rc   r   r   r   r   T)r   r   )r2   rn   r   r   r0   r   r   )	r   r=  r>  Z
remotelinkZremotelink_objZremotelink_appro   r   r   r   r   r   _get_remotelinks  s0    



zCrossLinkMixin._get_remotelinksc              
   C   s   d}zb|j jpd}t|d}|js(W d S | | ddd |jjD |_ |jrd|j	dd t
  W nL tk
r } z.t  | jtj d| d	| d
d d}W 5 d }~X Y nX t|S )NFr[   r1  c                 S   s   g | ]}t |qS r   r2  r3  r   r   r   ru     s     z?CrossLinkMixin._process_comment_cross_links.<locals>.<listcomp>TZ	only_datauQ    Не удалось обработать ссылки в комментарии z. ERR-0034)rG   )rM   r   r	   htmlr  rm   r9  r:  
is_changedr3   rX   r   cmf_rollbackrZ   r   r   r   )r   comment	has_errorZcomment_textr   r   r   r   r   _process_comment_cross_links  s&    


z+CrossLinkMixin._process_comment_cross_linksc                 C   s(  d}d }d| dt _ztj|dddddd	d
dddg
d}d|j dt _t|jdd\}}|t _| j	
t j d |jjpd}t|d}|jr| | |jdkr| | | | | | | ||j ddd |jjD |_|jdkrL|jrL|jj}|jj}	|d}
|
rL| |
}
|
|d< |
|	d< ||_|	|_|jdkrv|jrv| |jj|jj|_|j rt!|dr|j"dd n|j"dd t#  |j$D ] }|j%dkrĐq| &| qW nJ t'k
r } z*t(  | j)t j d| d|d d}W 5 d }~X Y nX t*|S ) NF[]r%   rM   Z
text_draftr>  	macros_dbmacros_db_draftr   r   zcomments.log_levelzcomments.textr   r   r   u/    Обработка ссылок объектаr[   r1  r   c                 S   s   g | ]}t |qS r   r2  r3  r   r   r   ru     s     z;CrossLinkMixin._process_obj_cross_links.<locals>.<listcomp>r;  r   T)Zsave_importrB  r?   uQ    Не удалось обработать перекрестные ссылки. rC  )rG   rY   )+r   r   cmfutilget_obj_by_idrN   r   r   r   r   r>   debugrM   r   r	   rD  r  rU   r  r%  r'  r/  r%   rm   r9  r:  rL  rM  r2   r<  r   rA  r>  rE  r   r3   rX   ZcommentsZ	log_levelrI  r   rF  rZ   r   )r   obj_idrH  rY   r   _Zobj_textr   rL  rM  r;  rG  r   r   r   r   _process_obj_cross_links  s    








z'CrossLinkMixin._process_obj_cross_linksc              	   C   s`   ddl m} d}|dd2 |  r&qH| }|dkr8qH|| |7 }qW 5 Q R X || d S )Nr   )cmf_contextF)Zinit_views_and_dsDONE)Zcmf.apprT  	is_cancelr2   rS  put)r   	obj_queueerror_queuerT  error_countrQ  r   r   r   _cross_links_worker9  s    z"CrossLinkMixin._cross_links_workerc                 C   s|  t  h t  R t  < t  & |   |  | _d}tt	| }d }|rht	j
j|d}| d|j d| d|  t }t }	g }
| d| j  t }t| jD ]D}tj| jd| ||	dd	}|
| |  | d
|  q| d|j d d}ddd gdddgg}|rF|dd|g |j|ddg||| gd}|D ]*}|  rz q|d7 }||j qf|
D ]}|d q|
D ]}|  qt | }| d|j dd d|| dd |	 s||	 7 }q| d|j d|  |W  5 Q R  W  5 Q R  W  5 Q R  W  5 Q R  S Q R X W 5 Q R X W 5 Q R X W 5 Q R X d S )Nr   )r;   rJ  uc   ] Обработка ссылок на локальные задачи и документы start=z limit=uJ   Обрабатываем ссылки в несколько тредов: r[  )rX  rY  )r  r$   rD   u.   Параллельный обработчик u2   ] Ожидание обработки ссылокr   r   import_original==Tr%   r   r  r;   )r   r   slicer   rU  z] z
----------u    скорость .3fu#    объектов в секундуuD   ] Завершена обработка ссылок. Ошибок: )rN  disable_acldisable_notifyenable_import_modeensure_recursion_limit_prepare_multiprocessingr   r   varsr0   r   r2   rC   verbose_namequeueQueuethreading_max_forkstimeperf_counterrange	threadingThreadr[  r   r9   ZslistrV  rW  r;   rm   empty)r   
model_namer9   limit
project_idrZ  modelr   rX  rY  threads
start_timeithreadZcnt_filterr   rY   elapsed_timer   r   r   process_cross_links_by_modelJ  sx    




z+CrossLinkMixin.process_cross_links_by_modelc              
   C   s   dd l }d| d|tj|d kr$|nd|j dd}ddd | D }|jddd	d
| j d| dgddtddtddd}| j	d|j
 dddd | D  d |S )Nr   r   )rp  r9   rq  rr  , c                 S   s   g | ]}t |qS r   r2  )rq   pr   r   r   ru     s     z7CrossLinkMixin._execute_cross_links.<locals>.<listcomp>/usr/bin/python3	manage.pyshellz&cmf_import = models.CmfImport.get(id='z+');cmf_import.process_cross_links_by_model(z);T"/var/log/eva-import-subprocess.loga+&/var/log/eva-import-subprocess.err.logZ	close_fdsZstart_new_sessionstdoutstderrz[PID u.   ] Запущен process_cross_links_by_model(c                 S   s   g | ]\}}| d | qS )r   r   rq   kvr   r   r   ru     s     ))r   r,   IMPORT_OBJ_CNTr;   rm   r5  Popenopenr>   rd   r   r6  )r   rp  r9   r   r   r$  Z
params_strprocr   r   r   _execute_cross_links  s,    
  &z#CrossLinkMixin._execute_cross_linksc                 C   s  d}|rzt |trt|}t |tjtjfrt }t	  || 
|j7 }W 5 Q R X t | }| jd| d|dd|  ntd|jj dW nF tk
r } z(t  | d| d|  |d	7 }W 5 d
}~X Y nX |S z|  | _W n< tk
r6 } z| d|  | W Y S d
}~X Y nX d}|d
k	r|}tjjddd|gdd|gdd|gdd|gddd| dggddd
ggd}|s| d| d |S t }	ddd
gdddgg}
|r|
dd|g d| }d D ]}tt| }|j|
d}|sqt  | jd!| d"|j d#| d$| d%| j 
 t }d}g }t| jD ]8}| |||}|| |tj 7 }||krf qqf| !  ||k rt"d	 t#|D ]T}|$ }|d
k	r||7 }|%| | |||}|| |tj 7 }| !  qĐqt#|D ] }|&  |j'r&||j'7 }q&t | }| jd&| d| d'|dd( qt |	 }| jd)| d'|dd|  |S )*u   
        Обработка ссылок на задачи и документы в тексте импортированных объектов
        r   rJ  u:   ] Обработка ссылок завершена за r_  u    сек. Ошибок: u5   Обработка ссылок в объектах 'u#   ' не поддерживаетсяu?   ] Ошибка обработки ссылок объекта: r   Nu.   Ошибка обработки ссылок: r[   r   task_code_prefixr   rN   r$   r;   r   r   %r   r   r   u    Не найден проект 'r   r\  r]  Tr%   u    проекта )r   r   u#   Обработка ссылок в u    объектах 'z' (r  u+    в несколько процессов: u$   Обработка ссылок в 'u    завершена за u    сек.u(   Обработка всех ссылок)(
isinstancer   rN  rO  r0   r   r   rj  rk  rc  rS  r;   r>   rP  r   r   r   rF  rZ   get_max_processesmax_processesr   r2   r   re  countrX   rd   rf  rl  r  r,   r  r   sleepr   Zpollr   Zcommunicate
returncode)r   r   rY   errorst1t2r   Zlog_projectZproject_identZtotal_t1rx  rp  rs  Zobj_cntZmodel_t1r9   rF   rR  r  r  Znew_procZmodel_t2Ztotal_t2r   r   r   process_cross_links  s    






$









z"CrossLinkMixin.process_cross_links)N)N)NN)r   r   r   r   propertyr   r   r   r   r   r   r  r  r  r  r%  r'  r/  r<  r,  r   rA  rI  rS  r   r[  rz  r  r  r   r   r   r   r      s2   

  4,(!$MO
G
r   c                       s8  e Zd Zejjd Zejjdddddddd	d
ddddg ZdZdZdZ	e
dZeedddZedd Zedd ZeedddZdd ZdoedddZed d! Z fd"d#Zd$d% Zd&d' Zd(d) Zed*d+ Zed,d- Zed.d/ Z e!d0d1d2Z"d3d4 Z#dpe$d5d6d7Z%d8d9 Z&dqd;d<Z'd=d> Z(d?d@ Z)eddAdBZ*dCdD Z+dEdF Z,dGdH Z-dIdJ Z.edredKdLdMZ/edddNdOZ0dPdQ Z1 fdRdSZ2 fdTdUZ3dVdW Z4e
ddXdYZ5dZd[ Z6d\d] Z7dsd_d`Z8dadb Z9eddcddZ:dedf Z;ee<dddgdhdidj Z=edte!e!dldmdnZ>  Z?S )u	CmfImport)CSV_SETTING_NAMEcsv_import_settings_fieldsr>   _last_statsrm  rg  ri  download_threading_max_forksr  import_settingsworker_flag_filecalc_import_settingscancelcheck_projectsdelete_dumpr   rf   rx   
pg_restorepreviewr9   stoptake_import_statstmplt_import_settingsZCSVNz/tmp/eva_import_worker.flagr    c                 C   s
   | j  S N)r  r~   clsr   r   r   worker_hereS  s    zCmfImport.worker_herec                 C   s   | j   d S r  )r  touchr  r   r   r   create_worker_flagW  s    zCmfImport.create_worker_flagc                 C   s   | j  r| j   d S r  )r  r~   unlinkr  r   r   r   remove_worker_flag[  s    
zCmfImport.remove_worker_flagc                 C   s.   | j s(| dg dd | jd D | _ | j S )Njson_settingsc                 S   s   i | ]}|d  |qS r$   r   )rq   sr   r   r   
<dictcomp>d  s      z-CmfImport.import_settings.<locals>.<dictcomp>r  )_import_settingsrV   r  r   r   r   r   r  `  s    zCmfImport.import_settingsc                 C   s   t j| _t j| _d S r  )r,   ZIMPORT_THREADSri  ZIMPORT_DOWNLOAD_THREADSr  r   r   r   r   rd  g  s    z"CmfImport._prepare_multiprocessingTc                 C   s   ddl }ddl}| }|d }|r:| jd| ddd | j}t|d }|rj| jd	| d
dd tjr|t	tj|}|r| jdtj ddd t	t|d |}|r| jd| ddd |st
d| d| d|S )u.  
        Рассчитывает максимальное количество процессов
        для создания нескольких независимых процессов

        Returns:
            int: максимальное количество процессов
        r   Nr   u4   Количество ядер системы (CPU): u    (не менее 2)T)r      @u%   Доступно памяти (RAM): u!    ГБ (по 2 ГБ на ядро)u/   Количество процессов (MAX): uB    (в параметре 'IMPORT_PROCESS' конфигурации)r?   u    (итоговое)uY   Недостаточно системных ресурсов для импорта (CPU: z, RAM: uq    ГБ). За дополнительной информацией обратитесь в техподдержку)multiprocessingr   	cpu_countrC   virtual_memoryZ	availabler   r,   ZIMPORT_PROCESSminr   )r   rC   r  r   r  r  Zavailable_memoryZavailable_memory_gbr   r   r   r  k  sB    



zCmfImport.get_max_processesc                 C   s6   ddl m} tjjd }|j| s2|j| dd} | S )Nr   )cmf_hashlibr  ZABCDEFGHIJKLMNOPQRSTUVWXYZ)Z	enc_table)Zcmf.utilr  r0   r   r   Zregex	fullmatchZshort_str_enc)r   r  r  r   r   r   get_correct_key  s
    zCmfImport.get_correct_keyc                    s(   | j  s| jjdd| _ t   d S )NZOPENstatus_type)statusloadworkflowget_default_statussuper_calc_statusr   r   r   r   r    s    
zCmfImport._calc_statusc                 C   s  | j d rd S | jr(| j | j d< d S | jdkr6d S | j d dtj tjjd | j d dtj	 tj	jd | j d dtj
 tj
jd | j d dtj tjjd | j d dtj tjjd | j d d	tj tjjd d S )
NZmodels_fieldsexcelu   Поля контактов)Zcaptionr   iconu   Поля задачu   Поля заметокu   Поля проектовu"   Поля списков задачu   Поля групп)r  rW   Zcalc_models_settingsr   r   r0   	CmfPersonZimport_shop_fieldsr  r   Z
CmfCommentr   CmfListZCmfPersonGroupr   r   r   r   _calc_models_settings  s>    

zCmfImport._calc_models_settingsc                 K   sz   |  ddddg | jd r d S | jj| d| jd< d| jd< d	| jd
< d	| jd< d| jd< d	| jd< | j| _|   d S )Nr  attachmentsr   rW   r  r   Tsend_invitesFremove_conflict_projects
add_suffix	pg_backupmerge_identic_names)rV   r  rW   r  r3   r   rD   r   r   r   r    s    





zCmfImport.calc_import_settingsc                 K   s   |  ddddg | jd r d S | jjdd| jd< | jjdd| jd< | jjd	d
| jd	< | jjdd| jd< | jjdd
| jd< | jj| d| jd< | j| _|   d S )Nr  r  r   rW   r  r  Tr  r  Fr  r  r   )rV   r  r   r2   rW   r  r3   r  r   r   r   r    s    
zCmfImport.tmplt_import_settingsc                 C   s:   |  dg | jd D ]}|d | jkr|d   S qg S )Nr  r  r$   r   )rV   r  r  )r   settingsr   r   r   r    s
    z$CmfImport.csv_import_settings_fieldsc                 O   s&   t j  t jd|  t j  dS )uJ   
        Запускаем в фоне импорт данных
        r9   N)r0   ZCmfAccessListZactivate_admin_moder  
run_workerr  	import_id_args_kwargsr   r   r   r9     s    
zCmfImport.startc                 O   s   t jd|  dS )uR   
        Останавливаем в фоне импорт данных
        r  N)r0   r  r  r  r   r   r   r     s    zCmfImport.stop)entity_typec                 K   s   |  dg d}||kr:| jjjdkr:td| ddd d|i}g }| D ]2\}}t|ttt	fsN|
| d	t|j  qN|rtd
d| ddd n
|| tjjd| j|d tj  dS )u   
        Запускает отдельную обработку сущностей (фильтры, связи, ссылки и др.)

        Args:
            entity_type (str): тип сущности (filters, relations, links, etc.)
        rW   filtersZ	relationsZcode_historyr   u4   Запуск отдельной обработки 'u?   ' возможен только для импорта из JiraTabortr  r]   uP   Недопустимые типы значений для параметров: r{  ud   . Значения параметров должны быть строками или числамиprocess_entityr$  N)rV   rW   r   rU   r`   r6  r  r   r   floatr   r   r   rm   updater0   r  r  r;   r  )r   r  rD   Zjira_entitiesr$  Zinvalid_kwargsr   r   r   r   r   r    s.    

zCmfImport.process_entityc                 O   s&   dd l }|  }| r"|| d S )Nr   )shutilget_download_pathr~   rmtree)r   re   rD   r  download_pathr   r   r   r  3  s    zCmfImport.delete_dump)r   c              	   C   s4  d}|dkr|j }|sg }i }t| jD ]Z\}}|d r(|| r(|d d dd |jkr^q(|d d |kr(|| ||d d < q(|s|S || d}	tt|	d	}
|D ]}|j|}t	|tj
st	|tjr,d}| D ]8}|jd
dd|| gd	d|| ggdgd}|r qq|r,t|	|| qt	|tjr<qt|	|||  || }t	|tjr~t|d}t|tjj}t	|tjrq||d|g q| jd r|j|dgd}|s0|d	}|r|j|dgdd}|r|
|	_|j|	jdgd}|r$|	j dttjd|	_|	}|  |S )u  
        Импортируем объект

        :param list row: Строка из файла
        :param models.* model: Модель для создания объекта
        :param list _filter: Для фильтрации объекта
        :param str key: Ключевое имя для сопоставления модели

        :return: Новый или найденный объект
        :rtype: Optional[models.*]
        Nmodel_fieldfield_qualnamer\   r   rf  
field_namer   rN   r   r$   r]  z**r   ZRUunionT)rN   r   include_deleted)r$   r   rR  z%Y%m%d-%H%M%S)rf  	enumerater  r   rU   r   r   r   r2   
issubclassZCmfRelationZCmfGenericRelationZrelated_modelssetattrZ
CmfRelBaseZCmfPhonephonenumbersr   Zformat_numberZPhoneNumberFormatZINTERNATIONALZ
CmfNumericr   r  rN   r$   r   r   r   utcr3   )r   r   rs  rx  r   result_fieldsrv  settingZnew_objZnew_coder  ZfieldZrel_objZ	rel_modelvalZphonerN   r   r   r   _process_obj9  sp    

zCmfImport._process_objc                 C   s   | j ddS )um   
        Ручка фронта для проверки конфликтующих проектов
        T)as_msg)get_conflict_projectsr   r   r   r   r    s    zCmfImport.check_projectsFc              	   C   s  |  dg | jjjdkrdS g }ddd}| jd d d	 }d
d |d D }|D ]^}| |d }|dpx|d }| jjj d|d  }	tj	j
ddd|	gddd|	 dggddddgd}
|
r|
jdp|
jd}|
r| jjjdkr |
jdksT||kr|
jd |krqTtj	jddd |gd!d |ggddd!d"d#gd}|D ]d}d}t|jop|jj| jjjk}| jjjdkr|jd$krd%|j d&|j d'|d(< |}n| jjjdkr$|jd$kr$|jdkr| jd) d d d*krqL|jsd+|d,< d-| d&|  d'|d(< |}n|jr:|js:|r>|}|rL|j d.|j d/}|jdkrn|d07 }n|jd$kr|d17 }|jr|d27 }n|r|d37 }|||f qLqTd4}|rd5d4d6d7 |D  d8d4d9d7 | D  d:}|r |S d;d |D S )<u  
        Возвращает список конфликтующих проектов или текст сообщения для предупреждения

        Args:
            as_msg (bool, optional): возвращать в виде текста для сообщения. Defaults to False.

        Return:
            list, str: список проектов или текст сообщения
        plugin.plugin.source_hashr   Nu^   отменить выбор аналогичных импортируемых проектовu   удалить существующие проекты (проекты и все их данные будут безвозвратно удалены))r  deleteZselectedObjectsr   r   c                 S   s$   g | ]}|d  r|d r|d  qS )rY   Z	isCheckedr   )rq   r  r   r   r   ru     s       z3CmfImport.get_conflict_projects.<locals>.<listcomp>r:  r   original_namer$   r   r;   r   r   r   r   r   r   Tr  r   r   )r   r  r   rT   r   project.agiler   r  zcmf_import.ext_idcmf_deletedr   u   добавить суффикс 'Wiki' к названию или коду существующих Wiki-проектов (пример: 'z Wiki' (zWIKI))r  Zimport_typer   u   объединить с существующими Agile-проектами, запустив импорт с опцией 'Импортировать в Документы Agile проекта'Zcombineu   импортировать с добавлением 'Wiki' к названию или коду проекта (пример: ' (r  u    <em>Agile-проект</em>u    <em>Wiki-проект</em>u(    <em>удален в корзину</em>uI    <em>импортирован из другого источника</em>r[   u               <p><strong>В системе уже существуют проекты с аналогичными названиями или кодами:</strong></p>
            <ul>c                 s   s   | ]\}}d | dV  qdS z<li>z</li>Nr   )rq   project_namerR  r   r   r   r)    s     z2CmfImport.get_conflict_projects.<locals>.<genexpr>u   </ul>
            <br />
            <p><strong>Для продолжения импорта вы можете:</strong></p>
            <ul>c                 s   s   | ]}d | dV  qdS r   r   )rq   actionr   r   r   r)    s     z</ul>
            c                 S   s   g | ]\}}|qS r   r   )rq   rR  r   r   r   r   ru     s     )rV   rW   r   rU   r  r  r2   r   r0   r   r#  r   r   r   r  r   r   r$   r  r  upperr   rm   r5  )r   r  Zconflicting_projectsactionsr  Zselected_projectsZprjZselected_project_keyZselected_project_nameZselected_project_ext_idr   r  Zmatching_projectsZmatching_projectZconflicting_projectZother_sourcer@   r   r   r   r    s    

	


zCmfImport.get_conflict_projectsc                 C   sB   t j D ]&}| jj |kr
t jj|d  S q
tddd d S )NZbackup_nameu   Бекап для данного импорта не существует. Воспользуйтесь функционалом "Отмена".Tr  )r0   CmfGlobalSettingsZpg_backup_lsrN   r   r"  r  r`   )r   Zbk_namer   r   r   r     s    zCmfImport.pg_restorec           	      C   s  |  dddg d}| jrdzz@t	
 , | jjdrVtjj| jj d | jjdr|  }|r|D ],}| jd	| tjd
 |jdd t  qtdtjd< d| _d| _| jjjj| _|   t  dtjd< | jD ]P}| j| D ]@}d}|dkr$t|   ! r$| j| | }| "||| qqtj#j$dd| gd | jj%| d}W 5 Q R X W n^ t&k
r } z>t'  t(| dt)*|j+d  }| ,d|  || _-W 5 d}~X Y nX W 5 |  | _|   tjj  |  S X  | j.dkr| / S dS )u9   
        Импортируем файл в бд
        r   plugin.plugin.*zplugin.*FNr  r  r  u7   Удаляем конфликтующий проект r   T)TEXKOM_db_deleter[   ZNO_CACHEr   1
downloadedr   r]  r   r   
r   u*   Ошибка работы импорта: r  )0rV   rW   get_redis_import_statsimport_statsr3   cmfapp	CMF_CACHEflushdbrN  rb  r  r   r2   r0   r  r  rN   r"  r  rC   r.   ZWARNINGr  rX   rj   environZimported_object_countprogressr   r   r   r  iterdirinc_statrR   Zbulk_deleteprocess_importr   rF  r   rO   	format_tb__traceback__rZ   	error_msgr   _process_import_excel)	r   r  Zprojectsr   obj_nameopr  err
error_textr   r   r   r  &  sP    




zCmfImport.process_importc           4      C   sd  ddl m} | jr| jd s dS d}zi }i }i }i }i }i }i }	|  }
t|
D ]&\}}|dkrr| jd rrqTi }i }d}d}t| jD ],\}}|d r|| sq|d d d	d }||i }|d d
 d	}|d }|| }|dkr|}qn|dkr|}qt	|dkrP|dkr2|||d < q||i }|| ||d < nZ|dkrt|dkrt|
|| }n6|dkr||| }n|dkrd||| i}|||< |||< q|di }|dd}||d}|s|| tj|\}}|||d< || tj|\}}|di }|drD|d |d< |di }|r|	|}|s|dkrtjjddtjjddd}ntjjddtjjddd}||	|< ||d < ||d< ||d!< ||d"< d#d$d%|jgdd%|d gg}|| tj||\} }| j| |   | ||d < |rH||g }!|!|  |!||< |rt||d g }"|"| |"||d < |d&i d'd}#|#r|# d(|jj }$||$i }%||%d!< |#|%d'< |%d)g }&|&|  |&|%d)< |%||$< ||d}'|'sftjjd#d*d%|jgd'd%d+ggd,}(d#d*d%|(jgd'd%d-gg})d-||(d.d/}*|j| tj|*|)d0\}'}|'||d< || tj|'| d1 qT| D ]\}$}+tjjd#d*d%|+d! jgd'd%d2ggd,}(d#d*d%|(jgd'd%|+d' gdd3d4gg})tjj|)d,},|,stj|+d! |(|+d' tj jd5dd6},|,  |+d) D ]} |,| _!| jd7d8 q q| D ]>\}}-||}.|.rF|-D ]}/|/j!"  |.|/_!|/  qbqF| D ]N\}}0||}.|.r|0D ].}1||1}/|/r|/j!"  |.|/_!|/  qqW n~ t#k
r^ }2 z^t$|2 d9| d:|2 d;t%&|2j'd<  }3| j()|3 |3| _*| j+j,d=d>| _-|   W Y dS d?}2~2X Y nX d7S )@u   
        Запуск импорта из CSV

        :return: Истина в случае успешного импорта
        r   )CmfPluginImportMixinr  FZ	first_rowr[   r  r  r\   r  parent_taskZchild_tasksr   	executorsr   r   priorityr  r  r  rN   r   
cmf_authorZ	cmf_ownerzproject.basez
task.base%base)rN   )Z	cmf_modelprefixZactivityztask.agile:softdev%Zsoftdevr  r   r%   ZANDZ	parent_idr]  r  r$   rR  tasksZtree_parent_idZSprintsr   u
   ДоскаZkanban)r$   r%   r   Z	list_type)r   rs  
obj_fields
filter_obj)leftrightZEpicsr   z	task.epicztask.epic:default)r%   r   r$   Z
logic_typeTrB  u   Строка r]   r  r   import-errorstatus_codeN).Z%common.models.cmf_plugin_import_mixinr  r  r  Z	_get_filer  r  r   r2   r(  Zget_logic_prefixZget_priorityZget_status_type
setdefaultZprocess_any_table_fieldsr0   r   r  CmfWorkflowZcalc_workflowZCmfActivityr;   r   r!  r   r3   rN   r   Z	CmfFolderr  ZCmfListCmfTaskr6  ZCmfLogicTyper   r  r   rF  rO   r  r  r>   	exceptionr  r  r  r  )4r   r  Z
number_rowZall_parent_taskZall_child_tasksZall_epic_tasksZ	all_tasksZ
cash_boardZcash_projectZcash_workflow_taskZ	file_readr   executorr  Zparent_task_codeZchild_tasks_codeidxr  rp  Z_rowZfields_namer  r   Zproject_fieldsr   r   rR  Zexecutor_objZtask_fieldsZvalue_statusr  Zfilter_taskZtask_objZtmp_parent_tasksZtmp_child_tasksZ	epic_nameZepic_keyZtmp_dataZ	tmp_tasksZlist_objZparent_folderr(  r'  dataZepic_objr&  r   Zsub_taskZ
tasks_codeZsub_task_coder  r  r   r   r   r  X  sL   








 




 




"zCmfImport._process_import_excelc                 C   s>  |  |tj}|r|sdS d}| jD ] }|d r$|d d dkr$|}q$|dg tjj|jt|d |j	jdgd}|stj|t|d |j	| d	}|
  |jjd
d t|jjD ]*}|jj| jkrq|  |jj| q| j |tjtjjdd|jgdd|jggd}|ddg ||_||_|jr:|
  |S )u;   
        Импорт товара в сделку
        Nr  r  zCmfProduct.pricescurrencyfile_valprice)
product_idr6  Zcurrency_idr   )productr6  r4  r   T)forceZdeal_idr]  r7  )r   rx  r8  Zsales_order)r  r0   Z
CmfProductr  rV   ZCmfPricer2   r;   r   r4  r3   Zpricesr  r   Z
deal_itemsr   r   r  r   ZCmfDealItemsrf  dealr8  rE  )r   r   r:  r8  Zprice_settingr  r6  itemr   r   r   _process_product  s@    
 zCmfImport._process_productc           	      C   s  |s|r|j sd S d }| jD ] }|d r|d d dkr|}q|sFd S g }tjj|d d}|sxtj|d d}|  |dd|jg |r|dd|jg n|dd|j jg | |tj	|}|
d	d
g |j s|r||_ n|j |_ |js||_|jr
|  |S )Nr  r  zCmfDeal.pipeliner5  r  Zpipeline_idr]  Z
company_idcompanypipeline)r=  r  r0   ZCmfPipeliner2   r3   r   r;   r  ZCmfDealrV   r>  rE  )	r   r   Zcontactr=  Zpipeline_settingr  rx  r>  r:  r   r   r   _process_deal:  s8    
zCmfImport._process_dealc                 C   s   dd l }dd l}dd l}| jr4|  | j dk r4d S |  | _t }z6||j|j}|d | d |d< |	  W n t
k
r   d|d< Y nX z| |d< W n t
k
r   d|d< Y nX | |d< ||  |d	< | jd
|  d S )Nr      )z8.8.8.8P   ipzIP unavailabler  )r   r   r   ZmemoryZdiskzSTATS )rj  r   socketr  r,  ZAF_INETZ
SOCK_DGRAMZconnectZgetsocknamecloseOSError
getloadavgr  
disk_usager  r>   rd   )r   rj  r   rC  statsr  r   r   r   	get_stats]  s*    

zCmfImport.get_statsc                 C   s   dd l }tj  |  }||\}}}|d }tjj| j	ddgd}|dk rd|_
|jr|  t  | jd|d	d
 dS |j
jdks|jdkrd|_
|jr|  t  | jd dS t  |   dS )Nr   r  r  cache_status_typer;   r   
   r+  u8   Импорт прерван, место на диске z.2fz	Gb < 10GbTimport-stoppingIN_PROGRESSimport-pauseduA   **** Импорт остановлен пользователемF)r  rN  rb  Zimport_heartbeatr  rG  r0   r  r2   r;   r  rE  r3   rX   r>   r_   rN   rJ  r   rI  )r   r  r  totalusedfreeZfree_gbrY   r   r   r   rV  z  s.    
zCmfImport.is_cancelr  c              	   C   s   ddl }d| dg}t|trH| D ]\}}|| d| d q(d|}|jdddd	|  d
| dgddtddtddd dS )ul  
        Запускает выполнение метода импорта в отдельном процессе 

        Args:
            method (str): метод импорта
            import_id (str): ID импорта (CmfImport)
            params (dict, optional): параметры запускаемого метода. Defaults to None.
        r   Nr  z="r  r}  r~  r  zHfrom common.models.cmf_import import CmfImportWorker; CmfImportWorker().(r  Tr  r  r  r  )r   r  r,  r6  r   rm   r  r  )methodr  r$  r   Zparams_lr  r  r   r   r   r    s"    


  zCmfImport.run_workerc                  O   s    t jd|d  t j  dS )/   
        Отменяем импорт
        r  r;   N)r0   r  r  r  )re   rD   r   r   r   r    s    zCmfImport.cancelc                 O   s    |  ddddg | jj| dS )uk   
        Предварительный просмотр получившихся объектов
        r  r  r   rW   r   )rV   rW   r  r   re   rD   r   r   r   r    s    zCmfImport.previewc                    s   t   ddddg S )Nr  r  r   rW   )r  save_preload_fieldsr   r  r   r   rW    s    zCmfImport.save_preload_fieldsc                    s   |    t jf |S r  )r  r  r3   r  r  r   r   r3     s    zCmfImport.savec                 C   sH   | j r
d S | jr0| jjdkr0tjjddgd| _ tjjddgd| _ d S )Nr   zimport.system.jira:defaultZsave_eval_code)rN   r   zimport.system:default)r  rW   rU   r0   r/  r2   r   r   r   r   _calc_workflow  s
    zCmfImport._calc_workflowc                 C   sZ   |  dg ttj| jj  d}| jjjj	rH|| jjjj	}|j
ddd |S )Nr  Z	_raw_dataT)rh   rg   )rV   r   r,   r   r}   rW   Zui_namer"  r   r   rv   )r   resr   r   r   r    s    zCmfImport.get_download_pathc                 C   s   | j |  d S r  )rW   download_datar   r   r   r   rZ    s    zCmfImport.download_datac                 C   s   | j |  d S r  )rW   download_filesr   r   r   r   r[    s    zCmfImport.download_filesr
  c                 C   s6  d|krt dd}| d| d| j }tj}| j d| d}|jj|dd}|  zr|j ^}
|
| jj| |d k	r|
j|||d
 n&||r|
| n|
j|d|d
 |
  W 5 Q R X W 5 z|  W nH tjj	k
r" }	 z$t
d|	 d|j d	|j  W 5 d }	~	X Y nX X |dkr2|s2d| d| j }| d}|jj|dd}|  zn||sd| jj|i kr|j 8}
|
| jj| |
j|| j| d |d
 |
  W 5 Q R X W 5 z|  W nH tjj	k
r. }	 z$t
d|	 d|j d	|j  W 5 d }	~	X Y nX X d S )Nr   uA   Нельзя использовать "-" в obj_name: {obj_name}i:	 z.lock   )timeoutzlock release error z, lock_name z
, timeout )exr   r
  zdownloaded-)r   r;   APPREDIS_DBredislockacquirerelease
exceptionsZ	LockErrorgrP  r$   r]  r>  Zsaddr   setr~   ZincrZexecuter  r2   )r   r  r  r   Zttlr   redis_dbZlock_keyrb  ra   piper   r   r   r    sH    
4
"zCmfImport.inc_statc                 C   sj   t j}i }|j| jjD ]J}| }||}|d^}}}||sTt	 ||< | || |< q|S )Nr   )
r_  r`  ra  Zsmembersr;   r   r   r2   r   r,  )r   rh  r  r   r   r  r  rR  r   r   r   r  		  s    


z CmfImport.get_redis_import_statsc                 C   s(   |  ddg | jdkr | jjS |  S )NrJ  r  rN  )rV   rJ  r  r   r  r   r   r   r   r  	  s    
zCmfImport.take_import_statsc                 C   s   |  ddddg | jdks(| jjdkr,dS tj st }| sd}| j	|t
jd	 || _| jjd
d| _|   |   dS dS )Nr  r  rJ  r  rN  import-plannedFu   Импорт прерван по неизвестной причине. Проверьте системные требования.r   r+  r,  T)rV   rJ  r  rN   rN  rb  Zimport_is_runningCmfImportWorker
is_runningrC   r.   rQ   r  r  r  r3   r  )r   Zworkerr  r   r   r   rl  	  s    
zCmfImport.is_runningz	@minutely)Z	only_onceZ
system_jobZschedulec                  C   s`   t j sd S td t jjdddgdddgggdd	dd
gdD ]} |  sBtd|  qBd S )Nz&cmf_deferred_job: CmfImport.cron_checkrJ  r]  rN  zstatus.codezNOT INrj  r  r  r  r   uH   Импорт прерван по неизвестным причинам)	r0   r  r  rf  rP  r   rl  rN  Zadmin_alert)rY   r   r   r   
cron_check.	  s    




zCmfImport.cron_checkreport.json)project_identifierreport_file_namec                 C   s  t jjdddd|  dgdd| gdd| gdd| ggd	d
dggddgd}|s\td|  d|jsrtd| d|jj}|jjd}|s|jjd}|std| dt|	 std| d| d|dkrt
t}|t
j ||_|d| d t }||}t }|| }	t||}
t|
d}t|| W 5 Q R X |jdrD|D ]}|d }|d }|d }|d  }|d!}|d" }|| d#| d$| d%| d& |r|d'|  d(|  |rj|d)|  d(|  qj|d*|	d+d,td-d. t|
tj d/ d |d0 nd1d2l!m!} d3d4 }g }|D ]}|"|| q`d5d6d7d8g}|d9|||d:d;  |d*|	d+ |d<td-d. t|
tj d/ d dS )=u  
        Собирает статистику количества сдампленных и обработанных объектов
        по проекту

        Args:
            project_identifier (str): ext_id, код, префикс кода задач или название проекта
            report_file_name (str, optional): имя файла отчета. Defaults to "report.json".
            logger (Logger, optional): вывод данных отчета.
        r   r   r   r  rN   r   r  r$   r   r   NrP   r   r   u   Проект 'u   ' не найденu   Проект u.    не содержит данных дампаproject_dirrk   u*   В данных дампа проекта uA    отсутствует путь до каталога дампаu@   Отсутствует каталог дампа проекта z: 'r   u3   Сбор статистики по проекту 'zw+r+   entitydumpedr@  r  undownloadedunprocessedu,    (сдамплено/обработано): z / r  r  u   Незагруженные r]   u   Необработанные u   Выполнено за z.4fu,   . Ссылка на файл отчета: 'Tr  zrdisk/file/z2--------------------------------------------------r   )tabulatec                 S   s   dd |   D S )Nc                 S   s   g | ]\}}|d kr|qS ))rr  rs  r@  r  r   r  r   r   r   ru   	  s   z>CmfImport.project_stats.<locals>.data_list.<locals>.<listcomp>)r6  )Z
stats_datar   r   r   	data_list	  s    z*CmfImport.project_stats.<locals>.data_listr[   u   Сдампленоu   Обработаноu   Результатr  Zgrid)headersZtablefmtu*   Ссылка на файл отчета: ')#r0   r   r2   r   r   r   rW   r   r   r~   r.   r:   r   r6   r-   r>   rd   rj  rk  project_statsr}   r  r  dumpr$   r   r   r"  r  r   r   r,   r   rv  r   )ro  rp  r>   r   rW   rq  ru  rH  Zend_timery  Zreport_filerr   Zentity_statsrr  rs  r@  r  rt  ru  rv  rw  r3  rx  r   r   r   ry  ?	  s    



"*"zCmfImport.project_stats)T)NN)F)N)r
  N)rn  N)@r   r   r   r   r  Zui_meta_skipZapi_methodsr  r  r  r   r  classmethodr  r  r  r  r  r,  r  rd  r   r  r   r  r  r  r  r  r
   r  r9   r  r   r  r  r   r  r  r  r  r  r  r<  r?  rI  rV  r  r  r  rW  r3   rX  r  rZ  r[  r  r  r  rl  Zcmf_deferred_jobrm  ry  __classcell__r   r   r  r   r  1  s   

9


	
,N
 2 B!#
,  r  c                    s   t   fdd}|S )Nc              
      sp   z0 | f||}t   | jd t  |W S  tk
rj } zt  | jd|  W 5 d }~X Y nX d S )Nu*   Импорт завершил работуu(   Ошибка работы демона: )rX   r>   rd   r  r  r   rF  r0  )r   re   rD   rY  r   fnr   r   wrapped	  s    z!catch_exceptions.<locals>.wrappedr   )r~  r  r   r}  r   catch_exceptions	  s    
r  c                   @   s   e Zd ZdddZdd Zdd Zdd	d
dZdd Zedd Z	edd Z
edd Zedd Zedd Zdd ZdS )rk  eva-import-workerc                 C   sb   ddl m} dd l}ddlm} ||| _|j| j|d| d|jd |d| d| _	d S )	Nr   r   r   z/var/logz.logr   z	/var/run/z.pid)
cmf.modules.logsr   r.   pathlibr   r:   r>   Zinit_loggerr/   r   )r   r  r   r.   r   r   r   r   __init__	  s     zCmfImportWorker.__init__c                 C   s  | j d tjjddd|gdd|ggdddd	gd
}|  |d |jjddd|_	|
  t  t @ t , t  | }td W 5 Q R X W 5 Q R X W 5 Q R X tjj|jdddd	gd}tjjdd|gd}|j	jdkrX|s|j d |jjdd|_	|
  n:|j	jdkrX|j d| d |jjdd|_	|
  tjjd|d}t|jtjd}tjj||j |j!d|j dt"#t$j%dd | d!d"d# d S )$Nu   Импорт запущенr   r;   r]  rN   r  r  r  r  r   u%   ***Запускаем импорт***rN  import-startedr  r-  r   rK  r   r   u2   ***Импорт успешно завершен***import-completedr,  CLOSEDu6   ***Импорт завершен с ошибками: u,   . Подробности в отчете.***r+  r"   r#   /files/u   Импорт данных 'u   ' завершен %d.%m.%Y %H:%Mz (UTC), <a href=(   >Журнал логирования</a>TrY   Zpersonr$   r@   Zforce_notify_current_person)&r>   rd   r0   r  r2   r   rC   r  r  r  r3   rX   rN  r`  ra  rb  r  geventr  r;   rR   r  rN   r  r1   r   r5   r   r,   r   	CmfNotifyplace_notifyr#  r$   r   r   r   r  )r   r  rY   rY  r  Zlog_filelog_pathr   r   r   run	  sD    

(


"zCmfImportWorker.runc                 C   s  | j d t . t  t  tjjddd|gdd|ggdddd	gd
}|	d |j
jddd|_|  t  | }| }tjjdd|gd}|r|r|s|j d |j
jdd|_|  n:|jjdkr|j d| d |j
jdd|_|  |j jd jtjd}W 5 Q R X W 5 Q R X W 5 Q R X tjj|tj|jdtt j!dd| ddd d S ) Nu   Дамп запущенr   r;   r]  rN   r  r  r  r  r   u!   ***Запускаем дамп***rN  r  r  r   r   u.   ***Дамп успешно завершен***r  r  u2   ***Дамп завершен с ошибками: z***r+  r,  r   r  u'   Дамп данных завершен r  z
, <a href=r  Tr  )"r>   rd   rN  r`  ra  rb  r0   r  r2   rC   r  r  r  r3   rX   rZ  r[  rR   r  r  r7   ZbaseFilenamer   r,   r   r  r  rf  Zcurrent_personr$   r   r   r   r  )r   r  rY   rY  Zres2r  r  r   r   r   	dump_data	  s8    $


6zCmfImportWorker.dump_dataNr    c                 C   sp  | j d t P t : t $ tjjddd|gdd|ggddgdd	}|j	j
d
d|_|  t  zz^d}d}|j d tjjdd|gddD ]^}z*|j d|  |jddd t  W q   t  |d7 }|j d| d Y qX qtjjddd|gdd|ggdddgdd	}|jD ]X}z*|j d|  |jddd t  W n&   t  |d7 }|j d Y nX q8|s|j	j
dd|_|j d n"|j d|  |j	j
dd|_W nX tk
r2 } z8t| |j d|  t||_|j	j
dd|_W 5 d}~X Y nX W 5 |  tjj  X W 5 Q R X W 5 Q R X W 5 Q R X dS )rU  u   Отмена запущенаr   r;   r]  rN   r  r  T)r   r   r  zimport-cancelingr,  r   Nu#   ***** Отменяем импортr   )r   r  u   Удаляем )r  r9  r   u#   Не удалось удалить uW   , видимо обьект использовали вне данных импортаimport_objectsuy   Не удалось удалить, видимо обьект использовали вне данных импортаzimport-canceledu,   Успешно отменили импортu#   Количество ошибок: r+  u   Ошибка удаления )r>   rd   rN  r`  ra  rb  r0   r  r2   r  r  r  r3   rX   r  r  r  r  r   r   r  rF  r0  r  r_   r   r   r  )r   r  rY   r  r   ra   r   r   r   _cancel_import
  s^    $ 
 


&zCmfImportWorker._cancel_importc                 K   s  t jjddd|gdd|ggddddgd	}d
d|jdi}|jjjdkrd|jj|dddd|jj|dddd|jj|dddd}|| ||}|s|j	
d| d d S |d }|di }	|	| |jjddd|_|  t  | j	|d  d t B t . t  |f |	 td  W 5 Q R X W 5 Q R X W 5 Q R X t jj|jddddgd!}t jjd"d|gd#}
|jjdkr|
s|jjd$d%|_|  n&|jjd&kr|jjd'd%|_|  tjj  | j	|d  d( d S ))Nr   r;   r]  rN   r  r  r  r  r   Zlinksu   Обработка ссылок)r$   rT  r   u   Импорт фильтровZ_process_filters)r   Zprocess_method)r$   rT  rD   u3   Обработка связей всех задачZ_process_relationsu7   Обработка истории кодов задачZ_process_code_historyr  uC   Конфигурация для запуска обработки 'u   ' не найденаrT  rD   rN  r  r  r$   u    запущенаr   rK  r   r   r  r,  r  r+  u    завершена) r0   r  r2   r  rW   r   rU   r  r  r>   r_   r  r  r  r3   rX   rd   rN  r`  ra  rb  r  r  r;   rR   r  rN   r  r  r  r  r  )r   r  r  rD   rY   Zprocess_configsZprocess_jira_configsZprocess_configrT  Zmethod_kwargsr  r   r   r   _process_entity8
  s    		



(	
zCmfImportWorker._process_entityc                 G   s>   | j  rtd| j tt  | j|  | j   d S Nu"   Импорт уже запущен)	r   r~   r   
write_textr   rj   getpidr  r  r   re   r   r   r   r9   
  s
    

zCmfImportWorker.startc                 G   s>   | j  rtd| j tt  | j|  | j   d S r  )	r   r~   r   r  r   rj   r  r  r  r  r   r   r   rz  
  s
    

zCmfImportWorker.dumpc                 G   s>   | j  rtd| j tt  | j|  | j   d S r  )	r   r~   r   r  r   rj   r  r  r  r  r   r   r   r  
  s
    

zCmfImportWorker.cancelc                 G   s2  t jjdddgddddgd}|r|  r|jd	 |jjd
d|_|	  t
  tdD ]2}td t jj|jddgd}|jdkr\ qq\n|jd |jjdd|_|	  t
  |jd | j s| jd d S | jd ztt| j tj W n   | jd Y nX | j  d S )NrJ  r]  rN  r  r  r  r  r   uQ   Пытаемся остановить импорт, таймаут 1 минутаrM  r,  <   r   rK  u"   Импорт уже прерванrO  u<   Импорт остановлен пользователемu    Импорт не запущенu'   Останавливаем импортuK   Не удалось завершить процесс, он запущен?)r0   r  r2   rl  r>   r   r  r  r  r3   rX   rl  r  r  r;   rJ  rd   r   r~   rj   killr   	read_textsignalSIGTERMr0  r  )r   re   rY   rv  r   r   r   r  
  s4    


zCmfImportWorker.stopc                 O   s@   | j  rtd| j tt  | j|| | j   d S r  )	r   r~   r   r  r   rj   r  r  r  rV  r   r   r   r  
  s
    
zCmfImportWorker.process_entityc                 C   s0   | j  r,tt| j  r"dS | j   d S )NT)r   r~   rN  Zcheck_process_runningr   r  r  r   r   r   r   rl  
  s    
zCmfImportWorker.is_running)r  )r   r   r   r  r  r  r  r  r  r9   rz  r  r  r  rl  r   r   r   r   rk  	  s    
% 2^




rk  ))r   decimalr   r   r   r.   r   rO   r  r   ra  r  Zbs4r	   r
   rj  rm  rg  r   Zcmf.includer  r   Zcommon.fieldsr   r  r   rj   r  	functoolsr   localr   rh  r8   ZFilterr   r   r   r  r  rk  r   r   r   r   <module>   s\    T        ?         