🔍 Code Extractor

function update_approval_comment

Maturity: 70

Updates an approval comment's text and/or status with permission checks, audit logging, and notifications for resolved comments.

File:
/tf/active/vicechatdev/CDocs/controllers/approval_controller.py
Lines:
634 - 789
Complexity:
complex

Purpose

This function manages the modification of approval comments within an active approval cycle. It enforces business rules such as only allowing updates during active approval cycles, restricting text changes to comment authors, and allowing document owners to change comment status. When comments are resolved, it logs the resolution details and notifies relevant users. The function is part of a document approval workflow system.

Source Code

def update_approval_comment(
    user: DocUser,
    comment_uid: str,
    comment_text: Optional[str] = None,
    status: Optional[str] = None
) -> Dict[str, Any]:
    """
    Update a approval comment.
    
    Args:
        user: User updating the comment
        comment_uid: UID of comment to update
        comment_text: Optional new comment text
        status: Optional new status (OPEN, RESOLVED, etc.)
        
    Returns:
        Dictionary with updated comment details
        
    Raises:
        ResourceNotFoundError: If comment not found
        ValidationError: If validation fails
        PermissionError: If user doesn't have permission
        BusinessRuleError: If a business rule is violated
    """
    try:
         # Direct permission check at the beginning
        logger.info(f"Checking if user {user.uid} has EDIT_APPROVE_COMMENT permission")
        if not permissions.user_has_permission(user, ["EDIT_APPROVE_COMMENT"]):
            logger.warning(f"Permission denied: User {user.uid} attempted to edit a comment without EDIT_APPROVE_COMMENT permission")
            raise PermissionError("You do not have permission to edit comments")
            
        logger.info(f"User {user.uid} has permission to create and initiate approval cycle")
        # Get comment instance
        comment = ApprovalComment(uid=comment_uid)
        if not comment:
            raise ResourceNotFoundError(f"Comment not found: {comment_uid}")
            
        # Get approval cycle
        approval_cycle = ApprovalCycle(uid=comment.approval_cycle_uid)
        if not approval_cycle:
            raise ResourceNotFoundError(f"Approval cycle not found for comment: {comment_uid}")
            
        # Check if approval is still active
        if approval_cycle.status not in ["PENDING", "IN_PROGRESS"]:
            raise BusinessRuleError(f"Cannot update comments for approval with status {approval_cycle.status}")
            
        # Check if user can edit this comment
        can_edit = False
        
        # User can edit their own comments
        if comment.user_uid == user.uid:
            can_edit = True
        
        # Document owner can change status (but not text)
        elif approval_cycle.document_uid:
            document = ControlledDocument(uid=approval_cycle.document_uid)
            if document and document.owner_uid == user.uid and comment_text is None:
                can_edit = True
                
        # Admins can edit any comment
        elif permissions.user_has_permission(user, "MANAGE_APPROVALS"):
            can_edit = True
            
        if not can_edit:
            raise PermissionError("User is not authorized to update this comment")
            
        # Track changes
        changes = {}
        
        # Update comment text if provided
        if comment_text is not None and comment_text != comment.comment_text:
            # Only the author can change the text
            if comment.user_uid != user.uid and not permissions.user_has_permission(user, "MANAGE_APPROVALS"):
                raise PermissionError("Only the comment author can modify comment text")
                
            old_text = comment.comment_text
            comment.comment_text = comment_text
            changes["comment_text"] = {"old": old_text, "new": comment_text}
            
        # Update status if provided
        if status is not None and status != comment.status:
            # Validate status
            if status not in settings.APPROVE_COMMENT_STATUSES:
                raise ValidationError(f"Invalid comment status: {status}")
                
            old_status = comment.status
            comment.status = status
            
            # Add resolution info if being resolved
            if status == "RESOLVED" and old_status != "RESOLVED":
                comment.resolved_by_uid = user.uid
                comment.resolved_by_name = user.name
                comment.resolved_date = datetime.now()
                
            changes["status"] = {"old": old_status, "new": status}
            
        # No changes
        if not changes:
            return {
                "success": True,
                "comment": comment.to_dict(),
                "message": "No changes made to comment"
            }
            
        # Update modified timestamp
        comment.modified_date = datetime.now()
        
        # Save comment to database
        comment.save()
        
        # Log comment update event
        audit_trail.log_approval_event(
            event_type="APPROVE_COMMENT_UPDATED",
            user=user,
            approval_uid=approval_cycle.uid,
            details={
                "comment_uid": comment.uid,
                "changes": changes
            }
        )
        
        # Send notifications if status changed
        if "status" in changes and changes["status"]["new"] == "RESOLVED":
            # Notify original comment author if different from resolver
            if comment.user_uid != user.uid:
                document = ControlledDocument(uid=approval_cycle.document_uid)
                notifications.send_notification(
                    notification_type="APPROVE_COMMENT_RESOLVED",
                    users=[comment.user_uid],
                    resource_uid=approval_cycle.uid,
                    resource_type="ApprovalCycle",
                    message=f"Your comment on {document.doc_number if document else 'document'} has been resolved",
                    details={
                        "approval_uid": approval_cycle.uid,
                        "comment_uid": comment.uid,
                        "resolved_by": user.name,
                        "doc_number": document.doc_number if document else "",
                        "title": document.title if document else ""
                    },
                    send_email=True,
                    email_template="approval_comment_resolved"
                )
        
        return {
            "success": True,
            "comment": comment.to_dict(),
            "changes": changes,
            "message": "Comment updated successfully"
        }
        
    except (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) as e:
        # Re-raise known errors
        raise
    except Exception as e:
        logger.error(f"Error updating approval comment: {e}")
        raise BusinessRuleError(f"Failed to update approval comment: {e}")

Parameters

Name Type Default Kind
user DocUser - positional_or_keyword
comment_uid str - positional_or_keyword
comment_text Optional[str] None positional_or_keyword
status Optional[str] None positional_or_keyword

Parameter Details

user: DocUser object representing the user attempting to update the comment. Must have EDIT_APPROVE_COMMENT permission. Used for permission checks and audit logging.

comment_uid: String UID (unique identifier) of the approval comment to update. Must correspond to an existing ApprovalComment record in the database.

comment_text: Optional string containing new text for the comment. Can only be modified by the original comment author or users with MANAGE_APPROVALS permission. Pass None to leave unchanged.

status: Optional string representing the new status for the comment. Must be one of the values defined in settings.APPROVE_COMMENT_STATUSES (e.g., 'OPEN', 'RESOLVED'). Pass None to leave unchanged.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean indicating operation success), 'comment' (dictionary representation of the updated ApprovalComment object), 'changes' (dictionary tracking old and new values for modified fields), and 'message' (string describing the outcome). If no changes were made, the changes key may be absent and message indicates no modifications.

Dependencies

  • logging
  • uuid
  • os
  • typing
  • datetime
  • traceback
  • CDocs.db
  • CDocs.config.settings
  • CDocs.config.permissions
  • CDocs.models.document
  • CDocs.models.approval
  • CDocs.models.user_extensions
  • CDocs.utils.audit_trail
  • CDocs.utils.notifications
  • CDocs.controllers

Required Imports

from typing import Dict, Any, Optional
from datetime import datetime
from CDocs.models.user_extensions import DocUser
from CDocs.models.approval import ApprovalComment, ApprovalCycle
from CDocs.models.document import ControlledDocument
from CDocs.config import settings, permissions
from CDocs.utils import audit_trail, notifications
from CDocs.controllers import ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError
import logging

Usage Example

from CDocs.models.user_extensions import DocUser
from CDocs.controllers.approval_controller import update_approval_comment

# Get the user performing the update
user = DocUser(uid='user123')

# Update comment text only
result = update_approval_comment(
    user=user,
    comment_uid='comment456',
    comment_text='Updated comment with additional details'
)

# Update comment status to resolved
result = update_approval_comment(
    user=user,
    comment_uid='comment456',
    status='RESOLVED'
)

# Update both text and status
result = update_approval_comment(
    user=user,
    comment_uid='comment456',
    comment_text='Final comment text',
    status='RESOLVED'
)

if result['success']:
    print(f"Comment updated: {result['message']}")
    print(f"Changes made: {result.get('changes', {})}")
    updated_comment = result['comment']

Best Practices

  • Always ensure the user has EDIT_APPROVE_COMMENT permission before calling this function
  • Only comment authors can modify comment text; document owners can only change status
  • Comments can only be updated when the approval cycle status is PENDING or IN_PROGRESS
  • When resolving a comment, the function automatically records resolver information and timestamp
  • The function sends email notifications to comment authors when their comments are resolved by others
  • All changes are tracked in the audit trail with detailed change information
  • Handle all four exception types: ResourceNotFoundError, ValidationError, PermissionError, and BusinessRuleError
  • Pass None for parameters you don't want to change rather than omitting them
  • The function is decorated with @log_controller_action for automatic action logging

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function update_approval_comment_v1 92.7% similar

    Updates an existing approval comment in a document approval workflow, allowing modification of comment text and status (e.g., marking as resolved) with permission checks and audit logging.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function update_review_comment 91.3% similar

    Updates an existing review comment's text and/or status with permission checks, audit logging, and notifications for resolved comments.

    From: /tf/active/vicechatdev/CDocs/controllers/review_controller.py
  • function add_approval_comment 81.3% similar

    Adds a comment to an approval cycle for a controlled document, with support for threaded comments, different comment types, and automatic notifications to relevant stakeholders.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function add_approval_comment_v1 76.6% similar

    Adds a comment to an approval cycle with optional location information, page references, and reply threading. Validates user permissions, logs audit trails, and sends notifications to other approvers for issue-type comments.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function add_review_comment 72.1% similar

    Adds a comment to a document review cycle with support for threaded comments, different comment types, and location-based annotations.

    From: /tf/active/vicechatdev/CDocs/controllers/review_controller.py
← Back to Browse