
    ic                         d dl mZmZ d dl 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 ej#                  d	      Z G d
 de      Zy)    )urlparse	parse_qsl)*N)contextmanager)HTTPAdapter)Retry)
Confluence)ApiNotFoundErrorzatlassian.rest_clientc                       e Zd ZdZddej
                  dej                         ddf fd	Zd Z	e
d1d       Zd Zd	 Zd
 Z fdZd2dZd3 fd	Zd4dZd Zd Zd Z fdZ fdZ	 	 d5dededededef
dZd1dededefdZd6defdZd1dZd1dZ d1dZ!d3d Z"ddd! fd"
Z#d7d#ed$e$fd%Z% fd&Z&d' Z'd1ded(ededefd)Z(	 	 	 	 d8ded*ededed+ededefd,Z)d- Z*defd.Z+d/ Z,d0 Z- xZ.S )9ConfluenceApiuK    Подключение по API к учетной записи Confluence NTFc	                 f   |j                  d      r|nd| }|j                  d      s|dz  }|r|}nd }t        
|   |f|||||||d|	 | j	                          t
        j                  j                  | _        dt        |      j                   | _
        d | _        | j                          y )Nhttphttps:///)usernamepasswordtimeout
verify_sslsessioncloudtokenzCONFLUENCE:COOKIE:)
startswithendswithsuper__init___set_session_retriesAPPREDIS_DBredisr   netloc	redis_keycookies_dict_init_cookies)selfurlr   r   r   r   r   r   r   kwargs	__class__s             ./modules/confluence/api.pyr   zConfluenceApi.__init__   s     ^^F+c8C51A||C 3JCHE
	
!
	
 
	
 	!!#\\''
-hsm.B.B-CD     c                     t        t        j                  t        j                  t        j                  d      }t	        |      }| j
                  j                  d|       | j
                  j                  d|       y)u   
        Конфигурирует стратегию повторных попыток
        и ассоциирует ее с сессией
           )totalstatusstatus_forcelistbackoff_factormax_retrieshttp://r   N)r   configIMPORT_REQUEST_RETRY_TOTAL!IMPORT_REQUEST_RETRY_STATUS_CODESr   _sessionmount)r$   retrieshttp_adapters      r(   r   z"ConfluenceApi._set_session_retries:   s`    
 3344#EE	
 #w7I|4J5r)   c              #     K   i }t        d      }dD ]F  }| j                  j                  j                  |      ||<   | j                  j	                  ||       H | j
                  }|r|| _        	 |  |j                         D ]J  \  }}|r| j                  j	                  ||       %| j                  j                  j                  |d       L |r|| _        yy# |j                         D ]J  \  }}|r| j                  j	                  ||       %| j                  j                  j                  |d       L |r|| _        w w xY ww)u<   
        Временно отключает Retry.
        r   r0   )r2   r   N)r   r6   adaptersgetr7   r   itemspop)r$   r   old_adaptersno_retry_adapterprefixold_timeoutadapters          r(   without_retryzConfluenceApi.without_retryI   s=    
 &15 . 	:F#'==#9#9#=#=f#EL MM(89	: ll"DL	+J $0#5#5#7 =MM''8MM**..vt<	= *  $0#5#5#7 =MM''8MM**..vt<	= * s    A/E
2C 6A(E
A)EE
c                 N   | j                   j                  | j                        }|re	 t        j                  |      }| j
                  j                  j                  |       | j
                  j                  j                         | _	        yy# t        j                  $ r Y yw xY w)u  
        Добавляет cookie в сессию при инициализации,
        что бы не выполнять повторную авторизацию, если cookie еще действуют.
        При недействительных cookie, выполнится авторизация,
        а cookie обновятся в сессии и кеше
        N)r   r<   r!   pickleloadsr6   cookiesupdateget_dictr"   PickleError)r$   cookies_picklerH   s      r(   r#   zConfluenceApi._init_cookiesi   s     7 ,,~6%%,,W5$(MM$9$9$B$B$D!	 
 %% s   A#B B$#B$c                     t        j                  | j                  j                        }| j                  j                  | j                  |d       y)u   
        Сохраняет cookie в кеш (Redis) для последующего использования
        без выполнения повторной авторизации
        i`T  )exN)rF   dumpsr6   rH   r   setr!   )r$   rL   s     r(   _save_cookieszConfluenceApi._save_cookiesy   s6    
  dmm&;&;<

t~~~+Fr)   c                     | j                   j                  j                         }| j                  |k7  r|| _        | j	                          yy)u   
        Проверяет изменение cookie и обновляет их в кеше при необходимости
        N)r6   rH   rJ   r"   rQ   )r$   current_cookies_dicts     r(   _check_cookieszConfluenceApi._check_cookies   sE      $}}44==? 44 4D  5r)   c                 F    t        |   |i |}| j                          |S N)r   requestrT   )r$   argsr&   responser'   s       r(   rW   zConfluenceApi.request   s'    7?D3F3r)   c           	         | j                   }|xs | j                  }| j                  d||       | j                  j	                  |d||| j
                  | j                        5 }t        j                  d| d|j                   d|j                          |j                          t        |d      5 }|j                  |	      D ]  }|j                  |        	 d
d
d
       d
d
d
       y
# 1 sw Y   xY w# 1 sw Y   y
xY w)us  
        Скачивает файл

        Args:
            download_url (_type_): url файла для скачивания
            save_path (_type_): путь для сохранения файла
            timeout (_type_, optional): Таймаут. Defaults to None.
            chunk_size (_type_, optional): _description_. Defaults to 64*1024.
        GET)methodr%   headersT)streamr]   r   verifyproxiesz
HTTP: GET z ->  zwb+)
chunk_sizeN)no_check_headersr   log_curl_debugr6   r<   r   r`   loggerdebugstatus_codereasonraise_for_statusopeniter_contentwrite)	r$   download_url	save_pathr   rb   r]   resfchunks	            r(   download_filezConfluenceApi.download_file   s     '')T\\5lGL]]??LL  
 	# LL:l^47H#**VW  "i' #1 ---D #EGGEN##	# 	## #	# 	#s%   &AC<5)C0C<0C9	5C<<Dc              #      K   |r|d   }|d   |d   z
  }nd}d}	 t         |   |||      }|r|j                  d      sy|d   D ]  }|  |ry||z  }=w)u   
        Получим все пространства из Confluence

        :return: Список всех пространств
        r   r+   d   )
space_typestartlimitresultsN)r   get_all_spacesr<   )r$   ru   slicerv   rw   ro   rowr'   s          r(   ry   zConfluenceApi.get_all_spaces   s      !HE!HuQx'EEE'(JeSX(YCcggi09~ 	 UNE s   AAc              #   b   K   	 | j                  |||||      }|sy|E d{    ||z  })7 
w)ud   
        Получает архивные документы из пространства
        )content_typeN)get_all_pages_from_space)r$   spacerv   rw   r-   r}   ro   s          r(    get_all_pages_from_space_archivez.ConfluenceApi.get_all_pages_from_space_archive   sG      //ueVZf/gCNNUNE  s    /-/c              #   6  K   t        dd      }|||<   d}	 	 | j                  ||      }|j                  d      sy |d   E d {    |dxx   |d   z  cc<   D7 # t        j                  $ r%}t        j                  d	| d
|        Y d }~y d }~ww xY ww)Nr      rv   rw   zrest/api/user/memberofparamsrx   rv   rw   uL   Не удалось получить группы пользователя "". )dictr<   requests	HTTPErrorre   warning)r$   keyvaluer   r%   ro   http_errs          r(   user_member_ofzConfluenceApi.user_member_of   s     AR(s&hhs6h2wwy)y>))w6'?2 
 *%% !mnsmttw  yA  xB   C  DsJ   B$A BA AA BA B1BBBBc                     	 | j                  |      }|S # t        $ r0}t        j                  d| d|        t	               }Y d }~|S d }~ww xY w)NuL   Не удалось получить данные пользователя "r   )get_mobile_parameters	Exceptionre   r   r   )r$   r   infoerrors       r(   get_user_detailzConfluenceApi.get_user_detail   s[    	--h7D
 	  	NNijrissvw|v}~6D		s    	A%A		Ac              #   >  K   | j                   rt        dddd      }	 | j                  d|      }|d   sy |d   D ]n  }|d	   | j                  d
         }j	                  fd|j                         D               | j                  d
d
         D cg c]  }| c}d<    p |dxx   |d   z  cc<   t        dddd      }	  | j                  di |}|d   sy |d   D ]  }|d	   d   dk(  rt        j                  d       $|d	   | j                  |d	   d         }j	                  fd|j                         D               | j                  dd         D cg c]  }| c}d<     |dxx   |d   z  cc<   c c}w c c}w w)Nr   r   zuser=""zoperations,personalSpace)rv   rw   cqlexpandzrest/api/search/userr   rx   user	accountIdr   c              3   >   K   | ]  \  }}|vs|d k7  r||f  yw N .0kvr   s      r(   	<genexpr>z.ConfluenceApi.get_all_users.<locals>.<genexpr>   -       =41a#$D=AG "#A  =   groupsrv   rw   z	type=userz&user.operations,user.status,user.emailr   recovery_adminu   В вашем Confluence включен режим восстановления! Не оставляйте Confluence в режиме восстановления и не используйте учетную запись recovery_admin!c              3   >   K   | ]  \  }}|vs|d k7  r||f  ywr   r   r   s      r(   r   z.ConfluenceApi.get_all_users.<locals>.<genexpr>  r   r   r   )
r   r   r<   r   rI   r=   r   r   re   r   )r$   r   ro   r{   	user_infogr   s         @r(   get_all_userszConfluenceApi.get_all_users   s    ::C]^Fhh5fhE9~y> Cv;D $ 4 4d;>O 4 PIKK  =9??3D  = =151D1D[RVWbRc1d%eAa%eDNJ w6'?2  EmnFdhh((9~y> C6{:.2BB (t u !v;D $ 4 4c&k*>U 4 VIKK  =9??3D  = =151D1DZQUV`Qa1b%cAa%cDNJ w6'?2!  &f& &ds   BF	F#C
F-	F6'Fc              #      K   t        dd      }	 t        |   di |}|sy |E d {    |dxx   |d   z  cc<   -7 w)Nr   r   r   rv   rw   r   )r   r   get_all_groups)r$   r   ro   r'   s      r(   r   zConfluenceApi.get_all_groups  sQ     AR('(262CNN7Ovg.O  s   &A?Ac              #      K   t        dd|d      }	 t        |   di |}|sy |D ]  }|  |dxx   |d   z  cc<   .w)Nr   r   zoperations,status)rv   rw   
group_namer   rv   rw   r   )r   r   get_group_members)r$   r   r   ro   r{   r'   s        r(   r   zConfluenceApi.get_group_members  s^     ARJGZ['+5f5C 	7Ovg.O s   ?A
content_idrv   rw   r   returnc              #   R  K   d| d}i }|t        |      |d<   |t        |      |d<   |||d<   |sd|d<   	 | j                  ||	      }|d
   D ]8  }	|r0|	d   dk(  r(| j                  |	d   ||      D 
cg c]  }
|
 c}
|	d<   |	 : |d   }|j                  d      }|syt        |      }t	        t        |j                              }|d   |d<   |j                  d      r|j                  d      |d<   |j                  d      r|j                  d      |d<   c c}
w w)u  
        Получает все комментарии к документу

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

        Yields:
            Iterator[list]: элемент
        rest/api/content/z/child/commentNrv   rw   r   alldepthr   rx   r-   currentid)r   childrenr   _linksnextcursor)intr<   get_page_commentsr   r   r   query)r$   r   rv   rw   r   r   r%   r   ro   resultobjlinksnext_
next_parser   s                  r(   r   zConfluenceApi.get_page_comments  si     "*^<!%jF7O!%jF7O%F8#F7O((3v(.Ci. x 0I =9=9O9OPVW[P\W]Ya :P :c *d## *dF:&  MEIIf%E!%J:#3#345E#GnF7Oyy"#(99X#6x yy !&6!2v- *ds   A6D'8	D"B&D'	key_spacec              #   v  K   d}d}	 | j                  |d|||d      }|d   D ]  }|d   |d   |d	   dg dd
id}|j                  d      rU| j                  |d   d      D cg c]  }| }	}|	j                  d        |	|d   d   d<   t	        |	      |d   d   d<   |  |d   sy||z  }c c}w w)ui  
        Получим все документы из корня пространства.

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

        :return: Соответствие id документа и его данных.
        r   2   rootpage)r   r   rv   rw   r}   rx   r   titletyperx   size)r   r   r   r   r   Fdetailedc                     | d   S Npositionr   ps    r(   <lambda>z9ConfluenceApi.get_root_pages_from_space.<locals>.<lambda>k  s
    * r)   r   r   N)get_space_contentr<   get_childrensortlen)
r$   r   r   rv   rw   ro   r{   datachildr   s
             r(   get_root_pages_from_spacez'ConfluenceApi.get_root_pages_from_spaceO  s     ((&W\di;A ) CC9~ d) \K')$%!!	
 77:&373D3DSYY^3D3_`%`H`MM&=M>:BD$V,Y77:8}D$V,V4
#$ y>UNE/    as   A#B9%	B4.AB9c              #      K   t        |||      }	  | j                  |fi |}|r|j                  d      sy |d   D ]  }|  |dxx   |d   z  cc<   Fw)N)rv   rw   r   rx   rv   rw   )r   get_attachments_from_contentr<   )r$   page_idrv   rw   r   r   ro   r{   s           r(   get_all_attachmentz ConfluenceApi.get_all_attachments  sn     Ev>3$33GFvFCcggi09~ 	7Ovg.O s   AAc                 H    	 | j                  ||      S # t        $ r Y y w xY w)N)userkeyr   )get_user_details_by_userkeyr
   )r$   r   r   s      r(   get_user_info_by_keyz"ConfluenceApi.get_user_info_by_key~  s/    	33GF3SS 		s    	!!c                 B    | j                   r| j                  ||      S y )N)r   )r   get_user_details_by_accountid)r$   r   r   s      r(   get_user_infozConfluenceApi.get_user_info  s$    ::55i5OO r)   c                     	 | j                   r(| j                  |      }| j                  |d   |      S | j                  ||      S # t        $ r Y y w xY w)Nr   r   )	accountidr   )r   r   )r   get_account_idr   get_user_details_by_usernamer
   )r$   r   r   r   s       r(   get_user_info_by_usernamez'ConfluenceApi.get_user_info_by_username  se    	zz**H*=99DDU^d9ee44hv4VV 		s   3A	 A	 		AAc                 R    d}|rd|i}nd|i}| j                  ||      }|d   d   S )Nzrest/api/user/bulk/migrationr   r   r   rx   r   r<   )r$   r   r   r%   r   ro   s         r(   r   zConfluenceApi.get_account_id  s?    , (+F)Fhhs6h*9~a  r)   )r   with_childrenc                    t        	|   |g|i |}|s|d   |d   |d   |d   d   d}|rF| j                  ||      D cg c]  }| }}|j                  d 	       d
|t	        |      di|d<   |S c c}w )u  
        Возвращает данные контента

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

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

        Returns:
            page (dict): данные контента
        r   r   r   
extensionsr   r   r   r   r   r   c                     | d   S r   r   r   s    r(   r   z.ConfluenceApi.get_page_by_id.<locals>.<lambda>  s
    * r)   r   r   r   r   )r   get_page_by_idr   r   r   )
r$   r   r   r   rX   r&   r   r   r   r'   s
            r(   r   zConfluenceApi.get_page_by_id  s    $ w%g???4jgV .z:	D +/+<+<Wx+<+XY%YHYMM5M6'M D  Zs   	A7typesr   c              #      K   || j                   sdgnddg}|D ]R  }d}d}	 | j                  ||||      }|s |r|E d{    n!|D ]  }|d   |d   |d	   |d
   d   d}	|	  ||z  }L y7 .w)u  
        Возвращает дочерние объекты(контент)

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

        Yields:
            dict: данные дочернего объекта(контента)
        Nr   folderr   r   )r   rv   rw   r   r   r   r   r   r   )r   get_page_child_by_type)
r$   	parent_idr   r   type_rv   rw   rx   r   r   s
             r(   r   zConfluenceApi.get_children  s      =$(JJVHVX4FE 	EEE55	 6  &&&") #"(,%+G_$*6N(.|(<Z(H	  #
# ) 		 's   ?A2A0/A2c              #   t   K   t        t        | 	  |      j                               d d E d {    y 7 w)N)listr    get_all_restrictions_for_contentvalues)r$   r   r'   s     r(   r   z.ConfluenceApi.get_all_restrictions_for_content  s1     @IPPRSTWUWXXXs   -868c              #      K   t        dd|      }	  | j                  di |}|d   E d {    |dxx   |d   z  cc<   |d   |d   k  ry <7 !w)	Nr   rt   )rv   rw   r   rx   rv   rw   r   r   )r   get_page_labels)r$   r   r   ro   s       r(   get_all_page_labelsz!ConfluenceApi.get_all_page_labels  sh     AS':&$&&00C9~%%7Ovg.O6{VG_,  &s   *AA"Aversion_numberc                 t    | j                   r	d| d| }nd| d| }i }|||d<   | j                  ||      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/r   r   )r   r<   )r$   r   r  r   r%   r   s         r(   get_page_versionzConfluenceApi.get_page_version  sY     ::%j\>:JKC.zl)NCSTC%F8xxFx++r)   current_versionlast_versionsc           	   #   $  K   |sy| j                   rd| d}nd| d}i }|t        |      |d<   |t        |      |d<   |||d<   d}		 	 | j                  ||	      }
|
d
   }|j                  d      }|
d   D ]%  }|	dz  }	d|cxk  r|	k  rn nd} n|d   dz
  }| ' |syt        |      }t        t        |j                              }|d   |d<   |j                  d      r|j                  d      |d<   |j                  d      r|j                  d      |d<   #  t        |dd      D ]V  }|	dz  }	d|cxk  r|	k  rn n nA	 | j	                  |||       /# t
        $ r}t        d| d|        Y d}~Pd}~ww xY w d}Y xY ww)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  rv   rw   r   r   r   r   r   rx   r+   Fnumberr   u   версия z. r   )
r   r   r<   ranger  r   r   r   r   r   )r$   r   r  rv   rw   r	  r   r%   r   version_countro   r   r   versionr  excr   r   s                     r(   get_page_versionszConfluenceApi.get_page_versions  s    2 ::%j\:C.zl(CC!%jF7O!%jF7O%F8hhs6h2H		&)"9~ "G!Q&MM9M9 %&-h&7!&;O!M"* !%J:#3#345E#GnF7Oyy"#(99X#6x yy !&6!2vO &+OQ&C QN!Q&MM9M9Q"33JPVWW$ Q'-7Gr#(OPPQQ sJ   A	FAD! "A?F!'F	EF	F(F ;F FFFc                     | j                   r%| j                  |d      }|j                  dg       S |dk\  rd| d}| j                  |      S d}ddd	|gd
}| j                  ||      j                  dg       S )Npermissions)	space_keyr   
   zrest/api/space/z/permissionsz!rpc/json-rpc/confluenceservice-v2z2.0getSpacePermissionSets   )jsonrpcr\   r   r   )r   r   )r   	get_spacer<   post)r$   r  r  
space_datar%   r   s         r(   get_space_permissionsz#ConfluenceApi.get_space_permissionsb  s    ::)MRJ>>-44]#I;l;C88C=  6C 2$+	D 99St9,002>>r)   c                 (    d}| j                  |      S )u   
        Получает связи с другими системами

        Return:
            applinks (dict): данные связей с другими системами
        zrest/applinks/3.0/applinksr   r$   r%   s     r(   get_applinkszConfluenceApi.get_applinkst  s     +xx}r)   c                 (    d}| j                  |      S )u7   Получить информацию о системеzrest/applinks/1.0/manifestr   r  s     r(   get_system_infozConfluenceApi.get_system_info  s    *xx}r)   c                 (    d}| j                  |      S )u^   
        Возвращает данные о текущем пользователе
        zrest/api/user/currentr   r  s     r(   get_current_userzConfluenceApi.get_current_user  s     &xx}r)   rV   )Ni   )NN)r   rt   archivedr   )r   r   NT)r   r   N)NT)r      r   N)/__name__
__module____qualname____doc__r3   !IMPORT_CONFLUENCE_REQUEST_TIMEOUTcmfutilrequests_sessionr   r   r   rD   r#   rQ   rT   rW   rr   ry   r   r   r   r   r   r   strr   r   r   r   r   r   r   r   r   r   r   boolr   r   r  r  r  r  r  r   r"  __classcell__)r'   s   @r(   r   r      s   U 88((*'R6 + +> G!
#:0	 !3F// 8:7;/3C /3!$/314/3"%/3@D/3b"3 " "t "H	/S 	/P! 7;% %N'T 'D 'RY,3 , ,S ,\` ,6 Q3Q3 Q3 	Q3
 Q3 Q3 Q3 
Q3f?$	d 	
r)   r   )urllib.parser   r   cmf.includerF   r   
contextlibr   requests.adaptersr   urllib3.util.retryr   	atlassianr	   atlassian.errorsr
   logging	getLoggerre   r   r   r)   r(   <module>r8     s?    ,    % ) $   -			2	3z	J z	r)   