🔍 Code Extractor

function update_review_comment

Maturity: 70

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

File:
/tf/active/vicechatdev/CDocs/controllers/review_controller.py
Lines:
658 - 824
Complexity:
complex

Purpose

This function manages the lifecycle of review comments in a document review system. It allows authorized users to modify comment text (author only) or change comment status (author, document owner, or admin). When a comment is marked as resolved, it records resolution metadata and sends notifications to relevant parties. The function enforces business rules such as preventing updates to comments in completed reviews and maintaining audit trails for compliance.

Source Code

def update_review_comment(
    user: DocUser,
    comment_uid: str,
    comment_text: Optional[str] = None,
    status: Optional[str] = None
) -> Dict[str, Any]:
    """
    Update a review 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_REVIEW_COMMENT permission")
        if not permissions.user_has_permission(user, ["EDIT_REVIEW_COMMENT"]):
            logger.warning(f"Permission denied: User {user.uid} attempted to edit a comment without EDIT_REVIEW_COMMENT permission")
            raise PermissionError("You do not have permission to edit comments")
            
        logger.info(f"User {user.uid} has permission to create and initiate review cycle")
        # Get comment instance
        comment = ReviewComment(uid=comment_uid)
        if not comment:
            raise ResourceNotFoundError(f"Comment not found: {comment_uid}")
            
        # Get review cycle
        review_cycle = ReviewCycle(uid=comment.review_cycle_uid)
        if not review_cycle:
            raise ResourceNotFoundError(f"Review cycle not found for comment: {comment_uid}")
            
        # Check if review is still active
        if review_cycle.status not in ["PENDING", "IN_PROGRESS"]:
            raise BusinessRuleError(f"Cannot update comments for review with status {review_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 review_cycle.document_uid:
            document = ControlledDocument(uid=review_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_REVIEWS"):
            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_REVIEWS"):
                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.REVIEW_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_review_event(
            event_type="REVIEW_COMMENT_UPDATED",
            user=user,
            review_uid=review_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=review_cycle.document_uid)
                notifications.send_notification(
                    notification_type="REVIEW_COMMENT_RESOLVED",
                    users=[comment.user_uid],
                    resource_uid=review_cycle.uid,
                    resource_type="ReviewCycle",
                    message=f"Your comment on {document.doc_number if document else 'document'} has been resolved",
                    details={
                    "doc_uid": document.uid,  # Add doc_uid for URL generation
                    "doc_number": document.doc_number,
                    "title": document.title,
                    "review_uid": review_cycle.uid,
                    "comment_uid": comment.uid,
                    "comment_text": comment_text[:100] + "..." if len(comment_text) > 100 else comment_text,
                    "commenter_name": user.name,
                    "department": document.department,
                    "doc_type": document.doc_type,
                    "version_number": document.current_version.version_number if document.current_version else "N/A"
                    },
                    send_email=True,
                    email_template="review_comment_resolved",
                    email_data={
                        "app_url": settings.APP_URL,
                        "doc_uid": document.uid,
                        "review_uid": review_cycle.uid,
                        "comment_uid": comment.uid
                    }
                )
        
        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 review comment: {e}")
        raise BusinessRuleError(f"Failed to update review 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 authenticated user attempting to update the comment. Used for permission checks and audit logging. Must have EDIT_REVIEW_COMMENT permission at minimum.

comment_uid: Unique identifier (string) of the ReviewComment to be updated. Must correspond to an existing comment in the database or ResourceNotFoundError will be raised.

comment_text: Optional string containing new text for the comment. Only the original comment author or users with MANAGE_REVIEWS permission can modify this. Pass None to leave text unchanged.

status: Optional string representing the new status for the comment. Must be one of the values defined in settings.REVIEW_COMMENT_STATUSES (e.g., 'OPEN', 'RESOLVED'). Pass None to leave status unchanged. When set to 'RESOLVED', automatically records resolution metadata.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean, always True on successful execution), 'comment' (dictionary representation of the updated ReviewComment object), 'changes' (dictionary mapping changed fields to their old and new values, e.g., {'status': {'old': 'OPEN', 'new': 'RESOLVED'}}), and 'message' (string describing the outcome). If no changes were made, the changes dict will be empty and message will indicate no modifications.

Dependencies

  • logging
  • uuid
  • os
  • typing
  • datetime
  • traceback
  • CDocs.db
  • CDocs.config.settings
  • CDocs.config.permissions
  • CDocs.models.document
  • CDocs.models.review
  • 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.review import ReviewComment, ReviewCycle
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, log_controller_action
import logging

Usage Example

from CDocs.models.user_extensions import DocUser
from CDocs.controllers.review_controller import update_review_comment

# Get the authenticated user
user = DocUser(uid='user123')

# Update comment text (only author can do this)
try:
    result = update_review_comment(
        user=user,
        comment_uid='comment-abc-123',
        comment_text='Updated comment with additional details',
        status=None
    )
    print(f"Comment updated: {result['message']}")
    print(f"Changes made: {result['changes']}")
except PermissionError as e:
    print(f"Permission denied: {e}")
except ResourceNotFoundError as e:
    print(f"Comment not found: {e}")

# Resolve a comment (document owner or author can do this)
try:
    result = update_review_comment(
        user=user,
        comment_uid='comment-abc-123',
        comment_text=None,
        status='RESOLVED'
    )
    print(f"Comment resolved by {result['comment']['resolved_by_name']}")
except BusinessRuleError as e:
    print(f"Cannot resolve: {e}")

Best Practices

  • Always wrap calls in try-except blocks to handle ResourceNotFoundError, PermissionError, ValidationError, and BusinessRuleError exceptions
  • Only the original comment author can modify comment text; document owners can only change status
  • Comments can only be updated when the review cycle status is PENDING or IN_PROGRESS
  • When resolving comments, the function automatically records resolver information and timestamp
  • Pass None for parameters you don't want to change rather than fetching and re-passing existing values
  • The function sends email notifications when comments are resolved, ensure notification system is properly configured
  • All changes are logged to the audit trail for compliance and tracking purposes
  • Users must have EDIT_REVIEW_COMMENT permission at minimum; MANAGE_REVIEWS permission grants full edit access
  • The function uses the @log_controller_action decorator for automatic action logging

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function update_approval_comment 91.3% similar

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

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function update_approval_comment_v1 84.6% 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 add_review_comment 80.7% 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
  • function add_approval_comment 71.1% 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 close_review_cycle 69.9% similar

    Closes a completed review cycle for a controlled document, with optional document status update, permission validation, and stakeholder notifications.

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