🔍 Code Extractor

function get_document_training_info

Maturity: 59

Retrieves comprehensive training information for a specific controlled document, including training configuration, assigned users, completion status, and statistics.

File:
/tf/active/vicechatdev/CDocs/controllers/training_controller.py
Lines:
1092 - 1217
Complexity:
moderate

Purpose

This function queries a Neo4j graph database to fetch training-related data for a controlled document. It returns information about whether training is enabled for the document, training configuration settings (validity period, quiz requirements, instructions), lists of assigned/completed/pending users, and calculated statistics like completion rates. It's designed for document management systems that track user training requirements on controlled documents.

Source Code

def get_document_training_info(document_uid: str) -> Dict[str, Any]:
    """
    Get training information for a specific document.
    
    Args:
        document_uid: Document UID
        
    Returns:
        Dictionary with training information
    """
    try:
        logger.info(f"Getting training info for document: {document_uid}")
        
        # Updated query to check document properties and relationships
        query = """
        OPTIONAL MATCH (d:ControlledDocument {UID: $document_uid})
        OPTIONAL MATCH (u:User)-[r:REQUIRES_TRAINING]->(d)
        WITH d, collect({
            user: u,
            relationship: r
        }) as user_trainings
        RETURN d, user_trainings
        """
        
        result = db.run_query(query, {'document_uid': document_uid})
        records = list(result)
        logger.info(f"Query returned {len(records)} records for document {document_uid}")
        
        if not records:
            logger.warning(f"No records found for document {document_uid}")
            return {
                'enabled': False,
                'document_uid': document_uid,
                'assigned_users': [],
                'completed_users': [],
                'pending_users': []
            }
        
        record = records[0]
        doc_data = record['d']
        user_trainings = record['user_trainings'] or []
        
        logger.info(f"Document data found: {doc_data is not None}")
        
        # Check training status from document properties (matches enable_document_training approach)
        training_enabled = False
        training_validity_days = 365
        training_quiz_required = False
        training_instructions = ''
        training_enabled_date = None
        
        if doc_data:
            training_enabled = doc_data.get('training_required', False)
            training_validity_days = doc_data.get('training_validity_days', 365)
            training_quiz_required = doc_data.get('training_quiz_required', False)
            training_instructions = doc_data.get('training_instructions', '')
            training_enabled_date = doc_data.get('training_enabled_date')
            
            logger.info(f"Document properties - training_required: {training_enabled}")
            logger.info(f"Document properties - training_validity_days: {training_validity_days}")
            logger.info(f"Document properties - training_quiz_required: {training_quiz_required}")
        
        # Process user training data
        assigned_users = []
        completed_users = []
        pending_users = []
        
        logger.info(f"Processing {len(user_trainings)} user training records")
        
        for ut_record in user_trainings:
            if ut_record and ut_record.get('user') and ut_record.get('relationship'):
                user_data = ut_record['user']
                rel_data = ut_record['relationship']
                
                user_info = {
                    'uid': user_data.get('UID'),
                    'username': user_data.get('username', user_data.get('Name', 'Unknown')),
                    'email': user_data.get('Mail', ''),
                    'name': user_data.get('Name', user_data.get('username', 'Unknown')),
                    'assigned_date': rel_data.get('assigned_date'),
                    'expires_date': rel_data.get('expires_date'),
                    'completed_date': rel_data.get('completed_date'),
                    'status': rel_data.get('status', 'REQUIRED'),
                    'assigned_by': rel_data.get('assigned_by')
                }
                
                assigned_users.append(user_info)
                
                if rel_data.get('status') == 'COMPLETED':
                    completed_users.append(user_info)
                else:
                    pending_users.append(user_info)
        
        logger.info(f"Final training enabled status for document {document_uid}: {training_enabled}")
        
        return {
            'enabled': training_enabled,
            'document_uid': document_uid,
            'document_title': doc_data.get('title') if doc_data else 'Unknown Document',
            'training_config': {
                'validity_days': training_validity_days,
                'quiz_required': training_quiz_required,
                'instructions': training_instructions,
                'enabled_date': training_enabled_date
            } if training_enabled else None,
            'assigned_users': assigned_users,
            'completed_users': completed_users,
            'pending_users': pending_users,
            'stats': {
                'total_assigned': len(assigned_users),
                'total_completed': len(completed_users),
                'total_pending': len(pending_users),
                'completion_rate': round((len(completed_users) / len(assigned_users)) * 100, 1) if assigned_users else 0
            }
        }
        
    except Exception as e:
        logger.error(f"Error getting document training info: {e}")
        return {
            'enabled': False,
            'document_uid': document_uid,
            'error': str(e),
            'assigned_users': [],
            'completed_users': [],
            'pending_users': []
        }

Parameters

Name Type Default Kind
document_uid str - positional_or_keyword

Parameter Details

document_uid: Unique identifier (UID) string for the controlled document. This is used to query the Neo4j database for the specific document node and its related training relationships. Must be a valid document UID that exists in the database.

Return Value

Type: Dict[str, Any]

Returns a dictionary containing: 'enabled' (bool) - whether training is required for the document; 'document_uid' (str) - the queried document UID; 'document_title' (str) - title of the document; 'training_config' (dict or None) - configuration with validity_days, quiz_required, instructions, enabled_date; 'assigned_users' (list) - all users with training assignments; 'completed_users' (list) - users who completed training; 'pending_users' (list) - users with incomplete training; 'stats' (dict) - aggregated statistics including total counts and completion rate percentage. On error, returns a minimal dictionary with 'enabled': False, 'document_uid', 'error' message, and empty user lists.

Dependencies

  • typing
  • datetime
  • logging
  • traceback
  • CDocs.config
  • CDocs.models.document
  • CDocs.models.user_extensions
  • CDocs.models.training
  • CDocs.utils
  • CDocs.db
  • CDocs.controllers

Required Imports

from typing import Dict, Any
import logging
from CDocs.db import db_operations as db

Usage Example

# Assuming db_operations and logger are properly configured
from typing import Dict, Any
import logging
from CDocs.db import db_operations as db

# Setup logger
logger = logging.getLogger(__name__)

# Get training info for a document
document_uid = "DOC-12345"
training_info = get_document_training_info(document_uid)

# Check if training is enabled
if training_info['enabled']:
    print(f"Training enabled for: {training_info['document_title']}")
    print(f"Validity days: {training_info['training_config']['validity_days']}")
    print(f"Quiz required: {training_info['training_config']['quiz_required']}")
    print(f"Completion rate: {training_info['stats']['completion_rate']}%")
    
    # List pending users
    for user in training_info['pending_users']:
        print(f"Pending: {user['name']} ({user['email']})")
else:
    print(f"Training not enabled for document {document_uid}")
    if 'error' in training_info:
        print(f"Error: {training_info['error']}")

Best Practices

  • Always check the 'enabled' field in the returned dictionary before processing training data
  • Handle the case where 'training_config' may be None if training is not enabled
  • Check for 'error' key in the returned dictionary to detect and handle exceptions gracefully
  • The function uses OPTIONAL MATCH in Cypher queries, so it handles non-existent documents gracefully
  • User lists may be empty even if training is enabled (no users assigned yet)
  • Completion rate calculation handles division by zero when no users are assigned
  • The function logs extensively - ensure appropriate log level configuration to avoid log spam
  • Document UID must be exact match (case-sensitive) as it queries by UID property
  • The function returns consistent structure even on errors, making it safe for downstream processing
  • Consider caching results if calling frequently for the same document to reduce database load

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function get_document_training_assignments 80.3% 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
  • function enable_document_training 76.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 76.2% 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
  • class DocumentTraining 75.6% 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
  • function get_training_assignment 73.6% similar

    Retrieves a specific training assignment for a user from a Neo4j graph database, validating user authorization and parsing a composite UID format.

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