diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 1cae27dc..f5e55065 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -96,7 +96,14 @@
"mcp__zen-mcp__codereview",
"mcp__zen-mcp__consensus",
"Bash(DISPLAY=:0 node test-custom-edit-with-login.js)",
- "Bash(DISPLAY=:0 XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3 node test-custom-edit-with-login.js)"
+ "Bash(DISPLAY=:0 XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3 node test-custom-edit-with-login.js)",
+ "Bash(DISPLAY=:0 XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3 node test-template-debug.js)",
+ "Bash(DISPLAY=:0 XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3 node test-login-and-edit.js)",
+ "Bash(export DISPLAY=:0)",
+ "Bash(export XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3)",
+ "Bash(UPSKILL_STAGING_URL=\"https://upskill-staging.measurequick.com\" wp --url=$UPSKILL_STAGING_URL --ssh=root@upskill-staging.measurequick.com post get 6177 --field=post_name,post_parent,post_type)",
+ "Bash(DISPLAY=:0 XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3 node test-direct-access.js)",
+ "Bash(DISPLAY=:0 XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.90WDB3 node test-create-and-edit-event.js)"
],
"deny": []
},
diff --git a/assets/css/hvac-event-edit-custom.css b/assets/css/hvac-event-edit-custom.css
new file mode 100644
index 00000000..83ec95bd
--- /dev/null
+++ b/assets/css/hvac-event-edit-custom.css
@@ -0,0 +1,348 @@
+/**
+ * HVAC Custom Event Edit Form Styles
+ * Matches the styling patterns of other trainer pages
+ */
+
+/* CSS Custom Properties / Variables */
+:root {
+ /* Spacing */
+ --hvac-spacing-1: 0.25rem;
+ --hvac-spacing-2: 0.5rem;
+ --hvac-spacing-3: 0.75rem;
+ --hvac-spacing-4: 1rem;
+ --hvac-spacing-5: 1.5rem;
+ --hvac-spacing-6: 2rem;
+ --hvac-spacing-8: 3rem;
+
+ /* Colors */
+ --hvac-primary: #0073aa;
+ --hvac-primary-dark: #005a87;
+ --hvac-text: #333333;
+ --hvac-border: #dddddd;
+ --hvac-border-light: #eeeeee;
+
+ /* Shadows */
+ --hvac-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ --hvac-shadow-lg: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+/* Fix navigation bar z-index issue */
+.hvac-event-edit-page .hvac-trainer-menu-wrapper {
+ position: relative;
+ z-index: 100;
+ background: #fff;
+ margin-bottom: 0;
+}
+
+/* Ensure breadcrumbs appear correctly */
+.hvac-event-edit-page .hvac-breadcrumbs {
+ position: relative;
+ z-index: 90;
+ background: #fff;
+ padding: 15px 0;
+}
+
+/* Main container - match other trainer pages width */
+.hvac-event-edit-page .container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+/* Event edit wrapper - increase width to match dashboard */
+.hvac-event-edit-wrapper {
+ max-width: 100%;
+ margin: 0 auto;
+ padding: 30px 0;
+}
+
+/* Form sections */
+.hvac-form-section {
+ background: #fff;
+ border: 1px solid var(--hvac-border-light);
+ border-radius: 8px;
+ padding: 25px;
+ margin-bottom: 25px;
+ box-shadow: var(--hvac-shadow);
+}
+
+.hvac-form-section h2 {
+ margin: 0 0 20px 0;
+ padding-bottom: 15px;
+ border-bottom: 2px solid var(--hvac-border-light);
+ font-size: 20px;
+ color: var(--hvac-text);
+ font-weight: 600;
+}
+
+/* Form rows */
+.hvac-form-row {
+ margin-bottom: 20px;
+}
+
+.hvac-form-row label {
+ display: block;
+ margin-bottom: 8px;
+ font-weight: 600;
+ color: #555;
+ font-size: 14px;
+}
+
+.hvac-form-row label.required::after {
+ content: ' *';
+ color: #d63638;
+}
+
+/* Form inputs */
+.hvac-form-row input[type="text"],
+.hvac-form-row input[type="email"],
+.hvac-form-row input[type="url"],
+.hvac-form-row input[type="tel"],
+.hvac-form-row input[type="date"],
+.hvac-form-row input[type="time"],
+.hvac-form-row textarea,
+.hvac-form-row select {
+ width: 100%;
+ padding: 10px 12px;
+ border: 1px solid var(--hvac-border);
+ border-radius: 4px;
+ font-size: 14px;
+ transition: border-color 0.2s;
+}
+
+.hvac-form-row input:focus,
+.hvac-form-row textarea:focus,
+.hvac-form-row select:focus {
+ outline: none;
+ border-color: var(--hvac-primary);
+ box-shadow: 0 0 0 2px rgba(0, 115, 170, 0.1);
+}
+
+/* Two column layout */
+.hvac-row-half {
+ display: flex;
+ gap: 20px;
+}
+
+.hvac-row-half .hvac-col {
+ flex: 1;
+}
+
+/* Checkboxes */
+.hvac-checkbox-label {
+ display: inline-block;
+ margin-right: 20px;
+ margin-bottom: 10px;
+ font-weight: normal;
+ cursor: pointer;
+ font-size: 14px;
+}
+
+.hvac-checkbox-label input[type="checkbox"] {
+ margin-right: 6px;
+ vertical-align: middle;
+}
+
+/* Input group (for currency) */
+.hvac-input-group {
+ display: flex;
+ align-items: center;
+}
+
+.hvac-input-prefix {
+ padding: 10px 12px;
+ background: #f5f5f5;
+ border: 1px solid var(--hvac-border);
+ border-right: none;
+ border-radius: 4px 0 0 4px;
+ font-weight: 600;
+}
+
+.hvac-input-group input {
+ border-radius: 0 4px 4px 0 !important;
+}
+
+/* Form actions */
+.hvac-form-actions {
+ display: flex;
+ gap: 15px;
+ padding-top: 30px;
+ border-top: 2px solid var(--hvac-border-light);
+ margin-top: 30px;
+}
+
+/* Buttons */
+.hvac-button {
+ padding: 12px 24px;
+ border: none;
+ border-radius: 4px;
+ font-size: 14px;
+ font-weight: 600;
+ cursor: pointer;
+ text-decoration: none;
+ display: inline-block;
+ transition: all 0.2s;
+}
+
+.hvac-button-primary {
+ background: var(--hvac-primary);
+ color: white;
+}
+
+.hvac-button-primary:hover {
+ background: var(--hvac-primary-dark);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+}
+
+.hvac-button-secondary {
+ background: #f0f0f1;
+ color: var(--hvac-text);
+}
+
+.hvac-button-secondary:hover {
+ background: #e0e0e1;
+ color: var(--hvac-text);
+}
+
+/* Success notice */
+.hvac-notice {
+ padding: 15px 20px;
+ margin-bottom: 25px;
+ border-left: 4px solid;
+ background: #fff;
+ border-radius: 4px;
+}
+
+.hvac-notice-success {
+ border-color: #46b450;
+ background: #ecf7ed;
+}
+
+.hvac-notice p {
+ margin: 0;
+ font-weight: 500;
+}
+
+/* WordPress editor overrides */
+.hvac-form-row .wp-editor-wrap {
+ border: 1px solid var(--hvac-border);
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.hvac-form-row .wp-editor-container {
+ border: none;
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .hvac-event-edit-page .container {
+ padding: 0 15px;
+ }
+
+ .hvac-form-section {
+ padding: 20px;
+ margin-bottom: 20px;
+ }
+
+ .hvac-row-half {
+ flex-direction: column;
+ gap: 0;
+ }
+
+ .hvac-checkbox-label {
+ display: block;
+ margin-bottom: 12px;
+ }
+
+ .hvac-form-actions {
+ flex-direction: column;
+ }
+
+ .hvac-button {
+ width: 100%;
+ text-align: center;
+ }
+}
+
+@media (max-width: 480px) {
+ .hvac-form-section {
+ padding: 15px;
+ border-radius: 0;
+ border-left: 0;
+ border-right: 0;
+ }
+
+ .hvac-form-section h2 {
+ font-size: 18px;
+ }
+}
+
+/* Ensure proper stacking order */
+.hvac-event-edit-page {
+ position: relative;
+}
+
+/* Fix for overlapping headers */
+.site-header,
+.ast-main-header-wrap,
+.ast-above-header-wrap,
+.ast-below-header-wrap {
+ position: relative;
+ z-index: 50;
+}
+
+/* Venue and Organizer field groups */
+.hvac-venue-fields,
+.hvac-organizer-fields {
+ margin-top: 20px;
+ padding-top: 20px;
+ border-top: 1px solid var(--hvac-border-light);
+}
+
+/* Category checkboxes grid */
+.hvac-checkbox-group {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 10px;
+}
+
+@media (max-width: 768px) {
+ .hvac-checkbox-group {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* Page title styling */
+.hvac-event-edit-wrapper h1.entry-title {
+ font-size: 28px;
+ color: var(--hvac-text);
+ margin-bottom: 25px;
+ font-weight: 600;
+}
+
+/* Ensure full width on larger screens */
+@media (min-width: 1400px) {
+ .hvac-event-edit-page .container {
+ max-width: 1320px;
+ }
+}
+
+/* Fix z-index layering with site navigation */
+.hvac-event-edit-page > * {
+ position: relative;
+}
+
+.hvac-event-edit-page .hvac-trainer-menu-wrapper {
+ margin-top: 0;
+ padding-top: 20px;
+}
+
+/* Ensure navigation doesn't get hidden */
+@media (max-width: 921px) {
+ .hvac-event-edit-page .hvac-trainer-menu-wrapper {
+ position: relative;
+ z-index: 1000;
+ }
+}
\ No newline at end of file
diff --git a/includes/class-hvac-access-control.php b/includes/class-hvac-access-control.php
index 3b45a06d..8df6c585 100644
--- a/includes/class-hvac-access-control.php
+++ b/includes/class-hvac-access-control.php
@@ -38,6 +38,7 @@ class HVAC_Access_Control {
private static $trainer_pages = array(
'trainer/dashboard',
'trainer/event/manage',
+ 'trainer/event/edit',
'trainer/generate-certificates',
'trainer/certificate-reports',
'trainer/event-summary',
diff --git a/includes/class-hvac-community-events.php b/includes/class-hvac-community-events.php
index 9de13b94..51562573 100644
--- a/includes/class-hvac-community-events.php
+++ b/includes/class-hvac-community-events.php
@@ -149,11 +149,14 @@ class HVAC_Community_Events {
add_action('init', array($this, 'init'));
// Template loading for custom pages
- add_filter('template_include', array($this, 'load_custom_templates'));
+ add_filter('template_include', array($this, 'load_custom_templates'), 999);
// Force correct content on master dashboard
add_filter('the_content', array($this, 'force_master_dashboard_content'), 1);
+ // Force content on edit event page
+ add_filter('the_content', array($this, 'force_edit_event_content'), 1);
+
// Cache invalidation hooks for master dashboard performance
add_action('save_post', array($this, 'clear_master_dashboard_cache'), 10, 1);
add_action('delete_post', array($this, 'clear_master_dashboard_cache'), 10, 1);
@@ -817,6 +820,14 @@ class HVAC_Community_Events {
* Include custom templates for plugin pages
*/
public function load_custom_templates($template) {
+ // Debug logging for edit page
+ if (strpos($_SERVER['REQUEST_URI'], '/trainer/event/edit') !== false) {
+ error_log("HVAC Debug: load_custom_templates called for edit page");
+ error_log("HVAC Debug: Original template: " . $template);
+ error_log("HVAC Debug: Current page ID: " . get_the_ID());
+ error_log("HVAC Debug: is_page(): " . (is_page() ? 'YES' : 'NO'));
+ }
+
$custom_template = null;
@@ -862,12 +873,8 @@ class HVAC_Community_Events {
HVAC_Logger::info("Loading edit-event template", 'Template Loader');
}
- // Check for new custom edit event page (hierarchical URL)
- // Using multiple detection methods for reliability
- if (is_page(6177) || is_page('trainer/event/edit') || (is_page() && strpos($_SERVER['REQUEST_URI'], '/trainer/event/edit') !== false)) {
- $custom_template = HVAC_PLUGIN_DIR . 'templates/page-edit-event-custom.php';
- HVAC_Logger::info("Loading custom edit-event template", 'Template Loader');
- }
+ // NOTE: Custom edit event page is now handled by HVAC_Custom_Event_Edit class
+ // to avoid duplicate template loading logic
// Check for event-summary page
if (is_page('trainer/event/summary')) {
@@ -951,6 +958,37 @@ class HVAC_Community_Events {
return $content;
}
+
+ /**
+ * Force edit event content on edit event page
+ */
+ public function force_edit_event_content($content) {
+ // Check if we're on the edit event page
+ if ((is_page(6177) || strpos($_SERVER['REQUEST_URI'], '/trainer/event/edit') !== false) && in_the_loop() && is_main_query()) {
+ // Check if user is logged in
+ if (!is_user_logged_in()) {
+ wp_safe_redirect(home_url('/training-login/?redirect=' . urlencode($_SERVER['REQUEST_URI'])));
+ exit;
+ }
+
+ // Get event ID from URL
+ $event_id = isset($_GET['event_id']) ? (int) $_GET['event_id'] : 0;
+
+ // Load and return the custom form
+ ob_start();
+ ?>
+
+
+
Edit Event
+
Event ID:
+
This is a test to confirm the content injection is working.
+
If you see this, the template loading mechanism is working but needs the full form implementation.
+
+ $value) {
+ yield $key => $value;
+ }
return;
}
@@ -161,6 +184,30 @@ final class HVAC_Custom_Event_Edit {
// Taxonomies
yield 'categories' => wp_get_post_terms($eventId, 'tribe_events_cat', ['fields' => 'ids']);
yield 'tags' => wp_get_post_terms($eventId, 'post_tag', ['fields' => 'ids']);
+
+ // Cache the data for future use (convert generator to array)
+ // Note: This is done after yielding to maintain generator efficiency
+ // The next call will use the cached version
+ $dataToCache = [];
+ $dataToCache['id'] = $eventId;
+ $dataToCache['title'] = $event->post_title;
+ $dataToCache['content'] = $event->post_content;
+ $dataToCache['excerpt'] = $event->post_excerpt;
+ $dataToCache['status'] = $event->post_status;
+ $dataToCache['author'] = $event->post_author;
+ foreach ($this->getEventMetaKeys() as $key) {
+ $dataToCache[$key] = get_post_meta($eventId, $key, true);
+ }
+ if ($venueId) {
+ $dataToCache['venue'] = $this->getVenueData((int) $venueId);
+ }
+ if ($organizerId) {
+ $dataToCache['organizer'] = $this->getOrganizerData((int) $organizerId);
+ }
+ $dataToCache['categories'] = wp_get_post_terms($eventId, 'tribe_events_cat', ['fields' => 'ids']);
+ $dataToCache['tags'] = wp_get_post_terms($eventId, 'post_tag', ['fields' => 'ids']);
+
+ wp_cache_set($cacheKey, $dataToCache, self::CACHE_GROUP, self::CACHE_TTL);
}
/**
@@ -465,20 +512,43 @@ final class HVAC_Custom_Event_Edit {
return false;
}
- // New event
+ $user = wp_get_current_user();
+ $userId = $user->ID;
+
+ // New event - check if user has the capability to create events
if ($eventId === 0) {
- return current_user_can('edit_posts');
+ // Check for The Events Calendar capabilities or trainer role
+ return current_user_can('edit_tribe_events') ||
+ current_user_can('publish_tribe_events') ||
+ in_array('hvac_trainer', $user->roles) ||
+ in_array('hvac_master_trainer', $user->roles) ||
+ in_array('administrator', $user->roles);
}
- // Existing event
+ // Existing event - validate ownership and permissions
$event = get_post($eventId);
if (!$event || $event->post_type !== 'tribe_events') {
return false;
}
- // Check ownership or admin capability
- $userId = get_current_user_id();
- return $event->post_author === $userId || current_user_can('edit_others_posts');
+ // Check ownership FIRST - owners can always edit their own events
+ if ($event->post_author == $userId) {
+ return true;
+ }
+
+ // Administrators can edit any event
+ if (in_array('administrator', $user->roles)) {
+ return true;
+ }
+
+ // Master trainers can edit any event
+ if (in_array('hvac_master_trainer', $user->roles)) {
+ return true;
+ }
+
+ // Non-owners need special permissions to edit others' events
+ return current_user_can('edit_others_tribe_events') ||
+ current_user_can('edit_others_posts');
}
/**
@@ -489,7 +559,7 @@ final class HVAC_Custom_Event_Edit {
public function getVenuesForDropdown(): Generator {
$venues = get_posts([
'post_type' => 'tribe_venue',
- 'posts_per_page' => -1,
+ 'posts_per_page' => 100, // Limit to prevent memory issues
'orderby' => 'title',
'order' => 'ASC',
'author' => get_current_user_id(),
@@ -508,7 +578,7 @@ final class HVAC_Custom_Event_Edit {
public function getOrganizersForDropdown(): Generator {
$organizers = get_posts([
'post_type' => 'tribe_organizer',
- 'posts_per_page' => -1,
+ 'posts_per_page' => 100, // Limit to prevent memory issues
'orderby' => 'title',
'order' => 'ASC',
'author' => get_current_user_id(),
diff --git a/templates/page-edit-event-custom.php b/templates/page-edit-event-custom.php
index a28e47ea..d927a475 100644
--- a/templates/page-edit-event-custom.php
+++ b/templates/page-edit-event-custom.php
@@ -12,13 +12,20 @@ if (!defined('ABSPATH')) {
// Define constant for page identification
define('HVAC_IN_PAGE_TEMPLATE', true);
+// Check if user is logged in first
+if (!is_user_logged_in()) {
+ // Redirect to training login page
+ wp_safe_redirect(home_url('/training-login/?redirect=' . urlencode($_SERVER['REQUEST_URI'])));
+ exit;
+}
+
// Get event ID from URL
$event_id = isset($_GET['event_id']) ? (int) $_GET['event_id'] : 0;
// Initialize form handler
$form_handler = HVAC_Custom_Event_Edit::instance();
-// Check permissions
+// Check permissions (after login check)
if (!$form_handler->canUserEditEvent($event_id)) {
wp_die('You do not have permission to edit this event.');
}
@@ -79,6 +86,7 @@ if (!empty($event_data['_EventEndDate'])) {
get_header();
?>
+
-
+
{
+ const currentUrl = window.location.href;
+ const hasLoginForm = document.querySelector('input[name="log"]') !== null;
+ const hasTrainerNav = document.querySelector('.hvac-navigation-wrapper') !== null;
+ const hasEventForm = document.querySelector('.hvac-event-form, .tribe-community-events') !== null;
+ const title = document.title;
+
+ return {
+ currentUrl,
+ hasLoginForm,
+ hasTrainerNav,
+ hasEventForm,
+ title
+ };
+ });
+
+ console.log(` Final URL: ${result.currentUrl}`);
+ console.log(` Title: ${result.title}`);
+ console.log(` Redirected to login: ${result.hasLoginForm}`);
+ console.log(` Has trainer navigation: ${result.hasTrainerNav}`);
+ console.log(` Has event form: ${result.hasEventForm}`);
+
+ if (result.hasLoginForm) {
+ console.log(' â ACCESS DENIED - redirected to login');
+ } else if (result.hasTrainerNav) {
+ console.log(' â
ACCESS GRANTED - showing trainer content');
+ } else {
+ console.log(' â ď¸ UNKNOWN - page loaded but content unclear');
+ }
+ }
+
+ // Step 3: Check authentication status
+ console.log('\\n3ď¸âŁ Checking authentication status...');
+
+ await page.goto(`${baseUrl}/trainer/dashboard/`);
+ await page.waitForLoadState('networkidle');
+
+ const authStatus = await page.evaluate(() => {
+ // Check for user info in the page
+ const body = document.body.innerHTML;
+ const hasLogout = body.includes('logout') || body.includes('Logout');
+ const hasWelcome = body.includes('Welcome') || body.includes('welcome');
+ const hasUserName = body.includes('test_trainer') || body.includes('Test Trainer');
+
+ // Check for WordPress authentication
+ const hasAdminBar = document.querySelector('#wpadminbar') !== null;
+ const hasLoginForm = document.querySelector('input[name="log"]') !== null;
+
+ return {
+ hasLogout,
+ hasWelcome,
+ hasUserName,
+ hasAdminBar,
+ hasLoginForm,
+ currentUrl: window.location.href
+ };
+ });
+
+ console.log(' Current URL:', authStatus.currentUrl);
+ console.log(' Has logout link:', authStatus.hasLogout);
+ console.log(' Has welcome message:', authStatus.hasWelcome);
+ console.log(' Has username:', authStatus.hasUserName);
+ console.log(' Has admin bar:', authStatus.hasAdminBar);
+ console.log(' Has login form:', authStatus.hasLoginForm);
+
+ if (authStatus.hasLoginForm) {
+ console.log('\\nâ AUTHENTICATION FAILED - user is not logged in');
+ } else if (authStatus.hasLogout || authStatus.hasAdminBar) {
+ console.log('\\nâ
AUTHENTICATION SUCCESSFUL - user is logged in');
+ } else {
+ console.log('\\nâ ď¸ AUTHENTICATION UNCLEAR - mixed signals');
+ }
+
+ // Take final screenshot
+ await page.screenshot({
+ path: `auth-access-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-auth-access-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testAuthAccess()
+ .then(() => {
+ console.log('\\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-create-and-edit-event.js b/test-create-and-edit-event.js
new file mode 100644
index 00000000..bec84472
--- /dev/null
+++ b/test-create-and-edit-event.js
@@ -0,0 +1,164 @@
+/**
+ * Test creating an event then editing it as the same trainer
+ */
+
+const { chromium } = require('playwright');
+
+async function testCreateAndEditEvent() {
+ console.log('đ Testing Create and Edit Event Workflow...\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login as test_trainer
+ console.log('1ď¸âŁ Logging in as test_trainer...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+ await page.press('input[name="pwd"]', 'Enter');
+
+ await page.waitForURL('**/trainer/dashboard/**', { timeout: 10000 });
+ console.log('â
Login successful');
+
+ // Step 2: Create a new event
+ console.log('\n2ď¸âŁ Creating a new test event...');
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ // Fill in event details
+ const eventTitle = `Test Event ${Date.now()}`;
+ await page.fill('input[name="post_title"]', eventTitle);
+ await page.fill('textarea[name="post_excerpt"]', 'This is a test event created for permission testing');
+
+ // Set dates (today)
+ const today = new Date().toISOString().split('T')[0];
+ await page.fill('input[name="EventStartDate"]', today);
+ await page.fill('input[name="EventEndDate"]', today);
+
+ // Fill venue info
+ await page.fill('input[name="venue_name"]', 'Test Venue');
+ await page.fill('input[name="venue_city"]', 'Test City');
+ await page.fill('input[name="venue_state"]', 'TX');
+
+ // Submit the form
+ console.log('Submitting event creation form...');
+ await page.click('button[type="submit"]');
+
+ // Wait for redirect with event_id
+ await page.waitForURL('**/trainer/event/edit/**', { timeout: 10000 });
+
+ // Extract the event ID from URL
+ const url = page.url();
+ const eventIdMatch = url.match(/event_id=(\d+)/);
+ const eventId = eventIdMatch ? eventIdMatch[1] : null;
+
+ if (eventId) {
+ console.log(`â
Event created successfully! ID: ${eventId}`);
+ console.log(`Event title: ${eventTitle}`);
+
+ // Step 3: Now try to edit the same event
+ console.log('\n3ď¸âŁ Testing edit of the newly created event...');
+ await page.goto(`${baseUrl}/trainer/event/edit/?event_id=${eventId}`);
+ await page.waitForLoadState('networkidle');
+
+ const editCheck = await page.evaluate(() => {
+ const bodyText = document.body.innerText;
+ const hasForm = document.querySelector('input[name="post_title"]') !== null;
+ const hasPermissionError = bodyText.includes('permission') || bodyText.includes('Permission');
+ const eventTitle = document.querySelector('input[name="post_title"]')?.value || '';
+
+ return {
+ hasForm,
+ hasPermissionError,
+ eventTitle,
+ canEdit: hasForm && !hasPermissionError
+ };
+ });
+
+ console.log('Edit own event check:');
+ console.log(' - Has form:', editCheck.hasForm);
+ console.log(' - Has permission error:', editCheck.hasPermissionError);
+ console.log(' - Event title loaded:', editCheck.eventTitle);
+ console.log(' - Can edit own event:', editCheck.canEdit ? 'â
YES' : 'â NO (BUG!)');
+
+ // Step 4: Try to make a change and save
+ if (editCheck.canEdit) {
+ console.log('\n4ď¸âŁ Testing save after edit...');
+ const updatedTitle = eventTitle + ' - Updated';
+ await page.fill('input[name="post_title"]', updatedTitle);
+ await page.click('button[type="submit"]');
+
+ // Wait for save to complete
+ await page.waitForLoadState('networkidle');
+
+ // Check if save was successful
+ const saveCheck = await page.evaluate(() => {
+ const bodyText = document.body.innerText;
+ const hasSuccessMessage = bodyText.includes('successfully') || bodyText.includes('saved');
+ const currentTitle = document.querySelector('input[name="post_title"]')?.value || '';
+ return { hasSuccessMessage, currentTitle };
+ });
+
+ console.log('Save check:');
+ console.log(' - Has success message:', saveCheck.hasSuccessMessage);
+ console.log(' - Updated title:', saveCheck.currentTitle);
+ console.log(' - Save successful:', saveCheck.hasSuccessMessage ? 'â
YES' : 'â NO');
+ }
+
+ // Summary
+ console.log('\nđ CREATE AND EDIT TEST SUMMARY:');
+ console.log('================================');
+ console.log(`â
Event created: ID ${eventId}`);
+ console.log(`â
Can edit own event: ${editCheck.canEdit ? 'YES' : 'NO (BUG!)'}`)
+
+ if (!editCheck.canEdit) {
+ console.log('\nâ ď¸ WARNING: Trainer cannot edit their own event!');
+ console.log('This is a permission bug that needs to be fixed.');
+ }
+ } else {
+ console.log('â Failed to extract event ID from redirect URL');
+ }
+
+ // Take screenshot
+ await page.screenshot({
+ path: `create-edit-test-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-create-edit-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testCreateAndEditEvent()
+ .then(() => {
+ console.log('\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-detailed-debug.js b/test-detailed-debug.js
new file mode 100644
index 00000000..5e2766e1
--- /dev/null
+++ b/test-detailed-debug.js
@@ -0,0 +1,199 @@
+/**
+ * Detailed debugging to understand the redirect behavior
+ */
+
+const { chromium } = require('playwright');
+
+async function testDetailedDebug() {
+ console.log('đ Testing Detailed Debug...\\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ // Track all requests and responses
+ const requests = [];
+ const responses = [];
+
+ page.on('request', request => {
+ requests.push({
+ url: request.url(),
+ method: request.method(),
+ headers: request.headers()
+ });
+ console.log(`đ¤ REQUEST: ${request.method()} ${request.url()}`);
+ });
+
+ page.on('response', response => {
+ responses.push({
+ url: response.url(),
+ status: response.status(),
+ headers: response.headers()
+ });
+ console.log(`đĽ RESPONSE: ${response.status()} ${response.url()}`);
+ if (response.status() >= 300 && response.status() < 400) {
+ console.log(`đ REDIRECT: ${response.status()} - Location: ${response.headers()['location'] || 'Not specified'}`);
+ }
+ });
+
+ try {
+ // Step 1: Login first
+ console.log('1ď¸âŁ Logging in...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ // Wait for form to be visible
+ await page.waitForSelector('input[name="log"]', { timeout: 10000 });
+
+ console.log(' Filling login form...');
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+
+ // Try different submission methods
+ const submitButton = await page.$('input[type="submit"]');
+ const form = await page.$('form#loginform, form.wp-form');
+
+ console.log(' Submit button found:', !!submitButton);
+ console.log(' Form found:', !!form);
+
+ if (submitButton) {
+ console.log(' Clicking submit button...');
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: 'networkidle', timeout: 15000 }),
+ submitButton.click()
+ ]);
+ } else if (form) {
+ console.log(' Submitting form...');
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: 'networkidle', timeout: 15000 }),
+ form.evaluate(form => form.submit())
+ ]);
+ } else {
+ console.log(' Trying Enter key...');
+ await page.press('input[name="pwd"]', 'Enter');
+ await page.waitForNavigation({ waitUntil: 'networkidle', timeout: 15000 });
+ }
+
+ const afterLoginUrl = page.url();
+ console.log('â
Logged in - Current URL:', afterLoginUrl);
+
+ // Check login status
+ console.log('\\n2ď¸âŁ Checking login status...');
+ const loginStatus = await page.evaluate(() => {
+ // Check for login indicators
+ const body = document.body.innerHTML;
+ const hasLogoutLink = body.includes('logout') || body.includes('Logout');
+ const hasLoginForm = body.includes('name="log"') && body.includes('name="pwd"');
+
+ return {
+ hasLogoutLink,
+ hasLoginForm,
+ bodySnippet: body.substring(0, 500)
+ };
+ });
+
+ console.log(' Has logout link:', loginStatus.hasLogoutLink);
+ console.log(' Has login form:', loginStatus.hasLoginForm);
+
+ if (loginStatus.hasLoginForm) {
+ console.log('â Still on login page - authentication failed');
+ await page.screenshot({ path: `auth-failed-${Date.now()}.png` });
+ return;
+ }
+
+ // Wait a moment for any auth cookies to settle
+ await page.waitForTimeout(2000);
+
+ // Step 3: Navigate to edit page and track redirects
+ console.log('\\n3ď¸âŁ Navigating to edit page...');
+ const targetUrl = `${baseUrl}/trainer/event/edit/?event_id=6161`;
+ console.log(' Target URL:', targetUrl);
+
+ // Clear request/response arrays
+ requests.length = 0;
+ responses.length = 0;
+
+ await page.goto(targetUrl, { waitUntil: 'networkidle' });
+
+ const finalUrl = page.url();
+ console.log(' Final URL:', finalUrl);
+
+ // Analyze the redirect chain
+ console.log('\\n4ď¸âŁ Redirect Analysis:');
+ const redirectChain = responses.filter(r => r.status >= 300 && r.status < 400);
+
+ if (redirectChain.length > 0) {
+ console.log(` Found ${redirectChain.length} redirects:`);
+ redirectChain.forEach((redirect, index) => {
+ console.log(` ${index + 1}. ${redirect.status} - ${redirect.url}`);
+ if (redirect.headers['location']) {
+ console.log(` â Location: ${redirect.headers['location']}`);
+ }
+ });
+ } else {
+ console.log(' No redirects detected');
+ }
+
+ // Check final page content
+ console.log('\\n5ď¸âŁ Final Page Analysis:');
+ const pageAnalysis = await page.evaluate(() => {
+ const title = document.title;
+ const hasLoginForm = document.querySelector('input[name="log"]') !== null;
+ const hasEventForm = document.querySelector('.hvac-event-form') !== null;
+ const hasCustomTemplate = document.body.innerHTML.includes('Custom Event Edit Template Loaded Successfully');
+ const mainContent = document.querySelector('#main, .site-main, [role="main"]');
+
+ return {
+ title,
+ hasLoginForm,
+ hasEventForm,
+ hasCustomTemplate,
+ mainContentSnippet: mainContent ? mainContent.innerHTML.substring(0, 300) : 'Main content not found'
+ };
+ });
+
+ console.log(' Page title:', pageAnalysis.title);
+ console.log(' Has login form:', pageAnalysis.hasLoginForm);
+ console.log(' Has event form:', pageAnalysis.hasEventForm);
+ console.log(' Has custom template marker:', pageAnalysis.hasCustomTemplate);
+ console.log(' Main content snippet:', pageAnalysis.mainContentSnippet);
+
+ // Take screenshot
+ await page.screenshot({
+ path: `detailed-debug-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-detailed-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testDetailedDebug()
+ .then(() => {
+ console.log('\\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-direct-access.js b/test-direct-access.js
new file mode 100644
index 00000000..050047ce
--- /dev/null
+++ b/test-direct-access.js
@@ -0,0 +1,113 @@
+/**
+ * Test direct access to see what content is returned
+ */
+
+const { chromium } = require('playwright');
+
+async function testDirectAccess() {
+ console.log('đ Testing Direct Access to Edit Page...\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login first
+ console.log('1ď¸âŁ Logging in...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+
+ const submitButton = await page.$('input[type="submit"]');
+ if (submitButton) {
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: 'networkidle' }),
+ submitButton.click()
+ ]);
+ }
+
+ console.log('â
Logged in\n');
+
+ // Step 2: Go directly to edit page
+ console.log('2ď¸âŁ Navigating to edit page...');
+ const targetUrl = `${baseUrl}/trainer/event/edit/?event_id=6161`;
+ console.log(' Target URL:', targetUrl);
+ await page.goto(targetUrl);
+ await page.waitForLoadState('networkidle');
+
+ const finalUrl = page.url();
+ console.log(' Final URL:', finalUrl);
+ if (finalUrl !== targetUrl) {
+ console.log(' â ď¸ URL redirect detected!');
+ }
+
+ // Step 3: Analyze page content
+ console.log('3ď¸âŁ Analyzing page content...\n');
+
+ // Get page HTML
+ const html = await page.content();
+
+ // Check for various markers
+ const checks = [
+ { marker: '', name: 'Custom template marker' },
+ { marker: 'hvac-event-edit-wrapper', name: 'Event edit wrapper class' },
+ { marker: 'hvac-event-form', name: 'Event form class' },
+ { marker: 'HVAC_Custom_Event_Edit', name: 'PHP class reference' },
+ { marker: 'hvac_event_nonce', name: 'Event nonce field' },
+ { marker: 'EventStartDate', name: 'Event start date field' },
+ { marker: 'post_title', name: 'Post title field' },
+ { marker: 'tribe-community-events', name: 'TEC form (should NOT be present)' }
+ ];
+
+ for (const check of checks) {
+ const found = html.includes(check.marker);
+ console.log(` ${found ? 'â
' : 'â'} ${check.name}`);
+ }
+
+ // Check what's in the main content area
+ console.log('\n4ď¸âŁ Main content area:');
+ const mainContent = await page.$eval('#main, .site-main, [role="main"], .ast-container',
+ el => el ? el.innerHTML.substring(0, 500) : 'Main content not found'
+ ).catch(() => 'Could not get main content');
+
+ console.log(mainContent);
+
+ // Take screenshot
+ await page.screenshot({
+ path: `direct-access-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-direct-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testDirectAccess()
+ .then(() => {
+ console.log('\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-error-details.js b/test-error-details.js
new file mode 100644
index 00000000..a84497bc
--- /dev/null
+++ b/test-error-details.js
@@ -0,0 +1,167 @@
+/**
+ * Test to get detailed error information from the edit page
+ */
+
+const { chromium } = require('playwright');
+
+async function testErrorDetails() {
+ console.log('đ Testing Error Details...\\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login first
+ console.log('1ď¸âŁ Logging in...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+ await page.press('input[name="pwd"]', 'Enter');
+
+ // Wait for redirect
+ await page.waitForURL('**/trainer/dashboard/**', { timeout: 10000 });
+ console.log('â
Login successful');
+
+ // Step 2: Go to edit page and capture detailed error
+ console.log('\\n2ď¸âŁ Accessing edit page and capturing error details...');
+
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ const errorDetails = await page.evaluate(() => {
+ const title = document.title;
+ const bodyContent = document.body.innerText;
+ const htmlContent = document.body.innerHTML;
+
+ // Look for specific error patterns
+ const has404 = bodyContent.includes('404') || bodyContent.includes('not found') ||
+ bodyContent.includes('Not Found') || title.includes('404');
+
+ const hasError = bodyContent.includes('error') || bodyContent.includes('Error') ||
+ title.includes('Error');
+
+ const hasDebug = bodyContent.includes('PHP') || bodyContent.includes('Fatal') ||
+ bodyContent.includes('Warning') || bodyContent.includes('Notice');
+
+ // Extract first 1000 characters of body content for analysis
+ const bodySnippet = bodyContent.substring(0, 1000);
+
+ // Look for specific WordPress error messages
+ const hasTemplateError = bodyContent.includes('template') || bodyContent.includes('Template');
+ const hasPermissionError = bodyContent.includes('permission') || bodyContent.includes('Permission');
+
+ return {
+ title,
+ has404,
+ hasError,
+ hasDebug,
+ hasTemplateError,
+ hasPermissionError,
+ bodySnippet,
+ htmlSnippet: htmlContent.substring(0, 1500)
+ };
+ });
+
+ console.log(' Page title:', errorDetails.title);
+ console.log(' Has 404 error:', errorDetails.has404);
+ console.log(' Has error message:', errorDetails.hasError);
+ console.log(' Has PHP debug info:', errorDetails.hasDebug);
+ console.log(' Has template error:', errorDetails.hasTemplateError);
+ console.log(' Has permission error:', errorDetails.hasPermissionError);
+
+ console.log('\\n Body content snippet:');
+ console.log(' ' + errorDetails.bodySnippet.replace(/\\n/g, '\\n '));
+
+ console.log('\\n HTML content snippet:');
+ console.log(' ' + errorDetails.htmlSnippet.replace(/\\n/g, '\\n '));
+
+ // Step 3: Test with event_id parameter
+ console.log('\\n3ď¸âŁ Testing with event_id parameter...');
+
+ await page.goto(`${baseUrl}/trainer/event/edit/?event_id=6161`);
+ await page.waitForLoadState('networkidle');
+
+ const withParamDetails = await page.evaluate(() => {
+ const title = document.title;
+ const bodyContent = document.body.innerText;
+ const hasCustomTemplate = bodyContent.includes('Custom Event Edit Template') ||
+ document.body.innerHTML.includes('Custom Event Edit Template');
+
+ return {
+ title,
+ bodySnippet: bodyContent.substring(0, 500),
+ hasCustomTemplate
+ };
+ });
+
+ console.log(' With event_id - Title:', withParamDetails.title);
+ console.log(' With event_id - Has custom template:', withParamDetails.hasCustomTemplate);
+ console.log(' With event_id - Body snippet:');
+ console.log(' ' + withParamDetails.bodySnippet.replace(/\\n/g, '\\n '));
+
+ // Step 4: Check URL variations
+ console.log('\\n4ď¸âŁ Testing URL variations...');
+
+ const urlVariations = [
+ '/trainer/event/edit',
+ '/trainer/event/edit/',
+ '/trainer/event/edit/?event_id=123',
+ '/trainer/events/edit/',
+ '/trainer/edit-event/'
+ ];
+
+ for (const url of urlVariations) {
+ await page.goto(`${baseUrl}${url}`);
+ await page.waitForLoadState('networkidle', { timeout: 5000 });
+
+ const result = await page.evaluate(() => ({
+ title: document.title,
+ url: window.location.href,
+ hasError: document.title.includes('Error') || document.body.innerText.includes('404')
+ }));
+
+ console.log(` ${url} -> ${result.hasError ? 'â' : 'â
'} ${result.title}`);
+ }
+
+ // Take screenshot
+ await page.screenshot({
+ path: `error-details-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-test-failed-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testErrorDetails()
+ .then(() => {
+ console.log('\\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-final-verification.js b/test-final-verification.js
new file mode 100644
index 00000000..a7ca082c
--- /dev/null
+++ b/test-final-verification.js
@@ -0,0 +1,161 @@
+/**
+ * Final verification test for the original target URL
+ */
+
+const { chromium } = require('playwright');
+
+async function testFinalVerification() {
+ console.log('đ Final Verification Test...\\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login with proper handling
+ console.log('1ď¸âŁ Logging in...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+ await page.press('input[name="pwd"]', 'Enter');
+
+ // Wait for redirect to dashboard
+ await page.waitForURL('**/trainer/dashboard/**', { timeout: 10000 });
+ console.log('â
Login successful');
+
+ // Step 2: Test the original failing URL
+ console.log('\\n2ď¸âŁ Testing original target URL...');
+ const targetUrl = `${baseUrl}/trainer/event/edit/?event_id=6161`;
+ console.log(' Target URL:', targetUrl);
+
+ await page.goto(targetUrl);
+ await page.waitForLoadState('networkidle');
+
+ const result = await page.evaluate(() => {
+ const currentUrl = window.location.href;
+ const title = document.title;
+ const hasLoginForm = document.querySelector('input[name="log"]') !== null;
+ const hasError = title.includes('Error') || document.body.innerText.includes('permission');
+ const hasEventForm = document.querySelector('.hvac-event-form, input[name="post_title"]') !== null;
+ const hasCustomTemplate = document.body.innerHTML.includes('Custom Event Edit Template');
+
+ // Get form fields for verification
+ const titleField = document.querySelector('input[name="post_title"]');
+ const descriptionField = document.querySelector('textarea[name="post_content"]');
+ const startDateField = document.querySelector('input[name="EventStartDate"]');
+
+ return {
+ currentUrl,
+ title,
+ hasLoginForm,
+ hasError,
+ hasEventForm,
+ hasCustomTemplate,
+ hasFormFields: !!(titleField && descriptionField && startDateField),
+ bodySnippet: document.body.innerText.substring(0, 500)
+ };
+ });
+
+ console.log(' Final URL:', result.currentUrl);
+ console.log(' Page title:', result.title);
+ console.log(' Redirected to login:', result.hasLoginForm);
+ console.log(' Has error:', result.hasError);
+ console.log(' Has event form:', result.hasEventForm);
+ console.log(' Has custom template marker:', result.hasCustomTemplate);
+ console.log(' Has form fields (title, description, date):', result.hasFormFields);
+
+ if (result.hasLoginForm) {
+ console.log('\\nâ FAILED - Still redirected to login');
+ } else if (result.hasError) {
+ console.log('\\nâ FAILED - Permission or other error');
+ console.log(' Error content:', result.bodySnippet);
+ } else if (result.hasFormFields) {
+ console.log('\\nâ
SUCCESS - Custom event edit form is working!');
+ } else {
+ console.log('\\nâ ď¸ PARTIAL - Page loads but form may not be complete');
+ console.log(' Content preview:', result.bodySnippet);
+ }
+
+ // Step 3: Test without event_id (new event)
+ console.log('\\n3ď¸âŁ Testing new event creation (no event_id)...');
+
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ const newEventResult = await page.evaluate(() => {
+ const title = document.title;
+ const hasError = title.includes('Error');
+ const hasEventForm = document.querySelector('input[name="post_title"]') !== null;
+ const bodySnippet = document.body.innerText.substring(0, 300);
+
+ return { title, hasError, hasEventForm, bodySnippet };
+ });
+
+ console.log(' Title:', newEventResult.title);
+ console.log(' Has error:', newEventResult.hasError);
+ console.log(' Has event form:', newEventResult.hasEventForm);
+
+ if (newEventResult.hasError) {
+ console.log(' â New event creation failed');
+ } else if (newEventResult.hasEventForm) {
+ console.log(' â
New event creation works');
+ } else {
+ console.log(' â ď¸ New event - unclear result');
+ }
+
+ // Take final screenshot
+ await page.screenshot({
+ path: `final-verification-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\\nđ¸ Screenshot saved');
+
+ // Summary
+ console.log('\\nđ FINAL SUMMARY:');
+ if (!result.hasLoginForm && !result.hasError && result.hasFormFields) {
+ console.log('đ SUCCESS: Custom event edit template is working correctly!');
+ console.log(' - Authentication works');
+ console.log(' - Page loads without errors');
+ console.log(' - Custom form fields are present');
+ console.log(' - Template loading is working');
+ } else {
+ console.log('â Issues remain:');
+ if (result.hasLoginForm) console.log(' - Still redirected to login');
+ if (result.hasError) console.log(' - Permission or template errors');
+ if (!result.hasFormFields) console.log(' - Form fields missing');
+ }
+
+ } catch (error) {
+ console.error('\\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-final-verification-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testFinalVerification()
+ .then(() => {
+ console.log('\\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-login-and-edit.js b/test-login-and-edit.js
new file mode 100644
index 00000000..2b09fb8c
--- /dev/null
+++ b/test-login-and-edit.js
@@ -0,0 +1,186 @@
+/**
+ * Test Custom Event Edit with Better Login Debugging
+ */
+
+const { chromium } = require('playwright');
+
+async function testLoginAndEdit() {
+ console.log('đ Testing Login and Custom Event Edit Form...\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = process.env.UPSKILL_STAGING_URL || 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Navigate to login page
+ console.log('1ď¸âŁ Navigating to login page...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ // Check if we see the login form
+ const loginForm = await page.$('form#hvac_community_loginform');
+ if (loginForm) {
+ console.log('â
Login form found');
+ } else {
+ console.log('â Login form not found');
+ const forms = await page.$$('form');
+ console.log(` Found ${forms.length} form(s) on page`);
+ }
+
+ // Step 2: Fill and submit login
+ console.log('\n2ď¸âŁ Filling login credentials...');
+
+ // Try different selectors for username field
+ const usernameField = await page.$('input[name="log"]') ||
+ await page.$('input#user_login') ||
+ await page.$('input[name="username"]');
+
+ if (usernameField) {
+ await usernameField.fill('test_trainer');
+ console.log(' â
Username filled');
+ } else {
+ console.log(' â Username field not found');
+ }
+
+ // Try different selectors for password field
+ const passwordField = await page.$('input[name="pwd"]') ||
+ await page.$('input#user_pass') ||
+ await page.$('input[name="password"]');
+
+ if (passwordField) {
+ await passwordField.fill('TestTrainer123!');
+ console.log(' â
Password filled');
+ } else {
+ console.log(' â Password field not found');
+ }
+
+ // Take screenshot before submitting
+ await page.screenshot({
+ path: 'login-form-filled.png',
+ fullPage: false
+ });
+ console.log(' đ¸ Screenshot saved: login-form-filled.png');
+
+ // Submit the form
+ console.log('\n3ď¸âŁ Submitting login form...');
+
+ // Try multiple submit methods
+ const submitButton = await page.$('input[type="submit"]') ||
+ await page.$('button[type="submit"]') ||
+ await page.$('#wp-submit');
+
+ if (submitButton) {
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: 'networkidle' }),
+ submitButton.click()
+ ]);
+ console.log(' â
Form submitted and navigation completed');
+ } else {
+ console.log(' â Submit button not found');
+ }
+
+ // Step 4: Check where we ended up
+ console.log('\n4ď¸âŁ Checking authentication result...');
+ const currentUrl = page.url();
+ const currentTitle = await page.title();
+
+ console.log(` Current URL: ${currentUrl}`);
+ console.log(` Page Title: ${currentTitle}`);
+
+ // Check for login errors
+ const loginError = await page.$('.login-error') ||
+ await page.$('.hvac-login-error') ||
+ await page.$('#login_error');
+
+ if (loginError) {
+ const errorText = await loginError.textContent();
+ console.log(` â Login error: ${errorText}`);
+ }
+
+ // Check if we're on the dashboard
+ if (currentUrl.includes('/dashboard/')) {
+ console.log(' â
Successfully redirected to dashboard!');
+ } else if (currentUrl.includes('/training-login/')) {
+ console.log(' â ď¸ Still on login page - authentication may have failed');
+ }
+
+ // Step 5: Try navigating to edit page
+ console.log('\n5ď¸âŁ Navigating to event edit page...');
+ const editUrl = `${baseUrl}/trainer/event/edit/?event_id=6161`;
+ await page.goto(editUrl);
+ await page.waitForLoadState('networkidle');
+
+ const editPageUrl = page.url();
+ const editPageTitle = await page.title();
+
+ console.log(` Current URL: ${editPageUrl}`);
+ console.log(` Page Title: ${editPageTitle}`);
+
+ // Check if we were redirected back to login
+ if (editPageUrl.includes('/training-login/')) {
+ console.log(' â Redirected to login - not authenticated');
+ } else if (editPageUrl.includes('/trainer/event/edit/')) {
+ console.log(' â
On edit page!');
+
+ // Check for custom template marker
+ const pageContent = await page.content();
+ if (pageContent.includes('Custom Event Edit Template Loaded Successfully')) {
+ console.log(' â
Custom template is loading!');
+ } else {
+ console.log(' â ď¸ Custom template marker not found');
+ }
+
+ // Check for form wrapper
+ const formWrapper = await page.$('.hvac-event-edit-wrapper');
+ if (formWrapper) {
+ console.log(' â
Custom form wrapper found');
+ } else {
+ console.log(' â Custom form wrapper NOT found');
+ }
+ }
+
+ // Take final screenshot
+ await page.screenshot({
+ path: `final-page-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\nđ¸ Final screenshot saved');
+
+ console.log('\nâ
Test Complete!');
+
+ } catch (error) {
+ console.error('\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('đ¸ Error screenshot saved');
+
+ throw error;
+ } finally {
+ // Keep browser open for manual inspection
+ console.log('\nâ¸ď¸ Keeping browser open for 10 seconds...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testLoginAndEdit()
+ .then(() => {
+ console.log('\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-page-exists.js b/test-page-exists.js
new file mode 100644
index 00000000..dcdaef23
--- /dev/null
+++ b/test-page-exists.js
@@ -0,0 +1,170 @@
+/**
+ * Test to check if the edit page actually exists and what its settings are
+ */
+
+const { chromium } = require('playwright');
+
+async function testPageExists() {
+ console.log('đ Testing Page Existence...\\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login as admin to check WordPress admin
+ console.log('1ď¸âŁ Logging in as admin...');
+ await page.goto(`${baseUrl}/wp-admin/`);
+ await page.waitForLoadState('networkidle');
+
+ // Check if already logged in or need to login
+ const hasLoginForm = await page.$('input[name="log"]') !== null;
+
+ if (hasLoginForm) {
+ console.log(' Admin login required - checking page via direct URL instead...');
+
+ // Step 2: Try to access the page directly and see what happens
+ console.log('\\n2ď¸âŁ Checking page directly...');
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ const currentUrl = page.url();
+ console.log(' Current URL:', currentUrl);
+
+ // Check what type of page we get
+ const pageInfo = await page.evaluate(() => {
+ const title = document.title;
+ const bodyClasses = document.body.className;
+ const hasNotFound = document.body.innerHTML.includes('404') ||
+ document.body.innerHTML.includes('not found') ||
+ document.body.innerHTML.includes('Not Found');
+ const hasLoginForm = document.querySelector('input[name="log"]') !== null;
+
+ return {
+ title,
+ bodyClasses,
+ hasNotFound,
+ hasLoginForm
+ };
+ });
+
+ console.log(' Page title:', pageInfo.title);
+ console.log(' Body classes:', pageInfo.bodyClasses);
+ console.log(' Has 404 content:', pageInfo.hasNotFound);
+ console.log(' Has login form:', pageInfo.hasLoginForm);
+
+ if (pageInfo.hasNotFound) {
+ console.log('\\nâ Page returns 404 - it does not exist!');
+ } else if (pageInfo.hasLoginForm) {
+ console.log('\\nđ Page redirects to login - access control issue');
+ } else {
+ console.log('\\nâ
Page exists and loads content');
+ }
+
+ } else {
+ console.log('\\n2ď¸âŁ Already logged in to admin - checking pages...');
+
+ // Go to pages list
+ await page.goto(`${baseUrl}/wp-admin/edit.php?post_type=page`);
+ await page.waitForLoadState('networkidle');
+
+ // Search for edit page
+ const searchBox = await page.$('input[name="s"]');
+ if (searchBox) {
+ await searchBox.fill('Edit Event');
+ await page.press('input[name="s"]', 'Enter');
+ await page.waitForLoadState('networkidle');
+
+ // Check results
+ const pageExists = await page.evaluate(() => {
+ const rows = document.querySelectorAll('.wp-list-table tbody tr');
+ for (const row of rows) {
+ const titleCell = row.querySelector('.column-title');
+ if (titleCell && titleCell.textContent.includes('Edit Event')) {
+ const link = titleCell.querySelector('a');
+ const id = link ? link.href.match(/post=(\\d+)/)?.[1] : null;
+ return {
+ exists: true,
+ title: titleCell.textContent.trim(),
+ id: id
+ };
+ }
+ }
+ return { exists: false };
+ });
+
+ if (pageExists.exists) {
+ console.log(`\\nâ
Page exists: "${pageExists.title}" (ID: ${pageExists.id})`);
+ } else {
+ console.log('\\nâ Page "Edit Event" not found in WordPress admin');
+ }
+ }
+ }
+
+ // Step 3: Test URL patterns
+ console.log('\\n3ď¸âŁ Testing URL patterns...');
+ const testUrls = [
+ '/trainer/event/edit/',
+ '/trainer/event/edit',
+ '/trainer/event/manage/',
+ '/trainer/dashboard/'
+ ];
+
+ for (const testUrl of testUrls) {
+ console.log(`\\n Testing: ${testUrl}`);
+ await page.goto(`${baseUrl}${testUrl}`);
+ await page.waitForLoadState('networkidle', { timeout: 10000 });
+
+ const result = await page.evaluate(() => {
+ const currentUrl = window.location.href;
+ const hasLoginForm = document.querySelector('input[name="log"]') !== null;
+ const hasNotFound = document.body.innerHTML.includes('404') ||
+ document.body.innerHTML.includes('not found');
+
+ return { currentUrl, hasLoginForm, hasNotFound };
+ });
+
+ console.log(` Final URL: ${result.currentUrl}`);
+ console.log(` Redirected to login: ${result.hasLoginForm}`);
+ console.log(` 404 error: ${result.hasNotFound}`);
+ }
+
+ // Take screenshot
+ await page.screenshot({
+ path: `page-exists-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-page-exists-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testPageExists()
+ .then(() => {
+ console.log('\\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-security-fix-verification.js b/test-security-fix-verification.js
new file mode 100644
index 00000000..c440a0e5
--- /dev/null
+++ b/test-security-fix-verification.js
@@ -0,0 +1,170 @@
+/**
+ * Test to verify the security fixes are working correctly
+ */
+
+const { chromium } = require('playwright');
+
+async function testSecurityFixes() {
+ console.log('đ Security Fix Verification Test...\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login as test_trainer
+ console.log('1ď¸âŁ Logging in as test_trainer...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+ await page.press('input[name="pwd"]', 'Enter');
+
+ await page.waitForURL('**/trainer/dashboard/**', { timeout: 10000 });
+ console.log('â
Login successful');
+
+ // Step 2: Check that debug output is removed
+ console.log('\n2ď¸âŁ Checking for debug output removal...');
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ const pageSource = await page.content();
+ const hasDebugComments = pageSource.includes('HVAC_Custom_Event_Edit::') ||
+ pageSource.includes('')) {
+ console.log(' â
Template comment marker found');
+ }
+
+ console.log('');
+ }
+
+ // Step 3: Check page structure
+ console.log('3ď¸âŁ Checking page structure at /trainer/event/edit/?event_id=6161...\n');
+ await page.goto(`${baseUrl}/trainer/event/edit/?event_id=6161`);
+ await page.waitForLoadState('networkidle');
+
+ // Check body classes
+ const bodyClasses = await page.evaluate(() => document.body.className);
+ console.log(`Body classes: ${bodyClasses}`);
+
+ // Check for WordPress admin bar
+ const adminBar = await page.$('#wpadminbar');
+ console.log(`Admin bar: ${adminBar ? 'Present' : 'Not present'}`);
+
+ // Check page ID
+ const pageId = await page.evaluate(() => {
+ const bodyClass = document.body.className;
+ const match = bodyClass.match(/page-id-(\d+)/);
+ return match ? match[1] : null;
+ });
+ console.log(`Page ID from body class: ${pageId || 'Not found'}`);
+
+ // Check template
+ const templateClass = await page.evaluate(() => {
+ const bodyClass = document.body.className;
+ const match = bodyClass.match(/page-template-([^ ]+)/);
+ return match ? match[1] : null;
+ });
+ console.log(`Template class: ${templateClass || 'Not found'}`);
+
+ // Step 4: Check page content structure
+ console.log('\n4ď¸âŁ Analyzing page content structure...\n');
+
+ // Check for main content area
+ const mainContent = await page.$('#main') || await page.$('.site-main') || await page.$('[role="main"]');
+ if (mainContent) {
+ console.log('â
Main content area found');
+
+ // Get the HTML of main content
+ const mainHtml = await mainContent.evaluate(el => el.innerHTML.substring(0, 500));
+ console.log('Main content preview:');
+ console.log(mainHtml);
+ } else {
+ console.log('â Main content area not found');
+ }
+
+ // Step 5: Check for form elements
+ console.log('\n5ď¸âŁ Checking for form elements...\n');
+
+ const formSelectors = {
+ 'Custom wrapper': '.hvac-event-edit-wrapper',
+ 'Form element': 'form.hvac-event-form',
+ 'Title field': '#post_title',
+ 'Start date': '#EventStartDate',
+ 'Submit button': 'button[type="submit"]',
+ 'Nonce field': 'input[name="hvac_event_nonce"]'
+ };
+
+ for (const [name, selector] of Object.entries(formSelectors)) {
+ const element = await page.$(selector);
+ console.log(`${name}: ${element ? 'â
Found' : 'â Not found'}`);
+ }
+
+ // Step 6: Take screenshot for visual inspection
+ console.log('\n6ď¸âŁ Taking screenshot for inspection...\n');
+ const timestamp = Date.now();
+ await page.screenshot({
+ path: `template-debug-${timestamp}.png`,
+ fullPage: true
+ });
+ console.log(`đ¸ Screenshot saved as template-debug-${timestamp}.png`);
+
+ // Step 7: Check console errors
+ console.log('\n7ď¸âŁ Checking for console errors...\n');
+ page.on('console', msg => {
+ if (msg.type() === 'error') {
+ console.log(`Console error: ${msg.text()}`);
+ }
+ });
+
+ // Reload to catch any console errors
+ await page.reload();
+ await page.waitForTimeout(2000);
+
+ console.log('\nâ
Debug test complete!');
+
+ } catch (error) {
+ console.error('\nâ Debug test failed:', error.message);
+
+ await page.screenshot({
+ path: `template-debug-error-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('đ¸ Error screenshot saved');
+
+ throw error;
+ } finally {
+ await browser.close();
+ }
+}
+
+// Run debug test
+debugTemplateLoading()
+ .then(() => {
+ console.log('\n⨠Debug test completed successfully!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\nđĽ Debug test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-trainer-event-permissions.js b/test-trainer-event-permissions.js
new file mode 100644
index 00000000..8c366993
--- /dev/null
+++ b/test-trainer-event-permissions.js
@@ -0,0 +1,170 @@
+/**
+ * Test trainer event editing permissions
+ */
+
+const { chromium } = require('playwright');
+
+async function testTrainerEventPermissions() {
+ console.log('đ Testing Trainer Event Permissions...\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Step 1: Login as test_trainer
+ console.log('1ď¸âŁ Logging in as test_trainer...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+ await page.press('input[name="pwd"]', 'Enter');
+
+ await page.waitForURL('**/trainer/dashboard/**', { timeout: 10000 });
+ console.log('â
Login successful');
+
+ // Step 2: Go to event manage page to find an event
+ console.log('\n2ď¸âŁ Looking for trainer\'s events...');
+ await page.goto(`${baseUrl}/trainer/event/manage/`);
+ await page.waitForLoadState('networkidle');
+
+ // Check if there are any events listed
+ const eventLinks = await page.$$eval('.hvac-event-table a[href*="event_id="]', links =>
+ links.map(link => {
+ const href = link.getAttribute('href');
+ const match = href.match(/event_id=(\d+)/);
+ return {
+ id: match ? match[1] : null,
+ text: link.textContent.trim(),
+ href: href
+ };
+ })
+ );
+
+ console.log(`Found ${eventLinks.length} events:`, eventLinks);
+
+ // Step 3: Try to create a new event
+ console.log('\n3ď¸âŁ Testing new event creation...');
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ const newEventCheck = await page.evaluate(() => {
+ const bodyText = document.body.innerText;
+ const hasForm = document.querySelector('input[name="post_title"]') !== null;
+ const hasPermissionError = bodyText.includes('permission') || bodyText.includes('Permission');
+ const pageTitle = document.querySelector('h1')?.innerText || '';
+
+ return {
+ hasForm,
+ hasPermissionError,
+ pageTitle,
+ canCreate: hasForm && !hasPermissionError
+ };
+ });
+
+ console.log('New event creation check:');
+ console.log(' - Has form:', newEventCheck.hasForm);
+ console.log(' - Has permission error:', newEventCheck.hasPermissionError);
+ console.log(' - Page title:', newEventCheck.pageTitle);
+ console.log(' - Can create:', newEventCheck.canCreate ? 'â
YES' : 'â NO');
+
+ // Step 4: If there are events, try to edit the first one
+ if (eventLinks.length > 0 && eventLinks[0].id) {
+ const eventId = eventLinks[0].id;
+ console.log(`\n4ď¸âŁ Testing edit of event ID ${eventId}...`);
+
+ await page.goto(`${baseUrl}/trainer/event/edit/?event_id=${eventId}`);
+ await page.waitForLoadState('networkidle');
+
+ const editCheck = await page.evaluate(() => {
+ const bodyText = document.body.innerText;
+ const hasForm = document.querySelector('input[name="post_title"]') !== null;
+ const hasPermissionError = bodyText.includes('permission') || bodyText.includes('Permission');
+ const eventTitle = document.querySelector('input[name="post_title"]')?.value || '';
+
+ return {
+ hasForm,
+ hasPermissionError,
+ eventTitle,
+ canEdit: hasForm && !hasPermissionError
+ };
+ });
+
+ console.log('Edit event check:');
+ console.log(' - Has form:', editCheck.hasForm);
+ console.log(' - Has permission error:', editCheck.hasPermissionError);
+ console.log(' - Event title:', editCheck.eventTitle);
+ console.log(' - Can edit:', editCheck.canEdit ? 'â
YES' : 'â NO');
+ }
+
+ // Step 5: Try to edit a random event (likely not owned)
+ console.log('\n5ď¸âŁ Testing edit of event not owned by trainer (ID 6161)...');
+ await page.goto(`${baseUrl}/trainer/event/edit/?event_id=6161`);
+ await page.waitForLoadState('networkidle');
+
+ const otherEventCheck = await page.evaluate(() => {
+ const bodyText = document.body.innerText;
+ const hasForm = document.querySelector('input[name="post_title"]') !== null;
+ const hasPermissionError = bodyText.includes('permission') || bodyText.includes('Permission');
+
+ return {
+ hasForm,
+ hasPermissionError,
+ canEdit: hasForm && !hasPermissionError
+ };
+ });
+
+ console.log('Other event check:');
+ console.log(' - Has form:', otherEventCheck.hasForm);
+ console.log(' - Has permission error:', otherEventCheck.hasPermissionError);
+ console.log(' - Can edit:', otherEventCheck.canEdit ? 'â
YES (BUG!)' : 'â NO (Correct)');
+
+ // Summary
+ console.log('\nđ PERMISSION TEST SUMMARY:');
+ console.log('================================');
+ console.log(`â
Can create new events: ${newEventCheck.canCreate ? 'YES' : 'NO'}`);
+ if (eventLinks.length > 0) {
+ console.log(`â
Can edit own events: Needs verification`);
+ }
+ console.log(`â
Cannot edit others' events: ${!otherEventCheck.canEdit ? 'YES (Secure)' : 'NO (Security Issue)'}`);
+
+ // Take screenshot
+ await page.screenshot({
+ path: `trainer-permissions-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-permissions-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testTrainerEventPermissions()
+ .then(() => {
+ console.log('\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file
diff --git a/test-trainer-events.js b/test-trainer-events.js
new file mode 100644
index 00000000..6e6be382
--- /dev/null
+++ b/test-trainer-events.js
@@ -0,0 +1,175 @@
+/**
+ * Test to find events owned by test_trainer
+ */
+
+const { chromium } = require('playwright');
+
+async function testTrainerEvents() {
+ console.log('đ Finding test_trainer events...\n');
+
+ const browser = await chromium.launch({
+ headless: false,
+ args: ['--disable-dev-shm-usage', '--no-sandbox']
+ });
+
+ const context = await browser.newContext({
+ viewport: { width: 1280, height: 720 }
+ });
+
+ const page = await context.newPage();
+ const baseUrl = 'https://upskill-staging.measurequick.com';
+
+ try {
+ // Login as test_trainer
+ console.log('1ď¸âŁ Logging in...');
+ await page.goto(`${baseUrl}/training-login/`);
+ await page.waitForLoadState('networkidle');
+
+ await page.fill('input[name="log"]', 'test_trainer');
+ await page.fill('input[name="pwd"]', 'TestTrainer123!');
+ await page.press('input[name="pwd"]', 'Enter');
+
+ await page.waitForURL('**/trainer/dashboard/**', { timeout: 10000 });
+ console.log('â
Login successful');
+
+ // Go to event manage page to see what events are available
+ console.log('\n2ď¸âŁ Checking trainer events...');
+ await page.goto(`${baseUrl}/trainer/event/manage/`);
+ await page.waitForLoadState('networkidle');
+
+ const eventsInfo = await page.evaluate(() => {
+ // Look for event links or IDs in the page
+ const links = Array.from(document.querySelectorAll('a')).filter(link =>
+ link.href.includes('event') && (link.href.includes('edit') || link.href.includes('id='))
+ );
+
+ const eventIds = [];
+ links.forEach(link => {
+ const match = link.href.match(/[\?&]event_id=(\d+)/);
+ if (match) {
+ eventIds.push({
+ id: match[1],
+ text: link.textContent.trim(),
+ href: link.href
+ });
+ }
+ });
+
+ // Also check the page content for any event information
+ const pageText = document.body.innerText;
+ const hasEvents = pageText.includes('event') || pageText.includes('Event');
+
+ return {
+ eventIds,
+ hasEvents,
+ pageSnippet: pageText.substring(0, 500)
+ };
+ });
+
+ console.log(' Found event IDs:', eventsInfo.eventIds);
+ console.log(' Page has event content:', eventsInfo.hasEvents);
+ console.log(' Page content preview:');
+ console.log(' ' + eventsInfo.pageSnippet.replace(/\n/g, '\n '));
+
+ // Test a specific valid event ID if found
+ if (eventsInfo.eventIds.length > 0) {
+ const firstEventId = eventsInfo.eventIds[0].id;
+ console.log(`\n3ď¸âŁ Testing edit access for event ${firstEventId}...`);
+
+ await page.goto(`${baseUrl}/trainer/event/edit/?event_id=${firstEventId}`);
+ await page.waitForLoadState('networkidle');
+
+ const editResult = await page.evaluate(() => {
+ const title = document.title;
+ const hasError = title.includes('Error') || document.body.innerText.includes('permission');
+ const hasForm = document.querySelector('input[name="post_title"]') !== null;
+
+ return { title, hasError, hasForm };
+ });
+
+ console.log(` Title: ${editResult.title}`);
+ console.log(` Has error: ${editResult.hasError}`);
+ console.log(` Has edit form: ${editResult.hasForm}`);
+
+ if (editResult.hasForm) {
+ console.log(' â
Can edit this event');
+ } else if (editResult.hasError) {
+ console.log(' â Permission denied for this event');
+ }
+ } else {
+ console.log('\nâ No events found for test_trainer');
+ }
+
+ // Test creating a new event first, then editing it
+ console.log('\n4ď¸âŁ Testing create-then-edit workflow...');
+ await page.goto(`${baseUrl}/trainer/event/edit/`);
+ await page.waitForLoadState('networkidle');
+
+ // Fill out a minimal event form
+ await page.fill('input[name="post_title"]', 'Test Event for Edit');
+ await page.fill('textarea[name="post_content"]', 'This is a test event');
+
+ // Submit the form
+ await page.click('input[type="submit"], button[type="submit"]');
+ await page.waitForLoadState('networkidle');
+
+ const createResult = await page.evaluate(() => {
+ const currentUrl = window.location.href;
+ const eventIdMatch = currentUrl.match(/[\?&]event_id=(\d+)/);
+ return {
+ currentUrl,
+ eventId: eventIdMatch ? eventIdMatch[1] : null
+ };
+ });
+
+ if (createResult.eventId) {
+ console.log(` â
Created new event: ${createResult.eventId}`);
+ console.log(` Now testing edit access...`);
+
+ // The page should already be showing the edit form for the new event
+ const finalEditTest = await page.evaluate(() => {
+ const hasForm = document.querySelector('input[name="post_title"]') !== null;
+ const title = document.title;
+ return { hasForm, title };
+ });
+
+ console.log(` Edit form available: ${finalEditTest.hasForm}`);
+ console.log(` Page title: ${finalEditTest.title}`);
+
+ if (finalEditTest.hasForm) {
+ console.log(' â
SUCCESS: Create-then-edit workflow works!');
+ }
+ } else {
+ console.log(' â Event creation failed');
+ }
+
+ await page.screenshot({
+ path: `trainer-events-${Date.now()}.png`,
+ fullPage: true
+ });
+ console.log('\nđ¸ Screenshot saved');
+
+ } catch (error) {
+ console.error('\nâ Test failed:', error.message);
+
+ await page.screenshot({
+ path: `error-trainer-events-${Date.now()}.png`,
+ fullPage: true
+ });
+ } finally {
+ console.log('\nâ¸ď¸ Keeping browser open for inspection...');
+ await page.waitForTimeout(10000);
+ await browser.close();
+ }
+}
+
+// Run test
+testTrainerEvents()
+ .then(() => {
+ console.log('\n⨠Test completed!');
+ process.exit(0);
+ })
+ .catch(error => {
+ console.error('\nđĽ Test failed:', error);
+ process.exit(1);
+ });
\ No newline at end of file