Adding more functionality
This commit is contained in:
785
includes/class-wpdd-api.php
Normal file
785
includes/class-wpdd-api.php
Normal file
@@ -0,0 +1,785 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WPDD_API {
|
||||
|
||||
/**
|
||||
* Initialize the API endpoints
|
||||
*/
|
||||
public static function init() {
|
||||
add_action('rest_api_init', array(__CLASS__, 'register_routes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API routes
|
||||
*/
|
||||
public static function register_routes() {
|
||||
// License validation
|
||||
register_rest_route('wpdd/v1', '/validate-license', array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array(__CLASS__, 'validate_license'),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'license_key' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'product_slug' => array(
|
||||
'required' => false,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'site_url' => array(
|
||||
'required' => false,
|
||||
'sanitize_callback' => 'esc_url_raw'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// License activation
|
||||
register_rest_route('wpdd/v1', '/activate-license', array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array(__CLASS__, 'activate_license'),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'license_key' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'site_url' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'esc_url_raw'
|
||||
),
|
||||
'site_name' => array(
|
||||
'required' => false,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'wp_version' => array(
|
||||
'required' => false,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'php_version' => array(
|
||||
'required' => false,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// License deactivation
|
||||
register_rest_route('wpdd/v1', '/deactivate-license', array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array(__CLASS__, 'deactivate_license'),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'license_key' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'site_url' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'esc_url_raw'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// Check for updates
|
||||
register_rest_route('wpdd/v1', '/check-update/(?P<product_slug>[a-zA-Z0-9-]+)', array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array(__CLASS__, 'check_update'),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'product_slug' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'license_key' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'version' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// Download update
|
||||
register_rest_route('wpdd/v1', '/download-update/(?P<product_slug>[a-zA-Z0-9-]+)', array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array(__CLASS__, 'download_update'),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'product_slug' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
),
|
||||
'license_key' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// Webhook endpoint with secure passcode
|
||||
register_rest_route('wpdd/v1', '/webhook/(?P<product_id>\d+)/(?P<passcode>[a-zA-Z0-9]+)', array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array(__CLASS__, 'handle_webhook'),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'product_id' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'absint'
|
||||
),
|
||||
'passcode' => array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field'
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate license endpoint
|
||||
*/
|
||||
public static function validate_license($request) {
|
||||
$license_key = $request->get_param('license_key');
|
||||
$product_slug = $request->get_param('product_slug');
|
||||
$site_url = $request->get_param('site_url');
|
||||
|
||||
if (!class_exists('WPDD_License_Manager')) {
|
||||
require_once WPDD_PLUGIN_PATH . 'includes/class-wpdd-license-manager.php';
|
||||
}
|
||||
|
||||
$result = WPDD_License_Manager::validate_license($license_key, $product_slug, $site_url);
|
||||
|
||||
if ($result['valid']) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => true,
|
||||
'message' => $result['message'],
|
||||
'license' => array(
|
||||
'status' => $result['license']->status,
|
||||
'expires_at' => $result['license']->expires_at,
|
||||
'activations' => $result['license']->activations_count,
|
||||
'max_activations' => $result['license']->max_activations
|
||||
)
|
||||
), 200);
|
||||
} else {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'error' => $result['error'],
|
||||
'message' => $result['message']
|
||||
), 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate license endpoint
|
||||
*/
|
||||
public static function activate_license($request) {
|
||||
$license_key = $request->get_param('license_key');
|
||||
$site_url = $request->get_param('site_url');
|
||||
$site_name = $request->get_param('site_name');
|
||||
$wp_version = $request->get_param('wp_version');
|
||||
$php_version = $request->get_param('php_version');
|
||||
|
||||
if (!class_exists('WPDD_License_Manager')) {
|
||||
require_once WPDD_PLUGIN_PATH . 'includes/class-wpdd-license-manager.php';
|
||||
}
|
||||
|
||||
$result = WPDD_License_Manager::activate_license($license_key, $site_url, $site_name, $wp_version, $php_version);
|
||||
|
||||
if ($result['success']) {
|
||||
return new WP_REST_Response($result, 200);
|
||||
} else {
|
||||
return new WP_REST_Response($result, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate license endpoint
|
||||
*/
|
||||
public static function deactivate_license($request) {
|
||||
$license_key = $request->get_param('license_key');
|
||||
$site_url = $request->get_param('site_url');
|
||||
|
||||
if (!class_exists('WPDD_License_Manager')) {
|
||||
require_once WPDD_PLUGIN_PATH . 'includes/class-wpdd-license-manager.php';
|
||||
}
|
||||
|
||||
$result = WPDD_License_Manager::deactivate_license($license_key, $site_url);
|
||||
|
||||
if ($result['success']) {
|
||||
return new WP_REST_Response($result, 200);
|
||||
} else {
|
||||
return new WP_REST_Response($result, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for updates endpoint
|
||||
*/
|
||||
public static function check_update($request) {
|
||||
global $wpdb;
|
||||
|
||||
$product_slug = $request->get_param('product_slug');
|
||||
$license_key = $request->get_param('license_key');
|
||||
$current_version = $request->get_param('version');
|
||||
|
||||
// Validate license first
|
||||
if (!class_exists('WPDD_License_Manager')) {
|
||||
require_once WPDD_PLUGIN_PATH . 'includes/class-wpdd-license-manager.php';
|
||||
}
|
||||
|
||||
$validation = WPDD_License_Manager::validate_license($license_key, $product_slug);
|
||||
if (!$validation['valid']) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'error' => $validation['error'],
|
||||
'message' => $validation['message']
|
||||
), 403);
|
||||
}
|
||||
|
||||
// Get product by slug
|
||||
$product = get_page_by_path($product_slug, OBJECT, 'wpdd_product');
|
||||
if (!$product) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Product not found.', 'wp-digital-download')
|
||||
), 404);
|
||||
}
|
||||
|
||||
// Get latest version
|
||||
$latest_version = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}wpdd_software_versions
|
||||
WHERE product_id = %d
|
||||
ORDER BY release_date DESC
|
||||
LIMIT 1",
|
||||
$product->ID
|
||||
));
|
||||
|
||||
if (!$latest_version) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => true,
|
||||
'update_available' => false,
|
||||
'message' => __('No updates available.', 'wp-digital-download')
|
||||
), 200);
|
||||
}
|
||||
|
||||
// Compare versions
|
||||
if (version_compare($latest_version->version, $current_version, '>')) {
|
||||
// Update available
|
||||
$update_data = array(
|
||||
'success' => true,
|
||||
'update_available' => true,
|
||||
'version' => $latest_version->version,
|
||||
'download_url' => home_url("/wp-json/wpdd/v1/download-update/{$product_slug}?license_key={$license_key}"),
|
||||
'package' => home_url("/wp-json/wpdd/v1/download-update/{$product_slug}?license_key={$license_key}"),
|
||||
'url' => get_permalink($product->ID),
|
||||
'tested' => $latest_version->tested_wp_version ?: get_bloginfo('version'),
|
||||
'requires' => $latest_version->min_wp_version ?: '5.0',
|
||||
'requires_php' => $latest_version->min_php_version ?: '7.0',
|
||||
'new_version' => $latest_version->version,
|
||||
'slug' => $product_slug,
|
||||
'plugin' => $product_slug . '/' . $product_slug . '.php', // Adjust based on your naming convention
|
||||
'changelog' => $latest_version->changelog,
|
||||
'release_notes' => $latest_version->release_notes
|
||||
);
|
||||
|
||||
return new WP_REST_Response($update_data, 200);
|
||||
} else {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => true,
|
||||
'update_available' => false,
|
||||
'message' => __('You have the latest version.', 'wp-digital-download')
|
||||
), 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download update endpoint
|
||||
*/
|
||||
public static function download_update($request) {
|
||||
global $wpdb;
|
||||
|
||||
$product_slug = $request->get_param('product_slug');
|
||||
$license_key = $request->get_param('license_key');
|
||||
|
||||
// Validate license
|
||||
if (!class_exists('WPDD_License_Manager')) {
|
||||
require_once WPDD_PLUGIN_PATH . 'includes/class-wpdd-license-manager.php';
|
||||
}
|
||||
|
||||
$validation = WPDD_License_Manager::validate_license($license_key, $product_slug);
|
||||
if (!$validation['valid']) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'error' => $validation['error'],
|
||||
'message' => $validation['message']
|
||||
), 403);
|
||||
}
|
||||
|
||||
// Get product
|
||||
$product = get_page_by_path($product_slug, OBJECT, 'wpdd_product');
|
||||
if (!$product) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Product not found.', 'wp-digital-download')
|
||||
), 404);
|
||||
}
|
||||
|
||||
// Get latest version
|
||||
$latest_version = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}wpdd_software_versions
|
||||
WHERE product_id = %d
|
||||
ORDER BY release_date DESC
|
||||
LIMIT 1",
|
||||
$product->ID
|
||||
));
|
||||
|
||||
if (!$latest_version || !$latest_version->package_url) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Update package not available.', 'wp-digital-download')
|
||||
), 404);
|
||||
}
|
||||
|
||||
// Get package file path
|
||||
$upload_dir = wp_upload_dir();
|
||||
$package_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $latest_version->package_url);
|
||||
|
||||
if (!file_exists($package_path)) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Update package file not found.', 'wp-digital-download')
|
||||
), 404);
|
||||
}
|
||||
|
||||
// Log download
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'wpdd_downloads',
|
||||
array(
|
||||
'order_id' => $validation['license']->order_id,
|
||||
'product_id' => $product->ID,
|
||||
'customer_id' => $validation['license']->customer_id,
|
||||
'file_id' => $latest_version->version,
|
||||
'download_date' => current_time('mysql'),
|
||||
'ip_address' => $_SERVER['REMOTE_ADDR'],
|
||||
'user_agent' => $_SERVER['HTTP_USER_AGENT']
|
||||
),
|
||||
array('%d', '%d', '%d', '%s', '%s', '%s', '%s')
|
||||
);
|
||||
|
||||
// Serve file
|
||||
$filename = basename($package_path);
|
||||
header('Content-Type: application/zip');
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
header('Content-Length: ' . filesize($package_path));
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: 0');
|
||||
readfile($package_path);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Git webhook for new releases (receives notifications FROM Git platforms like Gitea)
|
||||
*/
|
||||
public static function handle_webhook($request) {
|
||||
global $wpdb;
|
||||
|
||||
$product_id = $request->get_param('product_id');
|
||||
$passcode = $request->get_param('passcode');
|
||||
|
||||
// Validate passcode
|
||||
$stored_passcode = get_post_meta($product_id, '_wpdd_webhook_passcode', true);
|
||||
if (!$stored_passcode || $stored_passcode !== $passcode) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Invalid webhook passcode.', 'wp-digital-download')
|
||||
), 403);
|
||||
}
|
||||
|
||||
// Get payload from Git platform (Gitea, GitHub, GitLab, etc.)
|
||||
$payload = $request->get_body();
|
||||
$data = json_decode($payload, true);
|
||||
|
||||
if (!$data) {
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Invalid JSON payload.', 'wp-digital-download')
|
||||
), 400);
|
||||
}
|
||||
|
||||
// Determine event type based on payload structure
|
||||
$event_type = 'unknown';
|
||||
$is_release = false;
|
||||
|
||||
// Gitea release webhook
|
||||
if (isset($data['action']) && isset($data['release'])) {
|
||||
$event_type = 'release';
|
||||
$is_release = ($data['action'] === 'published' || $data['action'] === 'created');
|
||||
}
|
||||
// GitHub/GitLab push with tags
|
||||
elseif (isset($data['ref']) && strpos($data['ref'], 'refs/tags/') === 0) {
|
||||
$event_type = 'tag_push';
|
||||
$is_release = true;
|
||||
}
|
||||
// GitHub release webhook
|
||||
elseif (isset($data['action']) && isset($data['release']) && $data['action'] === 'published') {
|
||||
$event_type = 'github_release';
|
||||
$is_release = true;
|
||||
}
|
||||
|
||||
// Log webhook event
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'wpdd_webhook_events',
|
||||
array(
|
||||
'product_id' => $product_id,
|
||||
'event_type' => $event_type,
|
||||
'payload' => $payload,
|
||||
'processed' => 'pending',
|
||||
'received_at' => current_time('mysql')
|
||||
),
|
||||
array('%d', '%s', '%s', '%s', '%s')
|
||||
);
|
||||
|
||||
$event_id = $wpdb->insert_id;
|
||||
|
||||
if (!$is_release) {
|
||||
// Mark as ignored - not a release event
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'wpdd_webhook_events',
|
||||
array(
|
||||
'processed' => 'ignored',
|
||||
'processed_at' => current_time('mysql'),
|
||||
'error_message' => 'Not a release event'
|
||||
),
|
||||
array('id' => $event_id),
|
||||
array('%s', '%s', '%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
return new WP_REST_Response(array(
|
||||
'success' => true,
|
||||
'message' => __('Webhook received but not a release event.', 'wp-digital-download')
|
||||
), 200);
|
||||
}
|
||||
|
||||
// Extract version information based on platform
|
||||
$version = '';
|
||||
$tag = '';
|
||||
|
||||
if ($event_type === 'release' || $event_type === 'github_release') {
|
||||
// Gitea or GitHub release
|
||||
$tag = $data['release']['tag_name'] ?? '';
|
||||
$version = ltrim($tag, 'v');
|
||||
} elseif ($event_type === 'tag_push') {
|
||||
// Git tag push
|
||||
$tag = str_replace('refs/tags/', '', $data['ref']);
|
||||
$version = ltrim($tag, 'v');
|
||||
}
|
||||
|
||||
if (empty($version)) {
|
||||
// Mark as error
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'wpdd_webhook_events',
|
||||
array(
|
||||
'processed' => 'error',
|
||||
'processed_at' => current_time('mysql'),
|
||||
'error_message' => 'Could not extract version from payload'
|
||||
),
|
||||
array('id' => $event_id),
|
||||
array('%s', '%s', '%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
return new WP_REST_Response(array(
|
||||
'success' => false,
|
||||
'message' => __('Could not extract version from webhook payload.', 'wp-digital-download')
|
||||
), 400);
|
||||
}
|
||||
|
||||
// Check if this version already exists
|
||||
$existing = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT id FROM {$wpdb->prefix}wpdd_software_versions
|
||||
WHERE product_id = %d AND version = %s",
|
||||
$product_id,
|
||||
$version
|
||||
));
|
||||
|
||||
if (!$existing) {
|
||||
// Process new release
|
||||
$success = self::process_new_release($product_id, $version, $tag, $data);
|
||||
|
||||
if ($success) {
|
||||
// Mark webhook as processed
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'wpdd_webhook_events',
|
||||
array(
|
||||
'processed' => 'completed',
|
||||
'processed_at' => current_time('mysql')
|
||||
),
|
||||
array('id' => $event_id),
|
||||
array('%s', '%s'),
|
||||
array('%d')
|
||||
);
|
||||
} else {
|
||||
// Mark as error
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'wpdd_webhook_events',
|
||||
array(
|
||||
'processed' => 'error',
|
||||
'processed_at' => current_time('mysql'),
|
||||
'error_message' => 'Failed to process release'
|
||||
),
|
||||
array('id' => $event_id),
|
||||
array('%s', '%s', '%s'),
|
||||
array('%d')
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Mark as duplicate
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'wpdd_webhook_events',
|
||||
array(
|
||||
'processed' => 'duplicate',
|
||||
'processed_at' => current_time('mysql'),
|
||||
'error_message' => 'Version already exists'
|
||||
),
|
||||
array('id' => $event_id),
|
||||
array('%s', '%s', '%s'),
|
||||
array('%d')
|
||||
);
|
||||
}
|
||||
|
||||
return new WP_REST_Response(array(
|
||||
'success' => true,
|
||||
'message' => __('Webhook received and processed.', 'wp-digital-download')
|
||||
), 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process new release from webhook (receives data FROM Git platforms like Gitea)
|
||||
*/
|
||||
private static function process_new_release($product_id, $version, $tag, $webhook_data) {
|
||||
global $wpdb;
|
||||
|
||||
// Get Git repository settings
|
||||
$git_url = get_post_meta($product_id, '_wpdd_git_repository', true);
|
||||
$git_username = get_post_meta($product_id, '_wpdd_git_username', true);
|
||||
$git_token = get_post_meta($product_id, '_wpdd_git_token', true);
|
||||
|
||||
if (!$git_url) {
|
||||
error_log('WPDD: No Git URL configured for product ' . $product_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build package from Git repository at the specific tag
|
||||
$package_url = self::build_package_from_git($product_id, $git_url, $tag, $git_username, $git_token);
|
||||
|
||||
if (!$package_url) {
|
||||
error_log('WPDD: Failed to build package for product ' . $product_id . ' version ' . $version);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract changelog based on webhook source
|
||||
$changelog = '';
|
||||
$git_commit = null;
|
||||
|
||||
// Gitea/GitHub release with description
|
||||
if (isset($webhook_data['release'])) {
|
||||
$changelog = $webhook_data['release']['body'] ?? $webhook_data['release']['note'] ?? '';
|
||||
$git_commit = $webhook_data['release']['target_commitish'] ?? null;
|
||||
}
|
||||
// Git push webhook - use commit messages
|
||||
elseif (isset($webhook_data['commits']) && is_array($webhook_data['commits'])) {
|
||||
$messages = array();
|
||||
foreach ($webhook_data['commits'] as $commit) {
|
||||
if (isset($commit['message'])) {
|
||||
$messages[] = '- ' . $commit['message'];
|
||||
}
|
||||
}
|
||||
$changelog = implode("\n", $messages);
|
||||
$git_commit = $webhook_data['after'] ?? $webhook_data['head_commit']['id'] ?? null;
|
||||
}
|
||||
// Fallback - try to get from head commit
|
||||
elseif (isset($webhook_data['head_commit']['message'])) {
|
||||
$changelog = '- ' . $webhook_data['head_commit']['message'];
|
||||
$git_commit = $webhook_data['head_commit']['id'] ?? null;
|
||||
}
|
||||
|
||||
// Insert new version
|
||||
$result = $wpdb->insert(
|
||||
$wpdb->prefix . 'wpdd_software_versions',
|
||||
array(
|
||||
'product_id' => $product_id,
|
||||
'version' => $version,
|
||||
'changelog' => $changelog,
|
||||
'package_url' => $package_url,
|
||||
'git_tag' => $tag,
|
||||
'git_commit' => $git_commit,
|
||||
'release_date' => current_time('mysql')
|
||||
),
|
||||
array('%d', '%s', '%s', '%s', '%s', '%s', '%s')
|
||||
);
|
||||
|
||||
if ($result === false) {
|
||||
error_log('WPDD: Failed to insert version record for product ' . $product_id . ' version ' . $version);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update product version meta
|
||||
update_post_meta($product_id, '_wpdd_current_version', $version);
|
||||
|
||||
// Notify customers about update (optional)
|
||||
self::notify_customers_about_update($product_id, $version);
|
||||
|
||||
error_log('WPDD: Successfully processed new release for product ' . $product_id . ' version ' . $version);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build package from Git repository at specific tag
|
||||
*/
|
||||
private static function build_package_from_git($product_id, $git_url, $tag, $username = null, $token = null) {
|
||||
$upload_dir = wp_upload_dir();
|
||||
$package_dir = trailingslashit($upload_dir['basedir']) . 'wpdd-packages/' . $product_id;
|
||||
|
||||
if (!file_exists($package_dir)) {
|
||||
wp_mkdir_p($package_dir);
|
||||
}
|
||||
|
||||
$package_filename = sanitize_file_name("package-{$tag}.zip");
|
||||
$package_path = trailingslashit($package_dir) . $package_filename;
|
||||
$package_url = trailingslashit($upload_dir['baseurl']) . 'wpdd-packages/' . $product_id . '/' . $package_filename;
|
||||
|
||||
// Skip if package already exists
|
||||
if (file_exists($package_path)) {
|
||||
return $package_url;
|
||||
}
|
||||
|
||||
// Create temporary directory for cloning
|
||||
$temp_dir = trailingslashit(sys_get_temp_dir()) . 'wpdd-build-' . $product_id . '-' . uniqid();
|
||||
|
||||
// Build authentication URL if credentials provided
|
||||
$auth_url = $git_url;
|
||||
if ($username && $token) {
|
||||
$parsed_url = parse_url($git_url);
|
||||
if ($parsed_url) {
|
||||
$auth_url = $parsed_url['scheme'] . '://' . urlencode($username) . ':' . urlencode($token) . '@' . $parsed_url['host'];
|
||||
if (isset($parsed_url['port'])) {
|
||||
$auth_url .= ':' . $parsed_url['port'];
|
||||
}
|
||||
$auth_url .= $parsed_url['path'];
|
||||
}
|
||||
}
|
||||
|
||||
// Clone repository at specific tag
|
||||
$clone_cmd = sprintf(
|
||||
'git clone --depth 1 --branch %s %s %s 2>&1',
|
||||
escapeshellarg($tag),
|
||||
escapeshellarg($auth_url),
|
||||
escapeshellarg($temp_dir)
|
||||
);
|
||||
|
||||
$output = array();
|
||||
$return_code = 0;
|
||||
exec($clone_cmd, $output, $return_code);
|
||||
|
||||
if ($return_code !== 0) {
|
||||
error_log('WPDD: Git clone failed for ' . $git_url . ' tag ' . $tag . ': ' . implode(' ', $output));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove .git directory and other development files
|
||||
$cleanup_files = array('.git', '.gitignore', '.gitattributes', 'tests', 'test', '.phpunit.xml', 'composer.json', 'package.json');
|
||||
foreach ($cleanup_files as $cleanup_file) {
|
||||
$cleanup_path = trailingslashit($temp_dir) . $cleanup_file;
|
||||
if (file_exists($cleanup_path)) {
|
||||
if (is_dir($cleanup_path)) {
|
||||
self::remove_directory($cleanup_path);
|
||||
} else {
|
||||
unlink($cleanup_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create ZIP package
|
||||
if (class_exists('ZipArchive')) {
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($package_path, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
|
||||
self::add_directory_to_zip($zip, $temp_dir, '');
|
||||
$zip->close();
|
||||
|
||||
// Clean up temporary directory
|
||||
self::remove_directory($temp_dir);
|
||||
|
||||
return $package_url;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: tar command if ZipArchive not available
|
||||
$tar_cmd = sprintf(
|
||||
'cd %s && tar -czf %s . 2>&1',
|
||||
escapeshellarg($temp_dir),
|
||||
escapeshellarg($package_path . '.tar.gz')
|
||||
);
|
||||
|
||||
exec($tar_cmd, $output, $return_code);
|
||||
self::remove_directory($temp_dir);
|
||||
|
||||
if ($return_code === 0 && file_exists($package_path . '.tar.gz')) {
|
||||
return $package_url . '.tar.gz';
|
||||
}
|
||||
|
||||
error_log('WPDD: Failed to create package for ' . $git_url . ' tag ' . $tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively add directory to ZIP archive
|
||||
*/
|
||||
private static function add_directory_to_zip($zip, $dir, $base_path) {
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
$file_path = $file->getPathname();
|
||||
$relative_path = $base_path . substr($file_path, strlen($dir) + 1);
|
||||
$zip->addFile($file_path, $relative_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively remove directory
|
||||
*/
|
||||
private static function remove_directory($dir) {
|
||||
if (!is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isDir()) {
|
||||
rmdir($file->getPathname());
|
||||
} else {
|
||||
unlink($file->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify customers about new update
|
||||
*/
|
||||
private static function notify_customers_about_update($product_id, $version) {
|
||||
// Optional: Send email notifications to customers with active licenses
|
||||
// This could be a separate scheduled job to avoid timeout issues
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user