semantic
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
# #region StoragePlugin [TYPE Module] [SEMANTICS fastapi, storage, filesystem, backup, archive]
|
||||
#
|
||||
# @BRIEF Provides core filesystem operations for managing backups and repositories.
|
||||
# @LAYER: App
|
||||
# @RELATION IMPLEMENTS -> PluginBase
|
||||
# @RELATION DEPENDS_ON -> backend.src.models.storage
|
||||
# @LAYER App
|
||||
# @RELATION USES -> TaskContext
|
||||
#
|
||||
# @INVARIANT: All file operations must be restricted to the configured storage root.
|
||||
# @RELATION USES -> TaskContext
|
||||
# @RELATION USES -> TaskContext
|
||||
# @INVARIANT All file operations must be restricted to the configured storage root.
|
||||
# @RATIONALE Replaced Path(__file__).parents[3] with BASE_DIR import from database.py for path resolution consistency.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from typing import Any
|
||||
|
||||
from fastapi import UploadFile
|
||||
@@ -31,9 +30,9 @@ class StoragePlugin(PluginBase):
|
||||
"""
|
||||
|
||||
# region __init__ [TYPE Function]
|
||||
# @PURPOSE: Initializes the StoragePlugin and ensures required directories exist.
|
||||
# @PRE: Configuration manager must be accessible.
|
||||
# @POST: Storage root and category directories are created on disk.
|
||||
# @PURPOSE Initializes the StoragePlugin and ensures required directories exist.
|
||||
# @PRE Configuration manager must be accessible.
|
||||
# @POST Storage root and category directories are created on disk.
|
||||
def __init__(self):
|
||||
with belief_scope("StoragePlugin:init"):
|
||||
self.ensure_directories()
|
||||
@@ -41,10 +40,10 @@ class StoragePlugin(PluginBase):
|
||||
|
||||
@property
|
||||
# region id [TYPE Function]
|
||||
# @PURPOSE: Returns the unique identifier for the storage plugin.
|
||||
# @PRE: None.
|
||||
# @POST: Returns the plugin ID string.
|
||||
# @RETURN: str - "storage-manager"
|
||||
# @PURPOSE Returns the unique identifier for the storage plugin.
|
||||
# @PRE None.
|
||||
# @POST Returns the plugin ID string.
|
||||
# @RETURN str - "storage-manager"
|
||||
def id(self) -> str:
|
||||
with belief_scope("StoragePlugin:id"):
|
||||
return "storage-manager"
|
||||
@@ -52,10 +51,10 @@ class StoragePlugin(PluginBase):
|
||||
|
||||
@property
|
||||
# region name [TYPE Function]
|
||||
# @PURPOSE: Returns the human-readable name of the storage plugin.
|
||||
# @PRE: None.
|
||||
# @POST: Returns the plugin name string.
|
||||
# @RETURN: str - "Storage Manager"
|
||||
# @PURPOSE Returns the human-readable name of the storage plugin.
|
||||
# @PRE None.
|
||||
# @POST Returns the plugin name string.
|
||||
# @RETURN str - "Storage Manager"
|
||||
def name(self) -> str:
|
||||
with belief_scope("StoragePlugin:name"):
|
||||
return "Storage Manager"
|
||||
@@ -63,10 +62,10 @@ class StoragePlugin(PluginBase):
|
||||
|
||||
@property
|
||||
# region description [TYPE Function]
|
||||
# @PURPOSE: Returns a description of the storage plugin.
|
||||
# @PRE: None.
|
||||
# @POST: Returns the plugin description string.
|
||||
# @RETURN: str - Plugin description.
|
||||
# @PURPOSE Returns a description of the storage plugin.
|
||||
# @PRE None.
|
||||
# @POST Returns the plugin description string.
|
||||
# @RETURN str - Plugin description.
|
||||
def description(self) -> str:
|
||||
with belief_scope("StoragePlugin:description"):
|
||||
return "Manages local file storage for backups and repositories."
|
||||
@@ -74,10 +73,10 @@ class StoragePlugin(PluginBase):
|
||||
|
||||
@property
|
||||
# region version [TYPE Function]
|
||||
# @PURPOSE: Returns the version of the storage plugin.
|
||||
# @PRE: None.
|
||||
# @POST: Returns the version string.
|
||||
# @RETURN: str - "1.0.0"
|
||||
# @PURPOSE Returns the version of the storage plugin.
|
||||
# @PRE None.
|
||||
# @POST Returns the version string.
|
||||
# @RETURN str - "1.0.0"
|
||||
def version(self) -> str:
|
||||
with belief_scope("StoragePlugin:version"):
|
||||
return "1.0.0"
|
||||
@@ -85,18 +84,18 @@ class StoragePlugin(PluginBase):
|
||||
|
||||
@property
|
||||
# region ui_route [TYPE Function]
|
||||
# @PURPOSE: Returns the frontend route for the storage plugin.
|
||||
# @RETURN: str - "/tools/storage"
|
||||
# @PURPOSE Returns the frontend route for the storage plugin.
|
||||
# @RETURN str - "/tools/storage"
|
||||
def ui_route(self) -> str:
|
||||
with belief_scope("StoragePlugin:ui_route"):
|
||||
return "/tools/storage"
|
||||
# endregion ui_route
|
||||
|
||||
# region get_schema [TYPE Function]
|
||||
# @PURPOSE: Returns the JSON schema for storage plugin parameters.
|
||||
# @PRE: None.
|
||||
# @POST: Returns a dictionary representing the JSON schema.
|
||||
# @RETURN: Dict[str, Any] - JSON schema.
|
||||
# @PURPOSE Returns the JSON schema for storage plugin parameters.
|
||||
# @PRE None.
|
||||
# @POST Returns a dictionary representing the JSON schema.
|
||||
# @RETURN Dict[str, Any] - JSON schema.
|
||||
def get_schema(self) -> dict[str, Any]:
|
||||
with belief_scope("StoragePlugin:get_schema"):
|
||||
return {
|
||||
@@ -113,11 +112,11 @@ class StoragePlugin(PluginBase):
|
||||
# endregion get_schema
|
||||
|
||||
# region execute [TYPE Function]
|
||||
# @PURPOSE: Executes storage-related tasks with TaskContext support.
|
||||
# @PARAM: params (Dict[str, Any]) - Storage parameters.
|
||||
# @PARAM: context (Optional[TaskContext]) - Task context for logging with source attribution.
|
||||
# @PRE: params must match the plugin schema.
|
||||
# @POST: Task is executed and logged.
|
||||
# @PURPOSE Executes storage-related tasks with TaskContext support.
|
||||
# @PARAM params (Dict[str, Any]) - Storage parameters.
|
||||
# @PARAM context (Optional[TaskContext]) - Task context for logging with source attribution.
|
||||
# @PRE params must match the plugin schema.
|
||||
# @POST Task is executed and logged.
|
||||
async def execute(self, params: dict[str, Any], context: TaskContext | None = None):
|
||||
with belief_scope("StoragePlugin:execute"):
|
||||
# Use TaskContext logger if available, otherwise fall back to app logger
|
||||
@@ -131,9 +130,9 @@ class StoragePlugin(PluginBase):
|
||||
# endregion execute
|
||||
|
||||
# region get_storage_root [TYPE Function]
|
||||
# @PURPOSE: Resolves the absolute path to the storage root.
|
||||
# @PRE: Settings must define a storage root path.
|
||||
# @POST: Returns a Path object representing the storage root.
|
||||
# @PURPOSE Resolves the absolute path to the storage root.
|
||||
# @PRE Settings must define a storage root path.
|
||||
# @POST Returns a Path object representing the storage root.
|
||||
def get_storage_root(self) -> Path:
|
||||
with belief_scope("StoragePlugin:get_storage_root"):
|
||||
config_manager = get_config_manager()
|
||||
@@ -153,12 +152,12 @@ class StoragePlugin(PluginBase):
|
||||
# endregion get_storage_root
|
||||
|
||||
# region resolve_path [TYPE Function]
|
||||
# @PURPOSE: Resolves a dynamic path pattern using provided variables.
|
||||
# @PARAM: pattern (str) - The path pattern to resolve.
|
||||
# @PARAM: variables (Dict[str, str]) - Variables to substitute in the pattern.
|
||||
# @PRE: pattern must be a valid format string.
|
||||
# @POST: Returns the resolved path string.
|
||||
# @RETURN: str - The resolved path.
|
||||
# @PURPOSE Resolves a dynamic path pattern using provided variables.
|
||||
# @PARAM pattern (str) - The path pattern to resolve.
|
||||
# @PARAM variables (Dict[str, str]) - Variables to substitute in the pattern.
|
||||
# @PRE pattern must be a valid format string.
|
||||
# @POST Returns the resolved path string.
|
||||
# @RETURN str - The resolved path.
|
||||
def resolve_path(self, pattern: str, variables: dict[str, str]) -> str:
|
||||
with belief_scope("StoragePlugin:resolve_path"):
|
||||
# Add common variables
|
||||
@@ -177,10 +176,10 @@ class StoragePlugin(PluginBase):
|
||||
# endregion resolve_path
|
||||
|
||||
# region ensure_directories [TYPE Function]
|
||||
# @PURPOSE: Creates the storage root and category subdirectories if they don't exist.
|
||||
# @PRE: Storage root must be resolvable.
|
||||
# @POST: Directories are created on the filesystem.
|
||||
# @SIDE_EFFECT: Creates directories on the filesystem.
|
||||
# @PURPOSE Creates the storage root and category subdirectories if they don't exist.
|
||||
# @PRE Storage root must be resolvable.
|
||||
# @POST Directories are created on the filesystem.
|
||||
# @SIDE_EFFECT Creates directories on the filesystem.
|
||||
def ensure_directories(self):
|
||||
with belief_scope("StoragePlugin:ensure_directories"):
|
||||
root = self.get_storage_root()
|
||||
@@ -192,9 +191,9 @@ class StoragePlugin(PluginBase):
|
||||
# endregion ensure_directories
|
||||
|
||||
# region validate_path [TYPE Function]
|
||||
# @PURPOSE: Prevents path traversal attacks by ensuring the path is within the storage root.
|
||||
# @PRE: path must be a Path object.
|
||||
# @POST: Returns the resolved absolute path if valid, otherwise raises ValueError.
|
||||
# @PURPOSE Prevents path traversal attacks by ensuring the path is within the storage root.
|
||||
# @PRE path must be a Path object.
|
||||
# @POST Returns the resolved absolute path if valid, otherwise raises ValueError.
|
||||
def validate_path(self, path: Path) -> Path:
|
||||
with belief_scope("StoragePlugin:validate_path"):
|
||||
root = self.get_storage_root().resolve()
|
||||
@@ -208,13 +207,13 @@ class StoragePlugin(PluginBase):
|
||||
# endregion validate_path
|
||||
|
||||
# region list_files [TYPE Function]
|
||||
# @PURPOSE: Lists all files and directories in a specific category and subpath.
|
||||
# @PARAM: category (Optional[FileCategory]) - The category to list.
|
||||
# @PARAM: subpath (Optional[str]) - Nested path within the category.
|
||||
# @PARAM: recursive (bool) - Whether to scan nested subdirectories recursively.
|
||||
# @PRE: Storage root must exist.
|
||||
# @POST: Returns a list of StoredFile objects.
|
||||
# @RETURN: List[StoredFile] - List of file and directory metadata objects.
|
||||
# @PURPOSE Lists all files and directories in a specific category and subpath.
|
||||
# @PARAM category (Optional[FileCategory]) - The category to list.
|
||||
# @PARAM subpath (Optional[str]) - Nested path within the category.
|
||||
# @PARAM recursive (bool) - Whether to scan nested subdirectories recursively.
|
||||
# @PRE Storage root must exist.
|
||||
# @POST Returns a list of StoredFile objects.
|
||||
# @RETURN List[StoredFile] - List of file and directory metadata objects.
|
||||
def list_files(
|
||||
self,
|
||||
category: FileCategory | None = None,
|
||||
@@ -307,14 +306,14 @@ class StoragePlugin(PluginBase):
|
||||
# endregion list_files
|
||||
|
||||
# region save_file [TYPE Function]
|
||||
# @PURPOSE: Saves an uploaded file to the specified category and optional subpath.
|
||||
# @PARAM: file (UploadFile) - The uploaded file.
|
||||
# @PARAM: category (FileCategory) - The target category.
|
||||
# @PARAM: subpath (Optional[str]) - The target subpath.
|
||||
# @PRE: file must be a valid UploadFile; category must be valid.
|
||||
# @POST: File is written to disk and metadata is returned.
|
||||
# @RETURN: StoredFile - Metadata of the saved file.
|
||||
# @SIDE_EFFECT: Writes file to disk.
|
||||
# @PURPOSE Saves an uploaded file to the specified category and optional subpath.
|
||||
# @PARAM file (UploadFile) - The uploaded file.
|
||||
# @PARAM category (FileCategory) - The target category.
|
||||
# @PARAM subpath (Optional[str]) - The target subpath.
|
||||
# @PRE file must be a valid UploadFile; category must be valid.
|
||||
# @POST File is written to disk and metadata is returned.
|
||||
# @RETURN StoredFile - Metadata of the saved file.
|
||||
# @SIDE_EFFECT Writes file to disk.
|
||||
async def save_file(self, file: UploadFile, category: FileCategory, subpath: str | None = None) -> StoredFile:
|
||||
with belief_scope("StoragePlugin:save_file"):
|
||||
root = self.get_storage_root()
|
||||
@@ -341,12 +340,12 @@ class StoragePlugin(PluginBase):
|
||||
# endregion save_file
|
||||
|
||||
# region delete_file [TYPE Function]
|
||||
# @PURPOSE: Deletes a file or directory from the specified category and path.
|
||||
# @PARAM: category (FileCategory) - The category.
|
||||
# @PARAM: path (str) - The relative path of the file or directory.
|
||||
# @PRE: path must belong to the specified category and exist on disk.
|
||||
# @POST: The file or directory is removed from disk.
|
||||
# @SIDE_EFFECT: Removes item from disk.
|
||||
# @PURPOSE Deletes a file or directory from the specified category and path.
|
||||
# @PARAM category (FileCategory) - The category.
|
||||
# @PARAM path (str) - The relative path of the file or directory.
|
||||
# @PRE path must belong to the specified category and exist on disk.
|
||||
# @POST The file or directory is removed from disk.
|
||||
# @SIDE_EFFECT Removes item from disk.
|
||||
def delete_file(self, category: FileCategory, path: str):
|
||||
with belief_scope("StoragePlugin:delete_file"):
|
||||
root = self.get_storage_root()
|
||||
@@ -367,12 +366,12 @@ class StoragePlugin(PluginBase):
|
||||
# endregion delete_file
|
||||
|
||||
# region get_file_path [TYPE Function]
|
||||
# @PURPOSE: Returns the absolute path of a file for download.
|
||||
# @PARAM: category (FileCategory) - The category.
|
||||
# @PARAM: path (str) - The relative path of the file.
|
||||
# @PRE: path must belong to the specified category and be a file.
|
||||
# @POST: Returns the absolute Path to the file.
|
||||
# @RETURN: Path - Absolute path to the file.
|
||||
# @PURPOSE Returns the absolute path of a file for download.
|
||||
# @PARAM category (FileCategory) - The category.
|
||||
# @PARAM path (str) - The relative path of the file.
|
||||
# @PRE path must belong to the specified category and be a file.
|
||||
# @POST Returns the absolute Path to the file.
|
||||
# @RETURN Path - Absolute path to the file.
|
||||
def get_file_path(self, category: FileCategory, path: str) -> Path:
|
||||
with belief_scope("StoragePlugin:get_file_path"):
|
||||
root = self.get_storage_root()
|
||||
|
||||
Reference in New Issue
Block a user