Refactor getUserPlugins(), define pluginsManifest

This commit is contained in:
billz 2025-01-25 02:49:48 -08:00
parent 77f183817a
commit a9021c89f4

View File

@ -21,6 +21,7 @@ class PluginInstaller
private $destSudoers; private $destSudoers;
private $refModules; private $refModules;
private $rootPath; private $rootPath;
private $pluginsManifest;
public function __construct() public function __construct()
{ {
@ -30,6 +31,7 @@ class PluginInstaller
$this->destSudoers = '/etc/sudoers.d/'; $this->destSudoers = '/etc/sudoers.d/';
$this->refModules = '/refs/heads/master/.gitmodules'; $this->refModules = '/refs/heads/master/.gitmodules';
$this->rootPath = $_SERVER['DOCUMENT_ROOT']; $this->rootPath = $_SERVER['DOCUMENT_ROOT'];
$this->pluginsManifest = '/plugins/manifest.json';
} }
// Returns a single instance of PluginInstaller // Returns a single instance of PluginInstaller
@ -42,112 +44,51 @@ class PluginInstaller
} }
/** /**
* Returns user plugin details from associated manifest.json files * Returns availble user plugin details from a manifest.json file
* *
* @return array $plugins * @return array $plugins
*/ */
public function getUserPlugins() public function getUserPlugins()
{ {
$installedPlugins = $this->getPlugins();
try { try {
$submodules = $this->getSubmodules(RASPI_PLUGINS_URL); $manifestPath = $this->rootPath . $this->pluginsManifest;
if (!file_exists($manifestPath)) {
throw new \Exception("Manifest file not found at " . $manifestPath);
}
// decode manifest file contents
$manifestContents = file_get_contents($manifestPath);
$manifestData = json_decode($manifestContents, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Exception("Error parsing manifest.json: " . json_last_error_msg());
}
// fetch installed plugins
$installedPlugins = $this->getPlugins();
$plugins = []; $plugins = [];
foreach ($submodules as $submodule) { foreach ($manifestData as $pluginManifest) {
$manifestUrl = $submodule['url'] .$this->manifestRaw; $installed = false;
$manifest = $this->getPluginManifest($manifestUrl);
if ($manifest) { // Check if the plugin is installed
$installed = false; foreach ($installedPlugins as $plugin) {
if (str_contains($plugin, $pluginManifest['namespace'])) {
foreach ($installedPlugins as $plugin) { $installed = true;
if (str_contains($plugin, $manifest['namespace'])) { break;
$installed = true;
break;
}
} }
$plugins[] = [
'manifest' => $manifest,
'installed' => $installed
];
} }
$plugins[] = [
'manifest' => $pluginManifest,
'installed' => $installed
];
} }
return $plugins; return $plugins;
} catch (\Exception $e) { } catch (\Exception $e) {
echo "An error occured: " .$e->getMessage(); echo "An error occurred: " . $e->getMessage();
return [];
} }
} }
/**
* Retrieves a plugin's associated manifest JSON
*
* @param string $url
* @return array $json
*/
public function getPluginManifest(string $url): ?array
{
$options = [
'http' => [
'method' => 'GET',
'follow_location' => 1,
],
];
$context = stream_context_create($options);
$content = file_get_contents($url, false, $context);
if ($content === false) {
return null;
}
$json = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return null;
}
return $json;
}
/**
* Returns git submodules for the specified repository
*
* @param string $repoURL
* @return array $submodules
*/
public function getSubmodules(string $repoUrl): array
{
$gitmodulesUrl = $repoUrl .$this->refModules;
$gitmodulesContent = file_get_contents($gitmodulesUrl);
if ($gitmodulesContent === false) {
throw new \Exception('Unable to fetch .gitmodules file from the repository');
}
$submodules = [];
$lines = explode("\n", $gitmodulesContent);
$currentSubmodule = [];
foreach ($lines as $line) {
$line = trim($line);
if (strpos($line, '[submodule "') === 0) {
if (!empty($currentSubmodule)) {
$submodules[] = $currentSubmodule;
}
$currentSubmodule = [];
} elseif (strpos($line, 'path = ') === 0) {
$currentSubmodule['path'] = substr($line, strlen('path = '));
} elseif (strpos($line, 'url = ') === 0) {
$currentSubmodule['url'] = substr($line, strlen('url = '));
}
}
if (!empty($currentSubmodule)) {
$submodules[] = $currentSubmodule;
}
return $submodules;
}
/** /**
* Returns an array of installed plugins in pluginPath * Returns an array of installed plugins in pluginPath
* *
@ -419,13 +360,15 @@ class PluginInstaller
$html .= '<th scope="col">Version</th>'; $html .= '<th scope="col">Version</th>';
$html .= '<th scope="col">Description</th>'; $html .= '<th scope="col">Description</th>';
$html .= '<th scope="col"></th>'; $html .= '<th scope="col"></th>';
$html .= '</tr></thead></tbody>'; $html .= '</tr></thead><tbody>';
foreach ($plugins as $plugin) { foreach ($plugins as $plugin) {
$manifest = htmlspecialchars(json_encode($plugin['manifest']), ENT_QUOTES, 'UTF-8'); $manifestData = $plugin['manifest'][0] ?? []; // Access the first manifest entry or default to an empty array
$manifest = htmlspecialchars(json_encode($manifestData), ENT_QUOTES, 'UTF-8');
$installed = $plugin['installed']; $installed = $plugin['installed'];
if ($installed === true ) { if ($installed === true) {
$button = '<button type="button" class="btn btn-outline btn-primary btn-sm text-nowrap" $button = '<button type="button" class="btn btn-outline btn-primary btn-sm text-nowrap"
name="plugin-details" data-bs-toggle="modal" data-bs-target="#install-user-plugin" name="plugin-details" data-bs-toggle="modal" data-bs-target="#install-user-plugin"
data-plugin-manifest="' .$manifest. '" data-plugin-installed="' .$installed. '"> ' . _("Installed") .'</button>'; data-plugin-manifest="' .$manifest. '" data-plugin-installed="' .$installed. '"> ' . _("Installed") .'</button>';
@ -434,14 +377,23 @@ class PluginInstaller
name="install-plugin" data-bs-toggle="modal" data-bs-target="#install-user-plugin" name="install-plugin" data-bs-toggle="modal" data-bs-target="#install-user-plugin"
data-plugin-manifest="' .$manifest. '"> ' . _("Details") .'</button>'; data-plugin-manifest="' .$manifest. '"> ' . _("Details") .'</button>';
} }
$name = '<i class="' . htmlspecialchars($plugin['manifest']['icon']) .' link-secondary me-2"></i><a href="'
. htmlspecialchars($plugin['manifest']['plugin_uri']) $icon = htmlspecialchars($manifestData['icon'] ?? '');
$pluginUri = htmlspecialchars($manifestData['plugin_uri'] ?? '');
$nameText = htmlspecialchars($manifestData['name'] ?? 'Unknown Plugin');
$name = '<i class="' . $icon . ' link-secondary me-2"></i><a href="'
. $pluginUri
. '" target="_blank">' . '" target="_blank">'
. htmlspecialchars($plugin['manifest']['name']). '</a>'; . $nameText. '</a>';
$version = htmlspecialchars($manifestData['version'] ?? 'N/A');
$description = htmlspecialchars($manifestData['description'] ?? 'No description available');
$html .= '<tr><td>' .$name. '</td>'; $html .= '<tr><td>' .$name. '</td>';
$html .= '<td>' .htmlspecialchars($plugin['manifest']['version']). '</td>'; $html .= '<td>' .$version. '</td>';
$html .= '<td>' .htmlspecialchars($plugin['manifest']['description']). '</td>'; $html .= '<td>' .$description. '</td>';
$html .= '<td>' .$button. '</td>'; $html .= '<td>' .$button. '</td></tr>';
} }
$html .= '</tbody></table>'; $html .= '</tbody></table>';
return $html; return $html;