
    iԗ                       d Z ddlmZ ddlZddlZddlmZmZmZ ddlm	Z	m
Z
 ddlmZmZmZmZ ddlmZ ddlmZ dd	lmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+  ed
dg          Z, ej-        e.          Z/ e            Z0dddd~dZ1ddl2m3Z4m5Z6 ddZ7ddZ8ddZ9ddZ:ddZ;dd!Z<dd%Z=dd(Z>dd+Z?dd,Z@dd2ZAdd4ZBdd6ZCdd9ZDdd<ZEdd>ZFdd@ZGddCZHddFZIddIZJddKZKddNZLddQZMe,N                    dRdSdTdUeV          ddX            ZOe,N                    dYdZd[d\e*V          dd_            ZPe,N                    d`dadbdceV          ddf            ZQdddhZRe,N                    didjdkdleV          ddo            ZSe,N                    dpdqdrdse(V          ddv            ZTe,N                    dwdxdydze&V          dd}            ZUdS )u  
Nom du fichier : projects.py
Chemin : /var/www/html/gitlab-bridge/app/api/v1/projects.py
Description : Endpoints API liés aux projets GitLab compatibles OpenWebUI.
              Ce fichier expose :
              - le résumé d'un projet GitLab
              - la création d'un projet GitLab
              - la pré-vérification avant création
              - une orchestration conversationnelle de création
Options éventuelles :
    - POST /api/v1/projects/summary
    - POST /api/v1/projects/create
    - POST /api/v1/projects/check-create
    - POST /api/v1/projects/assistant-create
Auteur : Sylvain SCATTOLINI
Date de création / modification : 2026-03-26
Version : 1.8
    )annotationsN)datetime	timedeltatimezone)	AnnotatedAny)	APIRouterBodyHTTPExceptionstatus)GitLabClient)GitLabApiError)CandidateGroupProjectAssistantCreateRequestProjectAssistantCreateResponseProjectCheckCreateRequestProjectCheckCreateResponseProjectCreatePayloadProjectCreateRequestProjectCreateResponseProjectInfoProjectProgressResponseProjectProgressRequestProjectTasksRequestProjectTasksResponseProjectSummaryResponseSimilarProjectSummaryPayloadProjectAssistantProgressRequest ProjectAssistantProgressResponseProjectAssistantTasksRequestProjectAssistantTasksResponseProjectAssistantListRequestProjectAssistantListResponseProjectListItemz/api/v1/projectsprojects)prefixtags)query_paramspayloadmethodstrendpointr)   dict[str, Any] | Noner*   returnr   c                   	 t                               | |||          S # t          $ r%}|j        pd}t	          ||j                  |d}~ww xY w)uU   Adaptateur vers GitLabClient — remplace urllib, bénéficie du pooling et du retry.)params	json_body  status_codedetailN)
_gl_client_requestr   http_statusr   message)r+   r-   r)   r*   excr9   s         2/var/www/html/gitlab-bridge/app/api/v1/projects.py_gitlab_requestr=   B   sl    R""68LT["\\\ R R Ro,CKHHHcQRs     
A A

A)normalize_textcompute_similarity_scorevaluec                z    |                                                       d          }|st          dd          |S )N/  zLe chemin projet est vide.r4   stripr   r@   cleaneds     r<   _normalize_project_pathrH   T   s?    kkmm!!#&&G R4PQQQQN    c                z    |                                                       d          }|st          dd          |S )NrB   rC   zLe namespace_path est vide.r4   rD   rF   s     r<   _normalize_namespace_pathrK   [   s?    kkmm!!#&&G S4QRRRRNrI   c                    |                                                       d          }|st          dd          t          j        d|          st          dd          |S )NrB   rC   zLe champ path est vide.r4   z[a-zA-Z0-9._-]+u6   Le champ path contient des caractères non autorisés.)rE   r   re	fullmatchrF   s     r<   _normalize_project_slugrO   b   si    kkmm!!#&&G O4MNNNN<*G44 n4lmmmmNrI   c                |    |                                                                  }|dvrt          dd          |S )N>   publicprivateinternalrC   u6   La visibilité doit être private, internal ou public.r4   )rE   lowerr   )r@   
visibilitys     r<   _normalize_visibilityrV   m   sA    $$&&J:::4lmmmmrI   namec                    ddl m} 	  ||           }n1# t          $ r$}t          dt	          |                    |d }~ww xY wt          |          S )Nr   )slugifyrC   r4   )app.utils.helpersrY   
ValueErrorr   r,   rO   )rW   rY   slugr;   s       r<   _slugify_project_namer]   t   su    ))))))Gwt}} G G GCHH===3FG"4(((s    
A=Aproject_pathdict[str, Any]c                    t          | d          }t          dd|           }t          |t                    rd|vrt	          dd          |S )	N safeGET
/projects/idr3   u=   Réponse GitLab invalide lors de la récupération du projet.r4   quoter=   
isinstancedictr   )r^   encoded_project_pathprojects      r<   _get_project_by_pathrm   }   sd     B777e%H2F%H%HIIGgt$$ uG(;(;4sttttNrI   
project_idintlist[dict[str, Any]]c           
         t          dd|  ddddddd	
          }t          |t                    sg S d |D             S )Nrd   re   /issuesopenedd      
updated_atdesc)stateper_pagepageorder_bysortr)   c                <    g | ]}t          |t                    |S  ri   rj   .0issues     r<   
<listcomp>z%_list_open_issues.<locals>.<listcomp>   s'    AAAeE4)@)@AEAAArI   r=   ri   list)rn   issuess     r<   _list_open_issuesr      sm    (Z((($
 

 
 
F fd## 	AAvAAAArI   
str | Nonedatetime | Nonec                    | rt          | t                    sd S 	 t          j        |                     dd                                        t          j                  S # t          $ r Y d S w xY w)NZ+00:00)	ri   r,   r   fromisoformatreplace
astimezoner   utcr[   )r@   s    r<   _parse_gitlab_datetimer      sv     
5#.. t%emmC&B&BCCNNx|\\\   tts   AA   
A.-A.since_dtr   c                   t          dd|  dd|                    d                                                              dd          d	d
ddd          }t          |t                    sg S g }|D ]W}t          |t
                    st          |                    d                    }|||k    r|                    |           X|S )Nrd   re   rr   closedr   )microsecondr   r   rt   ru   rv   rw   )rx   updated_afterry   rz   r{   r|   r}   	closed_at)	r=   r   	isoformatri   r   rj   r   getappend)rn   r   r   filtered_issuesr   r   s         r<   _list_recent_closed_issuesr      s    (Z(((%--!-<<FFHHPPQY[^__$
 
  F fd## 	,.O * *%&& 	*599[+A+ABB	 Y(%:%:""5)))rI   c                |    t          dd|  ddddd          }t          |t                    sg S d	 |D             S )
Nrd   re   z/milestonesactive   ru   )rx   ry   rz   r}   c                <    g | ]}t          |t                    |S r   r   )r   	milestones     r<   r   z$_list_milestones.<locals>.<listcomp>   s'    QQQ)Z	45P5PQIQQQrI   r   )rn   
milestoness     r<   _list_milestonesr      sg     ,Z,,,
 
  J j$'' 	QQzQQQQrI   project_nameperiod_daysopen_issues_countclosed_issues_countr   c                   d|  dd| dd| dd| d| g}|r~|                     d	           |d d
         D ]]}t          |                    dd                    }|                    d          }	|                     d| |	rd|	 dndz              ^n|                     d           d                    |          S )Nu   ## Résumé du projet ra   z- Projet : ``u   - Période analysée : z jour(s)z- Issues ouvertes : u$   - Issues fermées sur la période : z- Milestones actives :   titlez
Sans titredue_datez  - u    (échéance : )z- Aucune milestone active
)r   r,   r   join)
r   r^   r   r   r   r   linesr   r   r   s
             r<   _build_markdown_summaryr      s    	0//
&|&&&7+7772022D/BDDE  2-...#BQB 	_ 	_I	g|<<==E }}Z00HLLH+\+HX+H+H+H+HZ\]^^^^	_
 	011199UrI   namespace_pathc                    t          | d          }t          dd|           }t          |t                    rd|vrt	          dd          |S )	Nra   rb   rd   /groups/rf   r3   u@   Réponse GitLab invalide lors de la récupération du namespace.r4   rg   )r   encoded_namespace_pathgroups      r<   _get_namespace_by_pathr      sd    ">;;;E#F.D#F#FGGEeT"" xd%&7&74vwwwwLrI   Nonec                ,    t          dd|             d S )NDELETEre   )r=   )rn   s    r<   _delete_projectr      s!    H7:7788888rI   	root_hintlimitc           	        t          dddt          |dz  d          dd          }t          |t                    sg S t	          |           }g }|D ]}t          |t
                    st          |                    d	d
                                                    }|sP|r#t	          |          	                    |          su|
                    |           |S )Nrd   z/groupsTr   2   ru   )all_availablery   rz   r}   	full_pathra   )r=   maxri   r   _normalize_textrj   r,   r   rE   
startswithr   )r   r   groupsnormalized_root_hintfilteredr   r   s          r<   _list_groupsr      s   !EAIr**
 
  F fd## 	*955%'H  %&& 			+r223399;;	 	 		(B(B(M(MNb(c(c 	OrI   target_group_hintlist[CandidateGroup]c           	     z   t          ||          }t          |           }g }|D ]}t          |                    dd                    }t          |                    dd                    }t	          t          ||          t          ||                    }	|t          |          v rt	          |	d          }	n!|t          |          v rt	          |	d          }	|	dk     r|                    t          t          |d                   |||	                     |	                    d	 
           |d |         S )NrW   ra   r   _   Z   (   rf   )rf   rW   r   scorec                     | j          | j        fS N)r   r   items    r<   <lambda>z*_search_candidate_groups.<locals>.<lambda>6  s    tzk4>%B rI   key)
r   r   r,   r   r   _compute_similarity_scorer   r   ro   r|   )
r   r   r   r   normalized_hint
candidatesr   rW   r   r   s
             r<   _search_candidate_groupsr     sR   )U++F%&788O')J 
 
599VR(())		+r2233	%ot<<%oyAA
 

 od3333rNNEE	 : :::rNNE2::uT{###	  	
 	
 	
 	
 OOBBOCCCfufrI   list[SimilarProject]c                T   t          dd| dt          |dz  d          dd          }t          |t                    sg S t	          |          }g }|D ]4}t          |t
                    st          |                    d	d
                    }|s?|r#t	          |                              |          sdt          t          | t          |                    dd
                              t          | |                    }|dk     r|
                    t          t          |d                   t          |                    dd
                    |t          |                    dd
                    |                     6|                    d            |d |         S )Nrd   	/projectsTr   r   ru   )searchsimplery   rz   r}   path_with_namespacera   rW   r   rf   web_urlrf   rW   r   r   r   c                     | j          | j        fS r   )r   r   r   s    r<   r   z*_search_similar_projects.<locals>.<lambda>i  s    tzk43K%L rI   r   )r=   r   ri   r   r   rj   r,   r   r   r   r   r   ro   r|   )	r   r   r   r&   r   r   rl   r   r   s	            r<   _search_similar_projectsr   :  s   "EAIr**	
 
	 	 	H h%% 	*955')J 
 
'4(( 	!'++.CR"H"HII" 	 	8K(L(L(W(WXl(m(m 	%lCFB8O8O4P4PQQ%l4GHH
 

 2::wt}%%VR0011$7GKK	26677  	
 	
 	
 	
 OOLLOMMMfufrI   r   c           
     $   |                                  }|                                 }|                                                      d          }t          |          }t          |          }t          |||          }	t	          |||          }
|	st          dd|g |
d| d          S |	d         }t          |	          dk    o|	d         j        |j        d	z
  k    }|rt          dd
||	|
d          S t          dd||j        |g|
d          S )NrB   Tgroup_not_found-   Je ne trouve pas de groupe correspondant à ''.)successr   suggested_project_pathcandidate_groupssimilar_projectsr:   r   ru   
   ambiguous_groupz!Plusieurs groupes sont possibles.readyu   Création possible.)r   r   r   resolved_groupr   r   r:   )	rE   ro   r]   r   r   r   lenr   r   )r   r   r   r   safe_project_namesafe_target_group_hintsafe_root_hint
safe_limitr   r   r   	top_group	ambiguouss                r<   _evaluate_project_creationr   m  sb    %**,,.4466__&&,,S11NUJ23DEE/0FXbcc/0A>S]^^ 
)$#9-^DZ^^^
 
 
 	
 !#I$%%)_.>q.A.G9?]_K_._I 
)$#9--7
 
 
 	
 &5 *#)%   rI   r    list[tuple[int, dict[str, Any]]]c                d   g }| d d         D ]\  }}|                     t          t          |d                   t          |                    dd                    t          |                    dd                    t          |                    dd                    |                     |S )Nr   rf   rW   ra   r   r   r   )r   r   ro   r,   r   )r   resultsr   rl   s       r<   '_build_similar_projects_from_candidatesr     s    $&G$RaR. 	
 	
wwt}%%VR0011$'4I2(N(N$O$OGKK	26677  	
 	
 	
 	
 NrI   project_hint7tuple[str, dict[str, Any] | None, list[SimilarProject]]c                    t          | |          }|sdd g fS t          |          dk    r3|d         d         |d         d         dz
  k    rdd t          |          fS d|d         d         t          |          fS )N	not_foundru   r   r   r   r   )_search_best_projectr   r   )r   r   r   s      r<   _resolve_project_candidatesr    s    %lI>>J %D"$$
:z!}Q/:a=3Cb3HHHD"I*"U"UUUJqM!$&Mj&Y&YYYrI   rl   (tuple[ProjectInfo, list[str], list[str]]c                :   t          | d                   }t          dd| dddd          }t          dd| dd	dd          }t          |t          | d
                   t          | d                             }d |D             }d |D             }|||fS )Nrf   rd   re   rr   rs   rt   rx   ry   r}   r   rW   r   rf   rW   r   c                ~    g | ]:}t          |t                    t          |                    d d                    ;S r   ra   ri   rj   r,   r   r   s     r<   r   z+_get_project_tasks_data.<locals>.<listcomp>  s?    ccc5:V[]aKbKbc3uyy"--..cccrI   c                ~    g | ]:}t          |t                    t          |                    d d                    ;S r	  r
  r   s     r<   r   z+_get_project_tasks_data.<locals>.<listcomp>  s?    gggUzZ_aeOfOfgS7B//00gggrI   )ro   r=   r   r,   )rl   rn   open_issuesclosed_issuesproject_infoopen_titlesclosed_titless          r<   _get_project_tasks_datar    s    WT]##J!(Z((('S99  K $(Z((('S99  M !!(= >??  L dcKcccKggmgggMm33rI   !tuple[ProjectInfo, int, int, int]c                   t          | d                   }t          dd| dddd          }t          dd| dd	dd          }t          |          t          |          z   }t          |          }|d
k    rt          ||z  dz            nd
}t          |t	          | d                   t	          | d                             }||||fS )Nrf   rd   re   rr   rs   rt   r  r}   r   r   rW   r   r  )ro   r=   r   r   r,   )rl   rn   r  r  totalr   progress_percentr  s           r<   _get_project_progress_datar    s   WT]##J!(Z((('S99  K $(Z((('S99  M s=111EF6;aiisFUNc1222Q!!(= >??  L (888rI   
group_pathlist[ProjectListItem]c                   t          |           }t          |          }t          |d                   }t          dd| ddt	          |d          ddd	d
d          }t          |t                    sg S g }|D ]}t          |t                    s|                    t          t          |d                   t          |                    d	d                    t          |                    dd                    t          |                    dd                    t          |                    dd                    t          |                    dd          pd                               |                    d            |S )Nrf   rd   r   r   Frt   ru   TrW   asc)include_subgroupsry   rz   r   r{   r|   r}   ra   r   r   rU   r   r   )rf   rW   r   r   rU   r   c                4    | j                                         S r   )rW   rT   r   s    r<   r   z)_list_projects_in_group.<locals>.<lambda>  s    $)//"3"3 rI   r   )rK   r   ro   r=   minri   r   rj   r   r%   r,   r   r|   )r  r   safe_group_pathr   group_idr&   r   rl   s           r<   _list_projects_in_groupr     s   /
;;O"?33E5;H&8&&&!&E3
 
  H h%% 	%'G 
 
'4(( 	wt}%%VR0011$'4I2(N(N$O$OGKK	26677w{{<<<=="%gkk2Eq&I&I&NQ"O"O  		
 		
 		
 		
 LL33L444NrI   
group_hint,tuple[str, str | None, list[CandidateGroup]]c                    t          | ||          }|sdd g fS |d         }t          |          dk    o|d         j        |j        dz
  k    }|rdd |fS d|j        |gfS )Nr  r   ru   r   r   r   )r   r   r   r   )r!  r   r   r   r   r   s         r<   _resolve_group_candidatesr$    s    )*iGGJ %D"$$1IJ!#S
1(;yQS?S(SI -D*,,I')44rI   z/check-createcheck_create_projectu-   Pré-vérifier une création de projet GitLabuJ   Recherche les groupes candidats et les projets similaires avant création.)operation_idsummarydescriptionresponse_modelr   c                   	 t                               dt                              |                                 d                     t          | j        | j        | j        | j	                  S # t          $ r  t          $ r?}t                               dt          |                     t          dd          |d }~ww xY w)	Nu4   Payload reçu sur /api/v1/projects/check-create : %sFensure_asciir   r   r   r   z0Erreur inattendue dans check_create_project : %s  u7   Erreur interne lors de la pré-vérification du projet.r4   )loggerinfojsondumps
model_dumpr   r   r   r   r   r   	Exception	exceptionr,   )r*   r;   s     r<   r%  r%  -  s    xBJJw))++%J@@	
 	
 	
 * -%7'-	
 
 
 	
     x x xKSQTXXVVV4mnnntwwxs   A-A0 0C:B>>Cz/assistant-listassistant_list_projectsz"Assistant liste des projets GitLabuW   Résout un groupe, demande clarification si besoin, puis retourne la liste des projets.r#   r$   c                T   	 t                               dt                              |                                 d                     t          | j                  }| j        rf| j        	                                st          dd          t          | j                  }t          ||          }t          ddd	| |g |
          S t          | j        | j        |          \  }}}|dk    rt          ddd| j         dd g g 
          S |dk    rt          dddd |g 
          S |J t          ||          }t          ddd	| |||
          S # t          $ r  t"          $ r?}t                               dt'          |                     t          dd          |d }~ww xY w)Nu6   Payload reçu sur /api/v1/projects/assistant-list : %sFr+  rC   z@Le champ resolved_group_path est obligatoire quand confirm=true.r4   Tresolvedu$   Liste des projets récupérée pour )r   r   r:   r   r   r&   r  r   r   r   clarification_neededO   J’ai trouvé plusieurs groupes possibles. Merci de préciser lequel utiliser.z3Erreur inattendue dans assistant_list_projects : %sr.  u?   Erreur interne lors de la récupération assistée des projets.)r/  r0  r1  r2  r3  ro   r   confirmresolved_group_pathrE   r   rK   r   r$   r$  r!  r   r4  r5  r,   )r*   r   r   r&   status_resolver   r;   s          r<   r6  r6  G  sK   IDJJw))++%J@@	
 	
 	

 ''
? 	.4466 # #]   
 7w7RSSN.~zJJH/!O~OO-!#!    <U<
 <
8(8 [((/"^HZ^^^#!#    [((/-i#!1    )))*>:FF+K>KK)-
 
 
 	
       NPSTWPXPXYYYT
 
 
 	s+   CE 
AE E (+E F'(:F""F'z/assistant-createassistant_create_projectu'   Assistant de création de projet GitLabuP   Orchestre la vérification, la clarification et la création d'un projet GitLab.r   r   c           
        	 t                               dt                              |                                 d                     | j                                        }| j                                                            d          }| j                                        }t          | j
                  }t          | j                  }t          | j                  }| j        r| j                                        st#          dd          t%          | j                  }t'          |          }t)          t+          ||||||                    }	t-          d	d
d|	j        j         |	j        ||g g           S t3          || j        ||          }
|
j        dk    rp|
j        rit)          t+          ||
j        |
j        |||                    }	t-          d	d
d|	j        j         |	j        |
j        |
j        |
j        |
j                  S |
j        dk    r&t-          d	ddd |
j        d |
j        |
j                  S t-          d	d|
j        d |
j        d |
j        |
j                  S # t"          $ r  t@          $ r?}t           !                    dtE          |                     t#          dd          |d }~ww xY w)Nu8   Payload reçu sur /api/v1/projects/assistant-create : %sFr+  rB   rC   z;Le champ resolved_group est obligatoire quand confirm=true.r4   rW   pathr   r(  rU   initialize_with_readmeTcreatedu   Projet créé : )r   r   r:   rl   r   r   r   r   r-  r   r   r9  r:  r   z4Erreur inattendue dans assistant_create_project : %sr.  u7   Erreur interne lors de l'assistant de création projet.)#r/  r0  r1  r2  r3  r   rE   r   r(  rV   rU   boolrB  ro   r   r;  r   r   rK   r]   create_projectr   r   rl   r   r   r   r   r   r   r   r:   r4  r5  r,   )r*   r   r   safe_descriptionsafe_visibilitysafe_initialize_with_readmer   r   r^   create_responsecheck_responser;   s               r<   r>  r>    sR   ixFJJw))++%J@@	
 	
 	

 $06688 *002288==".4466/0BCC&*7+I&J&J#''
? 	)//11 # #X   
 7w7MNNN01BCCL,$*%#1 0.+F  	 	O 2 X?+B+VXX'/'3-!#!#	 	 	 	 4*%7$	
 
 
  G++0M+,$*'>#1#@ 0.+F  	 	O 2 X?+B+VXX'/'5'L-<!/!@!/!@	 	 	 	  $5551-: '5'L#!/!@!/!@    .$"*#1#H+<+<	
 	
 	
 		
     x x xOQTUXQYQYZZZ4mnnntwwxs+   E?I1 BI1 0I1 *I1 1K:J??Kra   c                J   t          dd| ddd          }t          |t                    sg S g }|D ]}t          |t                    st	          |                    dd                    }|r0t          |                              t          |                    smt          t          | t	          |                    d	d                              t          | |                    }|d
k     r|
                    ||f           |                    dd            |S )Nrd   r   Tr   )r   r   ry   r}   r   ra   rW   r   c                    | d         S )Nr   r   r   s    r<   r   z&_search_best_project.<locals>.<lambda>4  s
    47 rI   )reverser   )r=   ri   r   rj   r,   r   r   r   r   r   r   r|   )r   r   r&   r   rl   rA  r   s          r<   r  r    sF   "
 
  H h%% 	J , ,'4(( 	7;;4b99:: 	_T22==oi>X>XYY 	%lCFB8O8O4P4PQQ%lD99
 

 2::5'*++++OOD&:&:O;;;rI   z/createrE  u   Créer un projet GitLabuJ   Crée un projet GitLab à partir d'un payload simple compatible OpenWebUI.r   r   c                   	 | j                                         }t          | j                  }| j                                        }t          | j                  }t          | j                  }| j	                                        }d|v rt          |          }ndt          |          }t          j        dd|          }t          j        dd|          }t          j        dd|                              d          }t          |          }t                              dt"                              ||||||dd	
                     t'          |          }|                    d          }	t+          |	t,                    st/          dd          |||	|||d}
t                              dt"                              |
d	
                     t1          dd|
          }t+          |t2                    st/          dd          t5          |                    dd                                                                                    }|                                 d}|                    |          s|                    d          }t+          |t,                    rY	 t;          |           t                              d|||           n+# t>          $ r t                               d|           Y nw xY wt/          dd| d| d          t                              d|                    d          |                    d                     tC          dtE          t-          |d                   t5          |d                   t5          |d                   t5          |d                    !          "          S # t.          $ r  tF          $ r?}t                               d#t5          |                     t/          dd$          |d }~wt>          $ r?}t                               d%t5          |                     t/          d&d'          |d }~ww xY w)(NrB   z\s+-z[^a-zA-Z0-9._-]+z-{2,}z-._u.   Payload reçu sur /api/v1/projects/create : %sr@  Fr+  rf   r3   u4   Réponse GitLab invalide : namespace_id introuvable.r4   )rW   rA  namespace_idr(  rU   rB  u4   Payload envoyé à GitLab pour création projet : %sPOSTr   )r*   u8   Réponse GitLab invalide lors de la création du projet.r   ra   uZ   Projet supprimé car créé dans un mauvais namespace : attendu=%s obtenu=%s project_id=%suR   Impossible de supprimer le projet créé dans le mauvais namespace : project_id=%si  u5   Projet créé dans un namespace inattendu : attendu 'z', obtenu 'r   u9   Projet GitLab créé avec succès : project_id=%s path=%sTrW   r   )rf   rW   r   r   )r   rl   z.Champ GitLab manquant dans create_project : %su;   Réponse GitLab incomplète lors de la création du projet.z*Erreur inattendue dans create_project : %sr.  u.   Erreur interne lors de la création du projet.)$rW   rE   rK   r   r(  rV   rU   rD  rB  rA  r]   r   rM   subrO   r/  r0  r1  r2  r   r   ri   ro   r   r=   rj   r,   rT   r   r   warningr4  r5  r   r   KeyError)r*   	safe_namesafe_namespace_pathrF  rG  rH  raw_path	safe_path	namespacerP  create_payloadrl   created_path_with_namespaceexpected_prefixrn   r;   s                   r<   rE  rE  8  s   moL&&((	78NOO".4466/0BCC&*7+I&J&J#<%%''(??,Y77HH&x00Hvfc844Hv13AAHvhX66<<UCCH+H55	<JJ%%&9#3"1.I  #  
 
	
 	
 	
 ++>??	 }}T**,,, 	pC8noooo (+)&A*
 *
 	BJJ~EJ::	
 	
 	

 "&+~NNN'4(( 	tC8rssss&)'++6KR*P*P&Q&Q&W&W&Y&Y&_&_&a&a#06688;;;*55oFF 	 T**J*c** #J///NNt+3"	    !   $$l"      ` 3` `@[` ` `    	GKKKK-..	
 	
 	
 %(wt}%%))$'0E(F$G$GGI.//	  
 
 
 	
     | | |I3s88TTT4qrrrx{{ o o oEs3xxPPP4deeeknnosI   J'O
 *,K O
 %K?<O
 >K??C
O
 
Q$:PQ$%:QQ$z/assistant-tasksassistant_project_tasksu   Assistant tâches projet GitLabuN   Résout un projet, demande clarification si besoin, puis retourne les tâches.r!   r"   c           	     l   	 t                               dt                              |                                 d                     | j        r|| j                                        st          dd          t          t          | j                            }t          |          \  }}}t          ddd	|j         |||g 
          S t          | j        | j                  \  }}}|dk    rt          ddd| j         dd g g g 
          S |dk    rt          dddd g g |
          S |J t          |          \  }}}t          ddd	|j         ||||
          S # t          $ r  t"          $ r?}t                               dt'          |                     t          dd          |d }~ww xY w)Nu7   Payload reçu sur /api/v1/projects/assistant-tasks : %sFr+  rC   BLe champ resolved_project_path est obligatoire quand confirm=true.r4   Tr8  u   Tâches récupérées pour )r   r   r:   rl   r  r  candidate_projectsr  -   Je ne trouve pas de projet correspondant à 'r   r   r9  O   J’ai trouvé plusieurs projets possibles. Merci de préciser lequel utiliser.z3Erreur inattendue dans assistant_project_tasks : %sr.  u?   Erreur interne lors de la récupération assistée des tâches.)r/  r0  r1  r2  r3  r;  resolved_project_pathrE   r   rm   rH   r  r"   r   r  r   r   r4  r5  r,   )r*   rl   r  r  r  r=  r`  r;   s           r<   r]  r]    s^   JEJJw))++%J@@	
 	
 	

 ? 	06688 # #_   
 ++B7C`+a+abbG7Nw7W7W4L+}0!Xl6VXX$'+#%    7R 7
 7
3!3
 [((0"`H\``` #%    [((0-i #5    """3J73S3S0k=,T,2RTT #'1
 
 
 	
       NPSTWPXPXYYYT
 
 
 	s+   C	E  AE  E  +4E   F34:F..F3z/assistant-progressassistant_project_progressz#Assistant progression projet GitLabuQ   Résout un projet, demande clarification si besoin, puis retourne la progression.r   r    c           
     x   	 t                               dt                              |                                 d                     | j        r~| j                                        st          dd          t          t          | j                            }t          |          \  }}}}t          ddd	|j         ||||g 
          S t          | j        | j                  \  }}}|dk    r t          ddd| j         dd dddg 
          S |dk    rt          dddd ddd|
          S |J t          |          \  }}}}t          ddd	|j         |||||
          S # t          $ r  t"          $ r?}t                               dt'          |                     t          dd          |d }~ww xY w)Nu:   Payload reçu sur /api/v1/projects/assistant-progress : %sFr+  rC   r_  r4   Tr8  u   Progression calculée pour )r   r   r:   rl   r  r   r  r`  r  ra  r   r   r   r9  rb  z6Erreur inattendue dans assistant_project_progress : %sr.  u6   Erreur interne lors du calcul assisté de progression.)r/  r0  r1  r2  r3  r;  rc  rE   r   rm   rH   r  r    r   r  r   r   r4  r5  r,   )	r*   rl   r  r  r   r  r=  r`  r;   s	            r<   rd  rd    sr   NHJJw))++%J@@	
 	
 	

 ? 	06688 # #_   
 ++B7C`+a+abbG<VW^<_<_9L%)93!Xl6VXX$!1#%	 	 	 	 7R 7
 7
3!3
 [((3"`H\```!"#%	 	 	 	 [((3-i!"#5	 	 	 	 """8RSZ8[8[5eV%5/T,2RTT -1	
 	
 	
 		
       QSVWZS[S[\\\K
 
 
 	s+   CE& AE& E& /6E& &F9::F44F9)
r+   r,   r-   r,   r)   r.   r*   r.   r/   r   )r@   r,   r/   r,   )rW   r,   r/   r,   )r^   r,   r/   r_   )rn   ro   r/   rp   )r@   r   r/   r   )rn   ro   r   r   r/   rp   )r   r,   r^   r,   r   ro   r   ro   r   ro   r   rp   r/   r,   )r   r,   r/   r_   )rn   ro   r/   r   )r   r,   r   ro   r/   rp   )r   r,   r   r,   r   ro   r/   r   )r   r,   r   r,   r   ro   r/   r   )
r   r,   r   r,   r   r,   r   ro   r/   r   )r   r   r/   r   )r   r,   r   r,   r/   r   )rl   r_   r/   r  )rl   r_   r/   r  )r  r,   r   ro   r/   r  )r!  r,   r   r,   r   ro   r/   r"  )r*   r   r/   r   )r*   r#   r/   r$   )r*   r   r/   r   )ra   )r   r,   r   r,   )r*   r   r/   r   )r*   r!   r/   r"   )r*   r   r/   r    )V__doc__
__future__r   loggingrM   r   r   r   typingr   r   fastapir	   r
   r   r   app.clients.gitlab_clientr   app.core.exceptionsr   app.schemas.projectsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   router	getLogger__name__r/  r7   r=   rZ   r>   r   r?   r   rH   rK   rO   rV   r]   rm   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r   r$  postr%  r6  r>  r  rE  r]  rd  r   rI   r<   <module>rr     s   & # " " " " "  				 2 2 2 2 2 2 2 2 2 2 ! ! ! ! ! ! ! ! : : : : : : : : : : : : 2 2 2 2 2 2 . . . . . .                                                 4 
,J<	@	@	@		8	$	$ \^^
 +/%)R R R R R R w v v v v v v v            ) ) ) )   B B B B"      8R R R R"   :   9 9 9 9   <       F0 0 0 0f. . . .^   "	Z 	Z 	Z 	Z4 4 4 469 9 9 96' ' ' 'T5 5 5 5( ';\-   x x x x& *0i/   L L L L^ +5b1   jx jx jx jxZ% % % % %N !%\(   no no no no` *-`0   M M M M` -1c3   Q Q Q Q Q QrI   