
    8_inK              	          S SK J r   S SKrSSKJrJrJr  S SKJrJrJ	r	J
r
Jr  S SKrS SKrS SKJr  S SKJr   " S S	5      rS"S
\\\
4   S\	\   S\4S jjrS\S\	\\\
4      4S jrS\S\	\\\
4      4S jrS\	\\\
4      4S jrS#S\S\S\\\
4   4S jjrS\S\4S jrS\S
\\\
4   S\4S jrS\S\\\\
4      4S jrS rS rS$S jr S$S jr!S r"S r#S"S jr$S%S  jr%S! r&g)&    datetimeN   )dbChallengeRecordUser)DictListOptionalAnyUnion)current_app)flag_modifiedc            
       @   \ rS rSrSr\SS\\\4   S\	\
   S\
4S jj5       r\S\
S\	\\\4      4S	 j5       r\S
\S\	\\\4      4S j5       r\S\	\\\4      4S j5       r\SS\
S\
S\\\4   4S jj5       r\S\
S\4S j5       r\S\
S\\\4   S\4S j5       rSrg)ChallengeManager   u;   
题目管理类：处理题目记录的增删改查操作
Ndatauser_idreturnc                 n   SU ;   a+  U S   R                  SS5      nU S   R                  SS5      nO$U R                  SS5      nU R                  SS5      n[        R                  R                  US9R	                  5       nU(       a	  UnX%l        O[        5       nX%l        X5l        U R                  S5      Ul        U R                  S5      Ul        U R                  S	S
5      Ul	        U R                  SS5      Ul
        U R                  S5      Ul        SU ;   a
  U S   Ul        U(       a  Xl         U(       d  [        R                  R!                  U5        [        R                  R#                  5         UR$                  $ ! [&         a%  n[        R                  R)                  5         UeSnAff = f)u   
保存题目生成记录到数据库

Args:
    data: 包含题目详细信息的字典
    user_id: 用户ID，如果提供则关联到此用户
    
Returns:
    int: 新创建或更新的记录ID
challenge_infonameu   未命名题目description r   
output_dirlog_fileestimated_timeu	   1-2小时generation_status	completedgeneration_warning
deployableN)getr   query	filter_byfirstr   r   r   r   r   r   r!   r"   r   r   sessionaddcommitid	Exceptionrollback)r   r   r   r   existing_challenge	challengees          =/Users/yu22x/Desktop/ge/ctf/app/models/database/operations.pysave_challenge_record&ChallengeManager.save_challenge_record   s|    t#()--f6GHD/044]BGK88F$56D((="5K -22<<$<GMMO*I!N ()I!N !,#xx5	!XXj1	#'88,<k#J	 &*hh/BK&P	#'+xx0D'E	$ 4#'#5I   '	%

y)JJ<< 	JJ!G	s   5AF 
F4 F//F4challenge_idc                 b    [         R                  R                  U 5      nU(       a  SSKnUR	                  [
        5      nUR                  SUR                   SUR                   35        UR                  SUR                   SUR                   35        UR                  5       nUR                  SUR                  5        35        UR                  SUR                  S	5       35        U$ g! [         a5  n[        S
[        U5       35        SSKnUR#                  5          SnAgSnAff = f)u   
根据ID获取题目记录

Args:
    challenge_id: 题目记录ID

Returns:
    Optional[Dict]: 题目详细信息字典，如果不存在则返回None
r   Nu   找到题目记录: id=z, name=zoutput_dir=z, log_file=u   to_dict() 返回的 keys: u   to_dict() 中的 output_dir: r   u   获取题目记录失败: )r   r$   r#   logging	getLogger__name__debugr*   r   r   r   to_dictkeysr+   printstr	traceback	print_exc)r3   r.   r5   loggerresultr/   r=   s          r0   get_challenge_record%ChallengeManager.get_challenge_recordJ   s   	'--11,?I **846y||nGINNK[\]{9+?+?*@IL^L^K_`a"**,9&++-IJ<VZZ=U<VWX 	.s1vh78!		s   C+C/ /
D.9+D))D.r   c                     [         R                  R                  U S9R                  5       nU(       d  gUR	                  5       $ )u   
根据名称获取题目记录

Args:
    name: 题目名称
    
Returns:
    Optional[Dict]: 题目详细信息字典，如果不存在则返回None
r   N)r   r$   r%   r&   r9   )r   r.   s     r0   get_challenge_by_name&ChallengeManager.get_challenge_by_nameg   s;     $))333>DDF	  ""    c                      [         R                  R                  [         R                  R	                  5       5      R                  5       n U (       d  gU R                  5       $ )u   
获取最新生成的题目记录

Returns:
    Optional[Dict]: 最新题目详细信息字典，如果不存在则返回None
N)r   r$   order_by
created_atdescr&   r9   )r.   s    r0   get_latest_challenge%ChallengeManager.get_latest_challengex   sG     $))22?3M3M3R3R3TU[[]	  ""rF   pageper_pagec           	      X   [         R                  R                  [         R                  R	                  5       5      R                  XSS9n/ nUR                   H  nUR                  UR                  UR                  UR                  UR                  (       a  UR                  R                  OSUR                  (       a  UR                  R                  5       OSS.5        M     UR                  UR                  UR                  UR                   UR"                  UR$                  US.$ )u   
获取题目列表（分页）

Args:
    page: 页码
    per_page: 每页记录数
    
Returns:
    Dict: 包含分页信息和题目列表的字典
F)rM   rN   	error_outN)r*   r   r   
difficultyrI   )totalpagescurrent_pagerN   has_nexthas_prev
challenges)r   r$   rH   rI   rJ   paginateitemsappendr*   r   r   difficulty_level	isoformatrR   rS   rM   rN   rU   rV   )rM   rN   
paginationrW   r.   s        r0   list_challenges ChallengeManager.list_challenges   s     %**33O4N4N4S4S4UV__E ` 

 
#))Ill!(44AJA[A[i88==aeBKBVBVi22<<>\`  *  %%%%&OO"++"++"++$
 	
rF   c                    [         R                  R                  U 5      nU(       d  g SSKnSSKJn  UR                  (       a  UR                  R                  UR                  5      (       aT  UR                  UR                  5      nU(       a  [        SUR                   35        O1[        SUR                   35        O[        SUR                   35        UR                  (       a_  UR                  R                  UR                  5      (       a5   UR                  " UR                  5        [        SUR                   35        [        R                   R#                  U5        [        R                   R%                  5         [        S
U  SUR&                   35        g! [         a!  n[        S	[        U5       35         SnANSnAff = f! [         a%  n[        R                   R)                  5         UeSnAff = f)u   
删除题目记录（同时删除相关文件）

Args:
    challenge_id: 题目记录ID

Returns:
    bool: 是否成功删除
Fr   N)challenge_file_manageru   ✅ 已删除输出目录: u!   ⚠️ 删除输出目录失败: u   ⚠️ 输出目录不存在: u   ✅ 已删除日志文件: u!   ⚠️ 删除日志文件失败: u   ✅ 已删除题目记录: ID=z, Name=T)r   r$   r#   osapp.services.storagera   r   pathexistsdelete_directoryr;   r   remover+   r<   r   r'   deleter)   r   r,   )r3   r.   rb   ra   successr/   s         r0   delete_challenge!ChallengeManager.delete_challenge   s    $))--l;		C ##77>>)"6"6774EEiFZFZ[G ;I<P<P;QRS A)BVBVAWXY:9;O;O:PQR !!bggnnY5G5G&H&HHIIi0017	8J8J7KLM
 JJi(JJ2<.	GWXY ! H=c!fXFGGH  	JJ!G	sC   C,G 4F# 
AG #
G-G	G 	GG 
H  G;;H c                    [         R                  R                  U 5      nU(       d  g UR                  5        H#  u  p4[	        X#5      (       d  M  [        X#U5        M%     S H  nXQ;   d  M
  [        X%5        M     [        R                  R                  5         g! [         a%  n[        R                  R                  5         UeSnAff = f)u   
更新题目记录

Args:
    challenge_id: 题目记录ID
    data: 更新的数据
    
Returns:
    bool: 是否成功更新
F)	
tech_stackcore_functionsauxiliary_functionsnon_vulnerable_functionsproject_structure
code_filesbinary_files	file_listevaluation_resultTN)r   r$   r#   rY   hasattrsetattrr   r   r'   r)   r+   r,   )r3   r   r.   keyvaluefieldr/   s          r0   update_challenge!ChallengeManager.update_challenge   s     $))--l;		"jjl
9**IE2 +
Y =!)3	Y JJ 	JJ!G	s#   #B B ,-B 
C	$ CC	 Nr   
   )r7   
__module____qualname____firstlineno____doc__staticmethodr	   r<   r   r   intr1   rA   rD   rK   r^   boolrj   r{   __static_attributes__r}   rF   r0   r   r      sJ    7DcN 7Xc] 7VY 7 7r 3 8DcN3K  8 #C #HT#s(^,D # #  #(4S>": # # !
c !
 !
d38n !
 !
F ,s ,t , ,\  s  $sCx.  T    rF   r   r   r   r   c                 ,    [         R                  X5      $ )u<   保存题目生成记录到数据库（向后兼容函数）)r   r1   )r   r   s     r0   r1   r1      s    11$@@rF   r3   c                 ,    [         R                  U 5      $ )u2   根据ID获取题目记录（向后兼容函数）)r   rA   r3   s    r0   rA   rA     s    00>>rF   r   c                 ,    [         R                  U 5      $ )u6   根据名称获取题目记录（向后兼容函数）)r   rD   r   s    r0   rD   rD     s    11$77rF   c                  *    [         R                  5       $ )u9   获取最新生成的题目记录（向后兼容函数）)r   rK   r}   rF   r0   rK   rK     s    0022rF   rM   rN   c                 ,    [         R                  X5      $ )u*   获取题目列表（向后兼容函数）)r   r^   )rM   rN   s     r0   r^   r^     s    ++D;;rF   c                 ,    [         R                  U 5      $ )u*   删除题目记录（向后兼容函数）)r   rj   r   s    r0   rj   rj     s    ,,\::rF   c                 ,    [         R                  X5      $ )u*   更新题目记录（向后兼容函数）)r   r{   )r3   r   s     r0   r{   r{     s    ,,\@@rF   c                 Z    [         R                  R                  U S9R                  [         R                  R                  5       5      R                  5       nU Vs/ s H  o"R                  5       PM     sn$ s  snf ! [         a#  n[        S[        U5       35        / s SnA$ SnAff = f)um   
获取指定用户的所有题目记录

Args:
    user_id: 用户ID

Returns:
    List[Dict]: 题目列表
r   u    获取用户题目列表失败: N)r   r$   r%   rH   rI   rJ   allr9   r+   r;   r<   )r   rW   r.   r/   s       r0   get_challenges_by_userr     s    $**44W4ENNOiOiOnOnOpquuw
5?@Z	!!#Z@@@ 0Q9:	s0   AA= A85A= 8A= =
B*B%B*%B*c                     SSK JnJn  SU ;  a  SU ;   a  U S   U S'   UR                  U 5      nUR                  R                  U5        UR                  R                  5         U$ ! [         aO  nWR                  R                  5         [        S[        U5       35        SSKnUR                  5          SnAgSnAff = f)u   创建部署记录

Args:
    deployment_data: 部署数据字典
    
Returns:
    DeploymentRecord: 创建的部署记录对象
r   DeploymentRecordr   deployment_uuidr*   u   创建部署记录失败: N)app.models.database.modelsr   r   	from_dictr'   r(   r)   r+   r,   r;   r<   r=   r>   )deployment_datar   r   recordr/   r=   s         r0   create_deployment_recordr   -  s    C O38O1@1FO-. "++O< 	

v


 


*3q6(34s   A#A& &
B?0AB::B?c                      SSK Jn  UR                  R                  U S9R	                  5       nU(       a  UR                  5       $ g! [         a!  n[        S[        U5       35         SnAgSnAff = f)uo   通过UUID获取部署记录

Args:
    deployment_uuid: 部署UUID
    
Returns:
    Dict: 部署记录字典
r   r   r   Nu   获取部署记录失败: )	r   r   r$   r%   r&   r9   r+   r;   r<   )r   r   r   r/   s       r0   get_deployment_by_uuidr   L  sf    	?!''11/1RXXZ>>## *3q6(34s   AA 
A2A--A2c                     SSK Jn  UR                  R                  U S9R	                  UR
                  R                  5       5      R                  U5      R                  U5      R                  5       nU Vs/ s H  oUR                  5       PM     sn$ s  snf ! [         a#  n[        S[        U5       35        / s SnA$ SnAff = f)u   获取用户的部署记录列表

Args:
    user_id: 用户ID
    limit: 返回结果数量限制
    offset: 结果偏移量
    
Returns:
    List[Dict]: 部署记录字典列表
r   r   r   u    获取用户部署记录失败: Nr   r   r$   r%   rH   rI   rJ   offsetlimitr   r9   r+   r;   r<   )r   r   r   r   recordsr   r/   s          r0   get_deployments_by_userr   `  s    
?"((2272CX&116689VF^EE%L 	 077wV w777 0Q9:	0   A6B 8BB B 
C#C;CCc                     SSK Jn  UR                  R                  U S9R	                  UR
                  R                  5       5      R                  U5      R                  U5      R                  5       nU Vs/ s H  oUR                  5       PM     sn$ s  snf ! [         a#  n[        S[        U5       35        / s SnA$ SnAff = f)u   获取题目的部署记录列表

Args:
    challenge_id: 题目ID
    limit: 返回结果数量限制
    offset: 结果偏移量
    
Returns:
    List[Dict]: 部署记录字典列表
r   r   r   u    获取题目部署记录失败: Nr   )r3   r   r   r   r   r   r/   s          r0   get_deployments_by_challenger   w  s    
?"((222MX&116689VF^EE%L 	 077wV w777 0Q9:	r   c                 8    SSK JnJn  UR                  R	                  U S9R                  5       nU(       d  gUR                  nXl        UR                  SS5      nUR                  5        H#  u  p[        XX5      (       d  M  [        XXU	5        M%     Xa:w  a   U(       d  SU SU 3nUR                  X5        UR                  R                  5         g	! [         a;  n
WR                  R                  5         [!        S
[#        U
5       35         Sn
A
gSn
A
ff = f)u   更新部署状态

Args:
    deployment_uuid: 部署UUID
    status: 新状态
    **kwargs: 其他要更新的字段（包括message用于日志）
    
Returns:
    bool: 更新是否成功
r   r   r   FmessageNu
   状态从 u    变更为 Tu   更新部署状态失败: )r   r   r   r$   r%   r&   statuspoprY   rv   rw   add_status_logr'   r)   r+   r,   r;   r<   )r   r   kwargsr   r   r   
old_statuslog_messagerx   ry   r/   s              r0   update_deployment_statusr     s    "C "''11/1RXXZ ]]
 jjD1 !,,.JCv##U+ )
  *:,k&J!!&6 	

 


*3q6(34s$   6C AC AC 
D1DDc                 n    SSK JnJn  UR                  R	                  U S9R                  5       nU(       d  gUR                  R                  U5        UR                  R                  5         g! [         a;  nWR                  R                  5         [        S[        U5       35         SnAgSnAff = f)ue   删除部署记录

Args:
    deployment_uuid: 部署UUID
    
Returns:
    bool: 删除是否成功
r   r   r   FTu   删除部署记录失败: N)r   r   r   r$   r%   r&   r'   rh   r)   r+   r,   r;   r<   )r   r   r   r   r/   s        r0   delete_deployment_recordr     s    C "''11/1RXXZ 	

&!


 


*3q6(34s   6A/ 5A/ /
B491B//B4c                     SSK JnJn  UR                  R	                  U S9R                  5       nU(       d  gUR                  X5        UR                  R                  5         UR                  5       nU(       a  US   $ S$ ! [         a;  nWR                  R                  5         [        S[        U5       35         SnAgSnAff = f)u   添加部署状态日志

Args:
    deployment_uuid: 部署UUID
    status: 状态
    message: 消息
    
Returns:
    DeploymentStatusLog: 创建的日志对象，如果失败则返回None
r   r   r   Nu   添加部署日志失败: )r   r   r   r$   r%   r&   r   r'   r)   get_status_historyr+   r,   r;   r<   )r   r   r   r   r   r   historyr/   s           r0   add_deployment_logr     s    C "''11/1RXXZ 	f.


 ++-%wr{/4/ 


*3q6(34s#   6B AB  B 
C1CCc           
      
    SSK Jn  SSKJn  UR                  R	                  U S9R                  5       nU(       d  / $ UR                  5       n/ n[        U5       H  u  pxUR                  S5      n	[        U	[        5      (       a$   UR                  " U	R                  SS5      5      n	O![        X5      (       d  UR                  " 5       n	UR                  US-   UR                  UR                  S	S
5      UR                  SS
5      U	S.5        M     UR!                  S SS9  USU $ !   UR                  " 5       n	 Ns= f! ["         a7  n
[%        S[        U
5       35        SSKnUR)                  5         / s Sn
A
$ Sn
A
ff = f)u   获取部署日志

Args:
    deployment_uuid: 部署UUID
    limit: 返回结果数量限制
    
Returns:
    List[Dict]: 日志字典列表
r   r   r   r   	timestampZz+00:00r   r   r   r   )r*   deployment_idr   r   r   c                     U S   $ )Nr   r}   )xs    r0   <lambda>%get_deployment_logs.<locals>.<lambda>"  s    +rF   T)rx   reverseNu   获取部署日志失败: )r   r   r   r$   r%   r&   r   	enumerater#   
isinstancer<   fromisoformatreplacenowrZ   r*   sortr+   r;   r=   r>   )r   r   r   r   r   r   logsi	log_entryr   r/   r=   s               r0   get_deployment_logsr     s^   (?% "''11/1RXXZI ++- %g.LA!k2I)S))/ ( 6 6y7H7Hh7W XI  	44$LLN	KK!e!'#--"5$==B7&  /( 			.	=FU|/ (I  *3q6(34		s<   ;E AE "D))A?E )D><E 
F,E=7F=Fc                      SSK Jn Jn  SSKJnJn  UR
                  " UR                  5      nU R                  R                  U R                  U:  U R                  S:g  5      R                  5       nSnU H  nSUl
        US-  nM     UR                  R                  5         U$ ! [         a;  nWR                  R                  5         [!        S[#        U5       35         SnAgSnAff = f)uE   清理过期的部署记录

Returns:
    int: 清理的记录数量
r   r   )r   timezonedeletedr   u    清理过期部署记录失败: N)r   r   r   r   r   r   utcr$   filter
expires_atr   r   r'   r)   r+   r,   r;   r<   )	r   r   r   r   r   expiredcountr   r/   s	            r0   cleanup_expired_deploymentsr   *  s    C/ ll8<<("((//''#-##y0
 #% 	 F%FMQJE  	

 


0Q9:s   B"B% %
C*/1C%%C*r~   r   )r   r   )   )'r   jsonmodelsr   r   r   typingr	   r
   r   r   r   rb   globflaskr   sqlalchemy.orm.attributesr   r   r<   r   r1   rA   rD   rK   r^   r   rj   r{   r   r   r   r   r   r   r   r   r   r   r}   rF   r0   <module>r      s^     - - 3 3 	   3o ohAS#X A# ARU A?s ?xS#X/G ?8 8c3h(@ 83htCH~6 3<# <S <$sCx. <;3 ;4 ;A3 Ad38n A AC Dc3h,@ $>(..-^4>2hrF   