241 lines
8.0 KiB
PHP
241 lines
8.0 KiB
PHP
<?php
|
|
|
|
namespace Dabestaniha\AuthenticateBridge\App\Support;
|
|
|
|
final class PluginUpdater
|
|
{
|
|
private const API_URL = 'https://mahgit.ir/api/v1/repos/dabestaniha/mahak-authenticate-bridge/releases/latest';
|
|
private const RELEASE_ASSET = 'mahak-authenticate-bridge.zip';
|
|
private const RELEASE_CACHE = 'mahak_authenticate_bridge_gitea_release';
|
|
private const CHECK_ACTION = 'mahak_authenticate_check_updates';
|
|
|
|
private static ?self $instance = null;
|
|
|
|
private string $plugin;
|
|
private string $slug;
|
|
|
|
private function __construct()
|
|
{
|
|
$this->plugin = plugin_basename(MAHAK_AUTHENTICATE_BRIDGE_FILE);
|
|
$this->slug = dirname($this->plugin);
|
|
}
|
|
|
|
public static function boot(): void
|
|
{
|
|
if (self::$instance !== null) {
|
|
return;
|
|
}
|
|
|
|
self::$instance = new self();
|
|
add_filter('pre_set_site_transient_update_plugins', [self::$instance, 'addUpdate']);
|
|
add_filter('plugins_api', [self::$instance, 'addPluginInformation'], 20, 3);
|
|
add_action('admin_post_'.self::CHECK_ACTION, [self::$instance, 'checkNow']);
|
|
}
|
|
|
|
public function addUpdate($transient)
|
|
{
|
|
if (!is_object($transient) || empty($transient->checked)) {
|
|
return $transient;
|
|
}
|
|
|
|
$update = $this->availableUpdate();
|
|
|
|
if ($update !== null) {
|
|
if (!isset($transient->response) || !is_array($transient->response)) {
|
|
$transient->response = [];
|
|
}
|
|
|
|
$transient->response[$this->plugin] = $update;
|
|
}
|
|
|
|
return $transient;
|
|
}
|
|
|
|
public function addPluginInformation($result, string $action, $args)
|
|
{
|
|
if ($action !== 'plugin_information' || ($args->slug ?? '') !== $this->slug) {
|
|
return $result;
|
|
}
|
|
|
|
$release = $this->latestRelease();
|
|
|
|
if (is_wp_error($release)) {
|
|
return $result;
|
|
}
|
|
|
|
$package = $this->releasePackage($release);
|
|
|
|
if ($package === null) {
|
|
return $result;
|
|
}
|
|
|
|
return (object) [
|
|
'name' => 'Mahak Authenticate Bridge',
|
|
'slug' => $this->slug,
|
|
'version' => $this->releaseVersion($release),
|
|
'author' => 'Dabestaniha',
|
|
'homepage' => $release['html_url'] ?? 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge',
|
|
'download_link' => $package,
|
|
'requires_php' => '7.4',
|
|
'sections' => [
|
|
'description' => 'Authenticate WordPress users via JSON Web Tokens from the Mahakiha application.',
|
|
'changelog' => nl2br(esc_html((string) ($release['body'] ?? ''))),
|
|
],
|
|
];
|
|
}
|
|
|
|
public function checkNow(): void
|
|
{
|
|
if (!current_user_can('update_plugins')) {
|
|
wp_die(esc_html__('Sorry, you are not allowed to update plugins.'));
|
|
}
|
|
|
|
check_admin_referer(self::CHECK_ACTION);
|
|
delete_site_transient(self::RELEASE_CACHE);
|
|
delete_site_transient('update_plugins');
|
|
wp_update_plugins();
|
|
|
|
wp_safe_redirect(add_query_arg(
|
|
['page' => config('mahak.settings-page'), 'update-checked' => '1'],
|
|
admin_url('options-general.php')
|
|
));
|
|
exit;
|
|
}
|
|
|
|
public static function renderUpdatePanel(): void
|
|
{
|
|
if (self::$instance === null || !current_user_can('update_plugins')) {
|
|
return;
|
|
}
|
|
|
|
$updater = self::$instance;
|
|
$release = $updater->latestRelease();
|
|
|
|
echo '<hr><h2>'.esc_html__('Plugin updates').'</h2>';
|
|
echo '<p>'.sprintf(
|
|
esc_html__('Installed version: %s'),
|
|
'<strong>'.esc_html(MAHAK_AUTHENTICATE_BRIDGE_VERSION).'</strong>'
|
|
).'</p>';
|
|
|
|
if (is_wp_error($release)) {
|
|
echo '<div class="notice notice-warning inline"><p>'.esc_html($release->get_error_message()).'</p></div>';
|
|
} else {
|
|
$update = $updater->availableUpdate($release);
|
|
|
|
if ($update !== null) {
|
|
echo '<p>'.sprintf(esc_html__('Version %s is available.'), esc_html($update->new_version)).'</p>';
|
|
$updateUrl = wp_nonce_url(
|
|
self_admin_url('update.php?action=upgrade-plugin&plugin='.rawurlencode($updater->plugin)),
|
|
'upgrade-plugin_'.$updater->plugin
|
|
);
|
|
echo '<p><a class="button button-primary" href="'.esc_url($updateUrl).'">'.esc_html__('Update now').'</a></p>';
|
|
} else {
|
|
echo '<p>'.esc_html__('You are using the latest available version.').'</p>';
|
|
}
|
|
}
|
|
|
|
echo '<form method="post" action="'.esc_url(admin_url('admin-post.php')).'">';
|
|
echo '<input type="hidden" name="action" value="'.esc_attr(self::CHECK_ACTION).'">';
|
|
wp_nonce_field(self::CHECK_ACTION);
|
|
submit_button(esc_html__('Check for updates'), 'secondary', 'submit', false);
|
|
echo '</form>';
|
|
}
|
|
|
|
private function availableUpdate(?array $release = null): ?object
|
|
{
|
|
$release = $release ?? $this->latestRelease();
|
|
|
|
if (is_wp_error($release)) {
|
|
return null;
|
|
}
|
|
|
|
$version = $this->releaseVersion($release);
|
|
$package = $this->releasePackage($release);
|
|
|
|
if ($version === '' || $package === null || !version_compare($version, MAHAK_AUTHENTICATE_BRIDGE_VERSION, '>')) {
|
|
return null;
|
|
}
|
|
|
|
return (object) [
|
|
'id' => $release['html_url'] ?? self::API_URL,
|
|
'slug' => $this->slug,
|
|
'plugin' => $this->plugin,
|
|
'new_version' => $version,
|
|
'url' => $release['html_url'] ?? '',
|
|
'package' => $package,
|
|
'requires_php' => '7.4',
|
|
];
|
|
}
|
|
|
|
private function latestRelease()
|
|
{
|
|
$cached = get_site_transient(self::RELEASE_CACHE);
|
|
|
|
if (is_array($cached)) {
|
|
return $cached;
|
|
}
|
|
|
|
$response = wp_remote_get(self::API_URL, [
|
|
'headers' => [
|
|
'Accept' => 'application/json',
|
|
'User-Agent' => 'Mahak-Authenticate-Bridge/'.MAHAK_AUTHENTICATE_BRIDGE_VERSION,
|
|
],
|
|
'timeout' => 10,
|
|
]);
|
|
|
|
if (is_wp_error($response)) {
|
|
return new \WP_Error('mahak_update_request_failed', 'Could not contact Mahgit to check for plugin updates.');
|
|
}
|
|
|
|
if (wp_remote_retrieve_response_code($response) !== 200) {
|
|
return new \WP_Error('mahak_update_response_invalid', 'No published plugin release is currently available on Mahgit.');
|
|
}
|
|
|
|
$release = json_decode(wp_remote_retrieve_body($response), true);
|
|
|
|
if (!is_array($release) || !empty($release['draft']) || !empty($release['prerelease'])) {
|
|
return new \WP_Error('mahak_update_release_invalid', 'Mahgit returned invalid plugin release information.');
|
|
}
|
|
|
|
if ($this->releaseVersion($release) === '' || $this->releasePackage($release) === null) {
|
|
return new \WP_Error(
|
|
'mahak_update_asset_missing',
|
|
'The latest Mahgit release does not contain a valid mahak-authenticate-bridge.zip package.'
|
|
);
|
|
}
|
|
|
|
set_site_transient(self::RELEASE_CACHE, $release, 6 * HOUR_IN_SECONDS);
|
|
|
|
return $release;
|
|
}
|
|
|
|
private function releaseVersion(array $release): string
|
|
{
|
|
return ltrim((string) ($release['tag_name'] ?? ''), 'vV');
|
|
}
|
|
|
|
private function releasePackage(array $release): ?string
|
|
{
|
|
foreach (($release['assets'] ?? []) as $asset) {
|
|
if (($asset['name'] ?? '') !== self::RELEASE_ASSET) {
|
|
continue;
|
|
}
|
|
|
|
$url = esc_url_raw((string) ($asset['browser_download_url'] ?? ''));
|
|
|
|
$path = (string) wp_parse_url($url, PHP_URL_PATH);
|
|
|
|
if (
|
|
$url !== ''
|
|
&& wp_parse_url($url, PHP_URL_SCHEME) === 'https'
|
|
&& wp_parse_url($url, PHP_URL_HOST) === 'mahgit.ir'
|
|
&& strpos($path, '/dabestaniha/mahak-authenticate-bridge/releases/download/') === 0
|
|
) {
|
|
return $url;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|