add update button

This commit is contained in:
Boy132 2025-08-04 10:46:57 +02:00
parent 5427e08f3c
commit 02d18f28e3
4 changed files with 89 additions and 22 deletions

View File

@ -14,6 +14,7 @@ use Filament\Panel;
* @method static void requireComposerPackages(Plugin $plugin)
* @method static void runPluginMigrations(Plugin $plugin)
* @method static void installPlugin(Plugin $plugin)
* @method static void updatePlugin(Plugin $plugin)
* @method static void downloadPluginFromFile(UploadedFile $file)
* @method static void downloadPluginFromUrl(string $url)
* @method static void enablePlugin(string|Plugin $plugin)

View File

@ -84,7 +84,21 @@ class PluginResource extends Resource
->title('Plugin installed')
->send();
}),
// TODO: "update" button
Action::make('update')
->authorize(fn (Plugin $plugin) => auth()->user()->can('update', $plugin))
->icon('tabler-download')
->color('success')
->visible(fn (Plugin $plugin) => $plugin->isUpdateAvailable())
->action(function (Plugin $plugin) {
Plugins::updatePlugin($plugin);
redirect(ListPlugins::getUrl());
Notification::make()
->success()
->title('Plugin updated')
->send();
}),
Action::make('enable')
->authorize(fn (Plugin $plugin) => auth()->user()->can('update', $plugin))
->icon('tabler-check')

View File

@ -243,36 +243,66 @@ class Plugin extends Model implements HasPluginSettings
return !str($this->panel_version)->startsWith('^');
}
public function isUpdateAvailable(): bool
/** @return null|array<string, array{version: string, download_url: string}> */
private function getUpdateData(): ?array
{
if ($this->update_url === null) {
return false;
return null;
}
return cache()->remember("plugins.$this->id.update", now()->addMinutes(10), function () {
try {
return json_decode(file_get_contents($this->update_url), true, 512, JSON_THROW_ON_ERROR);
} catch (Exception $exception) {
report($exception);
}
return null;
});
}
public function isUpdateAvailable(): bool
{
$panelVersion = config('app.version', 'canary');
if ($panelVersion === 'canary') {
return false;
}
return cache()->remember("plugins.$this->id.update", now()->addHour(), function () use ($panelVersion) {
try {
/** @var array<string, array{version: string, download_url: string}> */
$updateData = json_decode(file_get_contents($this->update_url), true, 512, JSON_THROW_ON_ERROR);
if (array_key_exists('*', $updateData)) {
return version_compare($updateData['*']['version'], $this->version, '>');
}
if (array_key_exists($panelVersion, $updateData)) {
return version_compare($updateData[$panelVersion]['version'], $this->version, '>');
}
} catch (Exception $exception) {
report($exception);
$updateData = $this->getUpdateData();
if ($updateData) {
if (array_key_exists($panelVersion, $updateData)) {
return version_compare($updateData[$panelVersion]['version'], $this->version, '>');
}
return false;
});
if (array_key_exists('*', $updateData)) {
return version_compare($updateData['*']['version'], $this->version, '>');
}
}
return false;
}
public function getDownloadUrlForUpdate(): ?string
{
$panelVersion = config('app.version', 'canary');
if ($panelVersion === 'canary') {
return null;
}
$updateData = $this->getUpdateData();
if ($updateData) {
if (array_key_exists($panelVersion, $updateData)) {
return $updateData['panelVersion']['download_url'];
}
if (array_key_exists('*', $updateData)) {
return $updateData['*']['download_url'];
}
}
return null;
}
public function hasSettings(): bool

View File

@ -176,7 +176,24 @@ class PluginService
}
}
public function downloadPluginFromFile(UploadedFile $file): void
public function updatePlugin(Plugin $plugin): void
{
try {
$this->downloadPluginFromUrl($plugin->getDownloadUrlForUpdate(), true);
$this->requireComposerPackages($plugin);
$this->runPluginMigrations($plugin);
cache()->forget("plugins.$plugin->id.update");
} catch (Exception $exception) {
report($exception);
$this->setStatus($plugin, PluginStatus::Errored, $exception->getMessage());
}
}
public function downloadPluginFromFile(UploadedFile $file, bool $cleanDownload = false): void
{
$zip = new ZipArchive();
@ -185,6 +202,11 @@ class PluginService
}
$pluginName = str($file->getClientOriginalName())->before('.zip')->toString();
if ($cleanDownload) {
File::deleteDirectory(plugin_path($pluginName));
}
$extractPath = $zip->locateName($pluginName) ? base_path('plugins') : plugin_path($pluginName);
if (!$zip->extractTo($extractPath)) {
@ -194,7 +216,7 @@ class PluginService
$zip->close();
}
public function downloadPluginFromUrl(string $url): void
public function downloadPluginFromUrl(string $url, bool $cleanDownload = false): void
{
$info = pathinfo($url);
$tmpDir = TemporaryDirectory::make()->deleteWhenDestroyed();
@ -204,7 +226,7 @@ class PluginService
throw new InvalidFileUploadException('Could not write temporary file.');
}
$this->downloadPluginFromFile(new UploadedFile($tmpPath, $info['basename'], 'application/zip'));
$this->downloadPluginFromFile(new UploadedFile($tmpPath, $info['basename'], 'application/zip'), $cleanDownload);
}
public function enablePlugin(string|Plugin $plugin): void