🔍 Code Extractor

function assign_user_training

Maturity: 63

Assigns training requirements to multiple users for a specific controlled document, validating permissions, document training status, and user existence before creating assignments.

File:
/tf/active/vicechatdev/CDocs/controllers/training_controller.py
Lines:
121 - 258
Complexity:
complex

Purpose

This function manages the assignment of training requirements to users for controlled documents in a document management system. It verifies that training is enabled for the document, checks that the requesting user has appropriate permissions (either document owner or MANAGE_ALL_TRAINING permission), validates all target users exist, creates training assignments with specified validity periods, logs audit events, and sends notifications to assigned users. It handles partial success scenarios where some assignments succeed and others fail.

Source Code

def assign_user_training(
    user: DocUser,
    document_uid: str,
    user_uids: List[str],
    validity_days: int = 365
) -> Dict[str, Any]:
    """
    Assign training requirement to users.
    """
    try:
        logger.info(f"assign_user_training called by {user.name} for document {document_uid} with users {user_uids}")
        
        # Verify document exists and has training enabled
        document = ControlledDocument(uid=document_uid)
        if not document:
            raise ResourceNotFoundError(f"Document not found: {document_uid}")
        
        doc_training = DocumentTraining(document_uid=document_uid)
        logger.info(f"Training config data: {doc_training._data}")
        
        if not doc_training._data.get("training_required", False):
            raise BusinessRuleError("Training is not enabled for this document")
        
        # Check permissions
        if document.owner_uid != user.uid and not permissions.user_has_permission(user, "MANAGE_ALL_TRAINING"):
            raise PermissionError("Only document owner can assign training requirements")
        
        # Validate user UIDs
        if not user_uids:
            raise ValidationError("At least one user must be specified")
        
        assigned_count = 0
        failed_assignments = []
        
        logger.info(f"Attempting to assign training with validity_days: {validity_days}")
        
        for user_uid in user_uids:
            try:
                logger.info(f"Processing assignment for user {user_uid}")
                
                # Clean and validate UID
                clean_uid = str(user_uid).strip()
                
                # Verify user exists with better error handling
                try:
                    target_user = DocUser(uid=clean_uid)
                except Exception as e:
                    failed_assignments.append(f"Error loading user {clean_uid}: {str(e)}")
                    logger.warning(f"Error loading user {clean_uid}: {e}")
                    continue
                
                if not target_user or not target_user.uid:
                    failed_assignments.append(f"User {clean_uid} not found")
                    logger.warning(f"User {clean_uid} not found")
                    continue
                
                logger.info(f"Found target user: {target_user.name} ({target_user.uid})")
                
                # Assign training with all required parameters
                success = doc_training.assign_user_training(
                    user_uid=clean_uid,
                    assigned_by=user.uid,
                    validity_days=validity_days
                )
                
                logger.info(f"Assignment result for user {clean_uid}: {success}")
                
                if success:
                    assigned_count += 1
                    
                    # Log individual assignment
                    audit_trail.log_event(
                        event_type="TRAINING_ASSIGNED",
                        user=user,
                        resource_uid=document_uid,
                        resource_type="ControlledDocument",
                        details={
                            "assigned_user_uid": user_uid,
                            "assigned_user_name": target_user.name,
                            "doc_number": document.doc_number,
                            "validity_days": validity_days
                        }
                    )
                    
                    # Send notification
                    try:
                        notifications.send_notification(
                            notification_type="TRAINING_ASSIGNED",
                            users=[user_uid],
                            resource_uid=document_uid,
                            resource_type="ControlledDocument",
                            message=f"You have been assigned training for document {document.doc_number}",
                            details={
                                "document_uid": document_uid,
                                "doc_number": document.doc_number,
                                "title": document.title,
                                "assigned_by": user.name
                            },
                            send_email=True,
                            email_template="training_assigned"
                        )
                    except Exception as e:
                        logger.warning(f"Failed to send notification: {e}")
                        
                else:
                    failed_assignments.append(f"Failed to assign training to {target_user.name}")
                    logger.error(f"Failed to assign training to user {clean_uid}")
                    
            except Exception as e:
                error_msg = f"Error assigning training to user {user_uid}: {str(e)}"
                failed_assignments.append(error_msg)
                logger.error(error_msg)
        
        logger.info(f"Assignment complete. Assigned: {assigned_count}, Failed: {len(failed_assignments)}")
        
        if assigned_count > 0:
            return {
                "success": True,
                "message": f"Training assigned to {assigned_count} user(s)",
                "assigned_count": assigned_count,
                "failed_assignments": failed_assignments
            }
        else:
            return {
                "success": False,
                "message": f"Failed to assign training to any users. Errors: {'; '.join(failed_assignments)}",
                "assigned_count": 0,
                "failed_assignments": failed_assignments
            }
        
    except (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) as e:
        logger.error(f"Controller error: {e}")
        raise
    except Exception as e:
        logger.error(f"Unexpected error assigning training: {e}")
        import traceback
        logger.error(f"Traceback: {traceback.format_exc()}")
        raise BusinessRuleError(f"Failed to assign training: {e}")

Parameters

Name Type Default Kind
user DocUser - positional_or_keyword
document_uid str - positional_or_keyword
user_uids List[str] - positional_or_keyword
validity_days int 365 positional_or_keyword

Parameter Details

user: DocUser object representing the authenticated user making the training assignment request. Must have either document ownership or MANAGE_ALL_TRAINING permission.

document_uid: String unique identifier of the controlled document for which training is being assigned. Document must exist and have training enabled.

user_uids: List of string user unique identifiers representing the users who will be assigned the training requirement. Must contain at least one valid user UID. Invalid UIDs are logged but don't stop processing of valid ones.

validity_days: Integer number of days the training assignment remains valid before requiring renewal. Defaults to 365 days (one year). Must be a positive integer.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean indicating if any assignments succeeded), 'message' (string summary of operation result), 'assigned_count' (integer count of successful assignments), and 'failed_assignments' (list of strings describing each failed assignment with error details). If all assignments fail, success is False; if any succeed, success is True even with partial failures.

Dependencies

  • CDocs.config
  • CDocs.models.document
  • CDocs.models.user_extensions
  • CDocs.models.training
  • CDocs.utils
  • CDocs.db
  • CDocs.controllers

Required Imports

from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta
import logging
from CDocs.config import settings, permissions
from CDocs.models.document import ControlledDocument
from CDocs.models.user_extensions import DocUser
from CDocs.models.training import DocumentTraining, UserTraining
from CDocs.utils import audit_trail, notifications
from CDocs.db import db_operations as db
from CDocs.controllers import require_permission, log_controller_action, transaction
from CDocs.controllers import PermissionError, ResourceNotFoundError, ValidationError, BusinessRuleError
from CDocs.controllers import document_controller
import traceback

Conditional/Optional Imports

These imports are only needed under specific conditions:

import traceback

Condition: Used for detailed error logging when unexpected exceptions occur

Required (conditional)

Usage Example

from CDocs.models.user_extensions import DocUser
from CDocs.controllers.training_controller import assign_user_training

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

# Assign training to multiple users for a document
result = assign_user_training(
    user=current_user,
    document_uid='doc456',
    user_uids=['user789', 'user101', 'user202'],
    validity_days=180
)

if result['success']:
    print(f"Successfully assigned training to {result['assigned_count']} users")
    if result['failed_assignments']:
        print(f"Failed assignments: {result['failed_assignments']}")
else:
    print(f"Training assignment failed: {result['message']}")

Best Practices

  • Always ensure the calling user has appropriate permissions before invoking this function
  • Handle partial success scenarios - check both assigned_count and failed_assignments in the return value
  • Validate user_uids list is not empty before calling to avoid ValidationError
  • Consider the validity_days parameter based on organizational training renewal policies
  • Monitor failed_assignments list for systematic issues with user data or permissions
  • This function is decorated with transaction, so database changes are atomic - all succeed or all rollback
  • The function logs extensively - ensure logging is configured appropriately for production environments
  • Email notifications are sent asynchronously - notification failures don't cause assignment failures
  • The function requires training to be enabled on the document before assignments can be made
  • Only document owners or users with MANAGE_ALL_TRAINING permission can assign training

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function get_document_training_assignments 77.1% similar

    Retrieves training assignments and configuration for a specific controlled document, including assigned users and training requirements.

    From: /tf/active/vicechatdev/CDocs/controllers/training_controller.py
  • class DocumentTraining 75.7% similar

    A model class that manages training requirements and assignments for controlled documents, including enabling/disabling training, assigning training to users, and tracking training status.

    From: /tf/active/vicechatdev/CDocs/models/training.py
  • class UserTraining 72.0% similar

    A model class representing a user's training status for a specific controlled document, managing training assignments, completion tracking, and expiration dates.

    From: /tf/active/vicechatdev/CDocs/models/training.py
  • function enable_document_training 71.6% similar

    Enables training requirements for a controlled document, setting validity period, quiz requirements, and instructions for users who need to complete training on the document.

    From: /tf/active/vicechatdev/CDocs/controllers/training_controller.py
  • function complete_user_training_by_uid 69.5% similar

    Completes a user's training assignment for a controlled document by updating the training relationship status, recording completion date and score, and logging the event to the audit trail.

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