U
    Ќh                    @   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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)
HTTPStatus)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   retry>   s    z/backoff.<locals>.retry_exception.<locals>.retry)r   inspectZisgeneratorfunction)r*   r-   r.   r'   r(   r)   r+   r,   )r*   r   retry_exception)   s    
z backoff.<locals>.retry_exceptionr   )r(   r,   r)   r'   r+   r1   r   r0   r   backoff   s    -r2   c                       s(  e Zd ZdZ fddZ fddZ fddZ f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d*d+ Zdd,d-Zed.d/d0Zed1d2d3Z fd4d5Ze ed6d7d8Z!e d9d:d;Z"de eed=d>d?Z#de eed@dAdBZ$ fdCdDZ%dEdF Z& fdGdHZ'ddIdJZ(e dKdLdMZ)dee ddNdOZ*ddPdQZ+ddRdSZ,dTdU Z-dVdW Z.dXdY Z/e0e ef ddZd[Z1d\d] Z2dd^d_Z3dd`daZ4ddbdcZ5e dddedfZ6deddgdhZ7ee ddidjZ8dkdl Z9 fdmdnZ:dodp Z; fdqdrZ< fdsdtZ= fdudvZ> fdwdxZ? fdydzZ@d{d| ZAd}d~ ZBdd ZCdd ZDdd ZE fddZFdd ZGdd ZHdeeedddZIde e e dddZJdd ZKdd ZLdd ZMdd ZNdd ZOdd ZPdddZQe edddZRdd ZSdd ZTdd ZUe dddZVe eedddZWe dddZXe e dddZYe dddZZe dddZ[de e e e edddZ\dedddZ]edddZ^dd Z_ fddĄZ`  ZaS )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httpzhttps://cloudtokenpasswordtimeout,  ZsessionFzrest/auth/1/session)	
startswithgetcmfutilZrequests_sessionsuper__init__r7   _session_valid_session_url)r   urlr#   r$   	__class__r   r   r?   \   s    
zJiraApi.__init__c                    s   | j rt || dS )u   
        Переопределенный метод
        Базовая аутентификация устанавливается только для Jira Cloud
        N)r6   r>   _create_basic_session)r   usernamer8   rC   r   r   rE   p   s    zJiraApi._create_basic_sessionc                    sH   | j j  | j| jd}t jd| j|d}| j js>tdd| _	dS )u;   
        Выполняет авторизацию
        )rF   r8   ZPOST)pathdatauR   Ошибка аутентификации: файлы cookie не полученыTN)
_sessioncookiesclearrF   r8   r>   requestrA   RuntimeErrorr@   )r   rH   responserC   r   r   _authenticatex   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)rG   FN)r>   rL   rA   status_coder	   ZOKrequestsRequestException)r   rN   rC   r   r   _check_session   s    zJiraApi._check_sessionc                 C   sP   | j r| jstd| jjr<| js<|  r<d| _|   dS |   |   dS )u>   
        Создает валидную сессию
        u_   Учетные данные для аутентификации не предоставленыTN)	rF   r8   
ValueErrorrI   rJ   r@   rT   user_get_websudorO   r   r   r   r   _create_valid_session   s    zJiraApi._create_valid_sessionc              
      s   | j rt j||S zJ| js$|   t j||}|jtjkrZd| _|   t j||}|W S  tj	k
r } zBt
|dr|jjtjkrd| _|   t j|| W Y S  W 5 d}~X Y nX dS )u8  
        Переопределенный метод
        Используется только для Jira Server.
        Перед запросом проверяется валидность сессии
        и при необходимости выполняется авторизация 
        FrN   N)r6   r>   rL   r@   rX   rQ   r	   ZUNAUTHORIZEDrR   rS   r   rN   )r   r#   r$   rN   erC   r   r   rL      s"    zJiraApi.requestN    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 )ur  
        Скачивает файл

        Args:
            download_url (_type_): url файла для скачивания
            save_path (_type_): путь для сохранения файла
            timeout (_type_, optional): Таймаут. Defaults to None.
            chunk_size (_type_, optional): _description_. Defaults to 8*1024.
        rP   )methodrB   headersT)streamr\   r9   Zverifyproxiesz
HTTP: GET z ->  zwb+)
chunk_sizeN)no_check_headersr9   Zlog_curl_debugrI   r<   Z
verify_sslr^   loggerdebugrQ   reasonZraise_for_statusopenZiter_contentwrite)	r   Zdownload_urlZ	save_pathr9   r`   r\   resfchunkr   r   r   download_file   s"    

 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.jspaZfalse)ZwebSudoPasswordZwebSudoIsPostNzatlassian.xsrf.token	atl_token)rG   rH   filesr\   )r8   rI   rJ   Zget_dictr<   postform_token_headers)r   rB   rH   rk   rJ   r   r   r   rV      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/jqlsearch ZnextPageTokenstartAtparamsissuesisLasttotal)int
isinstancelisttuplesetjoinresource_urlr6   r<   extendlen)r   rs   rr   startlimitrt   validate_queryZnext_page_tokenr{   rB   resultsrN   r|   r~   r   r   r   jql_get_list_of_tickets   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)rs   r   r   rt   )r6   MAX_RESULTSr   r   )r   rs   r   start_atr~   max_resultsr|   r   r   r   
get_issues9  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   rt   r|   u    из r~   )r   r>   get_issues_for_boardgrc   r   )r   board_idr   rs   r   r~   r   r|   rC   r   r   r   S  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_sprintr<   )r   r   r   r   rg   rowr   r   r   get_sprintsi  s    zJiraApi.get_sprints)r   r   rr   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   ry   rp   rq   rr   rz   r|   ry   rp   N)r   r<   )	r   Z	sprint_idr   r   rr   rB   r{   rg   r   r   r   r   get_sprint_issuesu  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   ry   rp   rt   ZworkflowNamezworkflow/searchrz   errorMessagesr   Nry   )AssertionErrorr6   r   r<   	Exceptionr   Zget_all_workflows)r   namesr   rt   r{   rB   rg   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   	projectIdrz   r   Nry   )r6   r   r   r<   r   Zget_status_for_projectZget_all_statuses)r   r   
project_idrB   r{   rg   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   rz   r   r   r<   r   )r   r   rB   r{   rg   r   r   r   get_project_scheme  s    zJiraApi.get_project_schemec                 C   s   d| d}|  |S )Nzrest/api/3/workflowscheme/z	/workflowr<   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/workflowschemerz   r   r   ry   )r   r<   r   r   )r   r   r{   r   rg   r   r   r   get_all_workflow_schemes  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   )ry   rp   r   z"rest/api/3/issuetypescheme/projectrz   r   ry   )r<   r   )r   r   r{   r   rg   r   r   r   get_issue_type_schemes  s    zJiraApi.get_issue_type_schemes)r   c                 C   s   d|i}d}| j ||dS )Nr   zrest/api/3/issuetype/projectrz   r   )r   r   r{   r   r   r   r   get_issue_for_project  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Z
issue_typer   r   <lambda>      z)JiraApi.get_issue_types.<locals>.<lambda>nameuntranslatedName)	r6   r<   r>   get_issue_typesget_mypreferencesset_mypreferencesdelete_mypreferencesnextr   )r   r   issue_typescurrent_user_localeZissue_types_untranslatedZissue_type_untranslatedrC   r   r   r     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   rz   ZcommentsNry   )r   dictr<   r   )r   r   base_urlrB   r{   rg   r   r   r   get_comments$  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   r4   r   rz   r   Nr}   ry   )r   r<   r   )r   r   r   rB   r{   rg   r   r   r   get_changelog0  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   rz   r   ry   rp   )r<   r   )r   r   r   r   rB   r{   r   resultr   r   r   get_agile_board_projectA  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projectLocationry   rp   rz   )r   r<   )r   r   r   r   rB   r{   r   r   r   get_project_boardse  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   )r6   r   r>   get_all_agile_boardsr<   r   r   r   r   rg   r   rC   r   r   r   |  s    zJiraApi.get_all_agile_boardsc                 C   s   d}| j |d|id}|S )Nz3rest/greenhopper/1.0/rapidviewconfig/editmodel.jsonZrapidViewIdrz   r   )r   r   r   rN   r   r   r   get_advanced_board_settings  s    z#JiraApi.get_advanced_board_settingsc                 #   sJ   d}d}t  j|||d}|dg s(qF||7 }|d D ]
}|V  q8qd S )Nr   r   )keyr   r   r   )r>   get_project_versions_paginatedr<   r   rC   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   r~   Zrecords)r   r   r<   )r   r   rB   r   r   r{   rg   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   s4  | j rd}dddd}|r.|d |kr.||d< | j||d}|sBq|D ]}|| |d  |V  qF|d	  t|7  < |r.|d	 |kr.qq.nd
}dddd}|r|d |kr||d< |pd|d< d|d< | j||d}|sq0|D ]}|| |d  |V  q|d	  t|7  < |r|d	 |kr̐q0qdS )u   Возвращает список всех пользователей, включая активных,
            неактивных и ранее удаленных, у которых есть учетная запись Atlassian.
            в старых версиях невозможно получить больше 1000 учеток
            https://jira.atlassian.com/browse/JRASERVER-65089
            исправлено в 8.7.0, 8.6.1 и выше
            zrest/api/3/users/searchr   r4   z"operations,groups,applicationRolesr   rp   rz   Z	accountIdry   zrest/api/2/user/search.rF   TZincludeInactiver   N)r6   r<   updateget_user_infor   )r   rF   Z	limit_endr   r{   Zusers	user_infor   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   rt     userrR   	HTTPErrorrN   rQ   )r   r   rt   excr   r   r   get_user_info_by_key  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rF   rt   r   r   )r   rF   rt   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}n4| j||d}|s@| j||d}|sTt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_idrt   r   r   u   Пользователь u    не найден@ZemailAddressZdisplayName)r6   r   r   r   r   ZconfigZ
ORG_DOMAINZcmfrr   ZCmfEmailZ
max_lengthr   r<   r=   Ztranslit_strip)r   r   rt   r   ZpostfixZmax_lenr   r   r   r     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   rz   r   r~   ry   rp   r<   r   r   )r   r   rB   r{   rg   rN   r   r   r   _get_field_context  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   rz   r   r~   ry   rp   r   )r   ZfieldId	contextIdrB   r{   rg   rN   r   r   r   _get_field_options	  s    
zJiraApi._get_field_optionsc                 C   s   |   }t }|D ]}d|kr,|||d < n|||d < | jr|d rg |d< g |d< z`| |d |d< |d D ]@}z.| |d |d }||d< |d | W qr   Y qrX qrW q   Y qX qg |d< g |d< q|S )u]    Возвращает системные и настраиваемые поля задачи r   r   Zcustomcontextoptions)Zget_all_fieldsr   r6   r   r   r   )r   rr   rg   fieldr   r   r   r   r   
get_fields  s.    
zJiraApi.get_fieldsc                 C   s
   |  |S N)Zissue_editmeta)r   r   r   r   r   get_issue_meta4  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 )Nr4   z"project = "{project}" ORDER BY key)projectro   r   rr   r   r   rt   r|   )formatrs   advanced_mode)r   r   r   maxr   rs   rN   rg   r   r   r   get_all_project_issues7  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
        Nry   rp   rq   rr   rs   rt   ru   rv   rw   rz   )	r   r   r   r   r   r   r   r6   r<   )	r   rs   rr   r   r   rt   r   r{   rB   r   r   r   rs   I  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 )Nr4   project = "r    AND updated >= " AND updated <= " ORDER BY updatedro   r   r   r|   )rs   r   )
r   r   r   r   
start_dateend_dater   rs   rN   rg   r   r   r   get_all_project_issues_during`  s&    
z%JiraApi.get_all_project_issues_during)rs   c                 C   s,   d|i}|  d}| j||d}t|d S )u   
        Возвращает количество задач, которые соответствуют JQL

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

        Returns:
            int: количество задач
        rs   zsearch/approximate-count)rH   count)r   rm   r   )r   rs   rH   rB   rN   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   r~   )r6   r  rs   r   )r   r   r   r  rs   rN   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   rg   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   rz   r   ry   )r   r<   r   )r   r   r   r{   rg   r   r   r   get_board_quick_filters  s    
zJiraApi.get_board_quick_filtersc                    s"   t  |}| j|d dd}|S )Nr   all)rt   )r>   get_project_permission_schemeZget_permissionscheme)r   r   schemerC   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)r<   append)r   issue_idr   Z
propertiesrg   r   r   r   r   get_issue_properties  s    
zJiraApi.get_issue_propertiesc                    s   t  |}|d S )NZworklogs)r>   issue_get_worklog)r   r  rg   rC   r   r   r    s    zJiraApi.issue_get_worklogc                    s$   zt  |W S    i  Y S X d S r   )r>   !get_project_issue_security_scheme)r   r   rC   r   r   r    s    z)JiraApi.get_project_issue_security_schemec                 #   s$   t   D ]}| |d V  q
d S r   )r>   get_issue_security_schemesZget_issue_security_scheme)r   ZschrC   r   r   r    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   rz   r   r~   ry   rp   r   Ztabs)r6   r>   get_all_screensr<   r   r   get_screen_tabs)r   r   r{   rg   rN   ZscrrC   r   r   r    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_idrr   )r>   r  get_tab_fields)r   r  rN   ZtabrC   r   r   r    s    zJiraApi.get_screen_tabsc                 C   s$   z|  ||W S    g  Y S X d S r   )Zget_screen_tab_fields)r   r  r  r   r   r   r    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/issuetypescreenschemerz   r   r   ry   rp   )r6   r   r<   r   r   )r   r   r{   r   rN   r   r   r   get_screen_scheme  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   rz   r   r   r   ZissueTypeScreenSchemer   r   )r<   r   get_screen_scheme_issuetypes)r   r   rB   r{   rN   Zscreen_schemer   r   r   get_project_screen_scheme  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   )ry   rp   ZissueTypeScreenSchemeIdrz   r   r   ry   rp   ZscreenSchemeIdactions)r   r<   r   r   get_screen_scheme_actions)r   screen_scheme_idrB   r{   r   rN   r   r   r   r   r    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   rz   r   r   r   Zscreensr   )r   r  rB   r{   rN   r   r   r   r  )  s    z!JiraApi.get_screen_scheme_actionsc                    s"   zt   W S    g  Y S X d S r   )r>   get_all_prioritiesrW   rC   r   r   r  7  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   rz   r   r   r   ry   rp   )r<   r   r  )r   	scheme_idrB   r{   Zproject_keysrN   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 )Nr  z/prioritiesr   r:   r   rz   r   r   ry   rp   )r<   r   r   )r   r   rB   r{   
prioritiesrN   r   r   r   get_priority_scheme_prioritiesR  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schemesry   rp   rt   rz   r   ZprojectKeysr"  Z	optionIds)r6   r   r<   r!  r#  r  Zget_priority_by_id)r   r   r   rB   rt   r   r{   r$  rN   r
  Zpriority_idr   r   r   get_priority_schemesf  s8    zJiraApi.get_priority_schemes)r   r   
issuetypesc                 C   s`  d}d}z| j || jd}W nl tk
r } zNd| d}t|drp|d|jj d|jj d	|jj d
| 7 }t|W 5 d }~X Y nX | d}|dkrd| d| }t|d}	d|i}
|r||
d< |r||
d< z| j |	|
d}W np tk
rZ } zPd| d}t|drB|d|jj d|jj d	|jj d
| 7 }t|W 5 d }~X Y nX |S )Nu   Установите плагин "Smart Jira Configuration" версии 4.8.12, 4.8.9, 4.8.7, 4.7.3 или 4.5.1. по ссылке https://marketplace.atlassian.com/apps/1221996/smart-jira-configuration-formerly-smart-project-config-docs/version-historyz1rest/plugins/1.0/com.eis.jira.plugins.jiradoc-key)r\   u   Для получения полной конфигурации проекта не установлен плагин "Smart Jira Configuration". z. rN   u   Код ошибки - z, z - u   , адрес запроса: version)z4.8.12z4.8.9z4.8.7z4.7.3z4.5.1u.   Неверная версия плагина (z). z-rest/smart-configuration/1.0/getProjectConfig
projectKeyr   r&  rz   uN   Не удалось получить конфигурацию проекта "u6   " через плагин "Smart Jira Configuration". )	r<   ra   r   r   rN   rQ   rd   textZCmfError)r   r   r   r&  Z
error_textZ
plugin_urlrN   r   Zplugin_versionrB   r{   r   r   r   get_project_smart_config  sF    

&

&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   rz   r   r   ZissueSecurityLevelIdZholderry   rp   )r<   r   
setdefaultstrr  )r   Zsecurity_scheme_idrB   r{   Zsecurity_level_membersrN   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   ry   rp   rz   r   Nr   r<   )r   field_id
context_idrB   r{   rN   r   r   r   get_field_context  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`    Возвращает опции контекста пользовательского поля r0  r   r   r   r   rz   i  Nr   r   ry   rp   )r   r<   rR   r   rN   rQ   )
r   r3  r4  rB   r{   r   rN   r   r   valuer   r   r   get_field_context_option  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    Возвращает сопоставленный список типов задач и контекста пользователького поля r0  z/context/issuetypemappingr   r1  rz   r   issueTypeIdry   rp   )r   r<   r  r,  )r   r3  r4  rB   r{   r&  rN   r6  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    Возвращает список контекстов пользовательского поля для проекта r0  z/context/projectmappingr   r   rz   r   uA   Не удалось получить контексты поля u@   . Пользовательское поле не найдено.Nr   ry   rp   r   r   ZisGlobalContext)	r   r<   rR   r   rN   rQ   rb   Zwarningr   )
r   r3  r   rB   r{   ZcontextsrN   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   rz   r   ry   rp   Nr2  )r   Zfield_configuration_idrB   r{   rN   rr   r   r   r   r   get_field_config_fieldsD  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   )ry   rp   Z	isDefaultrz   r   ry   rp   N)r   r<   r   )r   Z
is_defaultrB   r{   Zfield_configurationsrN   r   r   r   get_field_configX  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fieldConfigurationSchemeIdrz   r   r   )r   r=  rB   r{   rN   r   r   r   "get_field_configuration_issue_typeq  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   rz   r   r   NZfieldConfigurationSchemer   r   )r   r   rB   r{   rN   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_responser\   r   )r   r   rB   rN   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   rB   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originalTrz   r   )r   r   rB   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|i}| j|||d}	|	d }
|	d	 }|D ]8}|d D ]* tt fd
d|
d}|rj | qjq^|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/2/workflowZuseTransitionLinksFormatT)r8  r   ZprojectAndIssueTypes)r{   rH   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  rm   r   r   r   )r   rD  r   rE  rB   r{   Zproject_and_issue_typesZissue_type_idrH   rN   rF  rG  Zworkflowstatusr   rI  r    get_simplified_project_workflows  s2    
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)r<   rR   r   rN   rQ   r)  )r   r   rB   r{   rN   r   r   r   r   r     s    


zJiraApi.get_mypreferences)r   rH   c                 C   s"   d}d|i}| j ||i |d dS )u   
        Устанавливает значение настройки текущего пользователя

        Args:
            key (str): ключ настройки
            data (str): значение настройки
        rL  r   )rH   rl   r{   N)Zput)r   r   rH   rB   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): ключ настройки
        rL  r   rz   N)deleterR   r   )r   r   rB   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   rN  rB   r   r   r   get_workflow_scheme*  s    
zJiraApi.get_workflow_scheme)r   r   r  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   r(  ZissueIdZissueKeyrq   permissionsrz   )r   r6   Zget_all_permissionsr   r  r<   )	r   r   r   r  r   rB   r{   Zall_permissionsrP  r   r   r   get_permissions4  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   rt   rs   ownerdescriptionZsharePermissionsZeditPermissionsrq   rz   r   r}   ry   rp   )r   r<   r   )r   rt   rB   r{   Zexpand_listfiltersrN   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}	| |	}
||
 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{   r\   r@  ZlxmltableZ	mf_browse)r   trzdata-filter-id)Zattrsaz	icon-next)class_rW  r!   )Zbs4rV  r<   rn   findZfind_allZ
get_filterr  )r   rV  rB   r{   rT  rN   ZsoupZtable_resultsZfilter_dataZ	filter_idZfilter_r   r   r   get_all_filters_server  s6    


zJiraApi.get_all_filters_serverc                 C   s   | j r|  S |  S dS )u8   
        Получает все фильтры
        N)r6   rU  r]  rW   r   r   r   get_all_filters  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   )r>   get_all_resolutionsr   r   r   r   r   )r   Zresolutionsr   Zresolutions_untranslatedZresolution_untranslatedrC   r`  r   ra    s$    




zJiraApi.get_all_resolutions)NrZ   )ro   r   NNNN)Nr   )r   )NNN)Nr   )r   N)r   )r   r   )Nr   r   )N)NN)N)N)r   N)ro   r   NNN)r   NNN)NN)r   r4   )NN)F)NNNN)N)br   r   r   r   r?   rE   rO   rT   rX   rL   rj   rV   r   r   r   r   r   r2   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   rs   r  r  r  r  r  r	  r  r  r  r  r  r  r  r  r  r  r  r  r!  r#  r%  r*  r/  r5  r7  r9  r:  r;  r<  r>  r?  rA  rB  rC  rK  r   r   r   rO  rQ  rU  r]  r^  ra  __classcell__r   r   rC   r   r3   Y   s   
      
;
   %

)$
*



      

	(7"
2    ()7	r3   )r   r   r   r   )r   typingr   r   r   r   r/   	functoolsr   timer   rR   r5   r	   Z	atlassianr
   Zcmf.includeZloggingZFilterr   Z	getLoggerrb   Z	addFilterr2   r3   r   r   r   r   <module>   s   

;