upskill-event-manager/includes/class-hvac-access-control.php
ben 1032fbfe85
Some checks failed
Security Monitoring & Compliance / Static Code Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Compliance Validation (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Has been cancelled
Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Has been cancelled
Security Monitoring & Compliance / Secrets & Credential Scan (push) Has been cancelled
Security Monitoring & Compliance / WordPress Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Summary Report (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Notification (push) Has been cancelled
Security Monitoring & Compliance / Security Team Notification (push) Has been cancelled
feat: complete PHP 8+ modernization with backward compatibility
Major modernization of HVAC plugin for PHP 8+ with full backward compatibility:

CORE MODERNIZATION:
- Implement strict type declarations throughout codebase
- Modernize main plugin class with PHP 8+ features
- Convert array syntax to modern PHP format
- Add constructor property promotion where applicable
- Enhance security helpers with modern PHP patterns

COMPATIBILITY FIXES:
- Fix PHP 8.1+ enum compatibility (convert to class constants)
- Fix union type compatibility (true|WP_Error → bool|WP_Error)
- Remove mixed type declarations for PHP 8.0 compatibility
- Add default arms to match expressions preventing UnhandledMatchError
- Fix method naming inconsistency (ensureRegistrationAccess callback)
- Add null coalescing in TEC integration for strict type compliance

DEPLOYMENT STATUS:
 Successfully deployed and tested on staging
 Site functional at https://upskill-staging.measurequick.com
 Expert code review completed with GPT-5 validation
 MCP Playwright testing confirms functionality

Ready for production deployment when requested.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 17:44:39 -03:00

363 lines
No EOL
11 KiB
PHP

<?php
declare(strict_types=1);
/**
* HVAC Community Events - Access Control
*
* Handles page access restrictions based on trainer status
*
* @package HVAC_Community_Events
* @since 1.0.0
*/
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class HVAC_Access_Control
*
* Manages access control for trainer pages based on account status
*/
class HVAC_Access_Control {
/**
* Pages that require authentication but no specific status
*/
private static $public_pages = [
'trainer/registration',
'registration-pending',
'community-login',
'training-login',
'trainer-account-pending',
'trainer-account-disabled',
];
/**
* Pages that require trainer to be active or inactive
*/
private static $trainer_pages = [
'trainer/dashboard',
'trainer/event/manage',
'trainer/event/edit',
'trainer/generate-certificates',
'trainer/certificate-reports',
'trainer/event/summary',
'trainer/email-attendees',
'trainer/communication-templates',
'edit-profile',
];
/**
* Pages that require master trainer role
*/
private static $master_trainer_pages = [
'master-trainer/master-dashboard',
'master-trainer/certificate-fix',
'master-trainer/google-sheets',
];
/**
* Constructor
*/
public function __construct() {
// Hook into template_redirect for access control
add_action( 'template_redirect', [ $this, 'check_page_access' ], 10 );
}
/**
* Check page access based on user status
*/
public function check_page_access() {
// Get current page path
$current_path = trim( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
// Check if this is a legacy URL that will be redirected
if ( $this->is_legacy_url( $current_path ) ) {
// Allow the redirect to happen first
return;
}
// Check if this is a public page
if ( $this->is_public_page( $current_path ) ) {
return;
}
// Check if this is a trainer page
if ( $this->is_trainer_page( $current_path ) ) {
$this->check_trainer_access( $current_path );
}
// Check if this is a master trainer page
if ( $this->is_master_trainer_page( $current_path ) ) {
$this->check_master_trainer_access( $current_path );
}
}
/**
* Check if current URL is a legacy URL that should be redirected
*
* @param string $path Current page path
* @return bool
*/
private function is_legacy_url( $path ) {
// Get the route manager instance
if ( ! class_exists( 'HVAC_Route_Manager' ) ) {
return false;
}
$route_manager = HVAC_Route_Manager::instance();
// Check if this path needs a redirect
return $route_manager->needs_redirect( $path ) !== false;
}
/**
* Check if current page is public
*
* @param string $path Current page path
* @return bool
*/
private function is_public_page( $path ) {
foreach ( self::$public_pages as $public_page ) {
if ( $path === $public_page || strpos( $path, $public_page ) === 0 ) {
return true;
}
}
return false;
}
/**
* Check if current page is a trainer page
*
* @param string $path Current page path
* @return bool
*/
private function is_trainer_page( $path ) {
foreach ( self::$trainer_pages as $trainer_page ) {
if ( $path === $trainer_page || strpos( $path, $trainer_page ) === 0 ) {
return true;
}
}
// Also check for pages that start with 'trainer/'
if ( strpos( $path, 'trainer/' ) === 0 ) {
return true;
}
return false;
}
/**
* Check if current page is a master trainer page
*
* @param string $path Current page path
* @return bool
*/
private function is_master_trainer_page( $path ) {
foreach ( self::$master_trainer_pages as $master_page ) {
if ( $path === $master_page || strpos( $path, $master_page ) === 0 ) {
return true;
}
}
// Also check for pages that start with 'master-trainer/'
if ( strpos( $path, 'master-trainer/' ) === 0 ) {
return true;
}
return false;
}
/**
* Check trainer access to protected pages
*
* @param string $path Current page path
*/
private function check_trainer_access( $path ) {
// First check if user is logged in
if ( ! is_user_logged_in() ) {
// Preserve the original URL for redirect after login
$redirect_url = home_url( '/' . $path . '/' );
$login_url = add_query_arg( 'redirect_to', $redirect_url, home_url( '/training-login/' ) );
wp_safe_redirect( $login_url );
exit;
}
$user_id = get_current_user_id();
$user = wp_get_current_user();
// Allow administrators full access
if ( current_user_can( 'manage_options' ) ) {
return;
}
// Check if user has trainer role
if ( ! in_array( 'hvac_trainer', $user->roles ) && ! in_array( 'hvac_master_trainer', $user->roles ) ) {
// Not a trainer, show access denied
$this->show_access_denied();
return;
}
// Get trainer status
if ( ! class_exists( 'HVAC_Trainer_Status' ) ) {
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-trainer-status.php';
}
$status = HVAC_Trainer_Status::get_trainer_status( $user_id );
// Handle based on status
switch ( $status ) {
case HVAC_Trainer_Status::STATUS_PENDING:
// Redirect to pending page
if ( $path !== 'trainer-account-pending' && strpos( $path, 'trainer-account-pending' ) !== 0 ) {
wp_safe_redirect( home_url( '/trainer-account-pending/' ) );
exit;
}
break;
case HVAC_Trainer_Status::STATUS_DISABLED:
// Redirect to disabled page
if ( $path !== 'trainer-account-disabled' && strpos( $path, 'trainer-account-disabled' ) !== 0 ) {
wp_safe_redirect( home_url( '/trainer-account-disabled/' ) );
exit;
}
break;
case HVAC_Trainer_Status::STATUS_APPROVED:
case HVAC_Trainer_Status::STATUS_ACTIVE:
case HVAC_Trainer_Status::STATUS_INACTIVE:
// Allow access
break;
default:
// Unknown status, treat as pending
wp_safe_redirect( home_url( '/trainer-account-pending/' ) );
exit;
}
}
/**
* Check master trainer access to protected pages
*
* @param string $path Current page path
*/
private function check_master_trainer_access( $path ) {
// First check if user is logged in
if ( ! is_user_logged_in() ) {
// Preserve the original URL for redirect after login
$redirect_url = home_url( '/' . $path . '/' );
$login_url = add_query_arg( 'redirect_to', $redirect_url, home_url( '/training-login/' ) );
wp_safe_redirect( $login_url );
exit;
}
$user = wp_get_current_user();
// Allow administrators full access
if ( current_user_can( 'manage_options' ) ) {
return;
}
// Check if user has master trainer role
if ( ! in_array( 'hvac_master_trainer', $user->roles ) ) {
// Not a master trainer, show access denied
$this->show_access_denied();
return;
}
// Master trainers have access to all their pages
// No need to check status for master trainers
}
/**
* Show access denied page
*/
private function show_access_denied() {
get_header();
?>
<style>
.hvac-access-denied {
max-width: 600px;
margin: 60px auto;
padding: 40px;
text-align: center;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.hvac-access-denied h1 {
color: #d63638;
margin-bottom: 20px;
}
.hvac-access-denied p {
margin-bottom: 15px;
color: #666;
line-height: 1.6;
}
.hvac-access-denied .button {
background: #0073aa;
color: white;
padding: 12px 24px;
text-decoration: none;
border-radius: 4px;
display: inline-block;
margin-top: 20px;
}
.hvac-access-denied .button:hover {
background: #005a87;
color: white;
}
</style>
<div class="content-area primary ast-container">
<main class="site-main">
<div class="hvac-access-denied">
<h1><?php _e( 'Access Denied', 'hvac-community-events' ); ?></h1>
<p><?php _e( 'You do not have permission to access this page.', 'hvac-community-events' ); ?></p>
<p><?php _e( 'If you believe this is an error, please contact an administrator.', 'hvac-community-events' ); ?></p>
<a href="<?php echo esc_url( home_url() ); ?>" class="button"><?php _e( 'Return to Home', 'hvac-community-events' ); ?></a>
</div>
</main>
</div>
<?php
get_footer();
exit;
}
/**
* Add custom pages that require specific access
*
* @param string $page Page path
* @param string $type 'public' or 'trainer'
*/
public static function add_custom_page( $page, $type = 'trainer' ) {
if ( $type === 'public' ) {
self::$public_pages[] = $page;
} else {
self::$trainer_pages[] = $page;
}
}
/**
* Remove a page from access control
*
* @param string $page Page path
* @param string $type 'public' or 'trainer'
*/
public static function remove_custom_page( $page, $type = 'trainer' ) {
if ( $type === 'public' ) {
$key = array_search( $page, self::$public_pages );
if ( $key !== false ) {
unset( self::$public_pages[$key] );
}
} else {
$key = array_search( $page, self::$trainer_pages );
if ( $key !== false ) {
unset( self::$trainer_pages[$key] );
}
}
}
}