
    	]jl                     \   d Z ddlZddlZddlZddlZddlmZmZ ddlm	Z	 ddl
mZ ddlmZmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ ddlmZ ddlm Z  ddl!m"Z" ddl#m$Z$ ddl%m&Z& ddl'm(Z(m)Z)m*Z* ddl+m,Z, ddl-m.Z.m/Z/m0Z0 ddl1m2Z2 ddl3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z:m;Z; ddl<m=Z= ddl>m?Z? ddl@mAZA ddlBmCZC ddlDmEZE ddlFmGZGmHZH ddlImJZJ dd lKmLZL dd!lMmNZN dd"lOmPZP dd#lQmRZR d$d%lSmTZTmUZUmVZVmWZWmXZX d$d&lYmZZZ d$d'l[m\Z\m]Z]m^Z^ d$d(l_m`Z`maZa  ej                  ec      Zd eRej                        Zf e)d)d*d+d,d-d.d/d0d1d2d/d0d3d4d/d0d5d6d/d0d7d8d9d0d:d;d<d=d/d>d?d@dAdBd0dCdDd<dEdFd>d?dGdHd<dIdFd>d?dJ	dKL       e)dMdNdOdFd0L      dPZg e$dQ e*dRgeg e(dSe&j                  dTdUV       e(dWe&j                  dXdYdZd[\       e(d]e&j                  dXd^d[d[\       e(d_dZdXd`dd[a      gdbdcj                  ej                  xs dde       e]dZf      dgdhdigdjk      l       G dm dne4j                               Zm e$dQ e*dRgdodp e(dSe&j                  dTdUV      g e^dZf       e)dqdrdsd,dtdtdud/d0idKL       e)dMv      dPdgdwdigdjx      l       G dy dze4j                               Zn e*dZ{       G d| d}em             Zo G d~ dem      Zp e$d e*dRgd e(de&j                  dXdV       e(ddZdXd      gddgddigdj      l       e$d e*dRgdddgddigdj      l       G d de4j                  j                  e4j                  j                  e4j                                      Zu e$d e*dRgdddgddigdj      l       e$d e*dRgdde\dgddigdj      l       e$d e*dRgdddgddigdj      l       G d de4j                                             Zw e$d e*dRgdddgddigdjd e)dv      i      l       G d de4j                               Zy e*dZ{       G d deC             Zzy)zThis file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
    N)unquoteurlparse)override_report_only_csp)flag_set)ViewClassPermissionall_permissions)start_job_async_or_sync)retry_database_lockedtimeit)extract_message)bool_from_requestlist_of_strings_from_request)csp)settings)FileSystemStorage)transaction)HttpResponse)method_decorator)OpenApiTypes)OpenApiParameterOpenApiResponseextend_schema)LabelInterface)ProjectProjectImportProjectReimport)RangedFileResponse)genericsstatus)ValidationError)
FormParser
JSONParserMultiPartParser)IsAuthenticated)Response)api_settings)APIView)update_tasks_counters)
PredictionTask)"sanitize_prediction_import_payload)User)WebhookAction)emit_webhooks_for_instance)	load_func   )async_import_backgroundasync_reimport_backgroundreformat_predictionsset_import_background_failureset_reimport_background_failure)
FileUpload)FileUploadSerializerImportApiSerializerPredictionSerializer)create_file_uploads
load_tasksa  Tasks successfully imported or import queued. **For non-Community editions**, the response will be `{"import": <import_id>}` which you can use to poll the import status. **For Community edition**, the response contains task counts and is processed synchronously.zTask creation responsezResponse format varies by edition. Non-Community editions return `{"import": <import_id>}` for async processing. Community edition returns the detailed response below with task counts.objectimportzImport ID for async operations (non-Community editions only). Use this ID to poll `/api/projects/{project_id}/imports/{import_id}` for status.integer)titledescriptiontype
task_countz:Number of tasks added (Community edition sync import only)annotation_countz@Number of annotations added (Community edition sync import only)predictions_countz@Number of predictions added (Community edition sync import only)durationz>Time in seconds to create (Community edition sync import only)numberfile_upload_idszCDatabase IDs of uploaded files (Community edition sync import only)arrayzFile Upload IDs)r?   rA   )r?   r@   rA   itemscould_be_tasks_listzjWhether uploaded files can contain lists of tasks, like CSV/TSV files (Community edition sync import only)booleanfound_formatszCThe list of found file formats (Community edition sync import only)zFile formatstringdata_columnszCThe list of found data columns (Community edition sync import only)zData column name)	r=   rB   rC   rD   rE   rG   rJ   rL   rN   )r?   r@   rA   
properties)r@   responsezBad RequestzIncorrect task datazString with error description)   i  postImportidpathz0A unique integer value identifying this project.)namerA   locationr@   commit_to_projectqueryz9Set to "true" to immediately commit tasks to the project.TF)rV   rA   rW   r@   defaultrequiredreturn_task_idsz1Set to "true" to return task IDs in the response.preannotated_from_fieldsa!  List of fields to preannotate from the task data. For example, if you provide a list of `{"text": "text", "prediction": "label"}` items in the request, the system will create a task with the `text` field and a prediction with the `label` field when `preannoted_from_fields=["prediction"]`.)rV   manyrW   r@   rZ   r[   zImport tasksa  
            Import data as labeling tasks in bulk using this API endpoint. You can use this API endpoint to import multiple tasks.
            One POST request is limited at 250K tasks and 200 MB.

            **Note:** Imported data is verified against a project *label_config* and must
            include all variables that were used in the *label_config*. For example,
            if the label configuration has a *$text* variable, then each item in a data object
            must include a "text" field.
            <br>

            ## Async Import Behavior
            <hr style="opacity:0.3">

            **For non-Community editions, this endpoint processes imports asynchronously.**
            
            - The POST request **can fail** for invalid parameters, malformed request body, or other request-level validation errors.
            - However, **data validation errors** that occur during import processing are handled asynchronously and will not cause the POST request to fail.
            - Upon successful request validation, a response is returned: `{{"import": <import_id>}}`
            - Use the returned `import_id` to poll the GET `/api/projects/{{project_id}}/imports/{{import_id}}` endpoint to check the import status and see any data validation errors.
            - Data-level errors and import failures will only be visible in the GET request response.

            For Community edition, imports are processed synchronously and return task counts immediately.
            <br>

            ## POST requests
            <hr style="opacity:0.3">

            There are three possible ways to import tasks with this endpoint:

            ### 1. **POST with data**
            Send JSON tasks as POST data. Only JSON is supported for POSTing files directly.
            Update this example to specify your authorization token and Label Studio instance host, then run the following from
            the command line.

            ```bash
            curl -H 'Content-Type: application/json' -H 'Authorization: Token abc123' \
            -X POST '{host}/api/projects/1/import' --data '[{{"text": "Some text 1"}}, {{"text": "Some text 2"}}]'
            ```

            ### 2. **POST with files**
            Send tasks as files. You can attach multiple files with different names.

            - **JSON**: text files in JavaScript object notation format
            - **CSV**: text files with tables in Comma Separated Values format
            - **TSV**: text files with tables in Tab Separated Value format
            - **TXT**: simple text files are similar to CSV with one column and no header, supported for projects with one source only

            Update this example to specify your authorization token, Label Studio instance host, and file name and path,
            then run the following from the command line:

            ```bash
            curl -H 'Authorization: Token abc123' \
            -X POST '{host}/api/projects/1/import' -F 'file=@path/to/my_file.csv'
            ```

            ### 3. **POST with URL**
            You can also provide a URL to a file with labeling tasks. Supported file formats are the same as in option 2.

            ```bash
            curl -H 'Content-Type: application/json' -H 'Authorization: Token abc123' \
            -X POST '{host}/api/projects/1/import' \
            --data '[{{"url": "http://example.com/test1.csv"}}, {{"url": "http://example.com/test2.csv"}}]'
            ```

            <br>
        zhttps://localhost:8080)host)r^   projectsimport_taskspublic)zx-fern-sdk-group-namezx-fern-sdk-method-namezx-fern-audiences)tags	responses
parameterssummaryr@   request
extensions)rV   	decoratorc                        e Zd Zej                  Zej                  egz   Z	e
eefZeZej"                  j%                         Zd Z fdZd Zd Zed        Zd Z xZS )	ImportAPIc                    | j                   j                  d      }|rIt        j                  t        j
                  j                  | j                  j                        |      }nd }|| j                  j                  dS )Npkrm   )projectuser)	kwargsgetr   get_object_or_404r   objectsfor_userrg   rp   )self
project_idro   s      F/root/env/lib/python3.12/site-packages/label_studio/data_import/api.pyget_serializer_contextz ImportAPI.get_serializer_context  s]    [[__T*
001I1I$,,J[J[1\aklGG"DLL,=,=>>    c                 *    t        t        | 
  |i |S N)superrk   rR   rv   argsrq   	__class__s      rx   rR   zImportAPI.post  s    Y*D;F;;rz   c                    | j                  |d      }|j                  d       |j                  | j                  d         }t	        j
                  t        j                  j                  | j                  j                        | j                  d         }t        | j                  j                  j                  |t        j                  |       ||fS )NT)datar^   )raise_exceptionrm   )rw   rn   )get_serializeris_validsaverq   r   rs   r   rt   ru   rg   rp   r.   active_organizationr-   TASKS_CREATED)rv   tasks
serializertask_instancesro   s        rx   _savezImportAPI._save  s    ((e$(?
D1#DKK4EF,,W__-E-EdllFWFW-X]a]h]him]no"LL117M<W<WYg	
 z))rz   c                    t        j                          }d }t        ||      \  }}	}
}}|r3t        dd      }t        j	                  d|        t        ||||      }|j                  rg }t        |j                        }t        |      D ]W  \  }}d|v st        |d         D ]<  \  }}	 |j                  |d      }|r!|D ]  }|j                  d| d	| d
|         > Y |r^dt        |       d}|D ]  }|d| dz  } t        dd      rt        d|gi      t        j!                  dt        |       d|        |r| j#                  |      \  }}t        |      }t        |j$                        }t        |j&                        }|||d}|j)                  |ddd|       t        j	                  d       |j*                  j-                  |       nt        |      }d }d }t        j                          |z
  }|||||	|
||d}|r|r|D cg c]  }|j.                   c}|d<   t1        |t2        j4                        S # t        $ r0}d| d	| dt        |       }|j                  |       Y d }~d }~ww xY wc c}w )N1fflag_feat_utc_210_prediction_validation_15082025autorp   z,Reformatting predictions with raise_errors: predictionsTreturn_errorszTask z, prediction :  : Error validating prediction - Prediction validation failed (
 errors):
z- 
z3Prediction validation failed, not raising error - (rB   rC   prediction_countFtasks_querysetmaximum_annotations_changed!overlap_cohort_percentage_changedtasks_number_changedrecalculate_stats_countsz(Tasks bulk_update finished (sync import))rB   rC   r   rE   rG   rJ   rL   rN   task_idsr   )timer;   r   loggerinfor3   label_config_is_not_defaultr   label_config	enumeratevalidate_predictionappend	Exceptionr   lenr    errorr   db_annotationsdb_predictions%update_tasks_counters_and_task_statesrf   update_data_columnsrT   r%   r   HTTP_201_CREATED) rv   rg   ro   r]   rX   r\   startr   parsed_datarG   rJ   rL   rN   raise_errorsvalidation_errorsliitaskj
predictionvalidation_errors_listr   e	error_msgerror_messager   rB   rC   r   r   rE   rP   s                                    rx   sync_importzImportAPI.sync_import  s
   		 ZddkmtYuV_&9=,##$W^deLKKF|nUV.{<TV]_klK .. " 4 45B$[1 
@4 D()243F)G @:@575K5KJfj5K5k25-C !cE$5$<$<uQC}UVTWWYZ_Y`=a$b!c	@
@ !"@EVAW@XXc d. 4E!r%^3M4 OV\])==/*JKKLLMcRcNdMeepq~p  A  $

; 7E:UJ":#<#<=":#<#<= )$4$4($ 99$,127%))A :  KKBCOO//< [)J##99;& % 0 0 .#6*(	
 _8=#>DGG#>HZ )@)@AA  ) @*/s-sBbcrstcubv(wI-44Y??@z $?s   ,6IJ	J%I??Jc           	         t         j                  j                  ||||      }t        |j                        rjt
        j                  d|j                          t        |j                  ||j                        \  }}||_	        ||_
        |j                  ddg       n(d|j                  v rtt
        j                  d|j                  j                  d              |j                  j                  d      }	|	st        d	      |	|_        |j                  dg       nd
|j                  v r@t#        |j                  t$              r&|j                  g|_        |j                  dg       nXd
|j                  v r?t#        |j                  t(              r%|j                  |_        |j                  dg       nt        d      t+        t,        |j.                  |j                  j.                  dt0        |j.                  |j                  j2                  j.                         d|j.                  i}
t5        |
t6        j8                        S )N)ro   r]   rX   r\   zImport from files: rG   rJ   )update_fieldsz!application/x-www-form-urlencodedzImport from url: urlz""url" is not found in request datazapplication/jsonr   z-load_tasks: No data found in DATA or in FILEShigh)
queue_name
on_failurerw   organization_idr=   r   )r   rt   creater   FILESr   debugr:   rp   rG   rJ   r   content_typer   rr   r    r   
isinstancedictr   listr	   r1   rT   r4   r   r%   r   r   )rv   rg   ro   r]   rX   r\   project_importrG   rJ   r   rP   s              rx   async_importzImportAPI.async_importv  s    '..55%=/+	 6 
 w}}LL.w}}o>?3Fw||U\^e^k^k3l0O0-<N*1DN./@BW.XY0G4H4HHLL,W\\-=-=e-D,EFG,,""5)C%&JKK!$Nug67#7#77Jw||UY<Z$+LL>N wi8  7#7#77Jw||UY<Z#*<<N wi8 ""QRR#LLOO4zz#LL<<??	
 n//0)@)@AArz   c                    t        |j                  dd      }t        |j                  dd      }t        |j                  dd       }t        j                  t
        j                  j                  | j                  j                        | j                  d         }t        j                  dk7  r| j                  |||||      S | j                  |||||      S )	NrX   Tr\   Fr]   rm   rn   	Community)r   query_paramsr   r   rs   r   rt   ru   rg   rp   rq   r   VERSION_EDITIONr   r   )rv   rg   r   rq   rX   r\   r]   ro   s           rx   r   zImportAPI.create  s    -g.B.BDWY]^+G,@,@BSUZ[#?@T@TVprv#w  ,,W__-E-EdllFWFW-X]a]h]him]no##{2$$Wg7OQbdstt##GW6NPacrssrz   )__name__
__module____qualname__r   projects_changepermission_requiredr&   DEFAULT_PERMISSION_CLASSESProjectImportPermissionpermission_classesr"   r#   r!   parser_classesr8   serializer_classr*   rt   allquerysetry   rR   r   r   r   r   r   __classcell__r   s   @rx   rk   rk      s    n *99%@@D[C\\ /:>N*||!H?<*YBv 0B 0Bdtrz   rk   zImport predictionsz<Import model predictions for tasks in the specified project.z!Predictions successfully importedzPredictions import responsezImport resultcreatedzNumber of predictions created)r@   import_predictions)rc   rf   r@   re   rg   rd   rh   c                   |    e Zd ZdZej
                  Zeee	fZ
eZej                  j                         Zd Zd Zd Zy)ImportPredictionsAPIab  
    API for importing predictions to a project.

    Memory optimization controlled by feature flag:
    'fflag_fix_back_4620_memory_efficient_predictions_import_08012025_short'

    When flag is enabled: Uses memory-efficient batch processing (reduces memory usage by 90-99%)
    When flag is disabled: Uses legacy implementation for safe fallback
    c                     | j                         }t        d| j                  j                        r| j	                  |      S | j                  |      S )NFfflag_fix_back_4620_memory_efficient_predictions_import_08012025_shortr   )
get_objectr   rg   rp   _create_memory_efficient_create_legacy)rv   rg   r   rq   ro   s        rx   r   zImportPredictionsAPI.create  sJ    //# \cgcococtctu0099&&w//rz   c                    t        t        dd      }| j                  j                  }t	        |      }t
        j                  d| d| d| d       d}t               }t        d||      D ]  }t        ||z   |      }||| }	|	D 
cg c]  }
|
j                  d       }}
t        t        j                  j                  ||	      j                  d
d            }g }|	D ]  }
t        |
      }
|
j                  d      }||vrt!        |
 d| d|       |j#                  t%        ||j&                  t%        j(                  |
j                  d      |      |
j                  d      |
j                  dd                   |j+                  |        t$        j                  j-                  |t        j.                        }|t	        |      z  }t
        j                  d| d|dz
   dt	        |       d| d	        |r.t1        t2        t        j                  j                  |             t5        d|it6        j8                        S c c}
w )z0Memory-efficient batch processing implementationPREDICTION_IMPORT_BATCH_SIZEi  
Importing  predictions to project z6 using memory-efficient batch processing (batch size: )r   r   ro   id__inrT   Tflatz( contains invalid "task" field: task ID z not found in project resultscoremodel_version	undefinedtask_idrw   r   r   r   
batch_sizezProcessed batch -r0   z
: created z predictions (total so far: r   r   r   )getattrr   rg   r   r   r   r   setrangeminrr   r*   rt   filtervalues_listr+   r    r   r)   rT   prepare_prediction_resultaddbulk_create
BATCH_SIZEr	   r(   r%   r   r   )rv   ro   PROCESSING_BATCH_SIZErequest_datatotal_predictionstotal_createdall_task_idsbatch_start	batch_endbatch_itemsitembatch_task_idsexisting_task_idsbatch_predictionsr   batch_createds                   rx   r   z-ImportPredictionsAPI._create_memory_efficient  s    !(2PRU V||((-*++CG9  MC  DY  CZ  Z[  \	
 u !$57LM *	KK*??ARSI&{9=K <GG4dhhv.GNG !$##GN#KWWX\cgWh!
 !## *9$?((6*"33)& H	Qklsktu  "(( '#*::)CCDHHXDVX_`"hhw/&*hh&L   )%** '..::;LYaYlYl:mMS//MLL";-q1ZMHZG[ \""/3O*	\ #$94<<;N;NVb;N;cdM26;R;RSSY Hs   Ic                    t        t        j                  j                  |      j	                  dd            }t
        j                  dt        | j                  j                         d| dt        |       d       t        |j                        }g }g }t        | j                  j                        D ]  \  }}t        |      }|j                  d	      |vrFt        d
d      r(|j!                  d| d|j                  d	       d       Zt#        | d| d      	 |j%                  |d      }|r|D ]  }	|j!                  d| d|	         	 	 |j!                  t+        |d	   |j,                  t+        j.                  |j                  d      |      |j                  d      |j                  dd                    |r<t        d
d      rt#        |      t
        j1                  dt        |       d|        t*        j                  j3                  |t4        j6                        }t9        t:        t        j                  j                  |             t=        d t        |      it>        j@                  !      S # t&        $ r+}
|j!                  d| dt)        |
              Y d}
~
d}
~
ww xY w# t&        $ r+}
|j!                  d| dt)        |
              Y d}
~
:d}
~
ww xY w)"z.Legacy implementation - kept for safe rollbackro   rT   Tr   r   r   z with z tasks (legacy mode)r   r   r   r   zPrediction z: Invalid task ID z - task not found in projectzY contains invalid "task" field: corresponding task ID couldn't be retrieved from project z tasksr   r   r   Nr   r   r   r   r   z : Failed to create prediction - r   r   r   r   r   r   )!r   r*   rt   r  r  r   r   r   rg   r   r   r   r   r+   rr   r   r   r    r   r   r   r)   rT   r  r   r  r   r  r	   r(   r%   r   r   )rv   ro   	tasks_idsr   r   r   r   r  r   r   r   predictions_objs               rx   r   z#ImportPredictionsAPI._create_legacy@  s   ++G+<HHTXHYZ	T\\../00H	QWX[\eXfWgg{|	
 G001  !2!23 ,	GAt5d;Dxxy0OV\]%,,%aS(:488F;K:LLhi  *& !((/y8 )+)?)?TX)?)Y& *!7 M)00;qcE71KLM	 *"" $V#*::)CCDHHXDVX_`"hhw/&*hh&LC,	^ KRXY%&788=cBS>T=UU`ar`stu$,,88QYQdQd8e 5t||7J7JR[7J7\]C$89&BYBYZZ9  !((;qc9YZijkZlYm)no  !((;qc9YZijkZlYm)nos1   $3JA.K	K  J;;K 	K7 K22K7N)r   r   r   __doc__r   r   r   r"   r#   r!   r   r9   r   r   rt   r   r   r   r   r    rz   rx   r   r     sN    V *99 /:>N+""$H0BTHE[rz   r   excludec                       e Zd Zy)TasksBulkCreateAPIN)r   r   r   r  rz   rx   r  r    s     	rz   r  c                   x     e Zd Zej                  Zd Zd Z e       d        Z	 e
ddd       fd       Z xZS )	ReImportAPIc           
      p   t        j                          }t        j                  |||      \  }}}t        j                         5  |j                  |       | j                  |      \  }}d d d        t        j                          |z
  }	t        |      }
t        j                        }t        |j                        }|j                  |ddd|
||d       t        j                  d       |j                  j                  |       t        |
|||	|||dt         j"                        S # 1 sw Y   xY w)	N)files_as_tasks_listFTr   r   z*Tasks bulk_update finished (sync reimport)rB   rC   r   rE   rG   rL   rN   r   )r   r6   load_tasks_from_uploaded_filesr   atomicremove_tasks_by_file_uploadsr   r   r   r   r   r   r   rf   r   r%   r   r   )rv   ro   rG   r#  r   r   rL   rN   r   rE   rB   rC   r   s                rx   sync_reimportzReImportAPI.sync_reimport  s1   		-7-V-V_:M.
*}l ! 	200A $

5 1E:	2 99;&Z
z889z889 	55 (-.3!%($4$4& 	6 
	
 	@A++E2 ($4$4$#2!. , **
 	
7	2 	2s   &D,,D5c           	         t         j                  j                  |||      }t        t        |j
                  || j                  j                  dt        |j
                         d|j
                  i}t        |t        j                        S )N)ro   rG   r#  r   )r   r   rw   reimportr   )r   rt   r   r	   r2   rT   rg   rp   r5   r%   r   r   )rv   ro   rG   r#  r   project_reimportrP   s          rx   async_reimportzReImportAPI.async_reimport  s    *2299_Re : 
 	 %LL6zz	
  0 3 34)@)@AArz   c           
      
   t        |j                  dd      }| j                  j                  j                  d      }t	        j
                  t        j                  j                  | j                  j                        | j                  d         }|s#t        ddddg i g dt        j                        S t        j                  d	k7  r(| j!                  ||||j                  j"                        S | j%                  |||      S )
Nr#  TrG   rm   rn   r   r$  r   r   )r   r   rg   rr   r   rs   r   rt   ru   rp   rq   r%   r   HTTP_200_OKr   r   r,  active_organization_idr(  )rv   rg   r   rq   r#  rG   ro   s          rx   r   zReImportAPI.create  s    />SUYZ,,++//0AB ,,W__-E-EdllFWFW-X]a]h]him]no"#()() !')%'$& ))  ##{2&&*=w||?b?b  %%g@STTrz   TzRe-import tasksz]
        Re-import tasks using the specified file upload IDs for a specific project.
        )r  rf   r@   c                 *    t        t        | 
  |i |S r|   )r}   r!  rR   r~   s      rx   rR   zReImportAPI.post  s     [$,d=f==rz   )r   r   r   r   r   r   r(  r,  r
   r   r   rR   r   r   s   @rx   r!  r!    sX    )99,
\B& U U8 !>>rz   r!  rr   zGet files listr   z6Set to "true" if you want to retrieve all file uploadsidszASpecify the list of file upload IDs to retrieve, e.g. ids=[1,2,3])rV   r^   rW   r@   zk
        Retrieve the list of uploaded files used to create labeling tasks for a specific project.
        filesr   )rc   rf   re   r@   rh   deletezDelete filesz?
        Delete uploaded files for a specific project.
        delete_many)rc   rf   r@   rh   c                       e Zd ZeeefZeZ e	e
j                  e
j                        Zej                  j!                         Zd Zd Zd Zy)FileUploadListAPI)GETDELETEc                    t        j                  t        j                  j	                  | j
                  j                        | j                  j                  dd            }|j                  s!t        | j
                  j                  dd      rWt        j                  d|        t        j                  j                  |j                   | j
                  j                        S t#        j$                  | j
                  j                  j                  dd	            }t        j                  d
|        t        j                  j                  |j                   || j
                  j                        S )Nrm   r   rn   r   Fz,Return all uploaded files for draft project )rw   rp   r1  z[]zFile Upload IDs found: )rw   r   rp   )r   rs   r   rt   ru   rg   rp   rq   rr   is_draftr   r   r   r   r6   r  rT   jsonloads)rv   ro   r1  s      rx   get_querysetzFileUploadListAPI.get_queryset/  s   ,,W__-E-EdllFWFW-X]a]h]h]l]lmqst]uv01J1JESXYLLGyQR%%,,

IZIZ,[[ jj2266udCD.se45!!((GJJsQUQ]Q]QbQb(ccrz   c                 .     | j                   |g|i |S r|   )r   )rv   rg   r   rq   s       rx   rr   zFileUploadListAPI.get;  s    tyy242622rz   c                 4   t        j                  t        j                  j	                  | j
                  j                        | j                  d         }| j
                  j                  j                  d      }|2t        j                  j                  |      j                         \  }}nNt        |t              r3t        j                  j                  ||      j                         \  }}nt        d      t!        d|it"        j$                        S )	Nrm   rn   rG   r  r   z6"file_upload_ids" parameter must be a list of integersdeletedr   )r   rs   r   rt   ru   rg   rp   rq   r   rr   r6   r  r3  r   r   
ValueErrorr%   r   r.  )rv   rg   r   rq   ro   r1  r@  _s           rx   r3  zFileUploadListAPI.delete>  s    ,,W__-E-EdllFWFW-X]a]h]him]noll##$56;#++2272CJJLJGQT"#++22732OVVXJGQUVVG,V5G5GHHrz   N)r   r   r   r"   r#   r!   r   r7   r   r   r   projects_viewr   r   r6   rt   r   r   r=  rr   r3  r  rz   rx   r6  r6    s[    Z !/:>N+-)).. !!%%'H
d3	Irz   r6  zGet file uploadz0Retrieve details about a specific uploaded file.patchzUpdate file uploadz Update a specific uploaded file.update)rc   rf   r@   rg   rh   zDelete file uploadz Delete a specific uploaded file.c                        e Zd ZeeefZefZe	Z
ej                  j                         Z fdZ fdZ fdZ ed       fd       Z xZS )FileUploadAPIc                 *    t        t        | 
  |i |S r|   )r}   rG  rr   r~   s      rx   rr   zFileUploadAPI.getx  s    ]D-t>v>>rz   c                 *    t        t        | 
  |i |S r|   )r}   rG  rD  r~   s      rx   rD  zFileUploadAPI.patch{  s    ]D/@@@rz   c                 *    t        t        | 
  |i |S r|   )r}   rG  r3  r~   s      rx   r3  zFileUploadAPI.delete~  s    ]D0$A&AArz   Tr  c                 *    t        t        | 
  |i |S r|   )r}   rG  putr~   s      rx   rL  zFileUploadAPI.put  s    ]D-t>v>>rz   )r   r   r   r"   r#   r!   r   r$   r   r7   r   r6   rt   r   r   rr   rD  r3  r   rL  r   r   s   @rx   rG  rG  J  s_    R !/:>N)++!!%%'H?AB 4 ? !?rz   rG  zDownload filez"Download a specific uploaded file.download   zFile downloaded successfully)rc   rf   r@   rh   rd   c                   >    e Zd ZdZefZe eg       d               Zy)UploadedFileResponsez%Serve uploaded files from local drive)SANDBOXc                    | j                   }|d   }t        j                  t        j                  j                  d      sdndz   |z   }t        j                  d|j                   d|        t        j                  j                  |      j                         }|j                  |j                        st        t        j                        S |j                  }|j                   j#                  |j$                        rOt'        j(                  t+        |j$                              \  }}|xs d}t-        ||j/                  d	
      |      S t        t        j0                        S )Nfilename/ Fetch uploaded file by user  => filer   application/octet-streamrbmoder   )rg   r   
UPLOAD_DIRendswithr   r   rp   r6   rt   r  lasthas_permissionr%   r   HTTP_403_FORBIDDENrY  storageexistsrV   	mimetypes
guess_typestrr   openHTTP_404_NOT_FOUND)	rv   r   rq   rg   rS  rY  file_uploadr   encodings	            rx   rr   zUploadedFileResponse.get  s    ,,*%""1D1D1M1Mc1RcXZ[^ff3GLL>dVLM ((//T/:??A))',,76#<#<==<<tyy)%.%9%9#dii.%I"L('E+EL%gtyydy/CR^__v8899rz   N)	r   r   r   r  r$   r   r   r   rr   r  rz   rx   rP  rP    s.    " 0)+_:  :rz   rP  c                   "    e Zd ZdZdgZefZd Zy)DownloadStorageDataa5  
    Secure file download API for persistent storage (S3, GCS, Azure, etc.)

    This view provides authenticated access to uploaded files and user avatars stored in
    cloud storage or local filesystems. It supports two operational modes for optimal
    performance and flexibility (simplicity).

    ## Operation Modes:

    ### 1. NGINX Mode (Default - USE_NGINX_FOR_UPLOADS=True)
    - **High Performance**: Uses X-Accel-Redirect headers for efficient file serving
    - **How it works**:
      1. Validates user permissions and file access
      2. Returns HttpResponse with X-Accel-Redirect header pointing to storage URL
      3. NGINX intercepts and serves the file directly from storage
    - **Benefits**: Reduces Django server load, better performance for large files

    ### 2. Direct Mode (USE_NGINX_FOR_UPLOADS=False)
    - **Direct Serving**: Django serves files using RangedFileResponse
    - **How it works**:
      1. Validates user permissions and file access
      2. Opens file from storage and streams it with range request support
      3. Supports partial content requests (HTTP 206)
    - **Benefits**: Works without NGINX, supports range requests for media files

    ## Content-Disposition Logic:
    - **Inline**: PDFs, audio, video files - because media files are directly displayed in the browser
    rr   c                 L   |j                   j                  d      }|t        t        j                        S t        |j                   d         }d}|j                  t        j                        r}t        j                  d|j                   d|        t        j                  j                  |      j                         }||j!                  |j                        r|j"                  }n|j                  t        j$                        rat&        j                  j                  |      j)                         }|1|j                  j*                  j-                  |      r|j.                  }|t        t        j0                        S t        j2                  rt5        |j6                  t8              r2t        j;                  d       t        d	d
it        j<                        S |j6                  j?                  |j@                  d      }tC        |      jD                  }	tG               }
d|	z   dz   |jI                  |	dz   d      z   }||
d<   d| d|
d<   |
S tK        jL                  |      \  }}|xs d}tO        ||jQ                  d      |      }
d| d|
d<   ||
d<   |
S )zGet export files listfilepathNr   rV  rW  rX  )avatarz{USE_NGINX_FOR_UPLOADS is enabled, but FileSystemStorage does not support storage_url=True; Set USE_NGINX_FOR_UPLOADS=False.detailzNGINX mode for uploads is not supported when using local FileSystemStorage. Disable USE_NGINX_FOR_UPLOADS or switch to a cloud storage backend that supports proxy URLs like S3/GCS/Azure.T)storage_urlz/file_download/rT  z://rU  zX-Accel-Redirectzinline; filename=""zContent-DispositionrZ  r[  r\  r^  rS  ))r7  rr   r%   r   rj  r   
startswithr   r_  r   r   rp   r6   rt   r  ra  rb  rY  AVATAR_PATHr,   firstr   has_userrq  rc  USE_NGINX_FOR_UPLOADSr   rd  r   warningHTTP_400_BAD_REQUESTr   rV   r   schemer   replacerf  rg  r   ri  )rv   rg   r   rq   rp  file_objrk  rp   r   protocolrP   redirectr   rB  s                 rx   rr   zDownloadStorageData.get  s_   ;;??:.6#<#<==7;;z23x223LL7~T(TU$,,333BGGIK&;+E+Egll+S&++  !5!56<<&&h&7==?DGLL$D$D$M$Md$S;;6#<#<== ))(**,=>Z    #I "66  ""&&x}}$&GC}++H#~H(83c9CKKSXHXZ\<]]H+3H'(0B8*A.NH*+O (228<OL!'E+EL)'8==d=3KZfgH0B8*A.NH*+#+HZ Orz   N)r   r   r   r  http_method_namesr$   r   rr   r  rz   rx   rn  rn    s    : )+6rz   rn  ){r  r;  loggingrf  r   urllib.parser   r   core.decoratorsr   core.feature_flagsr   core.permissionsr   r   
core.redisr	   core.utils.commonr
   r   core.utils.exceptionsr   core.utils.paramsr   r   csp.decoratorsr   django.confr   django.core.files.storager   	django.dbr   django.httpr   django.utils.decoratorsr   drf_spectacular.typesr   drf_spectacular.utilsr   r   r    label_studio_sdk.label_interfacer   projects.modelsr   r   r   ranged_fileresponser   rest_frameworkr   r   rest_framework.exceptionsr    rest_framework.parsersr!   r"   r#   rest_framework.permissionsr$   rest_framework.responser%   rest_framework.settingsr&   rest_framework.viewsr'   tasks.functionsr(   tasks.modelsr)   r*   tasks.serializersr+   users.modelsr,   webhooks.modelsr-   webhooks.utilsr.   label_studio.core.utils.commonr/   	functionsr1   r2   r3   r4   r5   modelsr6   serializersr7   r8   r9   uploaderr:   r;   	getLoggerr   r   PROJECT_IMPORT_PERMISSIONr   task_create_response_schemeINTBOOLformatHOSTNAMECreateAPIViewrk   r   r  r!  mixinsListModelMixinDestroyModelMixinGenericAPIViewr6  RetrieveUpdateDestroyAPIViewrG  RetrieveAPIViewrP  rn  r  rz   rx   <module>r     s       * 4 ' A . ; 1 M    7 ! $ 4 . R R ; C C 2 + 5 J J 6 , 0 ( 1 ) @  ) 5 4   X X 5			8	$#H$F$FG  
 ]- V & $t% *#_% 0#e%% 1#e%& (#c$ /#h#!2 )	$ 3 $P%( -#h#!. (	" ,#h#!3 (	!c:	?
B
F 
!*:

IL ^ 	Z-!%%N	 (!&& W &!&& O / ; 
/"
F AB F##?'?  
 $.%/&4!)

Yqtlut&& utmtlutr 	Z$R!%%N	
 %$/ ?:#2$!%.+J$-$#	 !)!
* &0&:!)

C&)Tc[811 c[U)Tc[L t	 	 	
i>) i>X 	Z !&& T	  _	
 '.Y&,!)

): 	Z '.Y&3!)

!I668Y8Y[c[r[r !I;X!IH 	Z!F&-Y&+!)

		 	Z$6$&-Y&.!)


 	Z$6&-Y&.!)

		?H99 ?P?( 	Z8&-Y&0!)

 -KL
 :833 :! :6 tW' W Wrz   