199 lines
6.4 KiB
Python
199 lines
6.4 KiB
Python
"""
|
|
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()
|