function get_document_training_info
Retrieves comprehensive training information for a specific controlled document, including training configuration, assigned users, completion status, and statistics.
/tf/active/vicechatdev/CDocs/controllers/training_controller.py
1092 - 1217
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
typingdatetimeloggingtracebackCDocs.configCDocs.models.documentCDocs.models.user_extensionsCDocs.models.trainingCDocs.utilsCDocs.dbCDocs.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
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function get_document_training_assignments 80.3% similar
-
function enable_document_training 76.6% similar
-
function complete_user_training_by_uid 76.2% similar
-
class DocumentTraining 75.6% similar
-
function get_training_assignment 73.6% similar