Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
224 lines
8.3 KiB
PHP
Executable File
224 lines
8.3 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* CODING CONVENTION:
|
|
* This file follows the coding convention where variable_names and function_names
|
|
* use snake_case (underscore_wherever_possible).
|
|
*/
|
|
|
|
namespace App\RSpade\Commands\Rsx;
|
|
|
|
use Illuminate\Console\Command;
|
|
use App\RSpade\Core\Ajax\Ajax;
|
|
use App\RSpade\Core\Ajax\Exceptions\AjaxAuthRequiredException;
|
|
use App\RSpade\Core\Ajax\Exceptions\AjaxUnauthorizedException;
|
|
use App\RSpade\Core\Ajax\Exceptions\AjaxFormErrorException;
|
|
use App\RSpade\Core\Ajax\Exceptions\AjaxFatalErrorException;
|
|
use App\RSpade\Core\Session\RsxSession;
|
|
use App\RSpade\Core\Debug\Debugger;
|
|
|
|
/**
|
|
* RSX Ajax Debug Command
|
|
* =======================
|
|
*
|
|
* PURPOSE:
|
|
* This command allows testing Internal API (Ajax) calls from the command line.
|
|
* It sets up session context (user_id, site_id) and executes Ajax::call() with
|
|
* the specified controller, action, and parameters.
|
|
*
|
|
* HOW IT WORKS:
|
|
* 1. Rotates logs for clean slate debugging
|
|
* 2. Sets user_id and/or site_id in RsxSession if provided
|
|
* 3. Calls Ajax::call() with the specified controller and action
|
|
* 4. Outputs pretty-printed JSON response
|
|
* 5. Handles special response types (AuthRequired, FormError, etc.)
|
|
* 6. Rotates logs again after test for clean slate on next run
|
|
*
|
|
* KEY FEATURES:
|
|
* - User context: Use --user-id to test as any user
|
|
* - Site context: Use --site-id to test with specific site
|
|
* - JSON parameters: Pass complex data structures as JSON
|
|
* - Pretty output: Responses are formatted for readability
|
|
* - Form error handling: Special formatting for validation errors
|
|
* - Log integration: Automatic log rotation for clean testing
|
|
*
|
|
* USAGE EXAMPLES:
|
|
* php artisan rsx:ajax:debug User_Api get_profile # Basic call
|
|
* php artisan rsx:ajax:debug User_Api update --args='{"name":"John"}' # With params
|
|
* php artisan rsx:ajax:debug Admin_Api list_users --user-id=1 # As user 1
|
|
* php artisan rsx:ajax:debug Site_Api get_stats --site-id=5 # With site 5
|
|
* php artisan rsx:ajax:debug Auth_Api login --args='{"email":"test@example.com","password":"secret"}'
|
|
*
|
|
* OUTPUT FORMAT:
|
|
* - Success: Pretty-printed JSON response
|
|
* - Auth Required: Shows authentication error with login URL
|
|
* - Unauthorized: Shows authorization error message
|
|
* - Form Error: Shows validation errors with field details
|
|
* - Fatal Error: Shows error message and stack trace
|
|
* - Invalid controller/action: Clear error message
|
|
*
|
|
* SECURITY:
|
|
* - Only available in local/development/testing environments
|
|
* - Throws fatal error if attempted in production
|
|
* - Bypasses normal HTTP authentication for testing
|
|
*/
|
|
class Ajax_Debug_Command extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'rsx:ajax:debug
|
|
{controller : The RSX controller name (e.g., User_Api, Admin_Api)}
|
|
{action : The action/method name (e.g., get_profile, update)}
|
|
{--args= : JSON-encoded arguments to pass to the action}
|
|
{--user-id= : Set user ID for session context}
|
|
{--site-id= : Set site ID for session context}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Debug Internal API (Ajax) calls from command line - executes Ajax::call() with session context (development only)';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function handle()
|
|
{
|
|
// Check environment - throw fatal error in production
|
|
if (app()->environment('production')) {
|
|
throw new \RuntimeException('FATAL: rsx:ajax:debug command is not available in production environment. This is a development-only debugging tool.');
|
|
}
|
|
|
|
// Get command arguments
|
|
$controller = $this->argument('controller');
|
|
$action = $this->argument('action');
|
|
|
|
// Parse arguments if provided
|
|
$args = [];
|
|
if ($this->option('args')) {
|
|
$args_json = $this->option('args');
|
|
$args = json_decode($args_json, true);
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
$this->error('❌ Invalid JSON in --args parameter: ' . json_last_error_msg());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Get user and site IDs
|
|
$user_id = $this->option('user-id');
|
|
$site_id = $this->option('site-id');
|
|
|
|
// Rotate logs before test to ensure clean slate
|
|
Debugger::logrotate();
|
|
|
|
// Set session context if provided
|
|
if ($user_id !== null) {
|
|
RsxSession::set_user_id((int)$user_id);
|
|
$this->info("✓ Set user_id to {$user_id}");
|
|
}
|
|
|
|
if ($site_id !== null) {
|
|
RsxSession::set_site_id((int)$site_id);
|
|
$this->info("✓ Set site_id to {$site_id}");
|
|
}
|
|
|
|
// Show what we're calling
|
|
$this->info("");
|
|
$this->info("Calling: {$controller}::{$action}");
|
|
if (!empty($args)) {
|
|
$this->info("Arguments: " . json_encode($args, JSON_PRETTY_PRINT));
|
|
}
|
|
$this->info("");
|
|
$this->line("─────────────────────────────────────────");
|
|
$this->info("");
|
|
|
|
try {
|
|
// Call the Ajax method
|
|
$response = Ajax::internal($controller, $action, $args);
|
|
|
|
// Output successful response
|
|
$this->info("✅ Success Response:");
|
|
$this->info("");
|
|
|
|
// Pretty print the JSON response
|
|
$json_output = json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
$this->line($json_output);
|
|
|
|
} catch (AjaxAuthRequiredException $e) {
|
|
// Handle auth required response
|
|
$this->error("🔒 Authentication Required");
|
|
$this->error("");
|
|
$this->error("Login URL: " . $e->getMessage());
|
|
return 1;
|
|
|
|
} catch (AjaxUnauthorizedException $e) {
|
|
// Handle unauthorized response
|
|
$this->error("⛔ Unauthorized");
|
|
$this->error("");
|
|
$this->error("Message: " . $e->getMessage());
|
|
return 1;
|
|
|
|
} catch (AjaxFormErrorException $e) {
|
|
// Handle form error response - format like /_ajax route
|
|
$this->error("❌ Form Validation Error");
|
|
$this->error("");
|
|
|
|
$details = $e->get_details();
|
|
|
|
// Format the response like the /_ajax route does
|
|
$formatted_response = [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
|
|
// Add any additional details from the exception
|
|
if (!empty($details)) {
|
|
foreach ($details as $key => $value) {
|
|
if ($key !== 'message') {
|
|
$formatted_response[$key] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
$json_output = json_encode($formatted_response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
$this->line($json_output);
|
|
return 1;
|
|
|
|
} catch (AjaxFatalErrorException $e) {
|
|
// Handle fatal error response
|
|
$this->error("💀 Fatal Error");
|
|
$this->error("");
|
|
$this->error("Message: " . $e->getMessage());
|
|
$this->error("");
|
|
$this->error("Stack Trace:");
|
|
$this->line($e->getTraceAsString());
|
|
return 1;
|
|
|
|
} catch (\InvalidArgumentException $e) {
|
|
// Handle invalid controller/action
|
|
$this->error("❌ Invalid Request");
|
|
$this->error("");
|
|
$this->error($e->getMessage());
|
|
return 1;
|
|
|
|
} catch (\Exception $e) {
|
|
// Handle unexpected exceptions
|
|
$this->error("💥 Unexpected Error");
|
|
$this->error("");
|
|
$this->error("Exception: " . get_class($e));
|
|
$this->error("Message: " . $e->getMessage());
|
|
$this->error("");
|
|
$this->error("Stack Trace:");
|
|
$this->line($e->getTraceAsString());
|
|
return 1;
|
|
}
|
|
|
|
// Rotate logs after test to clean slate for next run
|
|
Debugger::logrotate();
|
|
|
|
return 0;
|
|
}
|
|
} |