Initial commit
This commit is contained in:
198
app/core/storage_strategy.py
Normal file
198
app/core/storage_strategy.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""
|
||||
Storage strategy interface and concrete implementations for file upload system.
|
||||
"""
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
import uuid
|
||||
|
||||
from app.core.upload_enums import UploadContext
|
||||
from app.core.upload_policies import UploadPolicy, get_upload_policy
|
||||
from app.core.config import settings
|
||||
|
||||
|
||||
class StorageStrategy(ABC):
|
||||
"""Abstract base class for storage strategies."""
|
||||
|
||||
@abstractmethod
|
||||
def get_storage_path(
|
||||
self,
|
||||
tenant_id: uuid.UUID,
|
||||
file_id: uuid.UUID,
|
||||
file_extension: str,
|
||||
metadata: Dict[str, Any]
|
||||
) -> Path:
|
||||
"""
|
||||
Generate the storage path for a file.
|
||||
|
||||
Args:
|
||||
tenant_id: The tenant ID
|
||||
file_id: The unique file ID
|
||||
file_extension: The file extension (e.g., ".jpg")
|
||||
metadata: Additional metadata that may influence path generation
|
||||
|
||||
Returns:
|
||||
Path object representing the file storage location
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_upload_policy(self) -> UploadPolicy:
|
||||
"""
|
||||
Get the upload policy for this storage strategy.
|
||||
|
||||
Returns:
|
||||
UploadPolicy object with constraints and rules
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class AvatarStorageStrategy(StorageStrategy):
|
||||
"""Storage strategy for user avatar files."""
|
||||
|
||||
def get_storage_path(
|
||||
self,
|
||||
tenant_id: uuid.UUID,
|
||||
file_id: uuid.UUID,
|
||||
file_extension: str,
|
||||
metadata: Dict[str, Any]
|
||||
) -> Path:
|
||||
"""
|
||||
Generate storage path for avatar files.
|
||||
Path format: {GENERIC_FILE_PATH}/avatars/{tenant_id}/{file_id}{extension}
|
||||
"""
|
||||
base_path = Path(settings.GENERIC_FILE_PATH)
|
||||
return base_path / "avatars" / str(tenant_id) / f"{file_id}{file_extension}"
|
||||
|
||||
def get_upload_policy(self) -> UploadPolicy:
|
||||
"""Get upload policy for avatar context."""
|
||||
return get_upload_policy(UploadContext.AVATAR)
|
||||
|
||||
|
||||
class AppIconStorageStrategy(StorageStrategy):
|
||||
"""Storage strategy for application icon files."""
|
||||
|
||||
def get_storage_path(
|
||||
self,
|
||||
tenant_id: uuid.UUID,
|
||||
file_id: uuid.UUID,
|
||||
file_extension: str,
|
||||
metadata: Dict[str, Any]
|
||||
) -> Path:
|
||||
"""
|
||||
Generate storage path for app icon files.
|
||||
Path format: {GENERIC_FILE_PATH}/app_icons/{tenant_id}/{file_id}{extension}
|
||||
"""
|
||||
base_path = Path(settings.GENERIC_FILE_PATH)
|
||||
return base_path / "app_icons" / str(tenant_id) / f"{file_id}{file_extension}"
|
||||
|
||||
def get_upload_policy(self) -> UploadPolicy:
|
||||
"""Get upload policy for app_icon context."""
|
||||
return get_upload_policy(UploadContext.APP_ICON)
|
||||
|
||||
|
||||
class KnowledgeBaseStorageStrategy(StorageStrategy):
|
||||
"""Storage strategy for knowledge base files."""
|
||||
|
||||
def get_storage_path(
|
||||
self,
|
||||
tenant_id: uuid.UUID,
|
||||
file_id: uuid.UUID,
|
||||
file_extension: str,
|
||||
metadata: Dict[str, Any]
|
||||
) -> Path:
|
||||
"""
|
||||
Generate storage path for knowledge base files.
|
||||
Path format: {GENERIC_FILE_PATH}/knowledge_base/{tenant_id}/{kb_id}/{file_id}{extension}
|
||||
|
||||
If kb_id is provided in metadata, it will be included in the path for compatibility
|
||||
with existing knowledge base file structure.
|
||||
"""
|
||||
base_path = Path(settings.GENERIC_FILE_PATH)
|
||||
kb_id = metadata.get("kb_id")
|
||||
|
||||
if kb_id:
|
||||
# Include kb_id in path for compatibility with existing structure
|
||||
return base_path / "knowledge_base" / str(tenant_id) / str(kb_id) / f"{file_id}{file_extension}"
|
||||
else:
|
||||
# Default path without kb_id
|
||||
return base_path / "knowledge_base" / str(tenant_id) / f"{file_id}{file_extension}"
|
||||
|
||||
def get_upload_policy(self) -> UploadPolicy:
|
||||
"""Get upload policy for knowledge_base context."""
|
||||
return get_upload_policy(UploadContext.KNOWLEDGE_BASE)
|
||||
|
||||
|
||||
class TempStorageStrategy(StorageStrategy):
|
||||
"""Storage strategy for temporary files."""
|
||||
|
||||
def get_storage_path(
|
||||
self,
|
||||
tenant_id: uuid.UUID,
|
||||
file_id: uuid.UUID,
|
||||
file_extension: str,
|
||||
metadata: Dict[str, Any]
|
||||
) -> Path:
|
||||
"""
|
||||
Generate storage path for temporary files.
|
||||
Path format: {GENERIC_FILE_PATH}/temp/{tenant_id}/{file_id}{extension}
|
||||
"""
|
||||
base_path = Path(settings.GENERIC_FILE_PATH)
|
||||
return base_path / "temp" / str(tenant_id) / f"{file_id}{file_extension}"
|
||||
|
||||
def get_upload_policy(self) -> UploadPolicy:
|
||||
"""Get upload policy for temp context."""
|
||||
return get_upload_policy(UploadContext.TEMP)
|
||||
|
||||
|
||||
class AttachmentStorageStrategy(StorageStrategy):
|
||||
"""Storage strategy for attachment files."""
|
||||
|
||||
def get_storage_path(
|
||||
self,
|
||||
tenant_id: uuid.UUID,
|
||||
file_id: uuid.UUID,
|
||||
file_extension: str,
|
||||
metadata: Dict[str, Any]
|
||||
) -> Path:
|
||||
"""
|
||||
Generate storage path for attachment files.
|
||||
Path format: {GENERIC_FILE_PATH}/attachments/{tenant_id}/{file_id}{extension}
|
||||
"""
|
||||
base_path = Path(settings.GENERIC_FILE_PATH)
|
||||
return base_path / "attachments" / str(tenant_id) / f"{file_id}{file_extension}"
|
||||
|
||||
def get_upload_policy(self) -> UploadPolicy:
|
||||
"""Get upload policy for attachment context."""
|
||||
return get_upload_policy(UploadContext.ATTACHMENT)
|
||||
|
||||
|
||||
class StrategyFactory:
|
||||
"""Factory class for creating storage strategies based on upload context."""
|
||||
|
||||
_strategies = {
|
||||
UploadContext.AVATAR: AvatarStorageStrategy,
|
||||
UploadContext.APP_ICON: AppIconStorageStrategy,
|
||||
UploadContext.KNOWLEDGE_BASE: KnowledgeBaseStorageStrategy,
|
||||
UploadContext.TEMP: TempStorageStrategy,
|
||||
UploadContext.ATTACHMENT: AttachmentStorageStrategy,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_strategy(cls, context: UploadContext) -> StorageStrategy:
|
||||
"""
|
||||
Get the appropriate storage strategy for the given context.
|
||||
|
||||
Args:
|
||||
context: The upload context
|
||||
|
||||
Returns:
|
||||
An instance of the appropriate StorageStrategy
|
||||
|
||||
Raises:
|
||||
ValueError: If no strategy is defined for the given context
|
||||
"""
|
||||
strategy_class = cls._strategies.get(context)
|
||||
if strategy_class is None:
|
||||
raise ValueError(f"No storage strategy defined for context: {context}")
|
||||
return strategy_class()
|
||||
Reference in New Issue
Block a user