Files
WooNooW/includes/Api/SoftwareController.php

322 lines
10 KiB
PHP

<?php
/**
* Software Distribution API Controller
*
* REST API endpoints for software update checking and downloads.
*
* @package WooNooW\Api
*/
namespace WooNooW\Api;
if (!defined('ABSPATH')) exit;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WooNooW\Core\ModuleRegistry;
use WooNooW\Modules\Software\SoftwareManager;
use WooNooW\Modules\Licensing\LicenseManager;
class SoftwareController
{
/**
* Register REST routes
*/
public static function register_routes()
{
$namespace = 'woonoow/v1';
// Public endpoints (authenticated via license key)
// Check for updates
register_rest_route($namespace, '/software/check', [
'methods' => 'GET',
'callback' => [__CLASS__, 'check_update'],
'permission_callback' => '__return_true',
'args' => [
'license_key' => ['required' => true, 'type' => 'string'],
'slug' => ['required' => true, 'type' => 'string'],
'version' => ['required' => true, 'type' => 'string'],
'site_url' => ['required' => false, 'type' => 'string'],
],
]);
// Also support POST for update check (some clients prefer this)
register_rest_route($namespace, '/software/check', [
'methods' => 'POST',
'callback' => [__CLASS__, 'check_update'],
'permission_callback' => '__return_true',
]);
// Download file
register_rest_route($namespace, '/software/download', [
'methods' => 'GET',
'callback' => [__CLASS__, 'download'],
'permission_callback' => '__return_true',
'args' => [
'token' => ['required' => true, 'type' => 'string'],
],
]);
// Get changelog
register_rest_route($namespace, '/software/changelog', [
'methods' => 'GET',
'callback' => [__CLASS__, 'get_changelog'],
'permission_callback' => '__return_true',
'args' => [
'slug' => ['required' => true, 'type' => 'string'],
'version' => ['required' => false, 'type' => 'string'],
],
]);
// Admin endpoints (requires manage_woocommerce)
// Get all versions for a product
register_rest_route($namespace, '/software/products/(?P<product_id>\d+)/versions', [
'methods' => 'GET',
'callback' => [__CLASS__, 'get_versions'],
'permission_callback' => function () {
return current_user_can('manage_woocommerce');
},
]);
// Add new version
register_rest_route($namespace, '/software/products/(?P<product_id>\d+)/versions', [
'methods' => 'POST',
'callback' => [__CLASS__, 'add_version'],
'permission_callback' => function () {
return current_user_can('manage_woocommerce');
},
]);
}
/**
* Check for updates
*/
public static function check_update(WP_REST_Request $request)
{
// Check if module is enabled
if (!ModuleRegistry::is_enabled('software')) {
return new WP_REST_Response([
'success' => false,
'error' => 'module_disabled',
'message' => __('Software distribution module is not enabled', 'woonoow'),
], 503);
}
// Get parameters from GET or POST body
$params = $request->get_method() === 'POST'
? $request->get_json_params()
: $request->get_query_params();
$license_key = sanitize_text_field($params['license_key'] ?? '');
$slug = sanitize_text_field($params['slug'] ?? '');
$current_version = sanitize_text_field($params['version'] ?? '');
$site_url = esc_url_raw($params['site_url'] ?? '');
if (empty($license_key) || empty($slug) || empty($current_version)) {
return new WP_REST_Response([
'success' => false,
'error' => 'missing_params',
'message' => __('Missing required parameters: license_key, slug, version', 'woonoow'),
], 400);
}
// Log the check (optional - for analytics)
do_action('woonoow/software/update_check', $slug, $current_version, $site_url, $license_key);
$result = SoftwareManager::check_update($license_key, $slug, $current_version);
$status_code = isset($result['success']) && $result['success'] === false ? 400 : 200;
return new WP_REST_Response($result, $status_code);
}
/**
* Download file
*/
public static function download(WP_REST_Request $request)
{
// Check if module is enabled
if (!ModuleRegistry::is_enabled('software')) {
return new WP_REST_Response([
'success' => false,
'error' => 'module_disabled',
'message' => __('Software distribution module is not enabled', 'woonoow'),
], 503);
}
$token = sanitize_text_field($request->get_param('token'));
if (empty($token)) {
return new WP_REST_Response([
'success' => false,
'error' => 'missing_token',
'message' => __('Download token is required', 'woonoow'),
], 400);
}
// Validate token
$download = SoftwareManager::validate_download_token($token);
if (is_wp_error($download)) {
return new WP_REST_Response([
'success' => false,
'error' => $download->get_error_code(),
'message' => $download->get_error_message(),
], 403);
}
// Validate license is still active
$license = LicenseManager::get_license($download['license_id']);
if (!$license || $license['status'] !== 'active') {
return new WP_REST_Response([
'success' => false,
'error' => 'license_inactive',
'message' => __('License is no longer active', 'woonoow'),
], 403);
}
// Serve the file
SoftwareManager::serve_file($download['product_id']);
// Note: serve_file calls exit, so this won't be reached
return new WP_REST_Response(['success' => true], 200);
}
/**
* Get changelog
*/
public static function get_changelog(WP_REST_Request $request)
{
$slug = sanitize_text_field($request->get_param('slug'));
$version = sanitize_text_field($request->get_param('version'));
if (empty($slug)) {
return new WP_REST_Response([
'success' => false,
'error' => 'missing_slug',
'message' => __('Software slug is required', 'woonoow'),
], 400);
}
// Get product by slug
$product = SoftwareManager::get_product_by_slug($slug);
if (!$product) {
return new WP_REST_Response([
'success' => false,
'error' => 'product_not_found',
'message' => __('Software product not found', 'woonoow'),
], 404);
}
// Get all versions or specific version
if ($version) {
$changelog = SoftwareManager::get_version_changelog($product->get_id(), $version);
if (!$changelog) {
return new WP_REST_Response([
'success' => false,
'error' => 'version_not_found',
'message' => __('Version not found', 'woonoow'),
], 404);
}
return new WP_REST_Response([
'slug' => $slug,
'version' => $changelog['version'],
'release_date' => $changelog['release_date'],
'changelog' => $changelog['changelog'],
], 200);
}
// Get all versions
$versions = SoftwareManager::get_all_versions($product->get_id());
return new WP_REST_Response([
'slug' => $slug,
'versions' => array_map(function ($v) {
return [
'version' => $v['version'],
'release_date' => $v['release_date'],
'changelog' => $v['changelog'],
'download_count' => (int) $v['download_count'],
];
}, $versions),
], 200);
}
/**
* Get versions for a product (admin)
*/
public static function get_versions(WP_REST_Request $request)
{
$product_id = (int) $request->get_param('product_id');
$product = wc_get_product($product_id);
if (!$product) {
return new WP_REST_Response([
'success' => false,
'error' => 'product_not_found',
], 404);
}
$versions = SoftwareManager::get_all_versions($product_id);
$config = SoftwareManager::get_product_config($product_id);
return new WP_REST_Response([
'product_id' => $product_id,
'config' => $config,
'versions' => $versions,
], 200);
}
/**
* Add new version (admin)
*/
public static function add_version(WP_REST_Request $request)
{
$product_id = (int) $request->get_param('product_id');
$params = $request->get_json_params();
$version = sanitize_text_field($params['version'] ?? '');
$changelog = wp_kses_post($params['changelog'] ?? '');
$set_current = (bool) ($params['set_current'] ?? true);
if (empty($version)) {
return new WP_REST_Response([
'success' => false,
'error' => 'missing_version',
'message' => __('Version number is required', 'woonoow'),
], 400);
}
$product = wc_get_product($product_id);
if (!$product) {
return new WP_REST_Response([
'success' => false,
'error' => 'product_not_found',
], 404);
}
$result = SoftwareManager::add_version($product_id, $version, $changelog, $set_current);
if (is_wp_error($result)) {
return new WP_REST_Response([
'success' => false,
'error' => $result->get_error_code(),
'message' => $result->get_error_message(),
], 400);
}
return new WP_REST_Response([
'success' => true,
'version_id' => $result,
'message' => __('Version added successfully', 'woonoow'),
], 201);
}
}