diff --git a/ajax/plugins/do_plugin_install.php b/ajax/plugins/do_plugin_install.php new file mode 100755 index 000000000..08bf8a408 --- /dev/null +++ b/ajax/plugins/do_plugin_install.php @@ -0,0 +1,29 @@ +installPlugin($archiveUrl); + echo json_encode($return); + + } catch (Exception $e) { + http_response_code(500); + echo json_encode(['error' => $e->getMessage()]); + } +} else { + http_response_code(400); + echo json_encode(['error' => 'Plugin URI and version are required']); + exit; +} + diff --git a/app/js/custom.js b/app/js/custom.js index 53ea7ae35..eac5e17bd 100644 --- a/app/js/custom.js +++ b/app/js/custom.js @@ -468,6 +468,95 @@ $('#js-sys-reboot, #js-sys-shutdown').on('click', function (e) { }); }); +$('#install-user-plugin').on('shown.bs.modal', function (e) { + var button = $(e.relatedTarget); + var manifestData = button.data('plugin-manifest'); + var installed = button.data('plugin-installed'); + + if (manifestData) { + $('#plugin-uri').html(manifestData.plugin_uri + ? `${manifestData.plugin_uri}` + : 'Unknown' + ); + $('#plugin-icon').attr('class', `${manifestData.icon || 'fas fa-plug'} link-secondary h5 me-2`); + $('#plugin-name').text(manifestData.name || 'Unknown'); + $('#plugin-version').text(manifestData.version || 'Unknown'); + $('#plugin-description').text(manifestData.description || 'No description provided'); + $('#plugin-author').html(manifestData.author + ? manifestData.author + (manifestData.author_uri + ? ` (profile)` : '') : 'Unknown' + ); + $('#plugin-license').text(manifestData.license || 'Unknown'); + $('#plugin-locale').text(manifestData.default_locale || 'Unknown'); + $('#plugin-configuration').html(formatProperty(manifestData.configuration || {})); + $('#plugin-dependencies').html(formatProperty(manifestData.dependencies || {})); + $('#plugin-sudoers').html(formatProperty(manifestData.sudoers || [])); + $('#plugin-user-name').html(manifestData.user_nonprivileged.name || 'None'); + } + if (installed) { + $('#js-install-plugin-confirm').html('OK'); + } else { + $('#js-install-plugin-confirm').html('Install now'); + } +}); + +$('#js-install-plugin-confirm').on('click', function (e) { + var progressText = $('#js-install-plugin-confirm').attr('data-message'); + var successHtml = $('#plugin-install-message').attr('data-message'); + var successText = $('
').text(successHtml).text(); + var pluginUri = $('#plugin-uri a').attr('href'); + var pluginVersion = $('#plugin-version').text(); + var csrfToken = $('meta[name=csrf_token]').attr('content'); + + $("#install-user-plugin").modal('hide'); + + if ($('#js-install-plugin-confirm').text() === 'Install now') { + $("#install-plugin-progress").modal('show'); + + $.post('ajax/plugins/do_plugin_install.php?',{'plugin_uri': pluginUri, + 'plugin_version': pluginVersion, 'csrf_token': csrfToken},function(data){ + setTimeout(function(){ + response = JSON.parse(data); + if (response === true) { + $('#plugin-install-message').contents().first().replaceWith(successText); + $('#plugin-install-message').find('i') + .removeClass('fas fa-cog fa-spin link-secondary') + .addClass('fas fa-check'); + $('#js-install-plugin-ok').removeAttr("disabled"); + } else { + $('#plugin-install-message').contents().first().replaceWith('An error occurred installing the plugin.'); + $('#plugin-install-message').find('i').removeClass('fas fa-cog fa-spin link-secondary'); + $('#js-install-plugin-ok').removeAttr("disabled"); + } + },200); + }); + } +}); + +$('#js-install-plugin-ok').on('click', function (e) { + $("#install-plugin-progress").modal('hide'); + window.location.reload(); +}); + +function formatProperty(prop) { + if (Array.isArray(prop)) { + if (typeof prop[0] === 'object') { + return prop.map(item => { + return Object.entries(item) + .map(([key, value]) => `${key}: ${value}`) + .join('
'); + }).join('

'); + } + return prop.map(line => `${line}
`).join(''); + } + if (typeof prop === 'object') { + return Object.entries(prop) + .map(([key, value]) => `${key}: ${value}`) + .join('
'); + } + return prop || 'None'; +} + $(document).ready(function(){ $("#PanelManual").hide(); $('.ip_address').mask('0ZZ.0ZZ.0ZZ.0ZZ', { @@ -507,7 +596,6 @@ $('#wg-upload,#wg-manual').on('click', function (e) { } }); -// Add the following code if you want the name of the file appear on select $(".custom-file-input").on("change", function() { var fileName = $(this).val().split("\\").pop(); $(this).siblings(".custom-file-label").addClass("selected").html(fileName); diff --git a/config/config.php b/config/config.php index 2950632db..afd386a20 100755 --- a/config/config.php +++ b/config/config.php @@ -38,6 +38,9 @@ // Constant for the GitHub API latest release endpoint define('RASPI_API_ENDPOINT', 'https://api.github.com/repos/RaspAP/raspap-webgui/releases/latest'); +// Constant for the GitHub plugin submodules URL +define("RASPI_PLUGINS_URL", "https://raw.githubusercontent.com/RaspAP/plugins"); + // Constant for the 5GHz wireless regulatory domain define("RASPI_5GHZ_CHANNEL_MIN", 100); define("RASPI_5GHZ_CHANNEL_MAX", 192); diff --git a/includes/footer.php b/includes/footer.php old mode 100644 new mode 100755 diff --git a/includes/functions.php b/includes/functions.php index 3099defc2..02cce1c6d 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -1036,3 +1036,25 @@ function renderStatus($hostapd_led, $hostapd_status, $memused_led, $memused, $cp $interval) { + throw new \Exception('Operation timed out'); + } + + return $result; +} + diff --git a/includes/restapi.php b/includes/restapi.php old mode 100644 new mode 100755 diff --git a/includes/system.php b/includes/system.php index 31feaf798..7167cbd1a 100755 --- a/includes/system.php +++ b/includes/system.php @@ -9,6 +9,7 @@ function DisplaySystem(&$extraFooterScripts) { $status = new \RaspAP\Messages\StatusMessage; + $pluginInstaller = \RaspAP\Plugins\PluginInstaller::getInstance(); if (isset($_POST['SaveLanguage'])) { if (isset($_POST['locale'])) { @@ -85,53 +86,22 @@ function DisplaySystem(&$extraFooterScripts) $kernel = $system->kernelVersion(); $systime = $system->systime(); $revision = $system->rpiRevision(); - - // mem used + + // memory use $memused = $system->usedMemory(); - $memused_status = "primary"; - if ($memused > 90) { - $memused_status = "danger"; - $memused_led = "service-status-down"; - } elseif ($memused > 75) { - $memused_status = "warning"; - $memused_led = "service-status-warn"; - } elseif ($memused > 0) { - $memused_status = "success"; - $memused_led = "service-status-up"; - } + $memStatus = getMemStatus($memused); + $memused_status = $memStatus['status']; + $memused_led = $memStatus['led']; // cpu load $cpuload = $system->systemLoadPercentage(); - if ($cpuload > 90) { - $cpuload_status = "danger"; - } elseif ($cpuload > 75) { - $cpuload_status = "warning"; - } elseif ($cpuload >= 0) { - $cpuload_status = "success"; - } + $cpuload_status = getCPULoadStatus($cpuload); // cpu temp $cputemp = $system->systemTemperature(); - if ($cputemp > 70) { - $cputemp_status = "danger"; - $cputemp_led = "service-status-down"; - } elseif ($cputemp > 50) { - $cputemp_status = "warning"; - $cputemp_led = "service-status-warn"; - } else { - $cputemp_status = "success"; - $cputemp_led = "service-status-up"; - } - - // hostapd status - $hostapd = $system->hostapdStatus(); - if ($hostapd[0] == 1) { - $hostapd_status = "active"; - $hostapd_led = "service-status-up"; - } else { - $hostapd_status = "inactive"; - $hostapd_led = "service-status-down"; - } + $cpuStatus = getCPUTempStatus($cputemp); + $cputemp_status = $cpuStatus['status']; + $cputemp_led = $cpuStatus['led']; // theme options $themes = [ @@ -147,6 +117,21 @@ function DisplaySystem(&$extraFooterScripts) $extraFooterScripts[] = array('src'=>'app/js/huebee.js', 'defer'=>false); $logLimit = isset($_SESSION['log_limit']) ? $_SESSION['log_limit'] : RASPI_LOG_SIZE_LIMIT; + try { + $plugins = callbackTimeout(fn() => $pluginInstaller->getUserPlugins(), 3000); + $pluginsTable = $pluginInstaller->getHTMLPluginsTable($plugins); + } catch (\Exception $e) { + $errResponse = sprintf( + '
%s: %s. %s %s.
', + _('Network error'), + _('Unable to load plugins'), + _('Reload'), + _('and try again') + ); + $errResponse.= '
@@ -105,3 +107,83 @@ + + + + + + diff --git a/templates/system/plugins.php b/templates/system/plugins.php new file mode 100644 index 000000000..194e161e0 --- /dev/null +++ b/templates/system/plugins.php @@ -0,0 +1,19 @@ + +
+

+ + +
+
+ +
+ Details for more information and to install a plugin."); ?> +
+ +
+
+ +
+ diff --git a/templates/system/tools.php b/templates/system/tools.php index a30601db6..32eb19ca5 100644 --- a/templates/system/tools.php +++ b/templates/system/tools.php @@ -1,4 +1,4 @@ - +

@@ -36,4 +36,3 @@
-