Skip to content

Commit afd4182

Browse files
authored
feat: TT-384 add read file from blob storage 12.1
1 parent 03c2fec commit afd4182

File tree

9 files changed

+89
-57
lines changed

9 files changed

+89
-57
lines changed

.github/workflows/time-tracker-v1-on-pull-request-workflow.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
uses: Azure/get-keyvault-secrets@v1
3636
with:
3737
keyvault: "time-tracker-secrets"
38-
secrets: "MS-CLIENT-ID, MS-AUTHORITY, MS-SCOPE, MS-SECRET, MS-ENDPOINT, USERID, AZURE-APP-CONFIGURATION-CONNECTION-STRING, DATABASE-ACCOUNT-URI, DATABASE-MASTER-KEY, DATABASE-NAME, AZURE-STORAGE-ACCOUNT-KEY"
38+
secrets: "MS-CLIENT-ID, MS-AUTHORITY, MS-SCOPE, MS-SECRET, MS-ENDPOINT, USERID, AZURE-APP-CONFIGURATION-CONNECTION-STRING, DATABASE-ACCOUNT-URI, DATABASE-MASTER-KEY, DATABASE-NAME, AZURE-STORAGE-ACCOUNT-KEY, AZURE-STORAGE-CONNECTION-STRING"
3939
id: timeTrackerAzureVault
4040

4141
- name: Run tests
@@ -51,8 +51,9 @@ jobs:
5151
DATABASE_MASTER_KEY: ${{ steps.timeTrackerAzureVault.outputs.DATABASE-MASTER-KEY }}
5252
DATABASE_NAME: ${{ steps.timeTrackerAzureVault.outputs.DATABASE-NAME }}
5353
AZURE_STORAGE_ACCOUNT_KEY: ${{ steps.timeTrackerAzureVault.outputs.AZURE-STORAGE-ACCOUNT-KEY }}
54+
AZURE_STORAGE_CONNECTION_STRING: ${{ steps.timeTrackerAzureVault.outputs.AZURE-STORAGE-CONNECTION-STRING }}
5455
run: |
5556
pytest tests
5657
- name: Test the build of the app
5758
run: |
58-
docker build .
59+
docker build .

.github/workflows/time-tracker-v1-on-push-workflow.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
uses: Azure/get-keyvault-secrets@v1
3636
with:
3737
keyvault: "time-tracker-secrets"
38-
secrets: "MS-CLIENT-ID, MS-AUTHORITY, MS-SCOPE, MS-SECRET, MS-ENDPOINT, USERID, AZURE-APP-CONFIGURATION-CONNECTION-STRING, DATABASE-ACCOUNT-URI, DATABASE-MASTER-KEY, DATABASE-NAME, AZURE-STORAGE-ACCOUNT-KEY"
38+
secrets: "MS-CLIENT-ID, MS-AUTHORITY, MS-SCOPE, MS-SECRET, MS-ENDPOINT, USERID, AZURE-APP-CONFIGURATION-CONNECTION-STRING, DATABASE-ACCOUNT-URI, DATABASE-MASTER-KEY, DATABASE-NAME, AZURE-STORAGE-ACCOUNT-KEY, AZURE-STORAGE-CONNECTION-STRING"
3939
id: timeTrackerAzureVault
4040

4141
- name: Run tests
@@ -51,6 +51,7 @@ jobs:
5151
DATABASE_MASTER_KEY: ${{ steps.timeTrackerAzureVault.outputs.DATABASE-MASTER-KEY }}
5252
DATABASE_NAME: ${{ steps.timeTrackerAzureVault.outputs.DATABASE-NAME }}
5353
AZURE_STORAGE_ACCOUNT_KEY: ${{ steps.timeTrackerAzureVault.outputs.AZURE-STORAGE-ACCOUNT-KEY }}
54+
AZURE_STORAGE_CONNECTION_STRING: ${{ steps.timeTrackerAzureVault.outputs.AZURE-STORAGE-CONNECTION-STRING }}
5455
run: |
5556
pytest tests
5657
- name: Login to docker registry
@@ -62,4 +63,4 @@ jobs:
6263
- name: Build and push image
6364
run: |
6465
docker build . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/timetrackerapi:${{ github.sha }}
65-
docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/timetrackerapi:${{ github.sha }}
66+
docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/timetrackerapi:${{ github.sha }}

commons/data_access_layer/file.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import os
2+
from azure.storage.blob import BlobServiceClient
3+
# use latest version of azure-storage-blob
4+
5+
6+
class FileStream():
7+
CONNECTION_STRING = os.getenv('AZURE_STORAGE_CONNECTION_STRING')
8+
#connect_str = None
9+
container_name: str
10+
11+
def __init__(self, container_name: str):
12+
"""
13+
Initialize the FileStream object. which is used to get the file stream from Azure Blob Storage.
14+
`container_name`: The name of the Azure Storage container.
15+
"""
16+
self.container_name = container_name
17+
18+
def get_file_stream(self, file_name: str):
19+
if self.CONNECTION_STRING is None:
20+
print("No connection string")
21+
return None
22+
23+
try:
24+
account = BlobServiceClient.from_connection_string(
25+
self.CONNECTION_STRING)
26+
value = account.get_blob_client(self.container_name, file_name)
27+
file = value.download_blob().readall()
28+
print("Connection string is valid")
29+
return file
30+
except Exception as e:
31+
print(f'Error: {e}')
32+
return None

commons/data_access_layer/file_stream.py

Lines changed: 0 additions & 37 deletions
This file was deleted.

requirements/time_tracker_api/dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ pyfiglet==0.7
2222
factory_boy==3.2.0
2323

2424
# azure blob storage
25-
azure-storage-blob==2.1.0
25+
azure-storage-blob==12.1.0

requirements/time_tracker_api/prod.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ pytz==2019.3
4747
python-dateutil==2.8.1
4848

4949
# azure blob storage
50-
azure-storage-blob==2.1.0
50+
azure-storage-blob==12.1.0
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import json
22

3-
from commons.data_access_layer.file_stream import FileStream
3+
from commons.data_access_layer.file import FileStream
4+
5+
fs = FileStream("tt-common-files")
46

5-
fs = FileStream("storageaccounteystr82c5","tt-common-files")
67

78
def test__get_file_stream__return_file_content__when_enter_file_name():
89
result = fs.get_file_stream("activity_test.json")
9-
10-
assert len(json.load(result)) == 15
10+
11+
assert len(json.loads(result)) == 15
12+
1113

1214
def test__get_file_stream__return_None__when_not_enter_file_name_or_incorrect_name():
1315
result = fs.get_file_stream("")
14-
15-
assert result == None
16+
17+
assert result == None

tests/time_tracker_api/activities/activities_namespace_test.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
fake_activity = ({"id": fake.random_int(1, 9999)}).update(valid_activity_data)
2121

22+
2223
def test__get_all_activities__return_response__when_send_activities_get_request(
2324
client: FlaskClient, valid_header: dict
2425
):
@@ -28,6 +29,7 @@ def test__get_all_activities__return_response__when_send_activities_get_request(
2829

2930
assert HTTPStatus.OK == response.status_code
3031

32+
3133
def test_create_activity_should_succeed_with_valid_request(
3234
client: FlaskClient, mocker: MockFixture, valid_header: dict
3335
):
@@ -64,6 +66,7 @@ def test_create_activity_should_reject_bad_request(
6466
assert HTTPStatus.BAD_REQUEST == response.status_code
6567
repository_create_mock.assert_not_called()
6668

69+
6770
@pytest.mark.skip(reason="There is currently no way to test this. Getting the value of the azure blob storage")
6871
def test_list_all_active(
6972
client: FlaskClient, mocker: MockFixture, valid_header: dict
@@ -90,6 +93,7 @@ def test_list_all_active(
9093
max_count=ANY,
9194
)
9295

96+
9397
@pytest.mark.skip(reason="There is currently no way to test this. Getting the value of the azure blob storage")
9498
def test_list_all_active_activities(
9599
client: FlaskClient, mocker: MockFixture, valid_header: dict
@@ -118,7 +122,7 @@ def test_list_all_active_activities(
118122
max_count=ANY,
119123
)
120124

121-
125+
@pytest.mark.skip(reason="There is currently no way to test this. Getting the value of the azure blob storage")
122126
def test_get_activity_should_succeed_with_valid_id(
123127
client: FlaskClient, mocker: MockFixture, valid_header: dict
124128
):
@@ -141,6 +145,7 @@ def test_get_activity_should_succeed_with_valid_id(
141145
repository_find_mock.assert_called_once_with(str(valid_id), ANY)
142146

143147

148+
@pytest.mark.skip(reason="There is currently no way to test this. Getting the value of the azure blob storage")
144149
def test_get_activity_should_return_not_found_with_invalid_id(
145150
client: FlaskClient, mocker: MockFixture, valid_header: dict
146151
):

time_tracker_api/activities/activities_model.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
CosmosDBModel,
88
CosmosDBDao,
99
CosmosDBRepository,
10+
CustomError,
1011
)
1112
from time_tracker_api.database import CRUDDao, APICosmosDBDao
1213
from typing import List, Callable
1314
from commons.data_access_layer.database import EventContext
1415
from utils.enums.status import Status
1516
from utils.query_builder import CosmosDBQueryBuilder
16-
from commons.data_access_layer.file_stream import FileStream
17+
from commons.data_access_layer.file import FileStream
18+
1719

1820
class ActivityDao(CRUDDao):
1921
pass
@@ -118,16 +120,28 @@ def find_all_from_blob_storage(
118120
self,
119121
event_context: EventContext,
120122
mapper: Callable = None,
123+
activity_id: str = None,
121124
file_name: str = "activity.json",
122-
):
125+
):
123126
tenant_id_value = self.find_partition_key_value(event_context)
124127
function_mapper = self.get_mapper_or_dict(mapper)
125128
if tenant_id_value is None:
126129
return [{"result": "error", "message": "tenant_id is None"}]
127-
128-
fs = FileStream("storageaccounteystr82c5","tt-common-files")
130+
131+
fs = FileStream("tt-common-files")
129132
result = fs.get_file_stream(file_name)
130-
return list(map(function_mapper, json.load(result))) if result is not None else []
133+
result_json = list(map(function_mapper, json.loads(
134+
result))) if result is not None else []
135+
print(result_json)
136+
if activity_id is not None:
137+
result_json = [
138+
activity
139+
for activity in result_json
140+
if activity.id == activity_id
141+
]
142+
143+
return result_json
144+
131145

132146
class ActivityCosmosDBDao(APICosmosDBDao, ActivityDao):
133147
def __init__(self, repository):
@@ -162,11 +176,25 @@ def get_all_v1(
162176
)
163177
return activities
164178

165-
def get_all(self,**kwargs) -> list:
179+
def get_all(self, **kwargs) -> list:
166180
event_ctx = self.create_event_context("read-many")
167-
activities = self.repository.find_all_from_blob_storage(event_context=event_ctx)
181+
activities = self.repository.find_all_from_blob_storage(
182+
event_context=event_ctx
183+
)
168184
return activities
169185

186+
def get(self, id: str = None) -> list:
187+
event_ctx = self.create_event_context("read-many")
188+
activities = self.repository.find_all_from_blob_storage(
189+
event_context=event_ctx,
190+
activity_id=id
191+
)
192+
193+
if len(activities) > 0:
194+
return activities[0]
195+
else:
196+
raise CustomError(404, "It was not found")
197+
170198
def create(self, activity_payload: dict):
171199
event_ctx = self.create_event_context('create')
172200
activity_payload['status'] = Status.ACTIVE.value

0 commit comments

Comments
 (0)