Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ab72410
add [p] prefix for project folder when listing items under project
Mar 21, 2024
7778437
group itemprefix class with itemtype class
Mar 22, 2024
e86765f
add double quotation when item name contains space
Mar 22, 2024
2b6b7f2
udpate move/rename commands to distinguish project folder/name folder
Apr 1, 2024
3d76446
change enum type PROJECTFOLDER to SHAREDFOLDER
Apr 1, 2024
e1529a0
Merge branch 'PILOT-4734' into PILOT-4808
Apr 2, 2024
8673b94
update move/rename logic but will need to fix upload/list command for…
Apr 2, 2024
3f38db5
replace PROJECTFOLDER with SHAREDFOLDER
Apr 3, 2024
09c4ca3
replace PROJECTFOLDER with SHAREDFOLDER
Apr 3, 2024
bfadd0f
fixup test cases
Apr 3, 2024
1ce8df7
fixup logic for different prefix
Apr 3, 2024
7020626
add prefix for name folder
Apr 3, 2024
77133af
bump up version to 3.0.0
Apr 3, 2024
0602417
fixup test cases
Apr 3, 2024
b452c69
manually merged
Apr 4, 2024
36a8a66
fixup test cases
Apr 4, 2024
78698a5
replace hardcoded string with enum value in test cases
Apr 4, 2024
db9b73b
remove the reference of project_folder
Apr 4, 2024
69257e8
manually merged
Apr 5, 2024
88cda43
manually merged
Apr 5, 2024
68653a3
manually merged
Apr 5, 2024
1900019
fixup test cases
Apr 5, 2024
2f64a09
replace hardcode project folder with enum class
Apr 10, 2024
5b40507
add more download test cases
Apr 11, 2024
0f0a914
fixup test cases
Apr 23, 2024
38f24dd
merge
Apr 23, 2024
368bf2a
Merge branch 'develop' into PILOT-4808
Apr 25, 2024
6197fbd
remove SHAREFOLDER specific logic
Apr 25, 2024
d60c5d6
fixup test cases
Apr 25, 2024
551662b
merge
Apr 25, 2024
17dfd7c
remove old comments
Apr 25, 2024
a2e4677
Merge branch 'develop' into PILOT-4806
Apr 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions app/commands/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,12 @@ def file_download(**kwargs):
else:
item_res = []
for path in paths:
project_code, root_folder = path.strip('/').split('/')[:2]
target_path = '/'.join(path.split('/')[1::])
# search the root to check for name folder or project folder
root_item = search_item(project_code, zone, root_folder).get('result', {})
target_path = 'shared/' + target_path if root_item.get('type') == 'project_folder' else target_path
project_code, root_folder, object_path = path.strip('/').split('/', 2)
root_type = ItemType.get_type_from_keyword(root_folder)
object_path = os.path.join(root_type.get_prefix_by_type(), object_path)

# search the target item and download to local
item = search_item(project_code, zone, target_path)
item = search_item(project_code, zone, object_path)
if item.get('code') == 200 and item.get('result'):
item_status = 'success'
item_result = item.get('result')
Expand Down
5 changes: 5 additions & 0 deletions app/models/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ def get_prefix_by_type(self) -> str:
}

return prefix.get(self.value, '')


class ItemZone(str, Enum):
GREENROOM = 'greenroom'
CORE = 'core'
9 changes: 5 additions & 4 deletions app/services/file_manager/file_download/download_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import app.services.output_manager.message_handler as mhandler
from app.configs.app_config import AppConfig
from app.configs.user_config import UserConfig
from app.models.item import ItemZone
from app.models.service_meta_class import MetaService
from app.services.output_manager.error_handler import ECustomizedError
from app.services.output_manager.error_handler import SrvErrorHandler
Expand Down Expand Up @@ -53,7 +54,7 @@ def print_prepare_msg(self, message):
click.secho(f"{message}{'.'*i}\r", fg='white', nl=False)

def get_download_url(self, zone):
if zone == 'greenroom':
if zone == ItemZone.GREENROOM.value:
url = self.appconfig.Connections.url_download_greenroom
else:
url = self.appconfig.Connections.url_download_core
Expand Down Expand Up @@ -101,11 +102,11 @@ def prepare_download(self):
file_path = download_info.get('file_path')
pre_status = EFileStatus(response.get('status'))
elif res.status_code == 403:
SrvErrorHandler.customized_handle(ECustomizedError.NO_FILE_PERMMISION, self.interactive)
SrvErrorHandler.customized_handle(ECustomizedError.NO_FILE_PERMMISION, if_exit=self.interactive)
elif res.status_code == 400 and 'number of file must greater than 0' in res_json.get('error_msg'):
SrvErrorHandler.customized_handle(ECustomizedError.FOLDER_EMPTY, self.interactive)
SrvErrorHandler.customized_handle(ECustomizedError.FOLDER_EMPTY, if_exit=self.interactive)
else:
SrvErrorHandler.customized_handle(ECustomizedError.DOWNLOAD_FAIL, self.interactive)
SrvErrorHandler.customized_handle(ECustomizedError.DOWNLOAD_FAIL, if_exit=self.interactive)

return pre_status, file_path

Expand Down
5 changes: 1 addition & 4 deletions app/services/file_manager/file_download/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@
from enum import Enum


class EFileStatus(Enum):
class EFileStatus(str, Enum):
WAITING = 'WAITING'
RUNNING = 'RUNNING'
SUCCEED = 'SUCCEED'
FAILED = 'FAILED'

def __str__(self):
return '%s' % self.name
7 changes: 3 additions & 4 deletions tests/app/commands/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def test_file_download_success(requests_mock, mocker, cli_runner, parent_folder_
{
'code': 200,
'result': {
'type': parent_folder_type,
'type': parent_folder_type.value,
'name': 'test',
'id': 'id',
},
Expand All @@ -244,13 +244,12 @@ def test_file_download_success(requests_mock, mocker, cli_runner, parent_folder_
return_value=None,
)

project_code, target_folder = 'testproject', 'test/test.txt'
project_code, target_folder = 'testproject', parent_folder_type.get_prefix_by_type() + 'test/test.txt'
result = cli_runner.invoke(file_download, [f'{project_code}/{target_folder}', './'])
outputs = result.output.split('\n')
assert outputs[0] == ''

except_target_folder = 'test/test.txt' if parent_folder_type == 'name_folder' else 'shared/test/test.txt'
search_mock.assert_called_with(project_code, 'greenroom', except_target_folder)
search_mock.assert_called_with(project_code, 'greenroom', target_folder)
download_mock.assert_called_once()


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Copyright (C) 2022-2024 Indoc Systems
#
# Contact Indoc Systems for any questions regarding the use of this source code.

import click
import jwt
import pytest
from pytest_httpx import IteratorStream

from app.configs.app_config import AppConfig
from app.models.item import ItemZone
from app.services.file_manager.file_download.download_client import SrvFileDownload
from app.services.file_manager.file_download.model import EFileStatus
from app.services.output_manager.error_handler import ECustomizedError
from app.services.output_manager.error_handler import customized_error_msg
from tests.conftest import decoded_token


@pytest.mark.parametrize('file_status', [EFileStatus.SUCCEED, EFileStatus.FAILED, EFileStatus.WAITING])
def test_file_download_client_prepare_download_success(mocker, httpx_mock, file_status: EFileStatus):
test_file_path = 'test_file_path'
hash_token = jwt.encode({'file_path': test_file_path}, key='unittest', algorithm='HS256').decode('utf-8')

mocker.patch(
'app.services.user_authentication.token_manager.SrvTokenManager.decode_access_token',
return_value=decoded_token(),
)

download_client = SrvFileDownload(0, False)
download_client.file_geid = ['test']
download_client.project_code = 'test_project'

httpx_mock.add_response(
url=download_client.appconfig.Connections.url_v2_download_pre % (download_client.project_code),
method='POST',
status_code=200,
json={
'result': {
'payload': {
'hash_code': hash_token,
},
'status': file_status.value,
}
},
)

pre_status, file_path = download_client.prepare_download()
assert pre_status == file_status
assert file_path == test_file_path


@pytest.mark.parametrize(
'status_code',
[
403,
400,
500,
],
)
def test_file_download_client_prepare_download_failed(mocker, httpx_mock, capfd, status_code: int):
mocker.patch(
'app.services.user_authentication.token_manager.SrvTokenManager.decode_access_token',
return_value=decoded_token(),
)

download_client = SrvFileDownload(0, True)
download_client.file_geid = ['test']
download_client.project_code = 'test_project'

httpx_mock.add_response(
url=download_client.appconfig.Connections.url_v2_download_pre % (download_client.project_code),
method='POST',
status_code=status_code,
json={'error_msg': 'number of file must greater than 0'},
)

try:
download_client.pre_download()
except SystemExit:
out, _ = capfd.readouterr()

expect = {
500: ECustomizedError.DOWNLOAD_FAIL,
403: ECustomizedError.NO_FILE_PERMMISION,
400: ECustomizedError.FOLDER_EMPTY,
}
assert out == customized_error_msg(expect.get(status_code)) + '\n'
else:
AssertionError('SystemExit not raised')


@pytest.mark.parametrize(
'zone',
[
ItemZone.GREENROOM.value,
ItemZone.CORE.value,
],
)
def test_file_download_url_based_on_different_zones(zone: str):
download_client = SrvFileDownload(0, True)
download_client.file_geid = ['test']
download_client.project_code = 'test_project'

url = download_client.get_download_url(zone)
except_url = {
ItemZone.GREENROOM.value: AppConfig.Connections.url_download_greenroom,
ItemZone.CORE.value: AppConfig.Connections.url_download_core,
}.get(zone)

assert url == except_url


@pytest.mark.parametrize(
'total_size_presented',
[True, False],
)
def test_file_stream_download(mocker, httpx_mock, total_size_presented):
file_url = 'http://test.com'
file_content = b'123'

mocker.patch(
'app.services.user_authentication.token_manager.SrvTokenManager.decode_access_token',
return_value=decoded_token(),
)

httpx_mock.add_response(
url=file_url,
method='GET',
status_code=200,
content=IteratorStream([file_content]),
)

runner = click.testing.CliRunner()
with runner.isolated_filesystem():
download_client = SrvFileDownload(0, True)
download_client.file_geid = ['test']
download_client.project_code = 'test_project'
download_client.total_size = len(file_content) if total_size_presented else None

download_client.download_file(file_url, 'test_file')

with open('test_file', 'r') as f:
assert f.read() == '123'