U
    b*                     @   s  d dl Z d dl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 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 z,d dlmZ d dlmZmZ d dlmZ W n e k
r   edY nX dZ!G dd de
Z"eG dd deZ#dS )    N)	timedelta)SpooledTemporaryFile)ImproperlyConfiguredSuspiciousOperation)File)timezone)deconstructible)force_bytes)BaseStorage)check_location
clean_nameget_available_overwrite_name	safe_joinsetting)NotFound)BlobClient)_quotezfCould not load Google Cloud Storage bindings.
See https://github.com/GoogleCloudPlatform/gcloud-pythoncontent_typec                       s`   e Zd Zdd Zedd Zdd Zdd ZeeeZd fd
d	Z	 fddZ
dd Z  ZS )GoogleCloudFilec                 C   sd   || _ t|d | _|| _|| _|j|| _| jsTd|krTt	| j |j|j
d| _d | _d| _d S )Nr   w)
chunk_sizeF)name	mimetypes
guess_type	mime_type_mode_storagebucketget_blobblobr   blob_chunk_size_file	_is_dirty)selfr   modeZstorage r&   </tmp/pip-unpacked-wheel-_urp_i0d/storages/backends/gcloud.py__init__   s     zGoogleCloudFile.__init__c                 C   s   | j jS N)r    sizer$   r&   r&   r'   r*   ,   s    zGoogleCloudFile.sizec                 C   sR   | j d krLt| jjdtdd| _ d| jkrLd| _| j| j  | j 	d | j S )Nz.GSStorageFileZFILE_UPLOAD_TEMP_DIR)max_sizesuffixdirrFr   )
r"   r   r   max_memory_sizer   r   r#   r    Zdownload_to_fileseekr+   r&   r&   r'   	_get_file0   s    

zGoogleCloudFile._get_filec                 C   s
   || _ d S r)   )r"   )r$   valuer&   r&   r'   	_set_file=   s    zGoogleCloudFile._set_fileNc                    s*   d| j krtd|d krd}t |S )Nr/   z!File was not opened in read mode.)r   AttributeErrorsuperread)r$   	num_bytes	__class__r&   r'   r8   B   s
    
zGoogleCloudFile.readc                    s(   d| j krtdd| _t t|S )Nr   z"File was not opened in write mode.T)r   r6   r#   r7   writer	   )r$   contentr:   r&   r'   r<   K   s    
zGoogleCloudFile.writec                 C   sV   | j d k	rR| jrB| j| j}| jj| jd| j|	d| jj
d | j   d | _ d S )NTacl)rewindr   predefined_acl)r"   r#   r   get_object_parametersr   r    upload_from_filefiler   getdefault_aclclose)r$   blob_paramsr&   r&   r'   rF   Q   s    
  
zGoogleCloudFile.close)N)__name__
__module____qualname__r(   propertyr*   r2   r4   rC   r8   r<   rF   __classcell__r&   r&   r:   r'   r      s   

	r   c                       s   e Zd Z fddZdd Zedd Zedd Zd	d
 Zd'ddZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd( fd%d&	Z  ZS ))GoogleCloudStoragec                    s&   t  jf | t|  d | _d | _d S r)   )r7   r(   r   _bucket_client)r$   settingsr:   r&   r'   r(   ^   s    zGoogleCloudStorage.__init__c                 C   sh   t dt dt dt dd t ddt dt dd	t d
tddt dd	t dt di t ddt ddS )NZGS_PROJECT_IDZGS_CREDENTIALSZGS_BUCKET_NAMEZGS_CUSTOM_ENDPOINTZGS_LOCATION ZGS_DEFAULT_ACLZGS_QUERYSTRING_AUTHTZGS_EXPIRATIONiQ )secondsZGS_FILE_OVERWRITEZGS_CACHE_CONTROLZGS_OBJECT_PARAMETERSZGS_MAX_MEMORY_SIZEr   ZGS_BLOB_CHUNK_SIZE)
project_idcredentialsbucket_namecustom_endpointlocationrE   querystring_auth
expirationfile_overwritecache_controlobject_parametersr0   r!   )r   r   r+   r&   r&   r'   get_default_settingsf   s    z'GoogleCloudStorage.get_default_settingsc                 C   s"   | j d krt| j| jd| _ | j S )N)projectrT   )rO   r   rS   rT   r+   r&   r&   r'   clientz   s    
zGoogleCloudStorage.clientc                 C   s    | j d kr| j| j| _ | j S r)   )rN   r_   r   rU   r+   r&   r&   r'   r      s    
zGoogleCloudStorage.bucketc                 C   s4   zt | j|W S  tk
r.   td| Y nX dS )aA  
        Normalizes the name so that paths like /path/to/ignored/../something.txt
        and ./file.txt work.  Note that clean_name adds ./ to some paths so
        they need to be fixed here. We check to make sure that the path pointed
        to is not outside the directory specified by the LOCATION setting.
        z Attempted access to '%s' denied.N)r   rW   
ValueErrorr   r$   r   r&   r&   r'   _normalize_name   s    z"GoogleCloudStorage._normalize_namerbc                 C   s0   |  t|}t||| }|js,td| |S )NzFile does not exist: %s)rb   r   r   r    FileNotFoundError)r$   r   r%   file_objectr&   r&   r'   _open   s
    zGoogleCloudStorage._openc           	      C   s   t |}| |}||_t|d| }i }| |}|d| j|d< t|krV|j|t< |	 D ]\}}t
|j|| q^|jj|fd|jd| |S )Nrwr>   r@   T)r?   r*   )r   rb   r   r   rA   poprE   CONTENT_TYPEr   itemssetattrr    rB   r*   )	r$   r   r=   Zcleaned_namere   Zupload_paramsrG   propvalr&   r&   r'   _save   s    


zGoogleCloudStorage._savec                 C   s2   | j  }d|kr.| jr.tdt | j|d< |S )zOverride this to return a dictionary of overwritable blob-property to value.

        Returns GS_OBJECT_PARAMETRS by default. See the docs for all possible options.
        r[   zThe GS_CACHE_CONTROL setting is deprecated. Use GS_OBJECT_PARAMETERS to set any writable blob property or override GoogleCloudStorage.get_object_parameters to vary the parameters per object.)r\   copyr[   warningswarnDeprecationWarning)r$   r   r\   r&   r&   r'   rA      s    

z(GoogleCloudStorage.get_object_parametersc                 C   s8   |  t|}z| j| W n tk
r2   Y nX d S r)   )rb   r   r   Zdelete_blobr   ra   r&   r&   r'   delete   s
    zGoogleCloudStorage.deletec                 C   sN   |s0z| j | j W dS  tk
r.   Y dS X | t|}t| j|S )NTF)r_   Z
get_bucketr   r   rb   r   boolr   ra   r&   r&   r'   exists   s    zGoogleCloudStorage.existsc           
      C   s   |  t|}|r$|ds$|d7 }| jj|dd}t|}|j}g }g }|D ]}|jd}|	|d  qN|D ]}	|	d}|	|d  qrt||fS )N/)prefix	delimiterr5   )
rb   r   endswithr   Z
list_blobslistprefixesr   splitappend)
r$   r   iteratorZblobsr|   filesdirsr    partsZfolder_pathr&   r&   r'   listdir   s    
zGoogleCloudStorage.listdirc                 C   s&   | j |}|d kr"td||S )NzFile does not exist: {})r   r   r   formatr$   r   r    r&   r&   r'   	_get_blob   s    zGoogleCloudStorage._get_blobc                 C   s   |  t|}| |}|jS r)   )rb   r   r   r*   r   r&   r&   r'   r*      s    
zGoogleCloudStorage.sizec                 C   s$   |  t|}| |}t|jS r)   )rb   r   r   r   
make_naiveupdatedr   r&   r&   r'   modified_time   s    
z GoogleCloudStorage.modified_timec                 C   s4   |  t|}| |}|j}tdr*|S t|S )NUSE_TZ)rb   r   r   r   r   r   r   )r$   r   r    r   r&   r&   r'   get_modified_time   s    
z$GoogleCloudStorage.get_modified_timec                 C   s4   |  t|}| |}|j}tdr*|S t|S )z
        Return the creation time (as a datetime) of the file specified by name.
        The datetime will be timezone-aware if USE_TZ=True.
        r   )rb   r   r   Ztime_createdr   r   r   )r$   r   r    createdr&   r&   r'   get_created_time  s    
z#GoogleCloudStorage.get_created_timec                 C   s   |  t|}| j|}| |}|d| jdkp<| j }| jsN|rN|j	S |rjdj
| jt|dddS | js|j| jddS |j| j| jdd	S d
S )z
        Return public url or a signed url for the Blob.
        This DOES NOT check for existance of Blob - that makes codes too slow
        for many use cases.
        r>   Z
publicReadz {storage_base_url}/{quoted_name}s   /~)safe)Zstorage_base_urlZquoted_nameZv4)rY   version)Zbucket_bound_hostnamerY   r   N)rb   r   r   r    rA   rD   rE   rX   rV   Z
public_urlr   r   Zgenerate_signed_urlrY   )r$   r   r    rG   Zno_signed_urlr&   r&   r'   url  s,    


 zGoogleCloudStorage.urlNc                    s&   t |}| jrt||S t ||S r)   )r   rZ   r   r7   get_available_name)r$   r   
max_lengthr:   r&   r'   r   ,  s    
z%GoogleCloudStorage.get_available_name)rc   )N)rH   rI   rJ   r(   r]   rK   r_   r   rb   rf   rn   rA   rs   ru   r   r   r*   r   r   r   r   r   rL   r&   r&   r:   r'   rM   \   s(   


	
rM   )$r   rp   datetimer   tempfiler   Zdjango.core.exceptionsr   r   Zdjango.core.files.baser   Zdjango.utilsr   Zdjango.utils.deconstructr   Zdjango.utils.encodingr	   Zstorages.baser
   Zstorages.utilsr   r   r   r   r   Zgoogle.cloud.exceptionsr   Zgoogle.cloud.storager   r   Zgoogle.cloud.storage.blobr   ImportErrorri   r   rM   r&   r&   r&   r'   <module>   s(   >