🔍 Code Extractor

function add_reviewer_to_active_review

Maturity: 72

Adds a reviewer to an active review cycle with optional sequence ordering and instructions, handling permissions, notifications, and audit logging.

File:
/tf/active/vicechatdev/CDocs/controllers/review_controller.py
Lines:
1471 - 1613
Complexity:
complex

Purpose

This function manages the addition of reviewers to document review cycles in a controlled document management system. It validates permissions, checks review cycle status, prevents duplicate reviewer assignments, optionally sets sequence order for sequential reviews, sends notifications to the new reviewer, updates document sharing permissions, and logs the action for audit purposes. It is designed to be used in document review workflows where multiple reviewers may need to be assigned to review document versions.

Source Code

def add_reviewer_to_active_review(
    user: DocUser,
    review_uid: str,
    reviewer_uid: str,
    sequence_order: Optional[int] = None,
    instructions: Optional[str] = None  # New parameter
) -> Dict[str, Any]:
    """
    Add a reviewer to an active review cycle.
    
    Args:
        user: User adding the reviewer
        review_uid: UID of review cycle
        reviewer_uid: UID of user to add as reviewer
        sequence_order: Optional sequence order for sequential reviews
        
    Returns:
        Dictionary with addition details
        
    Raises:
        ResourceNotFoundError: If review cycle not found
        ValidationError: If validation fails
        PermissionError: If user doesn't have permission
        BusinessRuleError: If addition is not allowed
    """
    try:
        # Direct permission check at the beginning
        logger.info(f"Checking if user {user.uid} has MANAGE_REVIEWS permission")
        if not permissions.user_has_permission(user, "MANAGE_REVIEWS"):
            logger.warning(f"Permission denied: User {user.uid} attempted to add reviewer without MANAGE_REVIEWS permission")
            raise PermissionError("You do not have permission to add reviewers")
            
        logger.info(f"User {user.uid} has permission to add reviewer to review cycle {review_uid}")

        # Get review cycle instance
        review_cycle = ReviewCycle(uid=review_uid)
        if not review_cycle:
            raise ResourceNotFoundError(f"Review cycle not found: {review_uid}")
            
        # Check if review status allows adding reviewers
        if review_cycle.status not in ["PENDING", "IN_PROGRESS"]:
            raise BusinessRuleError(f"Cannot add reviewers to review with status {review_cycle.status}")
            
        # Validate reviewer UID
        reviewer = DocUser(uid=reviewer_uid)
        if not reviewer or not reviewer.uid:
            raise ValidationError(f"Invalid reviewer: {reviewer_uid}")
            
        # Check if already a reviewer
        if review_cycle.is_reviewer(reviewer_uid):
            raise BusinessRuleError(f"User {reviewer_uid} is already a reviewer for this review cycle")
            
        # Add reviewer using the model method - this creates the relationship and assignment
        success = review_cycle.add_reviewer(reviewer)
        
        if not success:
            raise BusinessRuleError(f"Failed to add reviewer {reviewer_uid}")
            
        # If sequence order provided (for sequential reviews), update it
        assignment = review_cycle.get_reviewer_assignment(reviewer_uid)
        if assignment:
            if sequence_order is not None:
                assignment.sequence_order = sequence_order
                
            # Set reviewer-specific instructions if provided
            if instructions is not None:
                assignment.instructions = instructions
                
            assignment.save()
            
        # Log the reviewer addition
        audit_trail.log_review_event(
            event_type="REVIEW_UPDATED",
            user=user,
            review_uid=review_uid,
            details={
                "action": "reviewer_added",
                "reviewer_uid": reviewer_uid,
                "reviewer_name": reviewer.name,
                "sequence_order": sequence_order
            }
        )
        
        # Send notification to new reviewer
        try:
            # Get document info for the notification
            document = None
            document_version = review_cycle.document_version
            if document_version:
                document = document_version.document
                
            notifications.send_notification(
                notification_type="REVIEW_ASSIGNED",
                users=[reviewer_uid],
                resource_uid=review_uid,
                resource_type="ReviewCycle",
                message=f"You have been added as a reviewer",
                details={
                    "review_uid": review_uid,
                    "document_uid": document.uid if document else None,
                    "doc_number": document.doc_number if document else "Unknown",
                    "title": document.title if document else "Unknown Document",
                    "due_date": review_cycle.due_date.isoformat() if review_cycle.due_date else None
                },
                send_email=True,
                email_template="review_assigned",
                email_data={
                    "app_url": settings.APP_URL,
                    "doc_uid": document.uid if document else None,
                    "review_uid": review_uid,
                    "due_date": review_cycle.due_date.isoformat() if review_cycle.due_date else None,
                    "instructions": instructions,
                    "assigned_by": user.name
                }
            )
        except Exception as notif_err:
            logger.error(f"Error sending reviewer notification: {notif_err}")
            # Continue even if notification fails
        
        # Update sharing permissions for document based on new review cycle
        from CDocs.controllers.share_controller import manage_document_permissions
        document = ControlledDocument(uid=document.uid)
        permission_result = manage_document_permissions(document)

        return {
            "success": True,
            "review_uid": review_uid,
            "reviewer": {
                "uid": reviewer.uid,
                "name": reviewer.name,
                "email": reviewer.email
            },
            "assignment": assignment.to_dict() if assignment else None,
            "message": f"Reviewer {reviewer.name} added successfully"
        }
        
    except (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) as e:
        # Re-raise known errors
        raise
    except Exception as e:
        logger.error(f"Error adding reviewer to review cycle: {e}")
        logger.error(traceback.format_exc())
        raise BusinessRuleError(f"Failed to add reviewer: {e}")

Parameters

Name Type Default Kind
user DocUser - positional_or_keyword
review_uid str - positional_or_keyword
reviewer_uid str - positional_or_keyword
sequence_order Optional[int] None positional_or_keyword
instructions Optional[str] None positional_or_keyword

Parameter Details

user: DocUser object representing the user performing the action. Must have MANAGE_REVIEWS permission. Used for permission checks and audit logging.

review_uid: String UID (unique identifier) of the review cycle to which the reviewer will be added. Must correspond to an existing ReviewCycle with status 'PENDING' or 'IN_PROGRESS'.

reviewer_uid: String UID of the user to be added as a reviewer. Must correspond to a valid DocUser and cannot already be a reviewer on this review cycle.

sequence_order: Optional integer specifying the order in which this reviewer should review (for sequential review workflows). If None, no specific order is enforced. Used to set the sequence_order field on the ReviewerAssignment.

instructions: Optional string containing specific instructions for this reviewer. If provided, these instructions are stored in the ReviewerAssignment and included in the notification email sent to the reviewer.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean, always True if no exception), 'review_uid' (string, the review cycle UID), 'reviewer' (dict with 'uid', 'name', 'email' of added reviewer), 'assignment' (dict representation of the ReviewerAssignment object or None), and 'message' (string confirmation message). If any error occurs, raises an exception instead of returning.

Dependencies

  • logging
  • uuid
  • os
  • typing
  • datetime
  • traceback
  • CDocs
  • CDocs.config
  • CDocs.models.document
  • CDocs.models.review
  • CDocs.models.user_extensions
  • CDocs.utils
  • CDocs.controllers
  • CDocs.controllers.document_controller
  • CDocs.controllers.share_controller
  • CDocs.db

Required Imports

import logging
import traceback
from typing import Dict, Any, Optional
from CDocs.config import settings, permissions
from CDocs.models.document import ControlledDocument
from CDocs.models.review import ReviewCycle
from CDocs.models.user_extensions import DocUser
from CDocs.utils import audit_trail, notifications
from CDocs.controllers import PermissionError, ResourceNotFoundError, ValidationError, BusinessRuleError
from CDocs.controllers.share_controller import manage_document_permissions

Conditional/Optional Imports

These imports are only needed under specific conditions:

from CDocs.controllers.share_controller import manage_document_permissions

Condition: imported within the function body for updating document permissions after reviewer addition

Required (conditional)

Usage Example

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

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

# Add a reviewer to a review cycle
result = add_reviewer_to_active_review(
    user=acting_user,
    review_uid='review456',
    reviewer_uid='reviewer789',
    sequence_order=2,
    instructions='Please focus on technical accuracy and compliance with standards'
)

print(f"Reviewer added: {result['reviewer']['name']}")
print(f"Assignment details: {result['assignment']}")

Best Practices

  • Ensure the acting user has MANAGE_REVIEWS permission before calling this function
  • Only call this function for review cycles with status 'PENDING' or 'IN_PROGRESS'
  • Verify that the reviewer_uid corresponds to a valid user before calling
  • Handle all four exception types: ResourceNotFoundError, ValidationError, PermissionError, and BusinessRuleError
  • Be aware that notification failures are logged but do not cause the function to fail
  • Use sequence_order parameter only for sequential review workflows where order matters
  • Provide clear instructions parameter to help reviewers understand their specific responsibilities
  • The function automatically updates document sharing permissions, so no additional permission management is needed
  • All actions are logged to the audit trail automatically for compliance tracking

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function remove_reviewer_from_active_review 78.1% similar

    Removes a reviewer from an active review cycle, updating assignment status, adjusting sequential review orders if needed, logging the event, and notifying the removed reviewer.

    From: /tf/active/vicechatdev/CDocs/controllers/review_controller.py
  • function add_approver_to_active_approval 77.1% similar

    Adds a new approver to an active approval cycle for a controlled document, with optional sequence ordering and custom instructions.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function add_review_comment 74.3% 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 complete_review 71.5% similar

    Completes a document review cycle by submitting a reviewer's decision (APPROVED/REJECTED), updating review status, managing sequential review workflows, and triggering notifications.

    From: /tf/active/vicechatdev/CDocs/controllers/review_controller.py
  • function add_approver_to_active_approval_v1 70.5% similar

    Adds a new approver to an active approval cycle with permission checks, validation, audit logging, and email notifications.

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