U
    ~4i!                     @   s   d dl Z d dlmZmZmZmZ d dlZd dlmZ d dl	m
Z
 d dlZd dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlT G dd dejZedZee  dddZG dd deZ dS )    N)DictListOptionalIterator)wrapssleep)contextmanager)HTTPAdapter)Retry)
HTTPStatus)Path)Jira)*c                   @   s   e Zd Zdd ZdS )SensitiveDataFilterc                 C   sb   t |dr^d}|jdd}td||}td||}td||}td||}||_d	S d S )
Nmsgz\1***\2z\""z("username":\s*")[^"]*(")z("password":\s*")[^"]*(")z ("webSudoPassword":\s*")[^"]*(")z("atl_token":\s*")[^"]*(")T)hasattrr   replaceresub)selfrecordreplZ	clean_msg r   ./modules/jira/api.pyfilter   s    
zSensitiveDataFilter.filterN)__name__
__module____qualname__r   r   r   r   r   r      s   r   zatlassian.rest_client皙?         c                    s    fdd}|S )u-  
    Декоратор для повторного выполнения функции через некоторое время, при возникновении ошибки.
    Использует экспоненциальный рост времени повтора(factor) до граничного времени ожидания(border_sleep_time)

    :param exception: исключения, которые отлавливаются
    :param start_sleep_time: начальное время повтора
    :param factor: во сколько раз нужно увеличить время ожидания
    :param border_sleep_time: граничное время ожидания
    :param max_attempts: максимальное количество попыток выполнения
    c                    sN   t   fdd}t   fdd}t rJ|S |S )Nc               
   ?   s~   d}}|d7 }z| |E d H W S  k
rv } z6|kr@|| krN }n|d  7 }t | W 5 d }~X Y qX qd S Nr      r!   r   argskwargsZattemptZtime_outerrorborder_sleep_time	exceptionfactorfuncmax_attemptsstart_sleep_timer   r   	gen_retry.   s    z3backoff.<locals>.retry_exception.<locals>.gen_retryc               
      sx   d}}|d7 }z| |W S  k
rp } z6|kr:|| krH }n|d  7 }t | W 5 d }~X Y qX qd S r$   r   r&   r*   r   r   retryB   s    z/backoff.<locals>.retry_exception.<locals>.retry)r   inspectZisgeneratorfunction)r.   r1   r2   r+   r,   r-   r/   r0   )r.   r   retry_exception-   s    
z backoff.<locals>.retry_exceptionr   )r,   r0   r-   r+   r/   r5   r   r4   r   backoff"   s    -r6   c                       sx  e Zd ZdZ fddZdd ZedddZ fd	d
Z fddZ	 fddZ
dd Zdd Z fddZdddZdd ZdddZdee ddd Zdه fd!d"	Zeed#d$ Zeedeeed%d&d'Zdee dd(d)Zdee dd*d+Zd,d- Zd.d/ Zd0d1 Zdd2d3Z ed4d5d6Z!ed7d8d9Z" fd:d;Z#e$ed<d=d>Z%e$d?d@dAZ&de$eedCdDdEZ'de$eedFdGdHZ( fdIdJZ)dKdL Z*dMdN Z+ fdOdPZ,ddQdRZ-e$dSdTdUZ.dee ddVdWZ/ddXdYZ0ddZd[Z1dd\d]Z2d^d_ Z3d`da Z4e5e$ef ddbdcZ6ddde Z7ddfdgZ8ddhdiZ9ddjdkZ:e$dldmdnZ;deddodpZ<ee ddqdrZ=dsdt Z> fdudvZ?dwdx Z@ fdydzZA fd{d|ZB fd}d~ZC fddZD fddZEdd ZFdd ZGdd ZHdd ZIdd ZJ fddZKdd ZLdd ZMdeeedddZNde$e$e$dddZOdd ZPdd ZQdd ZRdd ZSdd ZTdd ZUdddZVe$edddZWdd ZXdd ZYdd ZZe$dddZ[e$eedddZ\e$dddZ]e$e$dddZ^e$dddZ_e$dddZ`de$e$e$e$edddĄZadedddƄZbedddȄZcddʄ Zd fdd̄Ze fdd΄Zf fddЄZgdd҄ ZhddԄ Zi  ZjS )JiraApid   c                    s   | dr|nd| }|dr2|d|d< n|d|d< d|krPd|d< d|krdt |d< t j|f|| |   |d| _d	| _d
| _	d S )Nhttphttps://cloudtokenpasswordtimeout,  ZsessionFzrest/auth/1/session)

startswithgetcmfutilZrequests_sessionsuper__init___set_session_retriesr<   _session_valid_session_url)r   urlr'   r(   	__class__r   r   rD   `   s    
zJiraApi.__init__c                 C   s@   t tjtjtjdd}t|d}| jd| | jd| dS )u   
        Конфигурирует стратегию повторных попыток
        и ассоциирует ее с сессией
        r!   )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   rE   v   s    
zJiraApi._set_session_retriesNc                 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   rM   )rN   r:   N)r
   rP   ZadaptersrA   rQ   r>   itemspop)r   r>   Zold_adaptersZno_retry_adapterprefixZold_timeoutZadapterr   r   r   without_retry   s     

zJiraApi.without_retryc                    s   | j rt || dS )u   
        Переопределенный метод
        Базовая аутентификация устанавливается только для Jira Cloud
        N)r;   rC   _create_basic_session)r   usernamer=   rI   r   r   rV      s    zJiraApi._create_basic_sessionc                    s\   | j r| jstd| jj  | j | jd}t jd| j|d}| jjsRt	dd| _
dS )u;   
        Выполняет авторизацию
        u_   Учетные данные для аутентификации не предоставлены)rW   r=   ZPOST)pathdatauR   Ошибка аутентификации: файлы cookie не полученыTN)rW   r=   
ValueErrorrP   cookiesclearrC   requestrG   RuntimeErrorrF   )r   rY   responserI   r   r   _authenticate   s    zJiraApi._authenticatec                    s>   z t  jd| jd}|jtjkW S  tjk
r8   Y dS X dS )u~   
        Проверяет валидность текущей сессии через тестовый запрос
        GET)rX   FN)rC   r]   rG   status_coder   ZOKrequestsRequestException)r   r_   rI   r   r   _check_session   s    zJiraApi._check_sessionc                 C   s<   | j jr(| js(|  r(d| _|   dS |   |   dS )u>   
        Создает валидную сессию
        TN)rP   r[   rF   re   user_get_websudor`   r   r   r   r   _create_valid_session   s    zJiraApi._create_valid_sessionc                 C   s   | j jS N)rP   r[   rg   r   r   r   get_session_cookies   s    zJiraApi.get_session_cookiesc              
      s   | j rt j||S zJ| js$|   t j||}|jtjkrZd| _|   t j||}|W S  tj	k
r } zLt
|dr|jdk	r|jjtjkrd| _|   t j|| W Y S  W 5 d}~X Y nX dS )u8  
        Переопределенный метод
        Используется только для Jira Server.
        Перед запросом проверяется валидность сессии
        и при необходимости выполняется авторизация 
        Fr_   N)r;   rC   r]   rF   rh   rb   r   ZUNAUTHORIZEDrc   rd   r   r_   )r   r'   r(   r_   erI   r   r   r]      s,    zJiraApi.request   c              
   C   s  |p| j }|p| j}| jd||d | jj|d||| j| jd}td| d|j	 d|j
  |  |jdd	}td
|}|r|dp|d}	nd	}	t|d"}
|j|dD ]}|
| qW 5 Q R X t|}| j}|	|dW  5 Q R  S Q R X dS )u  
        Скачивает файл

        Args:
            download_url (_type_): url файла для скачивания
            save_path (_type_): путь для сохранения файла
            headers (_type_, optional): Заголовки. Defaults to None.
            timeout (_type_, optional): Таймаут. Defaults to None.
            chunk_size (_type_, optional): _description_. Defaults to 8*1024.
        ra   )methodrH   headersT)streamrn   r>   Zverifyproxiesz
HTTP: GET z ->  zContent-Disposition z!filename\*?=(?:"([^"]+)"|([^;]+))r%   r!   wb)
chunk_size)	file_name	file_sizeN)no_check_headersr>   Zlog_curl_debugrP   rA   Z
verify_sslrp   loggerdebugrb   reasonZraise_for_statusrn   r   searchgroupopenZiter_contentwriter   statst_size)r   Zdownload_urlZ	save_pathrn   r>   rt   resZcontent_dispositionmatchru   fchunkZ	file_pathrv   r   r   r   download_file	  s6    

 
zJiraApi.download_filec                 C   sR   d}| j dd}d}| jjr2| jj }|d}|r>||d< | j||g | jdS )u   
        Получает веб-куки sudo
        Переопределенный метод, так как метод в родительском классе выполняется некорректно
        z%secure/admin/WebSudoAuthenticate.jspafalse)ZwebSudoPasswordZwebSudoIsPostNzatlassian.xsrf.token	atl_token)rX   rY   filesrn   )r=   rP   r[   Zget_dictrA   postform_token_headers)r   rH   rY   r   r[   r   r   r   rf   ?  s    
zJiraApi.user_get_websudo*allr   c                 C   s0  i }|dk	rt ||d< |dk	rBt|tttfr:d|}||d< |dk	rR||d< |dk	rb||d< |dk	rr||d< | | jrdnd	}	g }
| jr|pd
|d< nt ||d< | j|	|d}|sq,|d }|
	| |dk	rސq,| jr|d rq,|d}qt |d }|t
|| krq,|t
|7 }q|
S )u   
        Переопределение метода jql_get_list_of_tickets класса Jira
        с учетом https://developer.atlassian.com/changelog/#CHANGE-2046
        N
maxResults,fieldsjqlexpandvalidateQuery
search/jqlr{   rr   ZnextPageTokenstartAtparamsissuesisLastrK   )int
isinstancelisttuplesetjoinresource_urlr;   rA   extendlen)r   r   r   startlimitr   validate_queryZnext_page_tokenr   rH   resultsr_   r   rK   r   r   r   jql_get_list_of_ticketsS  sD    

zJiraApi.jql_get_list_of_tickets)returnc                 c   s   |dkrd}| j rd| }d}d}|p,| j}| j|||dd}|sHdS ||7 }|E dH  |t|7 }d|  k rz|kr.n q.dS q.dS )u(    Получение всех задач Norder by created ASCzcreated > '1900-01-01' r   ZrenderedFields)r   r   r   r   )r;   MAX_RESULTSr   r   )r   r   r   start_atrK   max_resultsr   r   r   r   
get_issues  s(    


zJiraApi.get_issuesc                 #   s   d}d}d}|p| j }t j||||dd}|d s8d S ||7 }t| d|d   |d E d H  |t|d 7 }d|  k r|ksn ||d krd S qd S )Nr   r   changelog,renderedFields)r   r   r   r   u    из rK   )r   rC   get_issues_for_boardgry   r   )r   board_idr   r   r   rK   r   r   rI   r   r   r     s&    
"zJiraApi.get_issues_for_boardc                 c   sH   d}d}| j |||d}|dg s&qD||7 }|d D ]
}|V  q6qd S )Nr   2   r   r   r   values)Zget_all_sprintrA   )r   r   r   r   r   rowr   r   r   get_sprints  s    zJiraApi.get_sprints)r   r   r   c           	      c   sz   d| d}|pd|pdd}|r0d ||d< | j||d}|d	g sLqv|d
  |d 7  < |d	 D ]
}|V  qhq0dS )u  
        Возвращает все задачи в для заданного спринта.
        Включены только задачи, на просмотр которых у пользователя есть разрешение.

        Args:
            sprint_id (_type_): ID спринта
            start (int, optional): начальный индекс задач. Defaults to None.
            limit (int, optional): максимальное количество задач на странице. Defaults to None.
            fields (list, optional): необходимые поля задач. Defaults to None.

        Yields:
            dict: данные задачи
        zrest/agile/1.0/sprint/z/issuer   r   r   r   r   r   r   r   r   r   N)r   rA   )	r   Z	sprint_idr   r   r   rH   r   r   r   r   r   r   get_sprint_issues  s    zJiraApi.get_sprint_issuesc                 c   s   d}|dkst dd|pd|d}|r0||d< | jr| d}| j||d}d	|krbt|d	 |d
 sndS |d
 E dH  |d  t|d
 7  < |r@|d |kr@dS q@n|  E dH  dS )u    Получение всех workflow
        https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflows/#api-rest-api-3-workflow-search-get
        ztransitions,transitions.rules,transitions.properties,statuses,statuses.properties,default,schemes,projects,hasDraftWorkflow,operationsr   uG   Больше 50 за раз запросить не получится!r   r   r   r   ZworkflowNamezworkflow/searchr   errorMessagesr   Nr   )AssertionErrorr;   r   rA   	Exceptionr   Zget_all_workflows)r   namesr   r   r   rH   r   r   r   r   get_workflows  s&    
zJiraApi.get_workflowsc                 c   s   | j r| d}d|p| jdd}|r.||d< | j||d}|d sHdS |d E dH  |d	  t|d 7  < |r.|d	 |kr.dS q.n$|r| |E dH  n|  E dH  dS )
u.    Получение всех statuses
        zstatuses/searchr   Zusagesr   	projectIdr   r   Nr   )r;   r   r   rA   r   get_status_for_projectget_all_statuses)r   r   
project_idrH   r   r   r   r   r   get_statuses
  s"    

zJiraApi.get_statusesc                 C   s6   d}d|i}| j ||d}d|kr.t|d |d S )Nz!rest/api/3/workflowscheme/projectr   r   r   r   rA   r   )r   r   rH   r   r   r   r   r   get_project_scheme#  s    zJiraApi.get_project_schemec                 C   s   d| d}|  |S )Nzrest/api/3/workflowscheme/z	/workflowrA   r   idurir   r   r   get_issue_type_workflow_scheme+  s    z&JiraApi.get_issue_type_workflow_schemec                 C   s   d| }|  |S )Nzrest/api/3/issuetype/r   r   r   r   r   get_issue_type/  s    
zJiraApi.get_issue_typec                 c   s   d|p
| j d}d}| j||d}d|kr6t|d |d sBd S |d E d H  |d  t|d 7  < |r|d |krd S qd S )Nr   r   zrest/api/3/workflowschemer   r   r   r   )r   rA   r   r   )r   r   r   r   r   r   r   r   get_all_workflow_schemes3  s    z JiraApi.get_all_workflow_schemes)project_idsc                 c   sV   dd|d}d}| j ||d}|d s*d S |d E d H  |d  t|d 7  < qd S )Nr   r   )r   r   r   z"rest/api/3/issuetypescheme/projectr   r   r   )rA   r   )r   r   r   r   r   r   r   r   get_issue_type_schemesA  s    zJiraApi.get_issue_type_schemes)r   c                 C   s   d|i}d}| j ||dS )Nr   zrest/api/3/issuetype/projectr   r   )r   r   r   r   r   r   r   get_issue_for_projectK  s    zJiraApi.get_issue_for_projectc                 #   s   | j rd}| |E d H  n~t  }| d}| dd t  }|rX| d| n
| d |D ]2 tt fdd|d }|r|d  d<  V  qfd S )Nzrest/api/3/issuetypejira.user.localeen_UKc                    s   | d  d kS Nr   r   )Zitu
issue_typer   r   <lambda>o      z)JiraApi.get_issue_types.<locals>.<lambda>nameuntranslatedName)	r;   rA   rC   get_issue_typesget_mypreferencesset_mypreferencesdelete_mypreferencesnextr   )r   r   issue_typescurrent_user_localeZissue_types_untranslatedZissue_type_untranslatedrI   r   r   r   P  s*    




zJiraApi.get_issue_types)	issue_keyr   c                 c   sp   |  d}| d| d}tdddd}| j||d}|d	sDd
S |d	 E d
H  |d  t|d	 7  < q(d
S )u@    Получим все комментарии по задаче issue/z/commentr   r   zrenderedBody,propertiesr   r   ZcommentsNr   )r   dictrA   r   )r   r   base_urlrH   r   r   r   r   r   get_commentsy  s    

zJiraApi.get_comments)issue_id_or_keyc                 c   sv   |  d}| d| d}ddd}| j||d}|ds@d	S |d E d	H  |d
 rXqr|d  t|d 7  < q$d	S )u?    Получим историю изменений задачи r   r   z
/changelogr   r8   r   r   r   Nr   r   )r   rA   r   )r   r   r   rH   r   r   r   r   r   get_changelog  s    

zJiraApi.get_changelogr   r   c                 C   s   d| d}|dkrdn||dkr&dn|d}g }| j ||d}| dg sNq|||d  |dk	rfq||d	  |d
 7  < q2|S )u  
        Возвращает все проекты, связанные с доской,
        для заданного идентификатора доски.
        Если у пользователя нет разрешения на просмотр доски,
        никакие проекты не будут возвращены вообще.
        Возвращаемые проекты упорядочены по названию.

        Args:
            board_id (str): id доски
            start (int, optional): начальная позиция выборки. Defaults to 0.
            limit (int, optional): максимальное количество возвращаемых элементов.
                                   Если указано None, то вернет все элементы.
                                   Defaults to 50.

        Returns:
            list: список проектов
        rest/agile/1.0/board/z/projectNr   r   r   r   r   r   r   )rA   r   )r   r   r   r   rH   r   r   resultr   r   r   get_agile_board_project  s    zJiraApi.get_agile_board_projectproject_keyr   r   c                 C   sB   d}i }|r||d< |r$t ||d< |r4t ||d< | j||dS )u  
        Возвращает доски находящиеся в проекте Jira Cloud

        Args:
            project_key (_type_, optional): ключ или id проекта. Defaults to None.
            start (int, optional): начальная позиция выборки. Defaults to 0.
            limit (int, optional): максимальное количество возвращаемых элементов. Defaults to 50.

        Returns:
            _type_: _description_
        zrest/agile/1.0/boardZprojectLocationr   r   r   )r   rA   )r   r   r   r   rH   r   r   r   r   get_project_boards  s    zJiraApi.get_project_boardsc                 #   sb   d}d}| j r | j|||d}nt j|||d}|dg s@q^||7 }|d D ]
}|V  qPqd S )Nr   r   r   r   )r;   r   rC   get_all_agile_boardsrA   r   r   r   r   r   r   rI   r   r   r     s    zJiraApi.get_all_agile_boardsc                 C   s0   d}| j |d|id}| |}||d d< |S )Nz3rest/greenhopper/1.0/rapidviewconfig/editmodel.jsonZrapidViewIdr   ZcardColorConfig
strategies)rA    get_board_card_colors_strategies)r   r   r   r_   Zcard_colors_strategiesr   r   r   get_advanced_board_settings  s
    
z#JiraApi.get_advanced_board_settingsc           	   	   C   sp   d| d}ddi}i }ddddg}|D ]B}z(| d	| }| j ||d
}|||< W q( tk
rh   Y q(X q(|S )u   
        Получает стратегии присвоения цветов карточкам

        Args:
            board_id (int | str): ID доски

        Returns:
            dict: стратегии цветов карточек
        z rest/greenhopper/1.0/cardcolors/z	/strategyZpreloadValuestrueZ	issuetypepriorityZassigneeZcustomr   r   r   )	r   r   r   r   r   Zstrategy_typesZstrategy_typerH   r_   r   r   r   r     s$    
 z(JiraApi.get_board_card_colors_strategiesc                 #   sJ   d}d}t  j|||d}|dg s(qF||7 }|d D ]
}|V  q8qd S )Nr   r   )keyr   r   r   )rC   get_project_versions_paginatedrA   r   rI   r   r   r   
  s    z&JiraApi.get_project_versions_paginatedc                 c   sp   |  d}d}d}t }|r$||d< ||d< ||d< | ||}||d krNql||7 }|d D ]
}|V  q^q$d S )	Nzauditing/recordr   i  Z
projectIdsoffsetr   rK   Zrecords)r   r   rA   )r   r   rH   r   r   r   r   r   r   r   r   get_audit_records  s    
zJiraApi.get_audit_records)r   c                 C   s   |  |}|d S )u(   Наблюдатели по задачеwatchers)Zissue_get_watchers)r   r   r   r   r   r   get_watchers&  s    
zJiraApi.get_watchersc           	      c   s   ddd}|r"|d |kr"||d< | j r2d}d}nd}|p<d|d	< d
|d< d}| j||d}|sbq|D ]^}z"|| j|| |dd W n0 tk
r } ztt| W 5 d}~X Y nX |V  qf|d  t|7  < |rN|d |krNqqNdS )u   Возвращает список всех пользователей, включая активных,
            неактивных и ранее удаленных, у которых есть учетная запись Atlassian.
            в старых версиях невозможно получить больше 1000 учеток
            https://jira.atlassian.com/browse/JRASERVER-65089
            исправлено в 8.7.0, 8.6.1 и выше
            r   r8   r   r   zrest/api/3/users/searchZ	accountIdzrest/api/2/user/search.rW   TZincludeInactiver   r   r   )rW   Nr   )	r;   rA   updateget_user_infor   rx   r)   strr   )	r   rW   Z	limit_endr   r   Z
identifierZusers	user_infoexcr   r   r   	get_users+  s:     zJiraApi.get_usersc              
   C   sT   z| j ||dW S  tjk
rN } z|jjdkr:W Y d S |W 5 d }~X Y nX d S )Nr   r     userrc   	HTTPErrorr_   rb   )r   r   r   r   r   r   r   get_user_info_by_keyV  s    
zJiraApi.get_user_info_by_keyc              
   C   sT   z| j ||dW S  tjk
rN } z|jjdkr:W Y d S |W 5 d }~X Y nX d S )NrW   r   r  r  )r   rW   r   r   r   r   r   get_user_info_by_username^  s    
z!JiraApi.get_user_info_by_usernamec                 C   s   d}| j r | j|| dd}nZ| j||d}|sD| j|p<||d}|sz|r^d| d| dn
d| d}td	| d
dtj }tjj	j
t| }|dst|d d |  | |d< n(d|d kr|d d |  | |d< |S )Nzgroups,applicationRolesz,operations)Z
account_idr   r   r  'z' ()u   Пользователь u    не найден@ZemailAddressZdisplayName)r;   r  r  r  r   rO   Z
ORG_DOMAINZcmfr   ZCmfEmailZ
max_lengthr   rA   rB   Ztranslit_strip)r   r   rW   r   r   Zlog_userZpostfixZmax_lenr   r   r   r   f  s     "
$zJiraApi.get_user_infoc                 C   sb   d| d}ddd}g }| j ||d}||d  t||d krHq^|d	  |d
 7  < q|S )Nrest/api/2/field//contextr   r   r   r   r   rK   r   r   rA   r   r   )r   r   rH   r   r   r_   r   r   r   _get_field_contexty  s    
zJiraApi._get_field_contextc                 C   sh   d| d| d}ddd}g }| j ||d}||d  t||d	 krNqd|d
  |d 7  < q |S )Nr  	/context//optionr   r   r   r   r   rK   r   r   r  )r   ZfieldId	contextIdrH   r   r   r_   r   r   r   _get_field_options  s    
zJiraApi._get_field_optionsc                 C   sN   |   }t }|D ]6}d|kr,|||d < n|||d < g |d< g |d< q|S )u]    Возвращает системные и настраиваемые поля задачи r   r   contextoptions)Zget_all_fieldsr   )r   r   r   fieldr   r   r   
get_fields  s    
zJiraApi.get_fieldsc                 C   s
   |  |S ri   )Zissue_editmeta)r   r   r   r   r   get_issue_meta  s    zJiraApi.get_issue_metac                 c   sz   d}|r|| |kr|| }dj |d}| j|d||dd}| jrH|}n|d }|sXd S |E d H  ||7 }||krqvqd S )Nr8   z"project = "{project}" ORDER BY key)projectr   r   r   r   r   r   r   )formatr   advanced_mode)r   r   r   maxr   r   r_   r   r   r   r   get_all_project_issues  s    
zJiraApi.get_all_project_issuesc           	      C   s   i }|dk	rt ||d< |dk	r,t ||d< |dk	rVt|tttfrNd|}||d< |dk	rf||d< |dk	rv||d< |dk	r||d< | | jrd	nd
}| j||dS )u   
        Переопределение метода jql класса Jira
        с учетом https://developer.atlassian.com/changelog/#CHANGE-2046
        Nr   r   r   r   r   r   r   r   r{   r   )	r   r   r   r   r   r   r   r;   rA   )	r   r   r   r   r   r   r   r   rH   r   r   r   r     s"    
zJiraApi.jqlc           
      c   s   d}d| d}|r$|d| d7 }|r8|d| d7 }|d7 }|rX|| |krX|| }| j |d||dd	}| jrx|}	n|d
 }	|	sd S |	E d H  ||7 }||kr@qq@d S )Nr8   project = "r    AND updated >= " AND updated <= " ORDER BY updatedr   r   r  r   )r   r  )
r   r  r   r  
start_dateend_dater   r   r_   r   r   r   r   get_all_project_issues_during  s&    
z%JiraApi.get_all_project_issues_during)r   c                 C   s,   d|i}|  d}| j||d}t|d S )u   
        Возвращает количество задач, которые соответствуют JQL

        Args:
            jql (str): Выражение JQL

        Returns:
            int: количество задач
        r   zsearch/approximate-count)rY   count)r   r   r   )r   r   rY   rH   r_   r   r   r   jql_get_issue_count  s    

zJiraApi.jql_get_issue_countc                 C   sl   d| d}|r |d| d7 }|r4|d| d7 }|d7 }| j rL| |S | j|ddd}t|d	 S d S )
Nr  r   r  r   r!  r   r%   )r   r   rK   )r;   r&  r   r   )r   r   r"  r#  r   r_   r   r   r   get_project_issues_count_during  s    
z'JiraApi.get_project_issues_count_duringc                 c   s"   |   }|std|E dH  dS )u*   Возвращает все проектыuE   Не удалось получить ни одного проектаN)Zget_all_projectsr   )r   r   r   r   r   get_projects  s    zJiraApi.get_projectsc                 c   sb   d| d}t dddd}| j||d}|ds6d S |d E d H  |d	  t|d 7  < qd S )
Nr   z/quickfilterr   r   ZrenderedBodyr   r   r   r   )r   rA   r   )r   r   r   r   r   r   r   r   get_board_quick_filters
  s    
zJiraApi.get_board_quick_filtersc                    s"   t  |}| j|d dd}|S )Nr   all)r   )rC   get_project_permission_schemeZget_permissionscheme)r   r   schemerI   r   r   r+    s    z%JiraApi.get_project_permission_schemec                 C   sD   d| d}g }|  |}|d D ]}|| j |d dd q"|S )Nzrest/api/2/issue/z/propertieskeysr   T)absolute)rA   append)r   issue_idr   Z
propertiesr   r   r   r   r   get_issue_properties  s    
zJiraApi.get_issue_propertiesc                    s   t  |}|d S )NZworklogs)rC   issue_get_worklog)r   r0  r   rI   r   r   r2  !  s    zJiraApi.issue_get_worklogc                    s$   zt  |W S    i  Y S X d S ri   )rC   !get_project_issue_security_scheme)r   r   rI   r   r   r3  %  s    z)JiraApi.get_project_issue_security_schemec                 #   s$   t   D ]}| |d V  q
d S r   )rC   get_issue_security_schemesZget_issue_security_scheme)r   ZschrI   r   r   r4  +  s    z"JiraApi.get_issue_security_schemesc                    s   d}ddd}g }| j s$t  }qh| j||d}||d  t||d krRqh|d  |d	 7  < q|D ]}| |d
 |d< ql|S )Nzrest/api/2/screensr   r   r   r   r   rK   r   r   r   Ztabs)r;   rC   get_all_screensrA   r   r   get_screen_tabs)r   r   r   r   r_   ZscrrI   r   r   r5  /  s    

zJiraApi.get_all_screensc                    sH   z2t  |}|D ]}| j||d d|d< q|W S    g  Y S X d S )Nr   )	screen_idtab_idr   )rC   r6  get_tab_fields)r   r7  r_   ZtabrI   r   r   r6  E  s    zJiraApi.get_screen_tabsc                 C   s$   z|  ||W S    g  Y S X d S ri   )Zget_screen_tab_fields)r   r7  r8  r   r   r   r9  N  s    zJiraApi.get_tab_fieldsc                 C   sr   g }| j rnd| jd}d}| j||d}d|kr<t|d |dg sJqn||d  |d  |d 7  < q|S )	Nr   r   z rest/api/2/issuetypescreenschemer   r   r   r   r   )r;   r   rA   r   r   )r   r   r   r   r_   r   r   r   get_screen_schemeT  s    zJiraApi.get_screen_schemec                 C   sT   d}d|i}| j ||d}d|kr.t|d |d d d }| |d |d	< |S )
Nz(rest/api/3/issuetypescreenscheme/projectr   r   r   r   r   ZissueTypeScreenSchemer   r   )rA   r   get_screen_scheme_issuetypes)r   r   rH   r   r_   Zscreen_schemer   r   r   get_project_screen_schemeh  s    z!JiraApi.get_project_screen_schemec                 C   s   zd}d| j |d}g }| j||d}d|kr:t|d |dg sHql||d  |d  |d 7  < q|D ]}| |d	 |d
< qp|W S    g  Y S X d S )Nz(rest/api/3/issuetypescreenscheme/mappingr   )r   r   ZissueTypeScreenSchemeIdr   r   r   r   r   ZscreenSchemeIdactions)r   rA   r   r   get_screen_scheme_actions)r   screen_scheme_idrH   r   r   r_   r   r   r   r   r;  v  s&    z$JiraApi.get_screen_scheme_issuetypesc                 C   sV   z@d}d|i}| j ||d}d|kr0t|d |d d d W S    i  Y S X d S )Nzrest/api/3/screenschemer   r   r   r   r   Zscreensr   )r   r?  rH   r   r_   r   r   r   r>    s    z!JiraApi.get_screen_scheme_actionsc                    s"   zt   W S    g  Y S X d S ri   )rC   get_all_prioritiesrg   rI   r   r   r@    s    zJiraApi.get_all_prioritiesc                 C   s   d| d}ddd}g }| j ||d}d|kr<t|d | dg sJq||d D ]}||d	  qR|d
  |d 7  < q|S )Nrest/api/2/priorityscheme/z	/projectsr   r?   r   r   r   r   r   r   r   )rA   r   r/  )r   	scheme_idrH   r   Zproject_keysr_   r  r   r   r   get_priority_scheme_projects  s    
z$JiraApi.get_priority_scheme_projectsc                 C   sr   d| d}ddd}g }| j ||d}d|kr<t|d | dg sJqn||d  |d	  |d
 7  < q|S )NrA  z/prioritiesr   r?   r   r   r   r   r   r   )rA   r   r   )r   rB  rH   r   
prioritiesr_   r   r   r   get_priority_scheme_priorities  s    
z&JiraApi.get_priority_scheme_priorities)r   r   r   c                 C   s   | j rd}d }d}nd}d}d}i }|d k	r8t||d< |d k	rLt||d< |rX||d< g }| j||d	}||g sxq|| D ]d}	| j r| |	d
 |	d< | |	d
 |	d< n*g |	d< |	d D ]}
|	d | |
 q||	 q|d  |d 7  < q\|S )Nzrest/api/2/priorityschemer   zrest/api/2/priorityschemeszschemes.projectKeysschemesr   r   r   r   r   ZprojectKeysrD  Z	optionIds)r;   r   rA   rC  rE  r/  Zget_priority_by_id)r   r   r   rH   r   r   r   rF  r_   r,  Zpriority_idr   r   r   get_priority_schemes  s8    zJiraApi.get_priority_schemes)r   r  
issuetypesc                 C   s~  dddddddg}dd	 | d
}d}z| j|| jd}W nl tk
r } zNd| d}t|dr|d|jj d	|jj d|jj d| 7 }t	|W 5 d }~X Y nX |d}	|	|krt
d|	 d|  d}
d|i}|r||d< |r||d< z| j|
|d}W np tk
rx } zPd| d}t|dr`|d|jj d	|jj d|jj d| 7 }t	|W 5 d }~X Y nX |S )Nz5.2.7z5.2.3z4.8.12z4.8.9z4.8.7z4.7.3z4.5.1u   Установите плагин по ссылке https://marketplace.atlassian.com/apps/1221996/smart-jira-configuration-formerly-smart-project-config-docs/version-history(поддерживаемые версии: z, r	  z1rest/plugins/1.0/com.eis.jira.plugins.jiradoc-key)rn   u   Для получения полной конфигурации проекта не установлен плагин "Smart Jira Configuration". z. r_   u   Код ошибки - z - u   , адрес запроса: versionup   Установлена неподдерживаемая версия плагина 'Smart Jira Configuration': uF   . При импорте могут возникнуть ошибки. z-rest/smart-configuration/1.0/getProjectConfig
projectKeyr  rH  r   uN   Не удалось получить конфигурацию проекта "u6   " через плагин "Smart Jira Configuration". )r   rA   rw   r   r   r_   rb   rz   textZCmfErrorrx   warning)r   r   r  rH  Zsupported_versionsZ
error_textZ
plugin_urlr_   r   Zplugin_versionrH   r   r   r   r   get_project_smart_config  sV    

&

&z JiraApi.get_project_smart_configc                 C   s   d| d}ddd}i }| j ||d}d|kr<t|d | dg sJq|d D ]&}|t|d	 g }||d
  qR|d  |d 7  < q|S )Nz rest/api/2/issuesecurityschemes/z/membersr   r   r   r   r   r   ZissueSecurityLevelIdZholderr   r   )rA   r   
setdefaultr   r/  )r   Zsecurity_scheme_idrH   r   Zsecurity_level_membersr_   membermembersr   r   r    get_issue_security_level_members:  s    z(JiraApi.get_issue_security_level_membersc                 C   sD   d| d}|d| j d}| j||d}|dg s8dS |d d S )uR    Возвращает контекст пользовательского поляrest/api/3/field/r  r   r  r   r   r   r   Nr   rA   )r   field_id
context_idrH   r   r_   r   r   r   get_field_contextS  s    zJiraApi.get_field_contextc           
   
   C   s   d| d| d}d| j d}i }z| j||d}W n< tjk
rp } z|jjdkr^W Y 
dS  W 5 d}~X Y nX |d	g }|sq|D ]}	|	||	d
 < q|d  |d 7  < q"|S )u`    Возвращает опции контекста пользовательского поля rR  r  r  r   r   r   i  Nr   r   r   r   )r   rA   rc   r  r_   rb   )
r   rU  rV  rH   r   r  r_   r   r   valuer   r   r   get_field_context_optionc  s$    
z JiraApi.get_field_context_optionc                 C   s~   d| d}|d| j d}g }| j||d}|dg s:qz|d D ] }|drB|t|d  qB|d  |d	 7  < q|S )
u    Возвращает сопоставленный список типов задач и контекста пользователького поля rR  z/context/issuetypemappingr   rS  r   r   issueTypeIdr   r   )r   rA   r/  r   )r   rU  rV  rH   r   rH  r_   rX  r   r   r   #get_field_context_issuetype_mapping  s    
z+JiraApi.get_field_context_issuetype_mappingc           
   
   C   s   d| d}d| j d}g }z| j||d}W nN tjk
r| } z.|jjdkrhtd| d W Y 
q|W 5 d	}~X Y nX |d
g sq||d
  |d  |d 7  < qd	}|D ]0}	|	d|kr|	d   S |	dr|	d }q|S )uz    Возвращает список контекстов пользовательского поля для проекта rR  z/context/projectmappingr   r   r   r  uA   Не удалось получить контексты поля u@   . Пользовательское поле не найдено.Nr   r   r   r   r  ZisGlobalContext)	r   rA   rc   r  r_   rb   rx   rL  r   )
r   rU  r   rH   r   Zcontextsr_   r   Zglobal_contextr  r   r   r   !get_field_context_project_mapping  s.    

z)JiraApi.get_field_context_project_mappingc                 c   sb   d| d}d| j d}| j||d}|dg }|s8q^|D ]
}|V  q<|d  |d 7  < qd	S )
u8    Возвращает поля конфигурации zrest/api/3/fieldconfiguration/z/fieldsr   r   r   r   r   r   NrT  )r   Zfield_configuration_idrH   r   r_   r   r  r   r   r   get_field_config_fields  s    zJiraApi.get_field_config_fieldsFc                 C   sn   d}d| j |d}g }| j||d}|dg s2qV||d  |d  |d 7  < q|rf|rf|d S |S dS )	u    Возвращает список конфигураций или конфигурацию по умолчанию при is_default=Truezrest/api/3/fieldconfigurationr   )r   r   Z	isDefaultr   r   r   r   N)r   rA   r   )r   Z
is_defaultrH   r   Zfield_configurationsr_   r   r   r   get_field_config  s    zJiraApi.get_field_config)field_configuration_scheme_idr   c                 C   s"   d}d|i}| j ||d}|d S )u  
        Возвращает список сопоставления типа задачи и конфигурации поля

        Args:
            field_configuration_scheme_id (str): ID схемы конфигурации полей

        Returns:
            list: список сопоставления типа задачи и конфигурации поля
        z+rest/api/3/fieldconfigurationscheme/mappingZfieldConfigurationSchemeIdr   r   r   )r   r_  rH   r   r_   r   r   r   "get_field_configuration_issue_type  s    
z*JiraApi.get_field_configuration_issue_typec                 C   sD   d}d|i}| j ||d}|d d }d}| dr@|d d }|S )	uR    Возвращает схему конфигурации полей прокта z+rest/api/3/fieldconfigurationscheme/projectr   r   r   r   NZfieldConfigurationSchemer   r   )r   r   rH   r   r_   r   r_  r   r   r   &get_project_field_configuration_scheme  s    
z.JiraApi.get_project_field_configuration_schemec                 C   s"   d| }| j |dddid}|S )u   
        Получает бизнес-процесс как XML

        Args:
            name (str): название бизнес-процесса

        Returns:
            str: содержимое в формате XML
        zKsecure/admin/workflows/ViewWorkflowXml.jspa?workflowMode=live&workflowName=TZAcceptzapplication/xml)not_json_responsern   r   )r   r   rH   r_   r   r   r   get_workflow_as_xml  s    

zJiraApi.get_workflow_as_xmlc                 C   s   d}|  |S )u   
        Получает cloudId для Jira
        https://developer.atlassian.com/cloud/jira/software/rest/intro/#base-url-differences

        Returns:
            dict: результат ответа
        z_edge/tenant_infor   r   rH   r   r   r   get_cloud_id  s    zJiraApi.get_cloud_id)r   c                 C   s    d| }ddi}| j ||dS )u   
        Получает информацию о схеме бизнес-процессов проекта

        Args:
            project_key (str): Ключ проекта

        Returns:
            dict: результат ответа
        z$rest/projectconfig/1/workflowscheme/ZoriginalTr   r   )r   r   rH   r   r   r   r   get_project_workflow_scheme$  s    

z#JiraApi.get_project_workflow_scheme)cloud_idr   issue_type_idsc                    s   d| d}ddi}g }|D ]}| ||d qd|d}| j|||d}	|	d	 }
|	d
 }|D ]8}|d	 D ]* tt fdd|
d}|rl | qlq`|S )u  
        Получает информацию бизнес-процессов
        для проектов с упрощенной конфигурацией (simplified) 

        Args:
            cloud_id (str): ID облака
            project_id (int): ID проекта
            issue_type_ids (list): список ID типов задачи

        Returns:
            list: данные бизнес-процессов
        z-gateway/api/jira/project-configuration/query/z/3/workflowZuseTransitionLinksFormatT)rZ  r   r   )ZskipUsageLookupZprojectAndIssueTypes)r   rY   statuses	workflowsc                    s   | d  d kS )NZstatusReferencer   )sZworkflow_statusr   r   r   ]  r   z:JiraApi.get_simplified_project_workflows.<locals>.<lambda>N)r/  r   r   r   r   )r   rg  r   rh  rH   r   Zproject_and_issue_typesZissue_type_idrY   r_   ri  rj  ZworkflowrL   r   rl  r    get_simplified_project_workflows2  s6    
z(JiraApi.get_simplified_project_workflows)r   c              
   C   sf   d}d|i}z| j ||dd}W n> tjk
r^ } z|jjdkrJW Y dS |W 5 d}~X Y nX |jS )u   
        Возвращает значение настройки текущего пользователя

        Args:
            key (str): ключ настройки

        Returns:
            _type_: значение
        rest/api/2/mypreferencesr   T)r   r  r  N)rA   rc   r  r_   rb   rK  )r   r   rH   r   r_   r   r   r   r   r   g  s    


zJiraApi.get_mypreferences)r   rY   c                 C   s"   d}d|i}| j ||i |d dS )u   
        Устанавливает значение настройки текущего пользователя

        Args:
            key (str): ключ настройки
            data (str): значение настройки
        rn  r   )rY   r   r   N)Zput)r   r   rY   rH   r   r   r   r   r     s    zJiraApi.set_mypreferencesc                 C   s:   d}d|i}z| j ||d W n tjk
r4   Y nX dS )u   
        Удаляет значение настройки текущего пользователя

        Args:
            key (str): ключ настройки
        rn  r   r   N)deleterc   r  )r   r   rH   r   r   r   r   r     s    zJiraApi.delete_mypreferences)workflow_scheme_idc                 C   s   d| }|  |S )u   
        Получает информацию о схеме бизнес-процессов

        Args:
            workflow_scheme_id (str): id схемы бизнес-процесса
        zrest/api/2/workflowscheme/r   )r   rp  rH   r   r   r   get_workflow_scheme  s    
zJiraApi.get_workflow_scheme)r   r   r0  r   r   c           	      C   sx   |  d}i }|r||d< |r&||d< |r2||d< |r>||d< | jrb|  }d|d  |d< | j||d}|d S )	u,  
        Возвращает список разрешений, указывающий, какие разрешения есть у пользователя.
        Подробную информацию о разрешениях пользователя можно получить
        в глобальном контексте, контексте проекта или задачи

        Args:
            project_id (str, optional): ID проекта. Defaults to None.
            project_key (str, optional): Ключ проекта. Defaults to None.
            issue_id (str, optional): ID задачи. Defaults to None.
            issue_key (str, optional): Ключ задачи. Defaults to None.

        Returns:
            dict: Информация о разрешениях
        Zmypermissionsr   rJ  ZissueIdZissueKeyr   permissionsr   )r   r;   Zget_all_permissionsr   r-  rA   )	r   r   r   r0  r   rH   r   Zall_permissionsrr  r   r   r   get_permissions  s    
zJiraApi.get_permissionsc                 C   s   d}ddd}|r||d< ndddd	d
g}d ||d< g }| j||d}|dsVq||d  |d rnq|d  |d 7  < q<|S )u2  
        Получает список всех фильтров из Jira Cloud

        Args:
            expand (str, optional): параметры для получения расширенных данных. Defaults to None.

        Returns:
            list: список фильтров
        zrest/api/2/filter/searchr   r   r   r   r   ownerdescriptionZsharePermissionsZeditPermissionsr   r   r   r   r   r   )r   rA   r   )r   r   rH   r   Zexpand_listfiltersr_   r   r   r   get_all_filters_cloud  s,    


zJiraApi.get_all_filters_cloudc                 C   s   ddl m} d}dddddd}g }| j||| jdd}||d	}|jd
dd}|sVq|jdddidD ]`}|d}	z| |	}
||
 W qh tk
r } zt	
d|	 d|  W 5 d}~X Y qhX qh|jdddsq|d  d7  < q$|S )u  
        Получает список всех фильтров из Jira Server / Data Center

        В Jira Server / Data Center нет метода API для получения списка фильтров.
        Но можно получить ID фильтров через парсинг HTML-разметки страницы фильтров
        из раздела Администрирование > Система > Фильтры,
        и затем по ID фильтре получить информацию о нем через API.

        При указании параметров "decorator" и "contentOnly" в запросе, можно получить
        только необходимую часть HTML с таблицей списка фильтров и указателем пагинации.
        В таблице выводится по 20 фильтров на странице.

        Returns:
            list: список фильтров
        r   )BeautifulSoupz+secure/admin/filters/ViewSharedFilters.jspaZnoneTr   )Z	decoratorZcontentOnlyZ
sortColumnZsortAscendingpagingOffset)r   rn   rb  ZlxmltableZ	mf_browse)r   trzdata-filter-id)Zattrsu2   Ошибка получения фильтра id z: Naz	icon-next)class_ry  r%   )Zbs4rx  rA   r   findZfind_allZ
get_filterr/  r   rx   r)   )r   rx  rH   r   rv  r_   ZsoupZtable_resultsZfilter_dataZ	filter_idZfilter_r   r   r   r   get_all_filters_server  s<    


*zJiraApi.get_all_filters_serverc                 C   s   | j r|  S |  S dS )u8   
        Получает все фильтры
        N)r;   rw  r  rg   r   r   r   get_all_filters7  s    zJiraApi.get_all_filtersc                 #   s   t   }| d}| dd t   }|r<| d| n
| d |D ]2 tt fdd|d}|rv|d  d<  V  qJdS )uw   
        Получает все решения

        Yields:
            dict: данные решения
        r   r   c                    s   | d  d kS r   r   )ruZ
resolutionr   r   r   [  r   z-JiraApi.get_all_resolutions.<locals>.<lambda>Nr   r   )rC   get_all_resolutionsr   r   r   r   r   )r   Zresolutionsr   Zresolutions_untranslatedZresolution_untranslatedrI   r  r   r  @  s$    




zJiraApi.get_all_resolutionsc                 #   s   t   }| d}| dd t   }|r<| d| n
| d |D ]2 t fdd|D d}|rv|d  d<  V  qJdS )uw   
        Получает все статусы

        Yields:
            dict: данные статуса
        r   r   c                 3   s"   | ]}|d   d  kr|V  qdS r   Nr   .0ZuntranslatedrL   r   r   	<genexpr>  s   z+JiraApi.get_all_statuses.<locals>.<genexpr>Nr   r   )rC   r   r   r   r   r   )r   ri  r   untranslated_statusesuntranslated_statusrI   r  r   r   e  s"    




zJiraApi.get_all_statusesc                 #   s   t  |}| d}| dd t  |}|r@| d| n
| d |D ]d t fdd|D d}|r d D ]4|d }tfdd|D d}|rv|d d	< qv V  qNdS )
u   
        Получает все статусы проекта по типам задач

        Yields:
            dict: данные статуса
        r   r   c                 3   s"   | ]}|d   d  kr|V  qdS r  r   r  r   r   r   r    s   z1JiraApi.get_status_for_project.<locals>.<genexpr>Nri  c                 3   s"   | ]}|d   d  kr|V  qdS r  r   r  r  r   r   r    s   r   r   )rC   r   r   r   r   r   )r   r   r   r   Zuntranslated_issue_typesZuntranslated_issue_typer  r  rI   )r   rL   r   r     s4    



zJiraApi.get_status_for_projectc                 C   s   d| d}|  |S )u   
        Ссылки проекта

        Args:
            project_key (str): код проекта

        Returns:
            list: список ссылок проекта
        zrest/projects/1.0/project/z	/shortcutr   )r   r   rH   r   r   r   get_project_shortcuts  s    
zJiraApi.get_project_shortcutsc                 C   s   d}|  |S )u^   
        Возвращает данные о текущем пользователе
        zrest/api/2/myselfr   rd  r   r   r   
get_myself  s    zJiraApi.get_myself)N)NNrl   )r   r   NNNN)Nr   )r   )NNN)Nr   )r   N)r   )r   r   )Nr   r   )N)NN)N)N)N)r   N)r   r   NNN)r   NNN)NN)r   r8   )NN)F)NNNN)N)kr   r   r   r   rD   rE   r	   rU   rV   r`   re   rh   rj   r]   r   rf   r   r   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r   r  r  r   r  r  r  r   r$  r&  r'  r(  r)  r+  r1  r2  r3  r4  r5  r6  r9  r:  r<  r;  r>  r@  rC  rE  rG  rM  rQ  rW  rY  r[  r\  r]  r^  r`  ra  rc  re  rf  rm  r   r   r   rq  rs  rw  r  r  r  r   r   r  r  __classcell__r   r   rI   r   r7   ]   s  '   
6      
;
   %

)$
!
+




      

	(A"
5    ():	%%/r7   )r    r!   r"   r#   )!r   typingr   r   r   r   r3   	functoolsr   timer   rc   
contextlibr	   Zrequests.adaptersr
   Zurllib3.util.retryr   r9   r   pathlibr   Z	atlassianr   Zcmf.includeZloggingZFilterr   Z	getLoggerrx   Z	addFilterr6   r7   r   r   r   r   <module>   s"   

;