diff --git a/.dockerignore b/.dockerignore index a5130c8bd..5edf3de0d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,3 +5,4 @@ __pycache__ .git .github .pytest* +.env diff --git a/.env.example b/.env.example index 2be08224b..3b541eb7c 100644 --- a/.env.example +++ b/.env.example @@ -82,6 +82,12 @@ AWS_SECRET_ACCESS_KEY= # AWS_S3_REGION_NAME=None # "fr-par" # AWS_S3_ENDPOINT_URL=None # "https://s3.fr-par.scw.cloud" +# Commented are example values if you use Azure Blob Storage +# USE_AZURE=true +# AZURE_ACCOUNT_NAME= # "example-account-name" +# AZURE_ACCOUNT_KEY= # "base64-encoded-access-key" +# AZURE_CONTAINER= # "example-blob-container-name" +# AZURE_CUSTOM_DOMAIN= # "example-account-name.blob.core.windows.net" # Preview image generation can be computing and storage intensive ENABLE_PREVIEW_IMAGES=False diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 3b6a8f329..b54866e69 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -344,6 +344,7 @@ if USE_HTTPS: CSRF_COOKIE_SECURE = True USE_S3 = env.bool("USE_S3", False) +USE_AZURE = env.bool("USE_AZURE", False) if USE_S3: # AWS settings @@ -367,6 +368,27 @@ if USE_S3: DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.ImagesStorage" CSP_DEFAULT_SRC = ["'self'", AWS_S3_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS CSP_SCRIPT_SRC = ["'self'", AWS_S3_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS +elif USE_AZURE: + AZURE_ACCOUNT_NAME = env("AZURE_ACCOUNT_NAME") + AZURE_ACCOUNT_KEY = env("AZURE_ACCOUNT_KEY") + AZURE_CONTAINER = env("AZURE_CONTAINER") + AZURE_CUSTOM_DOMAIN = env("AZURE_CUSTOM_DOMAIN") + # Azure Static settings + STATIC_LOCATION = "static" + STATIC_URL = ( + f"{PROTOCOL}://{AZURE_CUSTOM_DOMAIN}/{AZURE_CONTAINER}/{STATIC_LOCATION}/" + ) + STATICFILES_STORAGE = "bookwyrm.storage_backends.AzureStaticStorage" + # Azure Media settings + MEDIA_LOCATION = "images" + MEDIA_URL = ( + f"{PROTOCOL}://{AZURE_CUSTOM_DOMAIN}/{AZURE_CONTAINER}/{MEDIA_LOCATION}/" + ) + MEDIA_FULL_URL = MEDIA_URL + STATIC_FULL_URL = STATIC_URL + DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.AzureImagesStorage" + CSP_DEFAULT_SRC = ["'self'", AZURE_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS + CSP_SCRIPT_SRC = ["'self'", AZURE_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS else: STATIC_URL = "/static/" MEDIA_URL = "/images/" diff --git a/bookwyrm/storage_backends.py b/bookwyrm/storage_backends.py index 4fb0feff0..6dd9f522c 100644 --- a/bookwyrm/storage_backends.py +++ b/bookwyrm/storage_backends.py @@ -2,6 +2,7 @@ import os from tempfile import SpooledTemporaryFile from storages.backends.s3boto3 import S3Boto3Storage +from storages.backends.azure_storage import AzureStorage class StaticStorage(S3Boto3Storage): # pylint: disable=abstract-method @@ -47,3 +48,16 @@ class ImagesStorage(S3Boto3Storage): # pylint: disable=abstract-method # Upload the object which will auto close the # content_autoclose instance return super()._save(name, content_autoclose) + + +class AzureStaticStorage(AzureStorage): # pylint: disable=abstract-method + """Storage class for Static contents""" + + location = "static" + + +class AzureImagesStorage(AzureStorage): # pylint: disable=abstract-method + """Storage class for Image files""" + + location = "images" + overwrite_files = False diff --git a/requirements.txt b/requirements.txt index b63c1f30c..5737d827d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,7 @@ responses==0.22.0 pytz>=2022.7 boto3==1.26.57 django-storages==1.13.2 +django-storages[azure] django-redis==5.2.0 opentelemetry-api==1.11.1 opentelemetry-exporter-otlp-proto-grpc==1.11.1