function update_document_v1
Updates properties of a controlled document including title, description, status, owner, and metadata, with special handling for status transitions that require format conversions or publishing workflows.
/tf/active/vicechatdev/CDocs single class/controllers/document_controller.py
1969 - 2105
complex
Purpose
This function serves as the primary interface for modifying document properties in a controlled document management system. It enforces business rules around status transitions, particularly when moving from editable to published states, ensures proper audit logging, validates ownership changes, and delegates to specialized publishing workflows when necessary. It's designed to maintain document integrity and compliance with document lifecycle management requirements.
Source Code
def update_document(
user: DocUser,
document_uid: str,
title: Optional[str] = None,
description: Optional[str] = None,
status: Optional[str] = None,
owner_uid: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
"""
Update a document's properties, handling format transitions when status changes.
Args:
user: User making the update
document_uid: UID of document to update
title: New document title (optional)
description: New document description (optional)
status: New document status (optional)
owner_uid: New document owner UID (optional)
metadata: New document metadata (optional)
Returns:
Dictionary with update status
"""
try:
# Get document instance
document = ControlledDocument(uid=document_uid)
if not document:
raise ResourceNotFoundError(f"Document not found: {document_uid}")
# Store original values for audit
original_values = {
'title': document.title,
'description': document.description,
'status': document.status,
'owner_uid': document.owner_uid
}
# Track what changed
changes = {}
# Update title if provided
if title is not None and title != document.title:
document.title = title
changes['title'] = {'old': original_values['title'], 'new': title}
# Update description if provided
if description is not None and description != document.description:
document.description = description
changes['description'] = {'old': original_values['description'], 'new': description}
# Handle status update with special consideration for format transitions
if status is not None and status != document.status:
current_status = document.status
target_status = status
# Check if the transition is valid
if not document.can_transition_to(target_status):
raise BusinessRuleError(f"Invalid status transition from {current_status} to {target_status}")
# Check if we're transitioning from editable to non-editable status
if is_editable_status(current_status) and is_published_status(target_status):
# Status requires PDF publishing
if target_status == STATUS_PUBLISHED:
# Call publish_document instead
result = publish_document(
user=user,
document_uid=document_uid,
publish_comment=metadata.get('comment', 'Status updated to Published') if metadata else None
)
return result
else:
# For other non-editable statuses, check if PDF exists
current_version = document.current_version
if current_version and not current_version.pdf_file_path:
raise BusinessRuleError(f"Document must be published before changing to {target_status}")
# For transitions that don't require special handling, update status normally
document.status = target_status
changes['status'] = {'old': current_status, 'new': target_status}
# Log status change
audit_trail.log_document_lifecycle_event(
event_type="DOCUMENT_STATUS_CHANGED",
user=user,
document_uid=document_uid,
details={
'old_status': current_status,
'new_status': target_status,
'comment': metadata.get('comment') if metadata else None
}
)
# Update owner if provided
if owner_uid is not None and owner_uid != document.owner_uid:
# Check if new owner exists
owner_exists = db.run_query(
"MATCH (u:User {UID: $uid}) RETURN COUNT(u) > 0 as exists",
{"uid": owner_uid}
)
if not owner_exists or not owner_exists[0].get('exists', False):
raise ValidationError(f"User not found: {owner_uid}")
# Update owner
document.owner = owner_uid
changes['owner_uid'] = {'old': original_values['owner_uid'], 'new': owner_uid}
# Update metadata if provided
if metadata:
# Merge with existing metadata if any
existing_metadata = getattr(document, 'metadata', {}) or {}
updated_metadata = {**existing_metadata, **metadata}
# Update in database
db.update_node(document_uid, {'metadata': updated_metadata})
changes['metadata'] = {'updated': True}
# Notify about document update if significant changes were made
if changes:
notifications.notify_document_update(document, "DOCUMENT_UPDATED")
# Return success response with changes
return {
"success": True,
"message": "Document updated successfully",
"document_uid": document_uid,
"changes": changes
}
except (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) as e:
# Re-raise known errors
raise
except Exception as e:
logger.error(f"Error updating document: {e}")
raise BusinessRuleError(f"Failed to update document: {e}")
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
user |
DocUser | - | positional_or_keyword |
document_uid |
str | - | positional_or_keyword |
title |
Optional[str] | None | positional_or_keyword |
description |
Optional[str] | None | positional_or_keyword |
status |
Optional[str] | None | positional_or_keyword |
owner_uid |
Optional[str] | None | positional_or_keyword |
metadata |
Optional[Dict[str, Any]] | None | positional_or_keyword |
Parameter Details
user: DocUser object representing the authenticated user performing the update. Used for permission checks, audit logging, and notification purposes.
document_uid: Unique identifier (string) of the document to be updated. Must correspond to an existing ControlledDocument in the database.
title: Optional new title for the document (string). If provided and different from current title, the document title will be updated. Pass None to leave unchanged.
description: Optional new description for the document (string). If provided and different from current description, the document description will be updated. Pass None to leave unchanged.
status: Optional new status for the document (string). Must be a valid status value (e.g., STATUS_DRAFT, STATUS_PUBLISHED). Status transitions are validated against business rules. Some transitions (like to STATUS_PUBLISHED) trigger special publishing workflows.
owner_uid: Optional UID (string) of the new document owner. If provided, the function validates that the user exists before transferring ownership. Pass None to leave ownership unchanged.
metadata: Optional dictionary containing additional metadata to merge with existing document metadata. Can include custom fields like 'comment' which is used in status change logging. Pass None to leave metadata unchanged.
Return Value
Type: Dict[str, Any]
Returns a dictionary with keys: 'success' (boolean indicating operation success), 'message' (string describing the outcome), 'document_uid' (string echoing the updated document's UID), and 'changes' (dictionary detailing what was modified, with each changed field showing 'old' and 'new' values). If status is changed to STATUS_PUBLISHED, returns the result from publish_document function instead.
Dependencies
logginguuidostempfiletypingdatetimeiopanelshutiltracebackjsonreCDocsconfig
Required Imports
from typing import Dict, List, Any, Optional, Union, BinaryIO, Tuple
from datetime import datetime, timedelta
from CDocs import db
from CDocs.config import settings, permissions
from CDocs.models.document import ControlledDocument, DocumentVersion
from CDocs.models.user_extensions import DocUser
from CDocs.utils import document_processor, notifications, audit_trail
from CDocs.db.schema_manager import NodeLabels, RelTypes
from CDocs.controllers import require_permission, log_controller_action, transaction, PermissionError, ResourceNotFoundError, ValidationError, BusinessRuleError, IntegrationError
from CDocs.models.document_status import is_editable_status, is_published_status, STATUS_DRAFT, STATUS_IN_REVIEW, STATUS_IN_APPROVAL, STATUS_APPROVED, STATUS_PUBLISHED, STATUS_EFFECTIVE, STATUS_ARCHIVED, STATUS_OBSOLETE, get_next_status
import logging
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.controllers.document_controller import publish_document
Condition: Required when status is being changed to STATUS_PUBLISHED, as the function delegates to publish_document for this specific transition
Required (conditional)Usage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.document_controller import update_document
from CDocs.models.document_status import STATUS_IN_REVIEW
# Assume user is already authenticated
user = DocUser(uid='user123')
document_uid = 'doc-456'
# Update document title and description
result = update_document(
user=user,
document_uid=document_uid,
title='Updated Document Title',
description='This document has been revised',
metadata={'comment': 'Updated per review feedback'}
)
if result['success']:
print(f"Document updated: {result['changes']}")
# Change document status with validation
result = update_document(
user=user,
document_uid=document_uid,
status=STATUS_IN_REVIEW,
metadata={'comment': 'Submitting for review'}
)
# Transfer document ownership
result = update_document(
user=user,
document_uid=document_uid,
owner_uid='newowner789',
metadata={'comment': 'Ownership transferred'}
)
Best Practices
- Always provide a user object with proper authentication and permissions before calling this function
- Use the metadata parameter to include comments explaining why changes are being made, especially for status transitions
- Be aware that changing status to STATUS_PUBLISHED will delegate to the publish_document function and may trigger PDF generation
- Validate that the target status is appropriate for the document's current state before calling
- Handle all possible exceptions: ResourceNotFoundError (document not found), ValidationError (invalid input), PermissionError (insufficient permissions), BusinessRuleError (invalid transitions)
- Only update fields that need to change; pass None for fields that should remain unchanged
- When changing ownership, ensure the new owner_uid corresponds to a valid user in the system
- The function operates within a transaction (via decorator), so all changes are atomic
- Check the 'changes' dictionary in the return value to see exactly what was modified
- For status transitions from editable to published states, ensure the document has all required content and approvals
- The function automatically logs audit trail events for status changes and sends notifications for significant updates
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function update_document 99.0% similar
-
function update_document_v3 97.2% similar
-
function update_document_v2 96.1% similar
-
function update_document_v4 77.8% similar
-
function update_status_after_approval 76.1% similar