| 1 |
<?php |
| 2 |
|
| 3 |
class Meow_MWCODE_Rest |
| 4 |
{ |
| 5 |
private $admin = null; |
| 6 |
private $core = null; |
| 7 |
private $snippet = null; |
| 8 |
private $namespace = 'code-engine/v1'; |
| 9 |
|
| 10 |
private $bearer_token = null; |
| 11 |
|
| 12 |
public function __construct( $core, $admin, $snippet ) { |
| 13 |
if ( !current_user_can( 'administrator' ) ) { |
| 14 |
return; |
| 15 |
} |
| 16 |
$this->core = $core; |
| 17 |
$this->admin = $admin; |
| 18 |
$this->snippet = $snippet; |
| 19 |
add_action( 'rest_api_init', array( $this, 'rest_api_init' ) ); |
| 20 |
} |
| 21 |
|
| 22 |
function rest_api_init() { |
| 23 |
try { |
| 24 |
#region REST Settings |
| 25 |
register_rest_route( $this->namespace, '/settings/update', array( |
| 26 |
'methods' => 'POST', |
| 27 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 28 |
'callback' => array( $this, 'rest_settings_update' ) |
| 29 |
) ); |
| 30 |
register_rest_route( $this->namespace, '/settings/list', array( |
| 31 |
'methods' => 'GET', |
| 32 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 33 |
'callback' => array( $this, 'rest_settings_list' ), |
| 34 |
) ); |
| 35 |
register_rest_route( $this->namespace, '/settings/reset', array( |
| 36 |
'methods' => 'POST', |
| 37 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 38 |
'callback' => array( $this, 'rest_settings_reset' ), |
| 39 |
) ); |
| 40 |
register_rest_route( $this->namespace, '/settings/functions', array( |
| 41 |
'methods' => 'GET', |
| 42 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 43 |
'callback' => array( $this, 'rest_export_functions' ), |
| 44 |
) ); |
| 45 |
register_rest_route( $this->namespace, '/settings/functions/replace', array( |
| 46 |
'methods' => 'POST', |
| 47 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 48 |
'callback' => array( $this, 'rest_replace_functions' ), |
| 49 |
) ); |
| 50 |
register_rest_route( $this->namespace, '/settings/functions/raw', array( |
| 51 |
'methods' => 'GET', |
| 52 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 53 |
'callback' => array( $this, 'rest_functions_raw' ), |
| 54 |
) ); |
| 55 |
register_rest_route( $this->namespace, '/settings/functions/raw', array( |
| 56 |
'methods' => 'POST', |
| 57 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 58 |
'callback' => array( $this, 'rest_functions_raw_update' ), |
| 59 |
) ); |
| 60 |
#endregion |
| 61 |
|
| 62 |
#region MISC |
| 63 |
|
| 64 |
register_rest_route( $this->namespace, '/server_clock', array( |
| 65 |
'methods' => 'GET', |
| 66 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 67 |
'callback' => array( $this, 'rest_server_clock' ), |
| 68 |
) ); |
| 69 |
|
| 70 |
#endregion |
| 71 |
|
| 72 |
#region REST AI Engine |
| 73 |
register_rest_route( $this->namespace, '/ai_read_comments', array( |
| 74 |
'methods' => 'POST', |
| 75 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 76 |
'callback' => array( $this, 'rest_ai_read_comments' ), |
| 77 |
) ); |
| 78 |
register_rest_route( $this->namespace, '/ai_query', array( |
| 79 |
'methods' => 'POST', |
| 80 |
'permission_callback' => array( $this->core, 'can_access_settings' ), |
| 81 |
'callback' => array( $this, 'rest_ai_query' ), |
| 82 |
) ); |
| 83 |
#endregion |
| 84 |
|
| 85 |
#region REST Run |
| 86 |
register_rest_route( $this->namespace, '/run/test', [ |
| 87 |
'methods' => 'POST', |
| 88 |
'callback' => [ $this, 'rest_test' ], |
| 89 |
'permission_callback' => [ $this->core, 'can_access_settings' ], |
| 90 |
] ); |
| 91 |
|
| 92 |
register_rest_route( $this->namespace, '/run/lint', [ |
| 93 |
'methods' => 'POST', |
| 94 |
'callback' => [ $this, 'rest_lint' ], |
| 95 |
'permission_callback' => [ $this->core, 'can_access_settings' ], |
| 96 |
] ); |
| 97 |
#endregion |
| 98 |
|
| 99 |
#region REST Snippets |
| 100 |
|
| 101 |
register_rest_route($this->namespace, '/snippets/list', [ |
| 102 |
'methods' => 'POST', |
| 103 |
'callback' => [$this, 'rest_list'], |
| 104 |
'permission_callback' => [$this->core, 'can_access_settings'], |
| 105 |
]); |
| 106 |
|
| 107 |
register_rest_route( $this->namespace, '/snippets/stats', [ |
| 108 |
'methods' => 'GET', |
| 109 |
'callback' => [$this, 'rest_stats'], |
| 110 |
'permission_callback' => [$this->core, 'can_access_settings'], |
| 111 |
]); |
| 112 |
|
| 113 |
register_rest_route($this->namespace, '/snippets/tags', [ |
| 114 |
'methods' => 'POST', |
| 115 |
'callback' => [$this, 'rest_tags'], |
| 116 |
'permission_callback' => [$this->core, 'can_access_settings'], |
| 117 |
]); |
| 118 |
|
| 119 |
register_rest_route($this->namespace, '/snippets/import', [ |
| 120 |
'methods' => 'GET', |
| 121 |
'callback' => [$this, 'rest_import'], |
| 122 |
'permission_callback' => [$this->core, 'can_access_settings'], |
| 123 |
]); |
| 124 |
|
| 125 |
register_rest_route($this->namespace, '/snippets/add', array( |
| 126 |
'methods' => 'POST', |
| 127 |
'callback' => array($this, 'rest_add'), |
| 128 |
'permission_callback' => array($this->core, 'can_access_settings') |
| 129 |
)); |
| 130 |
|
| 131 |
register_rest_route($this->namespace, '/snippets/update', array( |
| 132 |
'methods' => 'POST', |
| 133 |
'callback' => array($this, 'rest_update'), |
| 134 |
'permission_callback' => array($this->core, 'can_access_settings') |
| 135 |
)); |
| 136 |
|
| 137 |
register_rest_route($this->namespace, '/snippets/delete', array( |
| 138 |
'methods' => 'POST', |
| 139 |
'callback' => array($this, 'rest_delete'), |
| 140 |
'permission_callback' => array($this->core, 'can_access_settings') |
| 141 |
)); |
| 142 |
|
| 143 |
|
| 144 |
register_rest_route($this->namespace, '/snippets/replace', array( |
| 145 |
'methods' => 'POST', |
| 146 |
'callback' => array($this, 'rest_replace'), |
| 147 |
'permission_callback' => array($this->core, 'can_access_settings') |
| 148 |
)); |
| 149 |
|
| 150 |
|
| 151 |
// SNIPPETS ENDPOINTS |
| 152 |
$snippets = $this->snippet->select( |
| 153 |
null, // offset |
| 154 |
-1, // limit |
| 155 |
[ |
| 156 |
[ 'accessor' => 'active', 'value' => 1 ], |
| 157 |
[ 'accessor' => 'endpoint', 'value' => 1 ], |
| 158 |
], // filter |
| 159 |
null, // sort |
| 160 |
); |
| 161 |
|
| 162 |
$public_api_enabled = $this->core->get_option( 'api_endpoint', false ); |
| 163 |
if ( (int) $snippets['total'] > 0 && $public_api_enabled ) { |
| 164 |
|
| 165 |
$this->bearer_token = $this->core->get_option( 'api_token', null ); |
| 166 |
if ( !empty( $this->bearer_token ) ) { |
| 167 |
add_filter( 'mwcode_allow_public_api', [ $this, 'auth_via_bearer_token' ], 10, 3 ); |
| 168 |
} |
| 169 |
|
| 170 |
$data = $snippets['data']; |
| 171 |
|
| 172 |
foreach ( $data as $snippet ) { |
| 173 |
register_rest_route( $this->namespace, '/snippets-endpoint/' . $snippet['endpoint'], array( |
| 174 |
'methods' => $snippet['method'] ?: 'POST', |
| 175 |
'permission_callback' => function( $request ) { |
| 176 |
return $this->can_access_public_api( 'snippets-endpoint', $request ); |
| 177 |
}, |
| 178 |
'callback' => array( $this, 'rest_call_snippet' ), |
| 179 |
'args' => array( |
| 180 |
'id' => array( 'required' => true, 'default' => $snippet['id'] ), |
| 181 |
), |
| 182 |
) ); |
| 183 |
|
| 184 |
//$this->core->log( "Registered REST API endpoint: /{$this->namespace}/snippets-endpoint/{$snippet['endpoint']} ({$snippet['method']})" ); |
| 185 |
} |
| 186 |
} |
| 187 |
|
| 188 |
#endregion |
| 189 |
|
| 190 |
#region REST Logs |
| 191 |
register_rest_route( $this->namespace, '/get_logs', array( |
| 192 |
'methods' => 'GET', |
| 193 |
'permission_callback' => array( $this->core, 'can_access_features' ), |
| 194 |
'callback' => array( $this, 'rest_get_logs' ) |
| 195 |
) ); |
| 196 |
register_rest_route( $this->namespace, '/clear_logs', array( |
| 197 |
'methods' => 'GET', |
| 198 |
'permission_callback' => array( $this->core, 'can_access_features' ), |
| 199 |
'callback' => array( $this, 'rest_clear_logs' ) |
| 200 |
) ); |
| 201 |
|
| 202 |
#endregion |
| 203 |
} |
| 204 |
catch (Exception $e) { |
| 205 |
var_dump($e); |
| 206 |
} |
| 207 |
} |
| 208 |
|
| 209 |
#region Auth |
| 210 |
|
| 211 |
public function auth_via_bearer_token( $allow, $feature, $extra ) { |
| 212 |
if ( !empty( $extra ) && !empty( $extra->get_header( 'Authorization' ) ) ) { |
| 213 |
$token = $extra->get_header( 'Authorization' ); |
| 214 |
$token = str_replace( 'Bearer ', '', $token ); |
| 215 |
if ( $token === $this->bearer_token ) { |
| 216 |
$admin = $this->get_admin_user(); |
| 217 |
wp_set_current_user( $admin->ID, $admin->user_login ); |
| 218 |
return true; |
| 219 |
} |
| 220 |
} |
| 221 |
return $allow; |
| 222 |
} |
| 223 |
|
| 224 |
function can_access_public_api( $feature, $extra ) { |
| 225 |
$logged_in = is_user_logged_in(); |
| 226 |
return apply_filters( 'mwcode_allow_public_api', $logged_in, $feature, $extra ); |
| 227 |
} |
| 228 |
|
| 229 |
function get_admin_user() { |
| 230 |
$admin = get_users( [ 'role' => 'administrator' ] ); |
| 231 |
if ( !empty( $admin ) ) { |
| 232 |
return $admin[0]; |
| 233 |
} |
| 234 |
return null; |
| 235 |
} |
| 236 |
|
| 237 |
#endregion |
| 238 |
|
| 239 |
#region Logs |
| 240 |
|
| 241 |
function rest_get_logs() { |
| 242 |
$logs = $this->core->get_logs(); |
| 243 |
return new WP_REST_Response( [ 'success' => true, 'data' => $logs ], 200 ); |
| 244 |
} |
| 245 |
|
| 246 |
function rest_clear_logs() { |
| 247 |
$this->core->clear_logs(); |
| 248 |
return new WP_REST_Response( [ 'success' => true ], 200 ); |
| 249 |
} |
| 250 |
|
| 251 |
|
| 252 |
#endregion |
| 253 |
|
| 254 |
#region Settings |
| 255 |
|
| 256 |
function rest_settings_list() { |
| 257 |
return new WP_REST_Response( [ |
| 258 |
'success' => true, |
| 259 |
'options' => $this->core->get_all_options() |
| 260 |
], 200 ); |
| 261 |
} |
| 262 |
|
| 263 |
|
| 264 |
function rest_settings_update( $request ) { |
| 265 |
try { |
| 266 |
$params = $request->get_json_params(); |
| 267 |
$value = $params['options']; |
| 268 |
$options = $this->core->update_options( $value ); |
| 269 |
$success = !!$options; |
| 270 |
$message = __( $success ? 'OK' : "Could not update options.", 'code-engine' ); |
| 271 |
return new WP_REST_Response([ 'success' => $success, 'message' => $message, 'options' => $options ], 200 ); |
| 272 |
} |
| 273 |
catch ( Exception $e ) { |
| 274 |
return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 ); |
| 275 |
} |
| 276 |
} |
| 277 |
|
| 278 |
function rest_settings_reset() { |
| 279 |
try { |
| 280 |
$options = $this->core->reset_options(); |
| 281 |
$success = !!$options; |
| 282 |
$message = __( $success ? 'OK' : "Could not reset options.", 'code-engine' ); |
| 283 |
return new WP_REST_Response([ 'success' => $success, 'message' => $message, 'options' => $options ], 200 ); |
| 284 |
} |
| 285 |
catch ( Exception $e ) { |
| 286 |
return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 ); |
| 287 |
} |
| 288 |
} |
| 289 |
|
| 290 |
function rest_export_functions() { |
| 291 |
$functions = $this->snippet->get_functions(); |
| 292 |
return new WP_REST_Response([ 'success' => true, 'functions' => $functions ], 200); |
| 293 |
} |
| 294 |
|
| 295 |
function rest_replace_functions( $request ) { |
| 296 |
try { |
| 297 |
$params = $request->get_json_params(); |
| 298 |
$functions = $params['functions']; |
| 299 |
|
| 300 |
$this->snippet->set_functions( $functions ); |
| 301 |
|
| 302 |
return new WP_REST_Response([ 'success' => true, 'data' => $functions ], 200); |
| 303 |
} catch (Exception $e) { |
| 304 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 305 |
} |
| 306 |
|
| 307 |
} |
| 308 |
|
| 309 |
function rest_functions_raw() { |
| 310 |
$functions = $this->snippet->get_functions_raw(); |
| 311 |
return new WP_REST_Response([ 'success' => true, 'functions' => $functions ], 200); |
| 312 |
} |
| 313 |
|
| 314 |
function rest_functions_raw_update( $request ) { |
| 315 |
try { |
| 316 |
$params = $request->get_json_params(); |
| 317 |
$functions = $params['functions']; |
| 318 |
|
| 319 |
error_log( print_r( $functions, 1 ) ); |
| 320 |
|
| 321 |
if ( empty( $functions ) ) { |
| 322 |
$functions = []; |
| 323 |
} else { |
| 324 |
// Decode the JSON string into a PHP array |
| 325 |
$functions = json_decode($functions, true); |
| 326 |
|
| 327 |
// Check if decoding was successful |
| 328 |
if (json_last_error() !== JSON_ERROR_NONE) { |
| 329 |
return new WP_REST_Response([ 'success' => false, 'message' => 'Invalid JSON format' ], 400); |
| 330 |
} |
| 331 |
} |
| 332 |
|
| 333 |
$this->snippet->set_functions_raw( $functions ); |
| 334 |
|
| 335 |
return new WP_REST_Response([ 'success' => true, 'data' => $functions ], 200); |
| 336 |
} catch (Exception $e) { |
| 337 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 338 |
} |
| 339 |
} |
| 340 |
|
| 341 |
#endregion |
| 342 |
|
| 343 |
|
| 344 |
#region MISC |
| 345 |
|
| 346 |
function rest_server_clock() { |
| 347 |
$now = current_datetime(); |
| 348 |
$now = $now->format( 'H:i:s ( Y/m/d )' ); |
| 349 |
|
| 350 |
return new WP_REST_Response( [ 'success' => true, 'time' => $now ], 200 ); |
| 351 |
} |
| 352 |
|
| 353 |
#endregion |
| 354 |
|
| 355 |
#region AI Engine |
| 356 |
|
| 357 |
function rest_ai_query( $request ) { |
| 358 |
|
| 359 |
$query = $request->get_param('query'); |
| 360 |
$code = $request->get_param('code'); |
| 361 |
|
| 362 |
global $mwai; |
| 363 |
|
| 364 |
if ( is_null( $query ) || !isset( $query ) ) { |
| 365 |
return new WP_REST_Response([ 'success' => false, 'message' => 'No query provided.' ], 500 ); |
| 366 |
} |
| 367 |
|
| 368 |
if ( is_null( $mwai ) || !isset( $mwai ) ) { |
| 369 |
return new WP_REST_Response([ 'success' => false, 'message' => 'AI Engine is not available.' ], 500 ); |
| 370 |
} |
| 371 |
|
| 372 |
$prompt = "In your response, do not include any explanation outside the code if this is a functon, everything should be inside. Any information should be added as comments only, not example function calls. Do not use <?php tags or markdown ``` format, just provide the raw code. Based on the code provided, modify it as needed: $query\n\n$code"; |
| 373 |
$response = $mwai->simpleTextQuery( $prompt ); |
| 374 |
|
| 375 |
return new WP_REST_Response([ 'success' => true, 'code' => $response ], 200); |
| 376 |
} |
| 377 |
|
| 378 |
function rest_ai_read_comments( $request ) { |
| 379 |
$code = $request->get_param('code'); |
| 380 |
global $mwai; |
| 381 |
|
| 382 |
if ( is_null( $code ) || !isset( $code ) ) { |
| 383 |
return new WP_REST_Response([ 'success' => false, 'message' => 'No code provided.' ], 500 ); |
| 384 |
} |
| 385 |
|
| 386 |
if ( is_null( $mwai ) || !isset( $mwai ) ) { |
| 387 |
return new WP_REST_Response([ 'success' => false, 'message' => 'AI Engine is not available.' ], 500 ); |
| 388 |
} |
| 389 |
|
| 390 |
$prompt = "Based on the comments in the code, modify the snippet so it accords with what the comments say. In your response, only include the modfied code with the comments removed and nothing else, no <?php tag, no markdown ``` format, just the raw code.\n\n$code"; |
| 391 |
$prompt = apply_filters( 'mwcode_ai_suggestion_prompt', $prompt, $code ); |
| 392 |
|
| 393 |
$response = $mwai->simpleTextQuery( $prompt ); |
| 394 |
|
| 395 |
return new WP_REST_Response([ 'success' => true, 'code' => $response ], 200); |
| 396 |
|
| 397 |
} |
| 398 |
|
| 399 |
#endregion |
| 400 |
|
| 401 |
#region Snippets |
| 402 |
|
| 403 |
function rest_call_snippet( $request ) { |
| 404 |
try { |
| 405 |
$route = $request->get_route(); |
| 406 |
$endpoint = basename( $route ); |
| 407 |
|
| 408 |
$id = $request->get_param( 'id' ); |
| 409 |
|
| 410 |
$snippet = $this->snippet->select_one( $id ); |
| 411 |
if ( empty( $snippet ) || $snippet['endpoint'] !== $endpoint ) { |
| 412 |
return new WP_REST_Response( ['success' => false, 'message' => 'Snippet not found.' ], 404 ); |
| 413 |
} elseif ( !$snippet['active'] ) { |
| 414 |
return new WP_REST_Response( ['success' => false, 'message' => 'Snippet is not active.' ], 403 ); |
| 415 |
} |
| 416 |
|
| 417 |
// Get the arguments from the request |
| 418 |
$args = $request->get_param('args'); |
| 419 |
if ( !empty( $args ) ) { |
| 420 |
$args = json_decode( $args, true ); |
| 421 |
if ( json_last_error() !== JSON_ERROR_NONE ) { |
| 422 |
throw new Exception('Failed to decode JSON from args: ' . json_last_error_msg() ); |
| 423 |
} |
| 424 |
} |
| 425 |
|
| 426 |
// Get the body from the request |
| 427 |
$body = $request->get_body(); |
| 428 |
if ( !empty( $body ) ) { |
| 429 |
$bodyDecoded = json_decode( $body, true ); |
| 430 |
if ( json_last_error() !== JSON_ERROR_NONE ) { |
| 431 |
throw new Exception( 'Failed to decode JSON from body: ' . json_last_error_msg() ); |
| 432 |
} |
| 433 |
if ( !empty( $args ) && is_array( $args ) ) { |
| 434 |
$args = array_merge( $args, $bodyDecoded ); |
| 435 |
} else { |
| 436 |
$args = $bodyDecoded; |
| 437 |
} |
| 438 |
} |
| 439 |
|
| 440 |
$output = $this->core->run_snippet( $id, $args ); |
| 441 |
|
| 442 |
return new WP_REST_Response( $output, 200); |
| 443 |
} catch (ParseError $e) { |
| 444 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 445 |
} catch ( Exception $e ) { |
| 446 |
return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 ); |
| 447 |
} |
| 448 |
} |
| 449 |
|
| 450 |
public function rest_list( $request ) |
| 451 |
{ |
| 452 |
try { |
| 453 |
$params = $request->get_json_params(); |
| 454 |
$page = $params['page'] ? intval($params['page']) : 1; |
| 455 |
$limit = $params['limit'] ?? 10; |
| 456 |
$offset = ($page - 1) * $limit; |
| 457 |
|
| 458 |
$filters = $params['filters'] ?? []; |
| 459 |
|
| 460 |
$filters = array_filter( $filters, function( $filter ) { |
| 461 |
return $filter['value'] !== 'all'; |
| 462 |
}); |
| 463 |
|
| 464 |
foreach ($filters as $key => $filter) { |
| 465 |
if ( $filter['accessor'] === 'scope' && $filter['value'] === 'disabled' ) { |
| 466 |
$filters[] = ['accessor' => 'active', 'value' => 0]; |
| 467 |
unset( $filters[$key] ); |
| 468 |
} |
| 469 |
} |
| 470 |
|
| 471 |
$sort = ['accessor' => 'id', 'by' => 'asc']; |
| 472 |
$sortByFunctionName = $params['sort']['accessor'] == 'functionName'; |
| 473 |
|
| 474 |
if ( !$sortByFunctionName && !empty( $params['sort'] ) ) { |
| 475 |
$sort = $params['sort']; |
| 476 |
} |
| 477 |
|
| 478 |
|
| 479 |
if ( !empty( $filters['scope'] ) ) { |
| 480 |
//$filters['scope'] = [ 'accessor' => 'scope', 'value' => 'frontend' ]; |
| 481 |
} |
| 482 |
|
| 483 |
$list = $this->snippet->select( $offset, $limit, $filters, $sort ); |
| 484 |
|
| 485 |
//when listing let's reset any error message on the dashboard |
| 486 |
$this->core->update_option( 'fatal_error', '' ); |
| 487 |
|
| 488 |
|
| 489 |
//TODO: Delete in future versions, we are converting the scopes since they have changed |
| 490 |
$to_update = []; |
| 491 |
foreach ( $list['data'] as $key => $snippet ) { |
| 492 |
if ( $snippet['scope'] === 'admin' ) { |
| 493 |
$list['data'][$key]['scope'] = 'backend'; |
| 494 |
$to_update[] = $key; |
| 495 |
} |
| 496 |
|
| 497 |
if ( $snippet['scope'] === 'front' ) { |
| 498 |
$list['data'][$key]['scope'] = 'frontend'; |
| 499 |
$to_update[] = $key; |
| 500 |
} |
| 501 |
|
| 502 |
if ( $snippet['scope'] === 'front,admin' ) { |
| 503 |
$list['data'][$key]['scope'] = 'persistent'; |
| 504 |
$to_update[] = $key; |
| 505 |
} |
| 506 |
|
| 507 |
if ( $snippet['scope'] === 'library' ) { |
| 508 |
$list['data'][$key]['scope'] = 'persistent'; |
| 509 |
$to_update[] = $key; |
| 510 |
} |
| 511 |
|
| 512 |
if ( $snippet['scope'] === 'interval' ) { |
| 513 |
$list['data'][$key]['scope'] = 'scheduled'; |
| 514 |
$to_update[] = $key; |
| 515 |
} |
| 516 |
} |
| 517 |
|
| 518 |
foreach ( $to_update as $key ) { |
| 519 |
$snippet = $list['data'][$key]; |
| 520 |
$this->core->log( "Updating snippet for new scopes: " . $snippet['id'] ); |
| 521 |
$this->snippet->update( $snippet ); |
| 522 |
} |
| 523 |
|
| 524 |
if ( $sortByFunctionName ) { |
| 525 |
// Manually sort by functionName |
| 526 |
usort( $list['data'], function( $a, $b ) use ( $params ) { |
| 527 |
$result = strcmp( $a['functionName'], $b['functionName'] ); |
| 528 |
// If sorting by 'desc', invert the comparison result |
| 529 |
if ( $params['sort']['by'] === 'desc' ) { |
| 530 |
return -$result; |
| 531 |
} |
| 532 |
// Otherwise, return the comparison result for 'asc' |
| 533 |
return $result; |
| 534 |
} ); |
| 535 |
} |
| 536 |
|
| 537 |
//$this->core->log( "snippets" . print_r($list['data'], 1) ); |
| 538 |
|
| 539 |
return new WP_REST_Response([ 'success' => true, 'total' => $list['total'], 'data' => $list['data'] ], 200); |
| 540 |
} catch (Exception $e) { |
| 541 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 542 |
} |
| 543 |
} |
| 544 |
|
| 545 |
public function rest_stats( ) |
| 546 |
{ |
| 547 |
try { |
| 548 |
$stats = $this->snippet->stats(); |
| 549 |
return new WP_REST_Response([ 'success' => true, 'data' => $stats ], 200); |
| 550 |
} catch (Exception $e) { |
| 551 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 552 |
} |
| 553 |
} |
| 554 |
|
| 555 |
public function rest_tags() |
| 556 |
{ |
| 557 |
try { |
| 558 |
$list = $this->snippet->select_tags(); |
| 559 |
return new WP_REST_Response([ 'success' => true, 'data' => $list ], 200); |
| 560 |
} catch (Exception $e) { |
| 561 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 562 |
} |
| 563 |
} |
| 564 |
|
| 565 |
public function rest_import( ) |
| 566 |
{ |
| 567 |
try { |
| 568 |
$snippet = $this->snippet->import( ); |
| 569 |
return new WP_REST_Response([ 'success' => true, 'total' => $snippet ], 200); |
| 570 |
} catch (Exception $e) { |
| 571 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 572 |
} |
| 573 |
} |
| 574 |
|
| 575 |
public function rest_add( $request ) |
| 576 |
{ |
| 577 |
try { |
| 578 |
$params = $request->get_json_params(); |
| 579 |
$name = $params['name']; |
| 580 |
$code = $params['code']; |
| 581 |
if ( empty( $name ) || empty( $code ) ) { |
| 582 |
throw new Exception( __( 'Name and code are required.', 'code-engine' ) ); |
| 583 |
} |
| 584 |
$this->snippet->validate( $params ); |
| 585 |
|
| 586 |
$params = $this->snippet->formatParamsForDatabase( $params ); |
| 587 |
$result = $this->snippet->insert( $params ); |
| 588 |
$snippet = $this->snippet->select_one( $result ); |
| 589 |
|
| 590 |
if( $result ) { |
| 591 |
$params['id'] = (string)$result; |
| 592 |
|
| 593 |
$this->snippet->create_or_update_function_snippet( $params ); |
| 594 |
$this->snippet->create_or_update_interval_snippet( $params ); |
| 595 |
|
| 596 |
$this->snippet->get_function_snippets_data( $snippet ); |
| 597 |
} |
| 598 |
|
| 599 |
return new WP_REST_Response([ 'success' => true, 'data' => $result, 'snippet' => $snippet ], 200); |
| 600 |
} catch (Exception $e) { |
| 601 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 602 |
} |
| 603 |
} |
| 604 |
|
| 605 |
public function rest_update( $request ) |
| 606 |
{ |
| 607 |
try { |
| 608 |
$params = $request->get_json_params(); |
| 609 |
$id = $params['id']; |
| 610 |
if ( empty( $id ) ) { |
| 611 |
throw new Exception( __( 'ID is required.', 'code-engine' ) ); |
| 612 |
} |
| 613 |
|
| 614 |
$params['update'] = true; |
| 615 |
$this->snippet->validate( $params ); |
| 616 |
$this->snippet->create_or_update_function_snippet( $params ); |
| 617 |
$this->snippet->create_or_update_interval_snippet( $params ); |
| 618 |
|
| 619 |
$params = $this->snippet->formatParamsForDatabase( $params ); |
| 620 |
$result = $this->snippet->update( $params ); |
| 621 |
return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200); |
| 622 |
} catch (Exception $e) { |
| 623 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 624 |
} |
| 625 |
} |
| 626 |
|
| 627 |
|
| 628 |
public function rest_delete( $request ) |
| 629 |
{ |
| 630 |
try { |
| 631 |
$params = $request->get_json_params(); |
| 632 |
$id = $params['id']; |
| 633 |
|
| 634 |
if ( empty( $id ) ) { |
| 635 |
throw new Exception( __( 'ID is required.', 'code-engine' ) ); |
| 636 |
} |
| 637 |
|
| 638 |
$this->snippet->delete_function_snippet( $params ); |
| 639 |
$this->snippet->delete_interval_snippet( $params ); |
| 640 |
|
| 641 |
$result = $this->snippet->delete( $params ); |
| 642 |
|
| 643 |
return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200); |
| 644 |
} catch (Exception $e) { |
| 645 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 646 |
} |
| 647 |
} |
| 648 |
|
| 649 |
public function rest_replace( $request ){ |
| 650 |
try { |
| 651 |
$params = $request->get_json_params(); |
| 652 |
$snippets = $params['snippets']; |
| 653 |
|
| 654 |
// Delete all current snippets |
| 655 |
$this->snippet->delete_all(); |
| 656 |
|
| 657 |
// Insert new snippets |
| 658 |
$result = []; |
| 659 |
foreach ( $snippets as $snippet ) { |
| 660 |
$this->snippet->validate( $snippet ); |
| 661 |
$snippet = $this->snippet->formatParamsForDatabase( $snippet ); |
| 662 |
$result[] = $this->snippet->insert( $snippet ); |
| 663 |
} |
| 664 |
|
| 665 |
return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200); |
| 666 |
} catch (Exception $e) { |
| 667 |
return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 ); |
| 668 |
} |
| 669 |
} |
| 670 |
|
| 671 |
|
| 672 |
#endregion |
| 673 |
|
| 674 |
#region Run |
| 675 |
|
| 676 |
/** |
| 677 |
* Execute a function snippet and return the result. |
| 678 |
* |
| 679 |
* It executes the provided function code with the given arguments and returns the result or any error encountered. |
| 680 |
* |
| 681 |
* @param WP_REST_Request $request The REST API request object. |
| 682 |
* @return WP_REST_Response The REST API response containing the result or error. |
| 683 |
*/ |
| 684 |
public function rest_test( $request ) { |
| 685 |
if ( is_array( $request ) ) { |
| 686 |
$params = $request; |
| 687 |
} else { |
| 688 |
$params = $request->get_json_params(); |
| 689 |
} |
| 690 |
|
| 691 |
try { |
| 692 |
$output = $this->core->run_snippet( null, [], $params ); |
| 693 |
|
| 694 |
$error = $output['error'] ?? null; |
| 695 |
unset( $output['error'] ); |
| 696 |
|
| 697 |
return new WP_REST_Response( [ 'success' => true, 'return' => $output, 'error' => $error ], 200 ); |
| 698 |
} catch ( Exception $e ) { |
| 699 |
return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 ); |
| 700 |
} |
| 701 |
} |
| 702 |
|
| 703 |
|
| 704 |
/** |
| 705 |
* Lint the code. |
| 706 |
* |
| 707 |
* @param $request |
| 708 |
* @return WP_REST_Response |
| 709 |
*/ |
| 710 |
public function rest_lint( $request ) { |
| 711 |
try { |
| 712 |
$params = $request->get_json_params(); |
| 713 |
$code = $params['code']; |
| 714 |
|
| 715 |
if ( empty( $code ) ) { |
| 716 |
throw new Exception( __( 'Code is required.', 'code-engine' ) ); |
| 717 |
} |
| 718 |
|
| 719 |
$linting_new_code = empty( $params['id'] ); |
| 720 |
$result = $this->core->parse_snippet( $code, $linting_new_code ); |
| 721 |
|
| 722 |
return new WP_REST_Response( [ 'success' => true, 'lint' => $result ], 200 ); |
| 723 |
} catch ( ParseError $e ) { |
| 724 |
return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 ); |
| 725 |
} catch ( Exception $e ) { |
| 726 |
return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 ); |
| 727 |
} |
| 728 |
} |
| 729 |
#endregion |
| 730 |
} |
| 731 |
|