
    k)iF                        d Z ddlZddlZddlmZmZmZ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mZmZ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*m+Z+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4  ejj                  e6      Z7dede8de#fdZ9dedede8dee#   fdZ:dede;de"fdZ<dede8de;de;dee"   f
dZ=dede;dee8e>f   fdZ?	 d0dede8defd Z@de8ddfd!ZAd"eBde8ddfd#ZCd"eBddfd$ZDdeddfd%ZEded&ede8de#fd'ZFded(ee   de8dee#   fd)ZGdede8dee"   fd*ZHdede;de;dee"   fd+ZIdede8de fd,ZJd-e ddfd.ZKded-e deBfd/ZLy)1z
File services module for handling file operations.

This module provides services for file upload, download, listing, and deletion
operations with support for both local filesystem and CDN storage.
    N)DictListOptionalTupleAny)IntegrityError)Session)select)status)Response)StreamingResponse)get_active_cdn)get_approximate_filesizeremove_file_singleupload_file_multipleupload_file_singledownload_file_from_s3download_file_from_system_pathget_image_resolution)File)
FileSchemaFileResponseSchema)APIException)DBSortTypes	FileTypes)MAX_UPLOAD_LIMITMAX_UPLOAD_SIZE_MBALLOWED_FILE_CONTENT_TYPESMAX_UPLOAD_RESOLUTION$THUMBNAIL_ALLOWED_FILE_CONTENT_TYPESTHUMBNAIL_MAX_FILE_SIZE_BYTES)testINVOICE_UNIQUE_IDRECEIPT_UNIQUE_IDCONTRACT_UNIQUE_IDdb	file_typereturnc                    K   t        ||       |j                  j                         }t        ||       |dk(  rt	        ||       t        | |||j                   d      }t        | |||       d{   }|S 7 w)a  
    Upload a single file and create database entry.
    
    Args:
        db: Database session.
        file: FastAPI UploadFile object.
        file_type: Type of file being uploaded.
        created_by: User who is uploading the file.
        merchant: Merchant context for file organization.
        
    Returns:
        FileResponseSchema with file details.
        
    Raises:
        APIException: If validation fails or upload errors occur.
    	thumbnail/)r&   	file_datar'   
created_byN)_validate_file_type_and_contentfileread_validate_file_content _validate_thumbnail_requirementsr   merchant_id_create_file_database_entry)r&   r/   r'   r-   merchantfile_contentuploaded_file_datanew_files           Z/var/www/html/hwPaymentPortal-be-dev/hw-payment-portal-api/src/apps/files/file_services.pyupload_single_filer:   2   s     . $D)499>>#L<3K(|<+
D,8#7#7"8 : 1$	 H Os   A1A<3A:4A<filesc                    K   t        |      t        kD  r)t        t        i t        j
                  dt         d      t        |       t        | ||j                   d      }t        | |||       d{   }|S 7 w)a  
    Upload multiple files and create database entries.
    
    Args:
        db: Database session.
        files: List of FastAPI UploadFile objects.
        file_type: Type of files being uploaded.
        created_by: User who is uploading the files.
        merchant: Merchant context for file organization.
        
    Returns:
        List of FileResponseSchema with file details.
        
    Raises:
        APIException: If validation fails or upload errors occur.
    zA maximum of z files can be uploaded at oncemoduleerrorstatus_codemessager+   )r&   
files_datar'   r-   N)
lenr   r   __name__r   HTTP_400_BAD_REQUEST_validate_multiple_file_typesr   r3   &_create_multiple_file_database_entries)r&   r;   r'   r-   r5   uploaded_files_data	new_filess          r9   upload_multiple_filesrJ   _   s     . 5z$$33#$4#55ST	
 	
 "%(.
Eh**+1- =&	 I s   A3A>5A<6A>file_idc                   K   t        t              j                  t        j                  |k(        }| j	                  |      }|j                         }|s!t        t        i t        j                  d      t        j                  |      S w)a&  
    Retrieve a file by its ID.
    
    Args:
        db: Database session.
        file_id: ID of the file to retrieve.
        created_by: User requesting the file.
        
    Returns:
        FileSchema with file details.
        
    Raises:
        APIException: If file not found.
    No such file foundr=   )r
   r   whereidexecutescalar_one_or_noner   rD   r   HTTP_404_NOT_FOUNDr   model_validate)r&   rK   stmtresultfile_objs        r9   get_file_by_idrW      s{      $<7D ZZF((*H11(	
 	
 $$X..s   B	Bidsskiplimitc                 l   K   |rt        | ||       d{   S t        | |||       d{   S 7 7 w)a  
    List files for a user with optional filtering by IDs.
    
    Args:
        db: Database session.
        ids: Comma-separated string of file IDs to filter by.
        skip: Number of records to skip for pagination.
        limit: Maximum number of records to return.
        created_by: User requesting the files.
        
    Returns:
        List of FileSchema objects.
        
    Raises:
        APIException: If validation fails or files not found.
    N)_get_files_by_ids_get_paginated_files)r&   rX   rY   rZ   r-   s        r9   list_user_filesr^      s:     . &r3
;;;)"dE:FFF <Fs   404244c                 Z  K   t        t              j                  t        j                  |k(  t        j                  |j                  k(        }| j                  |      }|j                         }|s!t        t        i t        j                  d      	 | j                  |       | j                          t        |j                         ddiS # t        $ rQ}| j!                          t"        j%                  d| d|        t        t        i t        j&                  d      d	}~ww xY ww)
aE  
    Delete a file by its ID.
    
    Args:
        db: Database session.
        file_id: ID of the file to delete.
        created_by: User requesting the deletion.
        
    Returns:
        Dictionary indicating successful deletion.
        
    Raises:
        APIException: If file not found or deletion fails.
    rM   r=   pathdeletedTzError deleting file z: zFailed to delete fileN)r
   r   rN   rO   created_by_idrP   rQ   r   rD   r   rR   deletecommitr   upload_path	Exceptionrollbackloggerr?   HTTP_500_INTERNAL_SERVER_ERROR)r&   rK   r-   rT   rU   rV   es          r9   delete_file_by_idrl      s       $<7jmm+D ZZF((*H11(	
 	


		(
		 	 4 454   

+G9Bqc:;==+	
 	

s+   BD+:C D+	D(AD##D((D+ra   c                     |s!t        t        i t        j                  d      t	        | ||      }t        ||       t        | |      }t        ||j                        S )a;  
    Download a file by its path.
    
    Args:
        db: Database session.
        path: Path to the file.
        current_user: Currently authenticated user (optional).
        
    Returns:
        Response with file content.
        
    Raises:
        APIException: If file not found or access denied.
    zPath is requiredr=   )content
media_type)	r   rD   r   rE   _find_file_by_path_validate_file_access_download_file_contentr   mime)r&   ra   current_userrV   r6   s        r9   download_file_by_pathru      s]    & 33&	
 	
 ""dL9H(L1)"h7LLX]]CC    c                     | j                   j                  d      d   }|t        vr:t        t        i t
        j                  d| ddj                  t                     y)z2Validate file type and basic content requirements.r+      zCannot upload 'z#' files. Allowed content types are , r=   Ncontent_typesplitr   r   rD   r   rE   join)r/   r'   r{   s      r9   r.   r.   #  sf    $$**3/2L5533%l^3VW[W`W`a{W|V}~	
 	
 6rv   r6   c                     t        |       dk(  r!t        t        i t        j                  d      t        |       t
        dz  kD  r)t        t        i t        j                  dt
         d      y)z2Validate file content size and basic requirements.r   z*The file you are trying to upload is emptyr=   i@B #File exceeds maximum size limit of mbN)rC   r   rD   r   rE   r   )r6   r'   s     r9   r1   r1   /  sr    
<A33@	
 	
 <.89339:L9MRP	
 	
 :rv   c           
      $   | j                   t        vr/t        t        i t        j
                  d| j                    d      t        |      t        dz  kD  r)t        t        i t        j
                  dt         d      	 t        |      }|rU|d   t        d   kD  s|d   t        d   kD  r6t        t        i t        j
                  d	t        d    d
t        d    d      yy# t        $ r" t        t        i t        j
                  d      w xY w)z3Validate specific requirements for thumbnail files.zInvalid file type 'z '. Only JPG and PNG are allowed.r=   i   r   zKB.r   rx   z-Image resolution exceeds the maximum allowed xz pixels.z!Failed to parse image resolution.N)r{   r    r   rD   r   rE   rC   r!   r   r   
ValueError)r/   r6   
resolutions      r9   r2   r2   B  s8    DD33)$*;*;)<<\]	
 	
 <9D@A339:W9XX[\	
 	

),7
qM1!44qM1!44"77GH]^_H`Gaabcxyzc{b|  }E  F	  5   
337	
 	

s   A!C$ $+Dc                     | D ]b  }|j                   j                  d      d   }|t        vs*t        t        i t
        j                  d| ddj                  t                      y)z-Validate file types for multiple file upload.r+   rx   zCannot upload z$ files. Allowed file extensions are ry   r=   Nrz   )r;   r/   	extensions      r9   rF   rF   i  sp     %%++C03	66"77(3WX\XaXab|X}W~	 rv   r,   c           	      n  K   	 t        |       }t        |d   |d   d|d    z   |d   ||j                  |d   |r|j                  nd	      }| j                  |       | j	                          | j                  |       t        j                  |      }|d
   |_        |S # t        $ r2 | j                          t        t        i t        j                  d      t        $ rN}| j                          t         j#                  d|        t        t        i t        j$                  d      d}~ww xY ww)z+Create a single file entry in the database.r&   	file_nameoriginal_name.formatr{   ra   Nnamer   rs   r'   rc   ra   cdn_idfilesize#Attempting to create duplicate filer=   zError creating file entry: zFailed to create file entry)r   r   rO   addre   refreshr   rS   r   r   rh   r   rD   r   rE   rg   ri   r?   rj   )r&   r,   r'   r-   
active_cdnr8   rU   rk   s           r9   r4   r4   v  s'    %
#r*
;'#O49X;N:O7PP>*$--6"$.:==D
 	x
		


8#228<#J/ 

339	
 	
  

21#67==1	
 	

s+   D5BB" !D5"AD2$A	D--D22D5rB   c           
        K   	 t        |       }g }|D ]R  }t        |d   |d   d|d    z   |d   ||j                  |d   |r|j                  nd	      }|j                  |       T | j	                  |       | j                          g }|D ]b  }	| j                  |	       t        j                  |	      }
t        |j                   |	j                   |      |
_        |j                  |
       d |S # t        $ r2 | j                          t        t         i t"        j$                  d
      t&        $ rN}| j                          t(        j+                  d|        t        t         i t"        j,                  d      d}~ww xY ww)z-Create multiple file entries in the database.r   r   r   r   r   r{   ra   Nr   r   r=   z&Error creating multiple file entries: zFailed to create file entries)r   r   rO   appendadd_allre   r   r   rS   r   rf   ra   r   r   rh   r   rD   r   rE   rg   ri   r?   rj   )r&   rB   r'   r-   r   
files_listr,   r8   response_listrV   rU   rk   s               r9   rG   rG     s    -
#r*

# 
	(I{+'8Qy?R>S;TT~.#(mmv&(2z}}H h'
	( 	

:
		" 	)HJJx '66x@F6))*8==/:JFO   (	)  

339	
 	
  

=aSAB==3	
 	

s+   FC0C5 4F5AF7A	F  FFc                 z  K   	 |j                  d      D cg c]  }t        |       }}t        |      dkD  r!t        t        i t
        j                  d      t        t              j                  t        j                  j                  |      t        j                  |j                  k(        }| j                  |      }|j                         j                         }|D cg c]  }t!        j"                  |       c}S c c}w c c}w # t$        $ r" t        t        i t
        j                  d      w xY ww)z#Get files filtered by specific IDs.,
   z.A maximum of 10 files can be requested at oncer=   zInvalid file ID format)r|   intrC   r   rD   r   rE   r
   r   rN   rO   in_rc   rP   scalarsallr   rS   r   )	r&   rX   r-   fidfile_idsrT   rU   r;   rV   s	            r9   r\   r\     s    
(+		#7CH77x=2"77H	  d|!!GGKK!*--/
 D! $$&DIJ
))(3JJ! 8  K 
33,	
 	

s9   D;D DB;D $D D D;
D +D88D;c                   K   t        t              j                  t        j                  |j                  k(        j                  t        j                  j                               j                  |      j                  |      }| j                  |      }|j                         j                         }|D cg c]  }t        j                  |       c}S c c}w w)zGet paginated files for a user.)r
   r   rN   rc   rO   order_by
created_atdescoffsetrZ   rP   r   r   r   rS   )r&   rY   rZ   r-   rT   rU   r;   rV   s           r9   r]   r]     s     $<jmm+ht##%&vvd|EE%L 	 ZZFNN  "E@EFHJ%%h/FFFs   B6C8CCc           	         t        |       }|}|rB|j                  |j                  |j                  fD ]  }|s||v s|j	                  |d      } |j	                  dd      }t        t        t        t        fD cg c]  }t        ||       c}      }|rS|s!t        t        i t        j                  d      t        t              j!                  t        j"                  |k(        }	n/t        t              j!                  t        j                  |k(        }	| j%                  |	      }
|
j'                         }|s!t        t        i t        j(                  d      |S c c}w )z-Find file by path with proper access control.r    r+   /Authentication required to access this resourcer=   rM   )r   hostrootra   replaceanyr#   r$   r%   r"   r   rD   r   HTTP_403_FORBIDDENr
   r   rN   storage_keyrP   rQ   rR   )r&   ra   rt   r   sanitized_pathprefixfile_storage_keypatternis_private_filerT   rU   rV   s               r9   rp   rp     sL   2&J N!
I 	DF&N2!/!7!7!C	D
 &--c26)+<>PQ 	w' O "55I	  d|!!$"2"26F"FGd|!!$))~"=>ZZF((*H11(	
 	
 O;s   =E!rV   c                 d    | j                   r$|s!t        t        i t        j                  d      yy)z!Validate user access to the file.r   r=   N)r   r   rD   r   r   )rV   rt   s     r9   rq   rq   2  s4    L11E	
 	
 %1rv   c                 P   t        |       }|rB|j                  j                         dk(  r%t        |j                   |j
                         }n$t        |j                   |j
                         }|rt        |      dk  r!t        t        i t        j                  d      |S )z#Download file content from storage.r   s3r`   rx   z4The resource you are trying to access is unavailabler=   )r   labellowerr   rf   ra   r   rC   r   rD   r   rR   )r&   rV   r   r6   s       r9   rr   rr   =  s    2&Jj&&,,.$6,**+HMM?;
 6**+HMM?;
 3|,q011J	
 	
 rv   )N)M__doc__loggingostypingr   r   r   r   r   sqlalchemy.excr   sqlalchemy.ormr	   
sqlalchemyr
   	starletter   starlette.responsesr   fastapi.responsesr   src.apps.base.servicesr   src.apps.files.helper.ior   r   r   r   r   r   r   src.apps.files.models.filer   "src.apps.files.schemas.file_commonr   r   src.core.exceptionsr   src.core.utils.enumsr   r   src.core.utils.constantsr   r   r   r   r    r!   src.apps.base.utils.regexpr"   r#   r$   r%   	getLoggerrD   ri   strr:   rJ   r   rW   r^   boolrl   ru   r.   bytesr1   r2   rF   r4   rG   r\   r]   rp   rq   rr    rv   r9   <module>r      s    	 3 3 ) "   ( / 1   , M , 7   
		8	$** * *Z,,, , 

,^/W /s /z /@GG	G G 	G 
*G:0
 0
# 0
d3PT9o 0
l  D D
 D 	 DJ	
S 	
T 	

 
3 
4 
&$
 $
4 $
N
 
$ 
,
,
,
 ,

 ,
^4
4
T
4
 4

 

4
n
 
c 
$zBR 
:	G7 	G# 	Gc 	GRVWaRb 	G*7 *# * *Z
D 
4 
w $ 5 rv   