forked from mitodl/edx-sga
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: backend to supports multiple aws s3 buckets
- Loading branch information
Showing
3 changed files
with
175 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from storages.backends.s3boto3 import S3Boto3Storage | ||
from django.core.files.storage import default_storage | ||
|
||
AWS_S3_FIELDS = [ | ||
'aws_s3_access_key', | ||
'aws_s3_secret_key', | ||
'aws_s3_bucket_name', | ||
'aws_s3_region_name' | ||
] | ||
|
||
class StaffGradedAssignmentStorage: | ||
def __init__(self, aws_s3_bucket): | ||
self.aws_s3_storage = None | ||
|
||
if aws_s3_bucket: | ||
self.check_s3_bucket_keys(aws_s3_bucket) | ||
self.aws_s3_storage = S3Boto3Storage( | ||
access_key=aws_s3_bucket.get('aws_s3_access_key'), | ||
secret_key=aws_s3_bucket.get('aws_s3_secret_key'), | ||
bucket_name=aws_s3_bucket.get('aws_s3_bucket_name'), | ||
region_name=aws_s3_bucket.get('aws_s3_region_name') | ||
) | ||
|
||
def check_s3_bucket_keys(self, settings_dict): | ||
""" | ||
Method checks integrity and structure of the Xblock settings given. | ||
""" | ||
if not isinstance(settings_dict, dict): | ||
raise ValueError("Wrong XBlock settings definition. Expected dict.") | ||
|
||
for aws_s3_field in AWS_S3_FIELDS: | ||
if aws_s3_field not in settings_dict.keys() or not settings_dict[aws_s3_field]: | ||
raise ValueError(f"Error on Xblock settings with field '{aws_s3_field}'.") | ||
|
||
for value, key in settings_dict.items(): | ||
if not value and isinstance(value, str): | ||
raise ValueError(f"Value error on Xblock Settings: {key}.") | ||
|
||
def sga_storage(self): | ||
""" | ||
Returns the storage to be used wheter the default Django's storage or AWS S3 Bucket | ||
""" | ||
return self.aws_s3_storage if self.aws_s3_storage else default_storage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
|
||
import unittest | ||
from unittest.mock import MagicMock, patch | ||
from django.core.files.storage import default_storage | ||
from edx_sga.backends import StaffGradedAssignmentStorage | ||
|
||
|
||
class StaffGradedAssignmentStorageTest(unittest.TestCase): | ||
|
||
@patch('edx_sga.backends.S3Boto3Storage') | ||
def test_returns_s3_storage_xblock_settings_given(self, mock_s3_aws_storage): | ||
""" | ||
Test StaffGradedAssignmentStorage to return a valid S3 storage when the bucket data is given | ||
""" | ||
xblock_settings = { | ||
'aws_s3_access_key': 'access_key', | ||
'aws_s3_secret_key': 'secret_key', | ||
'aws_s3_bucket_name': 'bucket_name', | ||
'aws_s3_region_name': 'region_name' | ||
} | ||
|
||
xblock_storage = StaffGradedAssignmentStorage(xblock_settings).sga_storage() | ||
|
||
mock_s3_aws_storage.assert_called_with( | ||
access_key='access_key', | ||
secret_key='secret_key', | ||
bucket_name='bucket_name', | ||
region_name='region_name' | ||
) | ||
|
||
self.assertEqual(xblock_storage, mock_s3_aws_storage.return_value) | ||
|
||
def test_returns_default_storage_xblock_settings_no_given(self): | ||
""" | ||
Test StaffGradedAssignmentStorage to return the default Django's storage when no settings are defined | ||
""" | ||
xblock_settings = None | ||
|
||
xblock_storage = StaffGradedAssignmentStorage(xblock_settings).sga_storage() | ||
self.assertEqual(xblock_storage, default_storage) | ||
|
||
def test_check_s3_bucket_proper_values(self): | ||
""" | ||
Checks for check_s3_bucket_keys method to check and return the data given in the format expected. | ||
""" | ||
xblock_settings = { | ||
'aws_s3_access_key': 'access_key', | ||
'aws_s3_secret_key': 'secret_key', | ||
'aws_s3_bucket_name': 'bucket_name', | ||
'aws_s3_region_name': 'region_name' | ||
} | ||
|
||
try: | ||
xblock_storage_instance = StaffGradedAssignmentStorage(xblock_settings) | ||
xblock_storage_instance.check_s3_bucket_keys(xblock_settings) | ||
except ValueError: | ||
self.fail('Unexpected raise from check_s3_bucket_keys method.') | ||
|
||
|
||
def test_check_s3_bucket_incomplete_values(self): | ||
""" | ||
Checks for check_s3_bucket_keys method to raises an exception when the data passed doesn't fullfils the needs. | ||
""" | ||
xblock_settings = { | ||
'aws_s3_access_key': 'access_key', | ||
'aws_s3_secret_key': 'secret_key', | ||
} | ||
xblock_storage_instance = StaffGradedAssignmentStorage(None) | ||
with self.assertRaises(ValueError) as exception: | ||
xblock_storage_instance.check_s3_bucket_keys(xblock_settings) | ||
self.assertIn("Error on Xblock settings with field 'aws_s3_bucket_name'", str(exception.exception)) | ||
|
||
def test_sga_storage_returns_defined_storage(self): | ||
""" | ||
Test for StaffGradedAssignmentStorage to have assigned the expected storage when the data is passed | ||
""" | ||
mock_aws_s3_storage = MagicMock(name='MockS3Storage') | ||
xblock_settings = { | ||
'aws_s3_access_key': 'access_key', | ||
'aws_s3_secret_key': 'secret_key', | ||
'aws_s3_bucket_name': 'bucket_name', | ||
'aws_s3_region_name': 'region_name' | ||
} | ||
|
||
sga_storage_instance = StaffGradedAssignmentStorage(xblock_settings) | ||
sga_storage_instance.aws_s3_storage = mock_aws_s3_storage | ||
|
||
result = sga_storage_instance.sga_storage() | ||
self.assertEqual(result, mock_aws_s3_storage) | ||
|
||
@patch('edx_sga.backends.default_storage') | ||
def test_sga_storage_returns_default_storage(self, mock_default_storage): | ||
""" | ||
Test for StaffGradedAssignmentStorage to uses the Django's default storage. | ||
""" | ||
sga_storage_instance = StaffGradedAssignmentStorage({}) | ||
sga_storage_instance.aws_s3_storage = None | ||
|
||
result = sga_storage_instance.sga_storage() | ||
self.assertEqual(result, mock_default_storage) |