function assign_user_training
Assigns training requirements to multiple users for a specific controlled document, validating permissions, document training status, and user existence before creating assignments.
/tf/active/vicechatdev/CDocs/controllers/training_controller.py
121 - 258
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.configCDocs.models.documentCDocs.models.user_extensionsCDocs.models.trainingCDocs.utilsCDocs.dbCDocs.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
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function get_document_training_assignments 77.1% similar
-
class DocumentTraining 75.7% similar
-
class UserTraining 72.0% similar
-
function enable_document_training 71.6% similar
-
function complete_user_training_by_uid 69.5% similar