Skip to content

Commit bdebc3b

Browse files
aaronenbergcodingjoe
authored andcommitted
Fix #104 –– Add support for custom AWS_LOCATION or S3Boto3Storage.location (#105)
1 parent bd51d3e commit bdebc3b

File tree

6 files changed

+32
-12
lines changed

6 files changed

+32
-12
lines changed

s3file/forms.py

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from django.conf import settings
77
from django.utils.functional import cached_property
8+
from storages.utils import safe_join
89

910
from s3file.storages import storage
1011

@@ -18,6 +19,7 @@ class S3FileInputMixin:
1819
upload_path = getattr(
1920
settings, 'S3FILE_UPLOAD_PATH', pathlib.PurePosixPath('tmp', 's3file')
2021
)
22+
upload_path = safe_join(storage.location, upload_path)
2123
expires = settings.SESSION_COOKIE_AGE
2224

2325
@property

s3file/middleware.py

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def __call__(self, request):
2929
def get_files_from_storage(paths):
3030
"""Return S3 file where the name does not include the path."""
3131
for path in paths:
32+
path = path.replace(os.path.dirname(storage.location) + '/', '', 1)
3233
try:
3334
f = storage.open(path)
3435
f.name = os.path.basename(path)

s3file/storages.py

+9
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,21 @@
22
import datetime
33
import hmac
44
import json
5+
import os
56

67
from django.conf import settings
78
from django.core.files.storage import FileSystemStorage, default_storage
9+
from django.utils._os import safe_join
810

911

1012
class S3MockStorage(FileSystemStorage):
13+
@property
14+
def location(self):
15+
return settings.AWS_LOCATION
16+
17+
def path(self, name):
18+
return safe_join(os.path.abspath(self.base_location), self.location, name)
19+
1120
class connection:
1221
class meta:
1322
class client:

tests/test_forms.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
from contextlib import contextmanager
44

55
import pytest
6-
from django.core.files.storage import default_storage
76
from django.forms import ClearableFileInput
87
from selenium.common.exceptions import NoSuchElementException
98
from selenium.webdriver.support.expected_conditions import staleness_of
109
from selenium.webdriver.support.wait import WebDriverWait
1110

11+
from s3file.storages import storage
1212
from tests.testapp.forms import UploadForm
1313

1414
try:
@@ -35,11 +35,14 @@ def url(self):
3535
@pytest.fixture
3636
def freeze(self, monkeypatch):
3737
"""Freeze datetime and UUID."""
38-
monkeypatch.setattr('s3file.forms.S3FileInputMixin.upload_folder', 'tmp')
38+
monkeypatch.setattr(
39+
's3file.forms.S3FileInputMixin.upload_folder',
40+
os.path.join(storage.location, 'tmp'),
41+
)
3942

4043
def test_value_from_datadict(self, client, upload_file):
4144
with open(upload_file) as f:
42-
uploaded_file = default_storage.save('test.jpg', f)
45+
uploaded_file = storage.save('test.jpg', f)
4346
response = client.post(reverse('upload'), {
4447
'file': json.dumps([uploaded_file]),
4548
's3file': '["file"]',
@@ -96,7 +99,7 @@ def test_get_conditions(self, freeze):
9699
assert all(condition in conditions for condition in [
97100
{"bucket": 'test-bucket'},
98101
{"success_action_status": "201"},
99-
['starts-with', '$key', 'tmp'],
102+
['starts-with', '$key', 'custom/location/tmp'],
100103
["starts-with", "$Content-Type", ""]
101104
]), conditions
102105

@@ -139,7 +142,7 @@ def test_file_insert(self, request, driver, live_server, upload_file, freeze):
139142
assert file_input.get_attribute('name') == 'file'
140143
with wait_for_page_load(driver, timeout=10):
141144
file_input.submit()
142-
assert default_storage.exists('tmp/%s.txt' % request.node.name)
145+
assert storage.exists('tmp/%s.txt' % request.node.name)
143146

144147
with pytest.raises(NoSuchElementException):
145148
error = driver.find_element_by_xpath('//body[@JSError]')
@@ -208,5 +211,7 @@ def test_media(self):
208211
assert ClearableFileInput().media._js == ['s3file/js/s3file.js']
209212

210213
def test_upload_folder(self):
211-
assert ClearableFileInput().upload_folder.startswith('tmp/s3file/')
212-
assert len(ClearableFileInput().upload_folder) == 33
214+
assert ClearableFileInput().upload_folder.startswith(
215+
'custom/location/tmp/s3file/'
216+
)
217+
assert len(ClearableFileInput().upload_folder) == 49

tests/test_middleware.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
from django.core.files.base import ContentFile
2-
from django.core.files.storage import default_storage
32
from django.core.files.uploadedfile import SimpleUploadedFile
43

54
from s3file.middleware import S3FileMiddleware
5+
from s3file.storages import storage
66

77

88
class TestS3FileMiddleware:
99

1010
def test_get_files_from_storage(self):
1111
content = b'test_get_files_from_storage'
12-
default_storage.save('test_get_files_from_storage', ContentFile(content))
13-
files = S3FileMiddleware.get_files_from_storage(['test_get_files_from_storage'])
12+
name = storage.save('test_get_files_from_storage', ContentFile(content))
13+
files = S3FileMiddleware.get_files_from_storage([name])
1414
file = next(files)
1515
assert file.read() == content
1616

@@ -21,8 +21,10 @@ def test_process_request(self, rf):
2121
assert request.FILES.getlist('file')
2222
assert request.FILES.get('file').read() == b'uploaded'
2323

24-
default_storage.save('s3_file.txt', ContentFile(b's3file'))
25-
request = rf.post('/', data={'file': '["s3_file.txt"]', 's3file': '["file"]'})
24+
storage.save('s3_file.txt', ContentFile(b's3file'))
25+
request = rf.post('/', data={
26+
'file': '["custom/location/s3_file.txt"]', 's3file': '["file"]'
27+
})
2628
S3FileMiddleware(lambda x: None)(request)
2729
assert request.FILES.getlist('file')
2830
assert request.FILES.get('file').read() == b's3file'

tests/testapp/settings.py

+1
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,4 @@
5353
AWS_S3_REGION_NAME = 'eu-central-1'
5454
AWS_S3_SIGNATURE_VERSION = 's3v4'
5555
AWS_DEFAULT_ACL = None
56+
AWS_LOCATION = 'custom/location/'

0 commit comments

Comments
 (0)