function ensure_document_folders
Ensures all required folder hierarchies exist in FileCloud storage for a controlled document, creating them if they don't exist.
/tf/active/vicechatdev/CDocs/controllers/filecloud_controller.py
204 - 316
moderate
Purpose
This function manages the FileCloud folder structure for document storage. It handles two scenarios: (1) documents with custom paths where it creates the custom path and document folder, and (2) standard documents where it creates a hierarchical structure (root/department/doc_type/document). The function checks for folder existence before creation to avoid duplicates and ensures parent folders exist before creating child folders.
Source Code
def ensure_document_folders(document: Union[ControlledDocument, str]) -> Dict[str, str]:
"""
Ensure all required folders exist in FileCloud for document storage.
Args:
document: ControlledDocument instance or document UID
Returns:
Dictionary of created folder paths
Raises:
ResourceNotFoundError: If document not found
FileCloudError: If folder creation fails
"""
# Get document instance if UID provided
if isinstance(document, str):
doc = ControlledDocument(uid=document)
if not doc:
raise ResourceNotFoundError(f"Document not found: {document}")
else:
doc = document
# Check if document has a custom path
if doc.custom_path:
# For custom path, we need to ensure both the custom path and document folder exist
custom_path = doc.custom_path
document_folder = f"{custom_path}/{doc.doc_number}"
client = get_filecloud_client()
folders = {
"custom": custom_path,
"document": document_folder
}
# Create each folder if it doesn't exist
for folder_name, folder_path in folders.items():
try:
# First check if folder exists
folder_exists = False
try:
check_result = client.check_folder_exists(folder_path)
logger.info(f"Checking folder existence: {folder_path} - Result: {check_result}")
folder_exists = isinstance(check_result, bool) and check_result
except Exception:
folder_exists = False
# Create folder if it doesn't exist
if not folder_exists:
logger.info(f"Creating folder: {folder_path}")
# Split the path to get parent path and folder name
path_parts = folder_path.split('/')
parent_path = '/'.join(path_parts[:-1])
folder_name = path_parts[-1]
# Ensure parent path exists first (recursive folder creation)
if parent_path and not client.check_folder_exists(parent_path):
ensure_path_exists(client, parent_path)
result = client.create_folder(path=parent_path, folder_name=folder_name)
if not result.get('success', False):
logger.error(f"Failed to create folder {folder_path}: {result.get('message', 'Unknown error')}")
raise FileCloudError(f"Failed to create folder {folder_path}")
except Exception as e:
logger.error(f"Error creating folder {folder_path}: {e}")
raise FileCloudError(f"Error creating folder structure: {e}")
return folders
client = get_filecloud_client()
# Define folder hierarchy
root_folder = f"/{settings.FILECLOUD_ROOT_FOLDER}"
department_folder = f"{root_folder}/{doc.department}"
doc_type_folder = f"{department_folder}/{doc.doc_type}"
document_folder = f"{doc_type_folder}/{doc.doc_number}"
folders = {
"root": root_folder,
"department": department_folder,
"doc_type": doc_type_folder,
"document": document_folder
}
# Create each folder if it doesn't exist
for folder_name, folder_path in folders.items():
try:
# First check if folder exists
folder_exists = False
try:
check_result = client.check_folder_exists(folder_path)
logger.info(f"Checking folder existence: {folder_path} - Result: {check_result}")
folder_exists = isinstance(check_result, bool) and check_result
except Exception:
folder_exists = False
# Create folder if it doesn't exist
if not folder_exists:
logger.info(f"Creating folder: {folder_path}")
result = client.create_folder(path="/".join(folder_path.split('/')[:-1]), folder_name=folder_path.split('/')[-1])
if not result.get('success', False):
logger.error(f"Failed to create folder {folder_path}: {result.get('message', 'Unknown error')}")
raise FileCloudError(f"Failed to create folder {folder_path}")
except Exception as e:
logger.error(f"Error creating folder {folder_path}: {e}")
raise FileCloudError(f"Error creating folder structure: {e}")
return folders
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
document |
Union[ControlledDocument, str] | - | positional_or_keyword |
Parameter Details
document: Either a ControlledDocument instance or a string containing the document UID. If a string UID is provided, the function will attempt to retrieve the corresponding ControlledDocument. The document object must have attributes like doc_number, department, doc_type, and optionally custom_path.
Return Value
Type: Dict[str, str]
Returns a dictionary mapping folder type names to their full paths in FileCloud. For custom paths, returns {'custom': custom_path, 'document': document_folder}. For standard paths, returns {'root': root_folder, 'department': department_folder, 'doc_type': doc_type_folder, 'document': document_folder}. All paths are strings representing absolute FileCloud paths.
Dependencies
loggingtypingCDocs.config.settingsCDocs.models.document.ControlledDocumentCDocs.controllers.ResourceNotFoundErrorCDocs.controllers.FileCloudErrorCDocs.utils.FC_api.FileCloudAPI
Required Imports
from typing import Dict, Union
from CDocs.models.document import ControlledDocument
from CDocs.controllers import ResourceNotFoundError
from CDocs.controllers import FileCloudError
from CDocs.config import settings
import logging
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.utils.FC_api import get_filecloud_client
Condition: Required to obtain FileCloud API client for folder operations
Required (conditional)from CDocs.utils.FC_api import ensure_path_exists
Condition: Only used when creating folders with custom paths to recursively ensure parent directories exist
OptionalUsage Example
from CDocs.models.document import ControlledDocument
from CDocs.controllers.document_controller import ensure_document_folders
# Using with a ControlledDocument instance
doc = ControlledDocument(uid='DOC-12345')
folders = ensure_document_folders(doc)
print(f"Created folders: {folders}")
# Output: {'root': '/ControlledDocs', 'department': '/ControlledDocs/Engineering', 'doc_type': '/ControlledDocs/Engineering/SOP', 'document': '/ControlledDocs/Engineering/SOP/DOC-12345'}
# Using with a document UID string
folders = ensure_document_folders('DOC-12345')
# For documents with custom paths
doc_custom = ControlledDocument(uid='DOC-67890')
doc_custom.custom_path = '/CustomProjects/ProjectX'
folders = ensure_document_folders(doc_custom)
print(f"Custom folders: {folders}")
# Output: {'custom': '/CustomProjects/ProjectX', 'document': '/CustomProjects/ProjectX/DOC-67890'}
Best Practices
- Always handle the ResourceNotFoundError when passing document UIDs as strings, as the document may not exist in the database
- Ensure the FileCloud client is properly authenticated before calling this function
- The function is idempotent - it can be called multiple times safely as it checks for folder existence before creation
- For custom paths, ensure the custom_path attribute is properly set on the document before calling
- Monitor logs for folder creation failures as they indicate potential FileCloud connectivity or permission issues
- The function uses the @log_controller_action decorator, so all calls are automatically logged for audit purposes
- Parent folders are created recursively for custom paths, but standard paths assume the root folder structure is valid
- Handle FileCloudError exceptions to gracefully manage folder creation failures in production environments
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function get_filecloud_document_path 69.8% similar
-
function ensure_path_exists 63.8% similar
-
function upload_document_to_filecloud 63.1% similar
-
function create_controlled_document 62.2% similar
-
function delete_document_from_filecloud 61.7% similar