U
    >jt~                     @   s   d dl mZmZ d dlT 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mZmZ ed	ZG d
d deZdS )    )urlparse	parse_qsl)*N)contextmanager)HTTPAdapter)Retry)
Confluence)ApiNotFoundErrorApiPermissionErrorApiErrorzatlassian.rest_clientc                	       s  e Zd ZdZddejde ddf fdd	Zdd Z	e
d^d	d
Zdd Zdd Zdd Z fddZd_ddZd`ddZda fdd	ZdbddZdcdd Zd!d" Zd#d$ Zd%d& Z fd'd(Z fd)d*Zddeeeeed-d.d/Zdeeeeeed0d1d2Z dfed3d4d5Z!dgd6d7Z"dhd8d9Z#did:d;Z$djd<d=Z%dk fd>d?	Z&dleed@dAdBZ'dmdCdDZ(dnedFdGdHZ) fdIdJZ*dKdL Z+doeeeedMdNdOZ,dpeeeeeeedRdSdTZ-dUdV Z.edWdXdYZ/dZd[ Z0d\d] Z1  Z2S )qConfluenceApiuK    Подключение по API к учетной записи Confluence NTFc	           
   
      s   | dr|nd| }|ds*|d7 }|r4|}nd }t j|f|||||||d|	 |   tjj| _dt|j	 | _
d | _|   d S )Nhttphttps:///)usernamepasswordtimeout
verify_sslsessioncloudtokenzCONFLUENCE:COOKIE:)
startswithendswithsuper__init___set_session_retriesZAPPZREDIS_DBredisr   netloc	redis_keycookies_dict_init_cookies)
selfurlr   r   r   r   r   r   r   kwargs	__class__ ./modules/confluence/api.pyr      s0    
	
zConfluenceApi.__init__c                 C   s@   t tjtjtjdd}t|d}| jd| | jd| dS )u   
        Конфигурирует стратегию повторных попыток
        и ассоциирует ее с сессией
           )totalstatusZstatus_forcelistZbackoff_factorZmax_retrieshttp://r   N)r   configZIMPORT_REQUEST_RETRY_TOTALZ!IMPORT_REQUEST_RETRY_STATUS_CODESr   _sessionmount)r!   ZretriesZhttp_adapterr&   r&   r'   r   ;   s    
z"ConfluenceApi._set_session_retriesc                 c   s   i }t dd}dD ]$}| jj|||< | j|| q| j}|rH|| _z
| V  W 5 | D ],\}}|rx| j|| q\| jj|d q\|r|| _X dS )u<   
        Временно отключает Retry.
        r   r+   )r,   r   N)r   r.   Zadaptersgetr/   r   itemspop)r!   r   Zold_adaptersZno_retry_adapterprefixZold_timeoutZadapterr&   r&   r'   without_retryJ   s     

zConfluenceApi.without_retryc                 C   sX   | j | j}|rTz*t|}| jj| | jj | _	W n tj
k
rR   Y nX dS )u  
        Добавляет cookie в сессию при инициализации,
        что бы не выполнять повторную авторизацию, если cookie еще действуют.
        При недействительных cookie, выполнится авторизация,
        а cookie обновятся в сессии и кеше
        N)r   r0   r   pickleloadsr.   cookiesupdateget_dictr   ZPickleError)r!   cookies_pickler7   r&   r&   r'   r    j   s    
zConfluenceApi._init_cookiesc                 C   s&   t | jj}| jj| j|dd dS )u   
        Сохраняет cookie в кеш (Redis) для последующего использования
        без выполнения повторной авторизации
        i`T  )exN)r5   dumpsr.   r7   r   setr   )r!   r:   r&   r&   r'   _save_cookiesz   s    zConfluenceApi._save_cookiesc                 C   s(   | j j }| j|kr$|| _|   dS )u   
        Проверяет изменение cookie и обновляет их в кеше при необходимости
        N)r.   r7   r9   r   r>   )r!   Zcurrent_cookies_dictr&   r&   r'   _check_cookies   s    
zConfluenceApi._check_cookiesc                    s   t  j||}|   |S )N)r   requestr?   )r!   argsr#   responser$   r&   r'   r@      s    zConfluenceApi.request   c           	   
   C   s   | j }|p| j}| jd||d | jj|d||| j| jd`}td| d|j	 d|j
  |  t|d"}|j|d	D ]}|| q~W 5 Q R X W 5 Q R X d
S )us  
        Скачивает файл

        Args:
            download_url (_type_): url файла для скачивания
            save_path (_type_): путь для сохранения файла
            timeout (_type_, optional): Таймаут. Defaults to None.
            chunk_size (_type_, optional): _description_. Defaults to 64*1024.
        ZGET)methodr"   headersT)streamrE   r   Zverifyproxiesz
HTTP: GET z ->  zwb+)
chunk_sizeN)Zno_check_headersr   Zlog_curl_debugr.   r0   r   rG   loggerdebugstatus_codereasonZraise_for_statusopenZiter_contentwrite)	r!   Zdownload_urlZ	save_pathr   rI   rE   resfchunkr&   r&   r'   download_file   s"    

 zConfluenceApi.download_filec                 c   s`   |dkri }| j ||d}d|kr&dS | dg D ]
}|V  q2| di  d}|dkrq\qdS )ue  
        Используется для получения постраничных данных

        Args:
            url (str): URL для получения
            params (dict, optional): Параметры. Defaults to None.

        Yields:
            _type_: Объект-генератор для элементов данных
        Nparamsresults_linksnextr0   )r!   r"   rU   rB   valuer&   r&   r'   
_get_paged   s    zConfluenceApi._get_pagedc                 #   sp   |r|d }|d |d  }nd}d}t  j|||d}|rl|dsHql|d D ]
}|V  qP|rbql||7 }q&dS )u   
        Получим все пространства из Confluence

        :return: Список всех пространств
        r   r(   d   )
space_typestartlimitrV   N)r   get_all_spacesr0   )r!   r]   slicer^   r_   rP   rowr$   r&   r'   r`      s    zConfluenceApi.get_all_spacespagec              
   C   s   d}i }|r||d< |r ||d< |r,||d< |r8||d< |rD||d< |rP||d< zH| j sp|dkrp| j||d	W S | j||d	}	| j r|	W S |	d
W S W n> tjk
r }
 z|
jjdkrtd|
d W 5 d}
~
X Y nX dS )u  
        Получает все страницы пространства

        Переопределенный метод

        Args:
            space (str): Ключ пространства
            start (int, optional): Начальная позиция коллекции для возврата . Defaults to None.
            limit (int, optional): Ограничение на количество возвращаемых страниц. Defaults to None.
            status (str, optional): Статус страниц. Defaults to None.
            expand (str, optional): Список свойств для расширения данных страниц. Defaults to None.
            content_type (str, optional): Тип страниц. Defaults to "page".

        Raises:
            ApiPermissionError: _description_

        Returns:
            _type_: _description_
        zrest/api/contentZspaceKeyr^   r_   r*   expandtypeNrT   rV     z=The calling user does not have permission to view the contentrM   )advanced_moder[   r0   requests	HTTPErrorrB   rL   r
   )r!   spacer^   r_   r*   rd   content_typer"   rU   rB   er&   r&   r'   get_all_pages_from_space   s8    z&ConfluenceApi.get_all_pages_from_space   archivedc                 c   s    | j ||||||dE dH  dS )ud   
        Получает архивные документы из пространства
        )r^   r_   r*   rd   rl   N)rn   )r!   rk   r^   r_   r*   rd   rl   r&   r&   r'    get_all_pages_from_space_archive  s    z.ConfluenceApi.get_all_pages_from_space_archivec              
   c   s   t ddd}|||< d}zD| j||d}|ds8W d S |d E d H  |d  |d 7  < W q tjk
r } z td	| d
|  W Y d S d }~X Y qX qd S )Nr      r^   r_   zrest/api/user/memberofrT   rV   r^   r_   uL   Не удалось получить группы пользователя "". )dictr0   ri   rj   rJ   warning)r!   keyrZ   rU   r"   rP   Zhttp_errr&   r&   r'   user_member_of"  s    
zConfluenceApi.user_member_ofc              
   C   sR   z|  |}W n> tk
rL } z td| d|  t }W 5 d }~X Y nX |S )NuL   Не удалось получить данные пользователя "rt   )Zget_mobile_parameters	ExceptionrJ   rv   ru   )r!   r   infoerrorr&   r&   r'   get_user_detail2  s    zConfluenceApi.get_user_detailc                 #   sv  | j rtddddd}| jd|d}|d s0d S |d D ]\}|d	  | j d
 d}  fdd| D  dd | d
 d
 D  d<  V  q8|d  |d 7  < qntddddd}| jf |}|d sd S |d D ]|}|d	 d dkrt	d q|d	  | j|d	 d d}  fdd| D  dd | d d D  d<  V  q|d  |d 7  < qd S )Nr   rr   zuser=""zoperations,personalSpace)r^   r_   cqlrd   zrest/api/search/userrT   rV   user	accountIdr   c                 3   s*   | ]"\}}| ks|d kr||fV  qdS  Nr&   .0kvr~   r&   r'   	<genexpr>E  s     z.ConfluenceApi.get_all_users.<locals>.<genexpr>c                 S   s   g | ]}|qS r&   r&   r   gr&   r&   r'   
<listcomp>G  s     z/ConfluenceApi.get_all_users.<locals>.<listcomp>groupsr^   r_   z	type=userz&user.operations,user.status,user.emailr   Zrecovery_adminu   В вашем Confluence включен режим восстановления! Не оставляйте Confluence в режиме восстановления и не используйте учетную запись recovery_admin!c                 3   s*   | ]"\}}| ks|d kr||fV  qdS r   r&   r   r   r&   r'   r   X  s     c                 S   s   g | ]}|qS r&   r&   r   r&   r&   r'   r   Z  s     )
r   ru   r0   r|   r8   r1   rx   r}   rJ   rv   )r!   rU   rP   rb   Z	user_infor&   r   r'   get_all_users;  s4    
zConfluenceApi.get_all_usersc                 #   sF   t ddd}t jf |}|s"d S |E d H  |d  |d 7  < qd S )Nr   rr   rs   r^   r_   )ru   r   get_all_groups)r!   rU   rP   r$   r&   r'   r   ^  s    
zConfluenceApi.get_all_groupsc                 #   sP   t dd|dd}t jf |}|s&d S |D ]
}|V  q*|d  |d 7  < qd S )Nr   rr   zoperations,status)r^   r_   
group_namerd   r^   r_   )ru   r   get_group_members)r!   r   rU   rP   rb   r$   r&   r'   r   g  s    zConfluenceApi.get_group_membersr   rr   )
content_idr^   r_   rd   returnc                 c   s&  d| d}i }|dk	r$t ||d< |dk	r8t ||d< |dk	rH||d< |sTd|d< | j||d	}|d
 D ]F}	|r|	d dkrdd | j|	d ||dD |	d< ng |	d< |	V  qj|d }
|
d}|s̐q"t|}tt|j}|d |d< |dr|d|d< |drT|d|d< qTdS )u  
        Получает все комментарии к документу

        Args:
            content_id (str): ID страницы(документа) в Confluence
            expand (str): Cвойства элемента, которые нужно расширить, например, expand='body,version,history'
            children (bool): Создать иерархическую структуру с дочерними элементами

        Yields:
            Iterator[list]: элемент
        rest/api/content/z/child/commentNr^   r_   rd   alldepthrT   rV   r*   currentc                 S   s   g | ]}|qS r&   r&   )r   objr&   r&   r'   r     s    z3ConfluenceApi.get_page_comments.<locals>.<listcomp>id)rd   childrenr   rW   rX   cursor)intr0   get_page_commentsr   ru   r   query)r!   r   r^   r_   rd   r   r"   rU   rP   resultlinksnext_
next_parser   r&   r&   r'   r   q  sB    

zConfluenceApi.get_page_comments)	key_spacerd   detailedinclude_childrenr   c                 #   sv  ddddddh}d}d}|r\|r4d	d
 | dD ng }|d | jrR|d d|}| j|d|||dd}d|kr~dS |dg D ]  d d  d< |r$ d d d }	 d di d}
t|	p|
}|r
dd
 | j d ddD }|jdd d ng }d|t	|di d< |r2 V  q fdd|D V  q|di d }|dkrhqr||7 }q\dS )!ui  
        Получим все документы из корня пространства.

        :param key_space: Идентификатор пространства.
        :param expand: Дополнительные данные по документам.

        :return: Соответствие id документа и его данных.
        r   titlere   r*   positionr   r   2   c                 S   s   g | ]}|  r|qS r&   stripr   _r&   r&   r'   r     s      z;ConfluenceApi.get_root_pages_from_space.<locals>.<listcomp>,children.pagechildren.folderrootrc   )r   rd   r^   r_   rl   rV   N
extensionssizefolderc                 S   s   g | ]}|qS r&   r&   r   childr&   r&   r'   r     s     Fr   c                 S   s   | d S Nr   r&   pr&   r&   r'   <lambda>      z9ConfluenceApi.get_root_pages_from_space.<locals>.<lambda>rw   rV   r   c                    s   i | ]}| kr| | qS r&   r&   r   rw   rc   r&   r'   
<dictcomp>  s       z;ConfluenceApi.get_root_pages_from_space.<locals>.<dictcomp>rW   rX   )
splitappendr   joinZget_space_contentr0   boolget_childrensortlen)r!   r   rd   r   r   key_for_briefr^   r_   rB   has_page
has_folderhas_childrenr   has_nextr&   r   r'   get_root_pages_from_space  s^    	



z'ConfluenceApi.get_root_pages_from_spacerd   c           	      c   sv   t |||d}| j|f|}|rr|ds,qr|d D ]
}|V  q4|di d}|d kr\qr|d  |d 7  < qd S )N)r^   r_   rd   rV   rW   rX   r^   r_   )ru   Zget_attachments_from_contentr0   )	r!   page_idr^   r_   rd   rU   rP   rb   r   r&   r&   r'   get_all_attachment  s    z ConfluenceApi.get_all_attachmentc                 C   s,   z| j ||dW S  tk
r&   Y d S X d S )N)userkeyrd   )Zget_user_details_by_userkeyr	   )r!   r   rd   r&   r&   r'   get_user_info_by_key  s    z"ConfluenceApi.get_user_info_by_keyc                 C   s   | j r| j||dS d S )Nr   )r   get_user_details_by_accountid)r!   r   rd   r&   r&   r'   get_user_info  s    zConfluenceApi.get_user_infoc                 C   sR   z6| j r(| j|d}| j|d |dW S | j||dW S  tk
rL   Y d S X d S )Nr   r   )Z	accountidrd   )r   rd   )r   get_account_idr   Zget_user_details_by_usernamer	   )r!   r   rd   r~   r&   r&   r'   get_user_info_by_username  s    z'ConfluenceApi.get_user_info_by_usernamec                 C   s4   d}|rd|i}nd|i}| j ||d}|d d S )Nzrest/api/user/bulk/migrationr   r   rT   rV   r   rY   )r!   r   r   r"   rU   rP   r&   r&   r'   r     s    
zConfluenceApi.get_account_idc                    s  ddddddh}|rT|r,dd | d	D ng }|d
 | jrJ|d d	|}t j||||d  d d  d< |r d d d } d di d}	t|p|	}
|
rdd | j||dD }|j	dd d ng }d|t
|di d< |r  S  fdd|D S dS )u  
        Возвращает данные контента

        Николай1: expand='children.page' имеет лимит 25 элементов, запрашиваем детей вручную
        https://jira.atlassian.com/browse/CONFSERVER-52558?src=confmacro

        Bспользуется в двух местах, поэтому вынес в глобальный API

        Args:
            page_id (str, int): ID контента
            detailed (bool, optional): Вернуть подробные данные. Defaults to True.
            include_children (bool, optional): Запросить дочерние объекты. Defaults to False.

        Returns:
            page (dict): данные контента
        r   r   re   r*   r   r   c                 S   s   g | ]}|  r|qS r&   r   r   r&   r&   r'   r   =  s      z0ConfluenceApi.get_page_by_id.<locals>.<listcomp>r   r   r   )rd   r*   versionr   rc   r   r   c                 S   s   g | ]}|qS r&   r&   r   r&   r&   r'   r   K  s     r   c                 S   s   | d S r   r&   r   r&   r&   r'   r   L  r   z.ConfluenceApi.get_page_by_id.<locals>.<lambda>r   r   c                    s   i | ]}| kr| | qS r&   r&   r   r   r&   r'   r   Y  s       z0ConfluenceApi.get_page_by_id.<locals>.<dictcomp>N)r   r   r   r   r   get_page_by_idr0   r   r   r   r   )r!   r   rd   r*   r   r   r   r   r   r   r   r   r$   r   r'   r     s>    	


zConfluenceApi.get_page_by_id)typesr   c                 #   s~   dddddh}|dkr*| j s"dgnddg}|D ]J}| j|||d	D ]4  d
 d  d< |rb V  qB fdd|D V  qBq.dS )u  
        Возвращает дочерние объекты(контент)

        Args:
            parent_id (_type_): ID родительского контента
            types (list, optional): Список типов дочерних объектов. Defaults to None.
            detailed (bool, optional): Вернуть подробные данные. Defaults to True.

        Yields:
            dict: данные дочернего объекта(контента)
        r   r   re   r*   r   Nrc   r   )re   rd   r   c                    s   i | ]}| kr| | qS r&   r&   r   r   r&   r'   r   z  s       z.ConfluenceApi.get_children.<locals>.<dictcomp>)r   Zget_page_child_by_type)r!   Z	parent_idr   rd   r   r   type_r&   r   r'   r   [  s    zConfluenceApi.get_childrenc           
   
   C   s   i }|d k	rt ||d< |d k	r,t ||d< |d k	r<||d< d| d| }zH| jsl|d krl| j||dW S | j||d}| jr|W S |dW S W n> tjk
r }	 z|	jjdkrtd	|	d
 W 5 d }	~	X Y nX d S )Nr^   r_   rd   r   z/descendant/rT   rV   rf   zgThere is no content with the given id, or the calling user does not have permission to view the contentrg   )	r   rh   r[   r0   ri   rj   rB   rL   r   )
r!   r   rl   r^   r_   rd   rU   r"   rB   rm   r&   r&   r'   get_page_descendant_by_type|  s,    z)ConfluenceApi.get_page_descendant_by_typer\   )r   c                 c   s8   |dkrddg}|D ]}| j |||||dE dH  qdS )u  
        Возвращает потомков в контента для заданной страницы

        Args:
            page_id (int): ID страницы
            types (list, optional): типы потомков. Defaults to None.
            start (int, optional): Начальная позиция коллекции для возврата . Defaults to None.
            limit (int, optional): Ограничение на количество возвращаемых потомков. Defaults to 100.
            expand (str, optional): Список свойств для расширения данных. Defaults to None.

        Yields:
            _type_: _description_
        Nrc   r   )rl   r^   r_   rd   )r   )r!   r   r   r^   r_   rd   r   r&   r&   r'   get_descendants  s    zConfluenceApi.get_descendantsc                 #   s&   t t | d d E d H  d S )N)listr    get_all_restrictions_for_contentvalues)r!   r   r$   r&   r'   r     s    z.ConfluenceApi.get_all_restrictions_for_contentc                 c   sT   t dd|d}| jf |}|d E d H  |d  |d 7  < |d |d k rqPqd S )Nr   r\   )r^   r_   r   rV   r^   r_   r   )ru   Zget_page_labels)r!   r   rU   rP   r&   r&   r'   get_all_page_labels  s    z!ConfluenceApi.get_all_page_labels)r   version_numberrd   r   c                 C   sJ   | j rd| d| }nd| d| }i }|dk	r<||d< | j||dS )u  
        Получает определенную версию документа

        Args:
            content_id (str): ID страницы(документа) в Confluence
            version_number (int): номер версии страницы(документа)
            expand (str): Cвойства элемента, которые нужно расширить, например, expand='body,version,history'

        Return:
            dict: данные версии документа
        r   z	/version/rest/experimental/content/Nrd   rT   )r   r0   )r!   r   r   rd   r"   rU   r&   r&   r'   get_page_version  s    zConfluenceApi.get_page_version   r   )r   current_versionr^   r_   last_versionsrd   r   c                 c   s  |sdS | j rd| d}nd| d}i }|dk	r@t||d< |dk	rTt||d< |dk	rd||d< d}	zl| j||d	}
|
d
 }|d}|
d D ]>}|	d7 }	d|  kr|	k rn nd} q|d d }|V  qW n   t|ddD ]~}|	d7 }	d|  kr|	k rn n qhz| |||V  W q tk
rd } ztd| d| V  W 5 d}~X Y qX qd}Y nX |s|qt|}tt|j	}|d |d< |dr|d|d< |drh|d|d< qhdS )u  
        Получает версии страницы (историю документа)
        При большом количестве данных в версиях, limit > 5 может не работать,
        зависает, либо падает с ошибкой по таймауту.
        Получение версий списком может упасть с ошибкой 500 "Internal Server Error", если в ответе будет кривая версия.
        При получении ошибки при запросе списков, пытаемся получить версии по одной.

        Args:
            content_id (str): ID страницы(документа) в Confluence
            current_version (int): номер текущй версии страницы(документа)
            last_versions (int): колчество послених версий для получения, при "-1" - получение всех версий
            expand (str): Cвойства элемента, которые нужно расширить, например, expand='body,version,history'

        Yields:
            Iterator[list]: элемент
        Nr   z/versionr   r^   r_   rd   r   rT   rW   rX   rV   r(   Fnumberr   u   версия z. r   )
r   r   r0   ranger   ry   r   ru   r   r   )r!   r   r   r^   r_   r   rd   r"   rU   Zversion_countrP   r   r   r   r   excr   r   r&   r&   r'   get_page_versions  sV    
*

zConfluenceApi.get_page_versionsc                 C   sl   | j r | j|dd}|dg S |dkr>d| d}| |S d}ddd	|gd
}| j||ddg S d S )NZpermissions)	space_keyrd   
   zrest/api/space/z/permissionsz!rpc/json-rpc/confluenceservice-v2z2.0ZgetSpacePermissionSets   )ZjsonrpcrD   r   rU   )datar   )r   Z	get_spacer0   Zpost)r!   r   r   Z
space_datar"   r   r&   r&   r'   get_space_permissions.  s    
z#ConfluenceApi.get_space_permissions)r   c                 C   s   d}|  |S )u   
        Получает связи с другими системами

        Return:
            applinks (dict): данные связей с другими системами
        zrest/applinks/3.0/applinksrY   r!   r"   r&   r&   r'   get_applinks@  s    zConfluenceApi.get_applinksc                 C   s   d}|  |S )u7   Получить информацию о системеzrest/applinks/1.0/manifestrY   r   r&   r&   r'   get_system_infoK  s    zConfluenceApi.get_system_infoc                 C   s   d}|  |S )u^   
        Возвращает данные о текущем пользователе
        zrest/api/user/currentrY   r   r&   r&   r'   get_current_userP  s    zConfluenceApi.get_current_user)N)NrC   )N)NN)NNNNrc   )Nro   rp   Nrc   )r   rr   NT)NTF)r   rr   N)N)N)N)NN)NNNTF)NNT)rc   NNN)NNr\   N)N)r   r   r   N)3__name__
__module____qualname____doc__r-   Z!IMPORT_CONFLUENCE_REQUEST_TIMEOUTZcmfutilZrequests_sessionr   r   r   r4   r    r>   r?   r@   rS   r[   r`   rn   rq   rx   r|   r   r   r   strr   r   r   r   ru   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__r&   r&   r$   r'   r      s   )	


4
	#	        7F


	
     B!

    Sr   )urllib.parser   r   Zcmf.includer5   ri   
contextlibr   Zrequests.adaptersr   Zurllib3.util.retryr   Z	atlassianr   Zatlassian.errorsr	   r
   r   ZloggingZ	getLoggerrJ   r   r&   r&   r&   r'   <module>   s   
