feat: Divi tab with REST check, release and withdrawal
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Release;
|
||||
|
||||
use Closure;
|
||||
use LIT\MCP\Admin\DiviTab;
|
||||
use LIT\MCP\Admin\SettingsPage;
|
||||
use WP_REST_Response;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* "Prüfung starten" of the Divi tab (spec §6.1): POST /wp-json/lit-mcp/v1/divi-check. A REST request on purpose –
|
||||
* not admin-post – so the check runs in the same context as MCP calls (Divi renders its blocks in REST requests,
|
||||
* lit-page-render-summary). The form sends the wp_rest nonce as _wpnonce (cookie authentication); only manage_options.
|
||||
* One check at a time: the option LOCK (add_option is atomic); a lock older than LOCK_TTL is a dead check's and taken
|
||||
* over. Answers 303 back to the tab.
|
||||
*/
|
||||
final class DiviCheckRoute
|
||||
{
|
||||
public const NAMESPACE = 'lit-mcp/v1';
|
||||
public const ROUTE = '/divi-check';
|
||||
public const LOCK = 'lit_mcp_divi_check_lock';
|
||||
|
||||
private const LOCK_TTL = 600;
|
||||
|
||||
/** @param Closure(): CompatibilityCheck $check */
|
||||
public function __construct(private Closure $check, private ?CheckReportStore $reports = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function register(): void
|
||||
{
|
||||
add_action('rest_api_init', [$this, 'registerRoute']);
|
||||
}
|
||||
|
||||
public function registerRoute(): void
|
||||
{
|
||||
register_rest_route(self::NAMESPACE, self::ROUTE, [
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'handle'],
|
||||
'permission_callback' => static fn (): bool => current_user_can('manage_options'),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function url(): string
|
||||
{
|
||||
return rest_url(self::NAMESPACE . self::ROUTE);
|
||||
}
|
||||
|
||||
public function handle(): WP_REST_Response
|
||||
{
|
||||
$notice = 'divi_check_running';
|
||||
if (self::lock()) {
|
||||
try {
|
||||
$report = ($this->check)()->run(get_current_user_id());
|
||||
($this->reports ?? new CheckReportStore())->save($report);
|
||||
ReleaseGate::forget();
|
||||
$notice = 'divi_checked';
|
||||
} finally {
|
||||
delete_option(self::LOCK);
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response(
|
||||
null,
|
||||
303,
|
||||
['Location' => SettingsPage::url(DiviTab::SLUG, ['lit_mcp_notice' => $notice])]
|
||||
);
|
||||
}
|
||||
|
||||
private static function lock(): bool
|
||||
{
|
||||
if (add_option(self::LOCK, time(), '', false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$since = (int) get_option(self::LOCK, 0);
|
||||
if ($since > 0 && time() - $since < self::LOCK_TTL) {
|
||||
return false;
|
||||
}
|
||||
delete_option(self::LOCK);
|
||||
|
||||
return (bool) add_option(self::LOCK, time(), '', false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user