Skip to content

Commit 08acae8

Browse files
authored
Merge pull request #29 from TaskarCenterAtUW/feature-sas-url
SAS URL generation done
2 parents 9783582 + 0777d38 commit 08acae8

3 files changed

Lines changed: 124 additions & 5 deletions

File tree

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,71 @@
11
from abc import ABC, abstractmethod
22

33

4+
45
class StorageClient(ABC):
6+
"""Abstract base class for a storage client."""
7+
58
@abstractmethod
6-
def get_container(self, name: str): pass
9+
def get_container(self, name: str):
10+
"""Get a container by name.
11+
12+
Args:
13+
name (str): The name of the container.
14+
15+
Returns:
16+
The container object.
17+
"""
18+
pass
19+
20+
@abstractmethod
21+
def get_file(self, container_name: str, file_name: str):
22+
"""Get a file from a container.
23+
24+
Args:
25+
container_name (str): The name of the container.
26+
file_name (str): The name of the file.
27+
28+
Returns:
29+
The file object.
30+
"""
31+
pass
732

833
@abstractmethod
9-
def get_file(self, container_name: str, file_name: str): pass
34+
def get_file_from_url(self, container_name: str, full_url: str):
35+
"""Get a file from a URL.
36+
37+
Args:
38+
container_name (str): The name of the container.
39+
full_url (str): The full URL of the file.
40+
41+
Returns:
42+
The file object.
43+
"""
44+
pass
1045

1146
@abstractmethod
12-
def get_file_from_url(self, container_name: str, full_url: str): pass
47+
def get_sas_url(self, container_name: str, file_path: str, expiry_hours: int) -> str:
48+
"""Get a shared access signature (SAS) URL for a file.
49+
50+
Args:
51+
container_name (str): The name of the container.
52+
file_path (str): The path of the file.
53+
expiry_hours (int): The number of hours until the SAS URL expires.
54+
55+
Returns:
56+
The SAS URL as a string.
57+
"""
58+
pass
59+
# class StorageClient(ABC):
60+
# #
61+
# @abstractmethod
62+
# def get_container(self, name: str): pass
63+
64+
# @abstractmethod
65+
# def get_file(self, container_name: str, file_name: str): pass
66+
67+
# @abstractmethod
68+
# def get_file_from_url(self, container_name: str, full_url: str): pass
1369

70+
# @abstractmethod
71+
# def get_sas_url(self, container_name:str,file_path: str, expiry_hours:int) -> str: pass

src/python_ms_core/core/storage/providers/azure/azure_storage_client.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import logging
22
import urllib.parse
3-
from azure.storage.blob import BlobServiceClient
3+
from azure.storage.blob import BlobServiceClient, generate_blob_sas, BlobSasPermissions
44
from . import azure_file_entity, azure_storage_container
55
from ...abstract import storage_client
66
from ....resource_errors import ExceptionHandler
7-
7+
import datetime
88

99
class AzureStorageClient(storage_client.StorageClient):
10+
"""
11+
Represents a client for interacting with Azure Storage.
12+
"""
13+
1014
_blob_service_client: BlobServiceClient
1115

1216
def __init__(self, config):
@@ -16,6 +20,15 @@ def __init__(self, config):
1620

1721
@ExceptionHandler.decorated
1822
def get_container(self, container_name: str):
23+
"""
24+
Retrieves the Azure Storage container with the specified name.
25+
26+
Args:
27+
container_name (str): The name of the container.
28+
29+
Returns:
30+
azure_storage_container.AzureStorageContainer: The Azure Storage container object.
31+
"""
1932
if container_name:
2033
client_container = self._blob_service_client.get_container_client(container_name)
2134
return azure_storage_container.AzureStorageContainer(container_name, client_container)
@@ -25,12 +38,32 @@ def get_container(self, container_name: str):
2538

2639
@ExceptionHandler.decorated
2740
def get_file(self, container_name: str, file_name: str):
41+
"""
42+
Retrieves the Azure Storage file with the specified name from the specified container.
43+
44+
Args:
45+
container_name (str): The name of the container.
46+
file_name (str): The name of the file.
47+
48+
Returns:
49+
azure_file_entity.AzureFileEntity: The Azure Storage file object.
50+
"""
2851
client_container = self._blob_service_client.get_container_client(container_name)
2952
blob_client = client_container.get_blob_client(file_name)
3053
return azure_file_entity.AzureFileEntity(file_name, blob_client)
3154

3255
@ExceptionHandler.decorated
3356
def get_file_from_url(self, container_name: str, full_url: str):
57+
"""
58+
Retrieves the Azure Storage file from the specified URL.
59+
60+
Args:
61+
container_name (str): The name of the container.
62+
full_url (str): The full URL of the file.
63+
64+
Returns:
65+
azure_file_entity.AzureFileEntity: The Azure Storage file object.
66+
"""
3467
path = '/'.join(urllib.parse.unquote(full_url).split('/')[4:])
3568
file = azure_file_entity.AzureFileEntity
3669
client_container = self._blob_service_client.get_container_client(container_name)
@@ -40,3 +73,27 @@ def get_file_from_url(self, container_name: str, full_url: str):
4073
if file_info.file_path == path:
4174
file = file_info
4275
return file
76+
77+
78+
def get_sas_url(self, container_name: str, file_path: str, expiry_hours:int = 12) -> str:
79+
"""
80+
Generates a Shared Access Signature (SAS) URL for the specified Azure Storage file.
81+
82+
Args:
83+
container_name (str): The name of the container.
84+
file_path (str): The path of the file within the container.
85+
expiry_hours (int, optional): The number of hours until the SAS URL expires. Defaults to 12.
86+
87+
Returns:
88+
str: The SAS URL for the file.
89+
"""
90+
sas_token = generate_blob_sas(
91+
self._blob_service_client.account_name,
92+
container_name,
93+
file_path,
94+
account_key=self._blob_service_client.credential.account_key,
95+
permission=BlobSasPermissions(read=True),
96+
expiry=datetime.datetime.utcnow() + datetime.timedelta(hours=expiry_hours)
97+
)
98+
sas_url = f"https://{self._blob_service_client.account_name}.blob.core.windows.net/{container_name}/{file_path}?{sas_token}"
99+
return sas_url

src/python_ms_core/core/storage/providers/local/local_storage_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ def get_file_from_url(self, container_name: str, full_url: str):
3333
if file_info.path == path:
3434
file = file_info
3535
return file
36+
37+
@ExceptionHandler.decorated
38+
def get_sas_url(self, container_name: str, file_path: str, expiry_hours: int) -> str:
39+
return self.get_file_from_url(container_name, file_path).get_remote_url()

0 commit comments

Comments
 (0)