first commit
This commit is contained in:
commit
34ea15a54d
246 changed files with 18660 additions and 0 deletions
0
backend/app/utils/__init__.py
Normal file
0
backend/app/utils/__init__.py
Normal file
74
backend/app/utils/storage.py
Normal file
74
backend/app/utils/storage.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
class StorageBackend(ABC):
|
||||
@abstractmethod
|
||||
def save(self, key: str, data: bytes) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def public_url(self, key: str) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LocalStorage(StorageBackend):
|
||||
def __init__(self, root: str) -> None:
|
||||
self.root = Path(root)
|
||||
self.root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def save(self, key: str, data: bytes) -> str:
|
||||
path = self.root / key.replace("\\", "/").lstrip("/")
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_bytes(data)
|
||||
return key.replace("\\", "/").lstrip("/")
|
||||
|
||||
def public_url(self, key: str) -> str:
|
||||
normalized = key.replace("\\", "/").lstrip("/")
|
||||
return f"/media/{normalized}"
|
||||
|
||||
|
||||
class S3Storage(StorageBackend):
|
||||
def __init__(self) -> None:
|
||||
import boto3
|
||||
|
||||
if not settings.s3_bucket:
|
||||
raise RuntimeError("S3_BUCKET is required when STORAGE_BACKEND=s3")
|
||||
self.bucket = settings.s3_bucket
|
||||
self.client = boto3.client(
|
||||
"s3",
|
||||
region_name=settings.aws_region,
|
||||
aws_access_key_id=settings.aws_access_key_id,
|
||||
aws_secret_access_key=settings.aws_secret_access_key,
|
||||
)
|
||||
base = settings.s3_public_base_url
|
||||
self.public_base = (
|
||||
base.rstrip("/") if base else f"https://{self.bucket}.s3.{settings.aws_region}.amazonaws.com"
|
||||
)
|
||||
|
||||
def save(self, key: str, data: bytes) -> str:
|
||||
normalized = key.replace("\\", "/").lstrip("/")
|
||||
self.client.put_object(Bucket=self.bucket, Key=normalized, Body=data)
|
||||
return normalized
|
||||
|
||||
def public_url(self, key: str) -> str:
|
||||
normalized = key.replace("\\", "/").lstrip("/")
|
||||
return f"{self.public_base}/{normalized}"
|
||||
|
||||
|
||||
_storage: StorageBackend | None = None
|
||||
|
||||
|
||||
def get_storage() -> StorageBackend:
|
||||
global _storage
|
||||
if _storage is None:
|
||||
backend = settings.storage_backend.lower()
|
||||
if backend == "s3":
|
||||
_storage = S3Storage()
|
||||
else:
|
||||
_storage = LocalStorage(settings.upload_dir)
|
||||
return _storage
|
||||
Loading…
Add table
Add a link
Reference in a new issue