Skip to content

Commit 3c96ce1

Browse files
author
bkwi
authored
Upload external urls using /process endpoint (#54)
1 parent e5528ae commit 3c96ce1

File tree

3 files changed

+55
-75
lines changed

3 files changed

+55
-75
lines changed

filestack/uploads/external_url.py

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,31 @@
1-
import base64
2-
from collections import OrderedDict
3-
4-
from filestack.utils import requests
5-
61
from filestack import config
2+
from filestack.utils import requests
73

84

9-
def build_store_task(store_params):
10-
if not store_params:
11-
return 'store'
12-
13-
task_args = []
14-
store_params = OrderedDict(sorted(store_params.items(), key=lambda t: t[0]))
15-
for key, value in store_params.items():
16-
if key in ('filename', 'location', 'path', 'container', 'region', 'access', 'base64decode', 'workflows'):
17-
if key == 'workflows':
18-
value = '[{}]'.format(','.join('"{}"'.format(item) for item in value))
19-
if key == 'path':
20-
value = '"{}"'.format(value)
21-
task_args.append('{}:{}'.format(key, str(value).lower()))
22-
23-
return 'store={}'.format(','.join(task_args))
5+
def upload_external_url(url, apikey, store_params=None, security=None):
6+
store_params = store_params or {}
247

8+
# remove params that are currently not supported in external url upload
9+
for item in ('mimetype', 'upload_tags'):
10+
store_params.pop(item, None)
2511

26-
def upload_external_url(url, apikey, store_params=None, security=None):
27-
store_task = build_store_task(store_params or {})
28-
encoded_url = 'b64://{}'.format(base64.urlsafe_b64encode(url.encode()).decode())
29-
url_elements = [config.CDN_URL, apikey, store_task, encoded_url]
12+
payload = {
13+
'apikey': apikey,
14+
'sources': [url],
15+
'tasks': [{
16+
'name': 'store',
17+
'params': store_params
18+
}]
19+
}
3020

3121
if security is not None:
32-
url_elements.insert(3, security.as_url_string())
33-
34-
# TODO: use processing endpoint and "store" task for uploading external urls
35-
response = requests.get('/'.join(url_elements))
22+
payload['tasks'].append({
23+
'name': 'security',
24+
'params': {
25+
'policy': security.policy_b64,
26+
'signature': security.signature
27+
}
28+
})
29+
30+
response = requests.post('{}/process'.format(config.CDN_URL), json=payload)
3631
return response.json()['handle']

tests/client_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_wrong_storage():
2929

3030

3131
def test_store_external_url(client):
32-
@urlmatch(netloc=r'cdn.filestackcontent\.com', method='get', scheme='https')
32+
@urlmatch(netloc=r'cdn.filestackcontent\.com', method='post', scheme='https')
3333
def api_store(url, request):
3434
return response(200, {'handle': HANDLE})
3535

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,48 @@
1-
import base64
21
from unittest.mock import patch
32

43
import pytest
54

65
from tests.helpers import DummyHttpResponse
76
from filestack import config
8-
from filestack.models import Security
97
from filestack.uploads.external_url import upload_external_url
108

119
url = 'http://image.url'
12-
encoded_url = 'b64://{}'.format(base64.urlsafe_b64encode(url.encode()).decode())
1310
apikey = 'TESTAPIKEY'
1411

1512

16-
@patch('filestack.uploads.external_url.requests.get')
17-
def test_upload(post_mock):
18-
post_mock.return_value = DummyHttpResponse(json_dict={'handle': 'newHandle'})
19-
20-
handle = upload_external_url(url, apikey)
21-
assert handle == 'newHandle'
22-
post_mock.assert_called_once_with('{}/{}/store/{}'.format(config.CDN_URL, apikey, encoded_url))
23-
24-
25-
@pytest.mark.parametrize('store_params, expected_store_task', [
26-
[{'location': 'S3'}, 'store=location:s3'],
27-
[{'path': 'store/path/image.jpg'}, 'store=path:"store/path/image.jpg"'],
28-
[{'base64decode': True, 'access': 'public'}, 'store=access:public,base64decode:true'],
29-
[
30-
{'workflows': ['uuid-1', 'uuid-2'], 'container': 'bucket-name'},
31-
'store=container:bucket-name,workflows:["uuid-1","uuid-2"]'
32-
],
13+
@pytest.mark.parametrize('store_params, security, expected_store_tasks', [
14+
(
15+
{'location': 's3'},
16+
None,
17+
[
18+
{
19+
'name': 'store', 'params': {'location': 's3'}
20+
}
21+
]
22+
),
23+
(
24+
{'path': 'new-path/', 'mimetype': 'application/json'},
25+
type('SecurityMock', (), {'policy_b64': 'abc', 'signature': '123'}),
26+
[
27+
{
28+
'name': 'store', 'params': {'path': 'new-path/'}
29+
},
30+
{
31+
'name': 'security', 'params': {'policy': 'abc', 'signature': '123'}
32+
}
33+
]
34+
)
3335
])
34-
@patch('filestack.uploads.external_url.requests.get')
35-
def test_upload_with_store_params(post_mock, store_params, expected_store_task):
36+
@patch('filestack.uploads.external_url.requests.post')
37+
def test_upload_with_store_params(post_mock, store_params, security, expected_store_tasks):
38+
expected_payload = {
39+
'apikey': 'TESTAPIKEY',
40+
'sources': ['http://image.url'],
41+
'tasks': expected_store_tasks
42+
}
3643
post_mock.return_value = DummyHttpResponse(json_dict={'handle': 'newHandle'})
3744

38-
handle = upload_external_url(url, apikey, store_params=store_params)
45+
handle = upload_external_url(url, apikey, store_params=store_params, security=security)
3946
assert handle == 'newHandle'
4047
post_args, _ = post_mock.call_args
41-
req_url = post_args[0]
42-
assert expected_store_task in req_url
43-
44-
45-
@patch('filestack.uploads.external_url.requests.get')
46-
def test_upload_with_security(post_mock):
47-
post_mock.return_value = DummyHttpResponse(json_dict={'handle': 'newHandle'})
48-
security = Security({'expiry': 123123123123, 'call': ['write']}, 'SECRET')
49-
handle = upload_external_url(url, apikey, security=security)
50-
assert handle == 'newHandle'
51-
expected_url = '{}/{}/store/{}/{}'.format(
52-
config.CDN_URL, apikey, security.as_url_string(), encoded_url
53-
)
54-
post_mock.assert_called_once_with(expected_url)
55-
56-
57-
@patch('filestack.uploads.external_url.requests.get')
58-
def test_upload_exception(post_mock):
59-
error_message = 'Oops!'
60-
post_mock.side_effect = Exception(error_message)
61-
62-
with pytest.raises(Exception, match=error_message):
63-
upload_external_url(url, apikey)
48+
post_mock.assert_called_once_with('{}/process'.format(config.CDN_URL), json=expected_payload)

0 commit comments

Comments
 (0)