function add_approval_comment_v1
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.
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
419 - 540
moderate
Purpose
This function enables users to add comments to document approval cycles within a controlled document management system. It supports different comment types (GENERAL, ISSUE), threaded replies, page-specific annotations, and location-based comments. The function enforces permission checks to ensure only authorized approvers or users with MANAGE_APPROVALS permission can comment. It automatically creates audit trail entries and sends email notifications to other approvers when issues are raised, facilitating collaborative document review and approval workflows.
Source Code
def add_approval_comment(
user: DocUser,
approval_uid: str,
comment_text: str,
comment_type: str = "GENERAL",
page_number: Optional[int] = None,
location_info: Optional[Dict[str, Any]] = None,
parent_comment_uid: Optional[str] = None
) -> Dict[str, Any]:
"""
Add a comment to an approval cycle.
Args:
user: The user adding the comment
approval_uid: UID of the approval cycle
comment_text: Text of the comment
comment_type: Type of comment
page_number: Page number the comment applies to
location_info: Location information for the comment
parent_comment_uid: UID of parent comment if this is a reply
Returns:
Dictionary with success flag and comment information
"""
try:
# Get approval cycle
approval_cycle = ApprovalCycle(uid=approval_uid)
if not approval_cycle:
raise ResourceNotFoundError("Approval cycle not found")
# Verify user is an approver or has permissions
is_approver = approval_cycle.is_approver(user.uid)
has_permission = permissions.user_has_permission(user, "MANAGE_APPROVALS")
if not (is_approver or has_permission):
raise PermissionError("You do not have permission to comment on this approval")
# Additional properties for the comment
properties = {
"comment_type": comment_type,
"created_at": datetime.now()
}
if page_number is not None:
properties["page_number"] = page_number
if location_info:
properties.update(location_info)
if parent_comment_uid:
properties["parent_comment_uid"] = parent_comment_uid
# Add the comment
comment = approval_cycle.add_comment(
commenter=user,
text=comment_text,
requires_resolution=comment_type == "ISSUE",
properties=properties
)
if not comment:
raise BusinessRuleError("Failed to add comment")
# Create audit trail entry
document_uid = approval_cycle.document_uid
if document_uid:
audit_trail.log_event(
user=user,
resource_uid=document_uid,
resource_type='ApporvalCycle',
event_type="APPROVAL_COMMENT_ADDED",
details={
"approval_cycle_uid": approval_uid,
"comment_uid": comment.uid,
"comment_type": comment_type
}
)
# Send notifications to other approvers if this is an issue comment
if comment_type == "ISSUE":
from CDocs.controllers.document_controller import get_document
document_uid = approval_cycle.document_uid
document = get_document(document_uid=document_uid) if document_uid else None
for assignment in approval_cycle.get_approver_assignments():
if assignment.approver_uid != user.uid:
approver = DocUser(uid=assignment.approver_uid)
if approver:
notifications.send_notification(
notification_type="APPROVAL_COMMENT_ADDED",
users=approver.uid,
resource_uid=approval_uid,
resource_type="ApprovalCycle",
message=f"{user.name} commented: {comment_text[:50]}{'...' if len(comment_text) > 50 else ''}",
details={
"document_uid": document_uid,
"document_number": document.get("docNumber") if document else None,
"document_title": document.get("title") if document else None,
"approval_cycle_uid": approval_uid,
"comment_uid": comment.uid,
"comment_type": comment_type
},
send_email=True,
email_template="approval_comment_added"
)
return {
"success": True,
"message": "Comment added successfully",
"comment_uid": comment.uid,
"approval_uid": approval_uid
}
except (ResourceNotFoundError, PermissionError, BusinessRuleError) as e:
logger.warning(f"Error adding approval comment: {e}")
return {"success": False, "message": str(e)}
except Exception as e:
logger.error(f"Unexpected error adding approval comment: {e}")
import traceback
logger.error(traceback.format_exc())
return {"success": False, "message": "An unexpected error occurred"}
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
user |
DocUser | - | positional_or_keyword |
approval_uid |
str | - | positional_or_keyword |
comment_text |
str | - | positional_or_keyword |
comment_type |
str | 'GENERAL' | positional_or_keyword |
page_number |
Optional[int] | None | positional_or_keyword |
location_info |
Optional[Dict[str, Any]] | None | positional_or_keyword |
parent_comment_uid |
Optional[str] | None | positional_or_keyword |
Parameter Details
user: DocUser object representing the authenticated user adding the comment. Must be either an approver on the cycle or have MANAGE_APPROVALS permission.
approval_uid: Unique identifier (string) of the approval cycle to which the comment will be added. Must reference an existing ApprovalCycle.
comment_text: The actual text content of the comment. Can be of any length, though notifications truncate to 50 characters for preview.
comment_type: Type classification of the comment. Defaults to 'GENERAL'. When set to 'ISSUE', the comment requires resolution and triggers notifications to all other approvers. Expected values: 'GENERAL', 'ISSUE', or other custom types.
page_number: Optional integer specifying which page of the document this comment applies to. Useful for page-specific annotations in multi-page documents.
location_info: Optional dictionary containing spatial or contextual location information for the comment (e.g., coordinates, highlighted text ranges, section references). Structure depends on client implementation.
parent_comment_uid: Optional string UID of another comment. When provided, creates a threaded reply relationship, allowing nested comment discussions.
Return Value
Type: Dict[str, Any]
Returns a dictionary with keys: 'success' (boolean indicating operation success), 'message' (string describing the result or error), 'comment_uid' (string UID of the newly created comment, only present on success), and 'approval_uid' (string UID of the approval cycle, only present on success). On failure, only 'success' (False) and 'message' (error description) are returned.
Dependencies
CDocstypingdatetimeloggingtraceback
Required Imports
from typing import Dict, Any, Optional
from datetime import datetime
from CDocs.models.user_extensions import DocUser
from CDocs.models.approval import ApprovalCycle
from CDocs.config import permissions
from CDocs.utils import audit_trail, notifications
from CDocs.controllers import log_controller_action, ResourceNotFoundError, PermissionError, BusinessRuleError
import logging
import traceback
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.controllers.document_controller import get_document
Condition: only when comment_type is 'ISSUE' and notifications need to be sent with document details
Required (conditional)Usage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.approval_controller import add_approval_comment
# Get the current user
user = DocUser(uid='user_123')
# Add a general comment
result = add_approval_comment(
user=user,
approval_uid='approval_456',
comment_text='This section looks good to me.',
comment_type='GENERAL',
page_number=5
)
if result['success']:
print(f"Comment added: {result['comment_uid']}")
else:
print(f"Error: {result['message']}")
# Add an issue comment with location info
issue_result = add_approval_comment(
user=user,
approval_uid='approval_456',
comment_text='This calculation appears incorrect.',
comment_type='ISSUE',
page_number=12,
location_info={'x': 150, 'y': 300, 'width': 200, 'height': 50}
)
# Add a reply to an existing comment
reply_result = add_approval_comment(
user=user,
approval_uid='approval_456',
comment_text='I agree, we should revise this.',
parent_comment_uid='comment_789'
)
Best Practices
- Always check the 'success' field in the returned dictionary before accessing 'comment_uid' or 'approval_uid'
- Use comment_type='ISSUE' sparingly as it triggers email notifications to all approvers
- Provide page_number and location_info when adding comments about specific document locations for better context
- Handle PermissionError gracefully in the UI to inform users they lack necessary permissions
- The function is decorated with @log_controller_action, so all invocations are automatically logged
- When implementing threaded replies, ensure parent_comment_uid references a valid existing comment
- Comment text in notifications is truncated to 50 characters, so ensure important information is at the beginning
- The function catches and logs all exceptions, returning error messages instead of raising them, so check return values rather than using try-except blocks
- For ISSUE type comments, ensure email infrastructure is properly configured as notifications will be sent synchronously
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function add_approval_comment 92.5% similar
-
function add_review_comment 80.3% similar
-
function update_approval_comment_v1 79.3% similar
-
function update_approval_comment 76.6% similar
-
function add_approver_to_active_approval_v1 68.3% similar