upskill-event-manager/includes/class-hvac-approval-workflow.php
bengizmo f0edd05369 feat: Implement trainer approval workflow with status management
- Add trainer status system (pending, approved, active, inactive, disabled)
- Create access control system based on trainer status
- Refactor Master Dashboard with enhanced trainer table
  - Add status column and filtering
  - Implement search and pagination
  - Add bulk status update functionality
- Create status pages for pending and disabled trainers
- Implement approval workflow with email notifications
- Add email template management to settings page
- Include comprehensive test suite (unit, integration, E2E)

This allows Master Trainers to manage trainer accounts, approve new registrations,
and control access based on account status. Trainers must be approved before
accessing dashboard features.

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-28 12:38:34 -03:00

423 lines
No EOL
17 KiB
PHP

<?php
/**
* HVAC Community Events - Approval Workflow
*
* Handles trainer approval workflow and email notifications
*
* @package HVAC_Community_Events
* @since 1.0.0
*/
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class HVAC_Approval_Workflow
*
* Manages the trainer approval process including email notifications
*/
class HVAC_Approval_Workflow {
/**
* Constructor
*/
public function __construct() {
// Hook into trainer status changes
add_action( 'hvac_trainer_status_changed', array( $this, 'handle_status_change' ), 10, 3 );
// Add query variable for approval token
add_filter( 'query_vars', array( $this, 'add_query_vars' ) );
// Handle approval URL visits
add_action( 'template_redirect', array( $this, 'handle_approval_request' ), 5 );
// Add AJAX handlers for bulk updates
add_action( 'wp_ajax_hvac_bulk_update_trainer_status', array( $this, 'ajax_bulk_update_status' ) );
}
/**
* Add query variables for approval
*/
public function add_query_vars( $vars ) {
$vars[] = 'hvac_approve_trainer';
$vars[] = 'hvac_approval_token';
return $vars;
}
/**
* Handle trainer status changes
*
* @param int $user_id User ID
* @param string $new_status New status
* @param string $old_status Old status
*/
public function handle_status_change( $user_id, $new_status, $old_status ) {
// Send appropriate notifications based on status change
if ( $new_status === HVAC_Trainer_Status::STATUS_APPROVED && $old_status === HVAC_Trainer_Status::STATUS_PENDING ) {
$this->send_approval_notification( $user_id );
} elseif ( $new_status === HVAC_Trainer_Status::STATUS_DISABLED ) {
$this->send_disabled_notification( $user_id );
}
}
/**
* Send new registration notification to admins
*
* @param int $user_id User ID
* @param array $registration_data Registration form data
*/
public function send_new_registration_notification( $user_id, $registration_data ) {
$user = get_userdata( $user_id );
if ( ! $user ) {
return false;
}
// Get notification emails
$options = get_option( 'hvac_ce_options', array() );
$notification_emails = isset( $options['notification_emails'] ) ? $options['notification_emails'] : get_option( 'admin_email' );
// Convert comma-separated list to array
if ( is_string( $notification_emails ) ) {
$notification_emails = array_map( 'trim', explode( ',', $notification_emails ) );
}
// Generate approval token
$approval_token = $this->generate_approval_token( $user_id );
update_user_meta( $user_id, 'hvac_approval_token', $approval_token );
// Build approval URL
$approval_url = add_query_arg( array(
'hvac_approve_trainer' => $user_id,
'hvac_approval_token' => $approval_token,
), home_url( '/master-trainer/dashboard/' ) );
// Get email template
$template = $this->get_email_template( 'new_registration' );
// Replace placeholders
$replacements = array(
'{trainer_name}' => $user->display_name,
'{trainer_email}' => $user->user_email,
'{business_name}' => get_user_meta( $user_id, 'business_name', true ),
'{business_phone}' => get_user_meta( $user_id, 'business_phone', true ),
'{business_email}' => get_user_meta( $user_id, 'business_email', true ),
'{registration_date}' => date( 'F j, Y', strtotime( $user->user_registered ) ),
'{application_details}' => get_user_meta( $user_id, 'application_details', true ),
'{approval_url}' => $approval_url,
'{website_name}' => get_bloginfo( 'name' ),
'{website_url}' => home_url(),
);
$subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['subject'] );
$message = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['body'] );
// Send emails
$headers = array( 'Content-Type: text/html; charset=UTF-8' );
foreach ( $notification_emails as $email ) {
wp_mail( $email, $subject, $message, $headers );
}
return true;
}
/**
* Send approval notification to trainer
*
* @param int $user_id User ID
*/
public function send_approval_notification( $user_id ) {
$user = get_userdata( $user_id );
if ( ! $user ) {
return false;
}
// Get email template
$template = $this->get_email_template( 'account_approved' );
// Replace placeholders
$replacements = array(
'{trainer_name}' => $user->display_name,
'{trainer_email}' => $user->user_email,
'{business_name}' => get_user_meta( $user_id, 'business_name', true ),
'{dashboard_url}' => home_url( '/trainer/dashboard/' ),
'{login_url}' => home_url( '/community-login/' ),
'{website_name}' => get_bloginfo( 'name' ),
'{website_url}' => home_url(),
'{current_date}' => date( 'F j, Y' ),
);
$subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['subject'] );
$message = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['body'] );
// Send email
$headers = array( 'Content-Type: text/html; charset=UTF-8' );
return wp_mail( $user->user_email, $subject, $message, $headers );
}
/**
* Send disabled notification to trainer
*
* @param int $user_id User ID
*/
public function send_disabled_notification( $user_id ) {
$user = get_userdata( $user_id );
if ( ! $user ) {
return false;
}
// Get email template
$template = $this->get_email_template( 'account_disabled' );
// Replace placeholders
$replacements = array(
'{trainer_name}' => $user->display_name,
'{trainer_email}' => $user->user_email,
'{business_name}' => get_user_meta( $user_id, 'business_name', true ),
'{support_email}' => get_option( 'admin_email' ),
'{website_name}' => get_bloginfo( 'name' ),
'{website_url}' => home_url(),
'{current_date}' => date( 'F j, Y' ),
);
$subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['subject'] );
$message = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['body'] );
// Send email
$headers = array( 'Content-Type: text/html; charset=UTF-8' );
return wp_mail( $user->user_email, $subject, $message, $headers );
}
/**
* Get email template
*
* @param string $template_key Template key
* @return array Template data with subject and body
*/
private function get_email_template( $template_key ) {
$options = get_option( 'hvac_ce_email_templates', array() );
// Default templates
$defaults = array(
'new_registration' => array(
'subject' => 'New HVAC Trainer Registration - {trainer_name}',
'body' => '
<h2>New Trainer Registration Pending Approval</h2>
<p>A new HVAC trainer has registered and is awaiting approval.</p>
<h3>Trainer Details:</h3>
<ul>
<li><strong>Name:</strong> {trainer_name}</li>
<li><strong>Email:</strong> {trainer_email}</li>
<li><strong>Business:</strong> {business_name}</li>
<li><strong>Phone:</strong> {business_phone}</li>
<li><strong>Business Email:</strong> {business_email}</li>
<li><strong>Registration Date:</strong> {registration_date}</li>
</ul>
<h3>Application Details:</h3>
<p>{application_details}</p>
<p><a href="{approval_url}" style="display: inline-block; padding: 10px 20px; background: #0073aa; color: white; text-decoration: none; border-radius: 4px;">Approve This Trainer</a></p>
<p>Or copy this link: {approval_url}</p>
',
),
'account_approved' => array(
'subject' => 'Your HVAC Trainer Account Has Been Approved!',
'body' => '
<h2>Welcome to {website_name}!</h2>
<p>Dear {trainer_name},</p>
<p>Great news! Your HVAC trainer account has been approved and you now have full access to create and manage training events.</p>
<h3>What You Can Do Now:</h3>
<ul>
<li>Create and manage training events</li>
<li>Access your trainer dashboard</li>
<li>Generate certificates for attendees</li>
<li>Communicate with your attendees</li>
<li>View analytics and reports</li>
</ul>
<h3>Getting Started:</h3>
<ol>
<li><a href="{login_url}">Log in to your account</a></li>
<li>Visit your <a href="{dashboard_url}">Trainer Dashboard</a></li>
<li>Click "Create New Event" to post your first training event</li>
<li>Share your event with your network to maximize attendance</li>
</ol>
<p>If you have any questions or need assistance, please don\'t hesitate to reach out to our support team.</p>
<p>We\'re excited to have you as part of our training community!</p>
<p>Best regards,<br>
The {website_name} Team</p>
',
),
'account_disabled' => array(
'subject' => 'Your HVAC Trainer Account Has Been Disabled',
'body' => '
<h2>Account Status Update</h2>
<p>Dear {trainer_name},</p>
<p>We regret to inform you that your HVAC trainer account on {website_name} has been disabled.</p>
<p>Your account may have been disabled for one of the following reasons:</p>
<ul>
<li>Violation of our terms of service or community guidelines</li>
<li>Extended period of inactivity</li>
<li>Incomplete or inaccurate information</li>
<li>Quality concerns or complaints</li>
</ul>
<p>If you believe this action was taken in error or would like to discuss reactivating your account, please contact our support team at <a href="mailto:{support_email}">{support_email}</a>.</p>
<p>We appreciate your understanding.</p>
<p>Sincerely,<br>
The {website_name} Team</p>
',
),
);
// Return custom template if exists, otherwise default
if ( isset( $options[$template_key] ) ) {
return $options[$template_key];
}
return isset( $defaults[$template_key] ) ? $defaults[$template_key] : array( 'subject' => '', 'body' => '' );
}
/**
* Generate approval token
*
* @param int $user_id User ID
* @return string Token
*/
private function generate_approval_token( $user_id ) {
return wp_hash( $user_id . time() . wp_rand() );
}
/**
* Handle approval request from email link
*/
public function handle_approval_request() {
$user_id = get_query_var( 'hvac_approve_trainer' );
$token = get_query_var( 'hvac_approval_token' );
if ( ! $user_id || ! $token ) {
return;
}
// Verify token
$stored_token = get_user_meta( $user_id, 'hvac_approval_token', true );
if ( $token !== $stored_token ) {
wp_die( __( 'Invalid approval token.', 'hvac-community-events' ) );
}
// Check if user is logged in
if ( ! is_user_logged_in() ) {
// Store approval request in session/transient
set_transient( 'hvac_pending_approval_' . $token, $user_id, HOUR_IN_SECONDS );
// Redirect to login with return URL
$login_url = add_query_arg( array(
'redirect_to' => urlencode( add_query_arg( array(
'hvac_approve_trainer' => $user_id,
'hvac_approval_token' => $token,
), home_url( '/master-trainer/dashboard/' ) ) ),
), home_url( '/community-login/' ) );
wp_redirect( $login_url );
exit;
}
// Check if current user can approve trainers
if ( ! current_user_can( 'view_master_dashboard' ) && ! current_user_can( 'manage_options' ) ) {
wp_die( __( 'You do not have permission to approve trainers.', 'hvac-community-events' ) );
}
// Approve the trainer
if ( ! class_exists( 'HVAC_Trainer_Status' ) ) {
require_once HVAC_CE_PLUGIN_DIR . 'includes/class-hvac-trainer-status.php';
}
$result = HVAC_Trainer_Status::set_trainer_status( $user_id, HVAC_Trainer_Status::STATUS_APPROVED );
if ( $result ) {
// Delete the token
delete_user_meta( $user_id, 'hvac_approval_token' );
// Get trainer info for message
$trainer = get_userdata( $user_id );
$message = sprintf(
__( 'Trainer %s with email %s has been approved!', 'hvac-community-events' ),
$trainer->display_name,
$trainer->user_email
);
// Store success message in transient
set_transient( 'hvac_approval_message', $message, 30 );
}
// Redirect to master dashboard
wp_redirect( home_url( '/master-trainer/dashboard/' ) );
exit;
}
/**
* AJAX handler for bulk status updates
*/
public function ajax_bulk_update_status() {
// Check nonce
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'hvac_master_dashboard_nonce' ) ) {
wp_die( 'Security check failed' );
}
// Check permissions
if ( ! current_user_can( 'view_master_dashboard' ) && ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
}
// Get parameters
$user_ids = isset( $_POST['user_ids'] ) ? array_map( 'intval', $_POST['user_ids'] ) : array();
$new_status = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : '';
if ( empty( $user_ids ) || empty( $new_status ) ) {
wp_send_json_error( array( 'message' => 'Missing required parameters' ) );
}
// Load status class
if ( ! class_exists( 'HVAC_Trainer_Status' ) ) {
require_once HVAC_CE_PLUGIN_DIR . 'includes/class-hvac-trainer-status.php';
}
// Perform bulk update
$results = HVAC_Trainer_Status::bulk_update_status( $user_ids, $new_status );
if ( $results['success'] > 0 ) {
wp_send_json_success( array(
'message' => sprintf(
__( 'Successfully updated %d trainer(s). %d failed.', 'hvac-community-events' ),
$results['success'],
$results['failed']
),
'results' => $results,
) );
} else {
wp_send_json_error( array(
'message' => __( 'Failed to update trainer statuses.', 'hvac-community-events' ),
'results' => $results,
) );
}
}
}