Plugin Update (#16291)

* Plugin Update
Extract interfaces for use in plugin packages

# Conflicts:
#	composer.lock

* Fix some issues
settings_view -> content_view
This commit is contained in:
Tony Murray
2024-08-15 15:26:47 -05:00
committed by GitHub
parent f6fe0cf2da
commit 70c2c543f3
19 changed files with 79 additions and 58 deletions

View File

@@ -26,11 +26,12 @@
namespace App\Facades; namespace App\Facades;
use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\Facade;
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
class PluginManager extends Facade class PluginManager extends Facade
{ {
protected static function getFacadeAccessor() protected static function getFacadeAccessor()
{ {
return \App\Plugins\PluginManager::class; return PluginManagerInterface::class;
} }
} }

View File

@@ -3,11 +3,11 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Plugin; use App\Models\Plugin;
use App\Plugins\PluginManager; use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
class PluginAdminController extends Controller class PluginAdminController extends Controller
{ {
public function __invoke(PluginManager $manager): \Illuminate\Contracts\View\View public function __invoke(PluginManagerInterface $manager): \Illuminate\Contracts\View\View
{ {
// legacy v1 plugins // legacy v1 plugins
\LibreNMS\Plugins::scanNew(); \LibreNMS\Plugins::scanNew();

View File

@@ -3,13 +3,13 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Plugin; use App\Models\Plugin;
use App\Plugins\Hooks\PageHook;
use App\Plugins\PluginManager;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use LibreNMS\Interfaces\Plugins\Hooks\SinglePageHook;
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
class PluginPageController extends Controller class PluginPageController extends Controller
{ {
public function __invoke(PluginManager $manager, Plugin $plugin): \Illuminate\Contracts\View\View public function __invoke(PluginManagerInterface $manager, Plugin $plugin): \Illuminate\Contracts\View\View
{ {
if (! $manager->pluginEnabled($plugin->plugin_name)) { if (! $manager->pluginEnabled($plugin->plugin_name)) {
abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name])); abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name]));
@@ -20,10 +20,10 @@ class PluginPageController extends Controller
'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]), 'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]),
'plugin_name' => $plugin->plugin_name, 'plugin_name' => $plugin->plugin_name,
'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'), 'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'),
'settings_view' => 'plugins.missing', 'content_view' => 'plugins.missing',
'settings' => [], 'settings' => [],
], ],
(array) $manager->call(PageHook::class, [], $plugin->plugin_name)->first() $manager->call(SinglePageHook::class, [], $plugin->plugin_name)[0] ?? []
); );
return view('plugins.settings', $data); return view('plugins.settings', $data);

View File

@@ -3,14 +3,14 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Plugin; use App\Models\Plugin;
use App\Plugins\Hooks\SettingsHook;
use App\Plugins\PluginManager;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use LibreNMS\Interfaces\Plugins\Hooks\SettingsHook;
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
use LibreNMS\Util\Notifications; use LibreNMS\Util\Notifications;
class PluginSettingsController extends Controller class PluginSettingsController extends Controller
{ {
public function __invoke(PluginManager $manager, Plugin $plugin): \Illuminate\Contracts\View\View public function __invoke(PluginManagerInterface $manager, Plugin $plugin): \Illuminate\Contracts\View\View
{ {
if (! $manager->pluginEnabled($plugin->plugin_name)) { if (! $manager->pluginEnabled($plugin->plugin_name)) {
abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name])); abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name]));
@@ -21,10 +21,10 @@ class PluginSettingsController extends Controller
'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]), 'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]),
'plugin_name' => $plugin->plugin_name, 'plugin_name' => $plugin->plugin_name,
'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'), 'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'),
'settings_view' => 'plugins.missing', 'content_view' => 'plugins.missing',
'settings' => [], 'settings' => [],
], ],
(array) $manager->call(SettingsHook::class, [], $plugin->plugin_name)->first() $manager->call(SettingsHook::class, [], $plugin->plugin_name)[0] ?? []
); );
return view('plugins.settings', $data); return view('plugins.settings', $data);

View File

@@ -41,11 +41,11 @@ use App\Models\User;
use App\Models\UserPref; use App\Models\UserPref;
use App\Models\Vminfo; use App\Models\Vminfo;
use App\Models\WirelessSensor; use App\Models\WirelessSensor;
use App\Plugins\Hooks\MenuEntryHook;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\View\View; use Illuminate\View\View;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\Plugins\Hooks\MenuEntryHook;
use LibreNMS\Plugins; use LibreNMS\Plugins;
use LibreNMS\Util\ObjectCache; use LibreNMS\Util\ObjectCache;
use PluginManager; use PluginManager;

View File

@@ -33,7 +33,7 @@ class Page extends PageHook
{ {
// point to the view for your plugin's settings // point to the view for your plugin's settings
// this is the default name so you can create the blade file as in this plugin // this is the default name so you can create the blade file as in this plugin
// by ommitting the variable, or point to another one // by omitting the variable, or point to another one
// public string $view = 'resources.views.page'; // public string $view = 'resources.views.page';

View File

@@ -1,16 +0,0 @@
<?php
namespace App\Plugins;
interface Hook
{
/**
* Will be called by the plugin manager to check if the user is authorized. Will be called with Dependency Injection.
*/
// public function authorize(): bool;
/**
* Will be called by the plugin manager to execute this plugin at the correct time. Will be called with Dependency Injection.
*/
// public function handle();
}

View File

@@ -30,7 +30,7 @@ use App\Models\User;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Str; use Illuminate\Support\Str;
abstract class DeviceOverviewHook abstract class DeviceOverviewHook implements \LibreNMS\Interfaces\Plugins\Hooks\DeviceOverviewHook
{ {
public string $view = 'resources.views.device-overview'; public string $view = 'resources.views.device-overview';

View File

@@ -29,7 +29,7 @@ use App\Models\User;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Str; use Illuminate\Support\Str;
abstract class MenuEntryHook abstract class MenuEntryHook implements \LibreNMS\Interfaces\Plugins\Hooks\MenuEntryHook
{ {
public string $view = 'resources.views.menu'; public string $view = 'resources.views.menu';

View File

@@ -29,7 +29,7 @@ use App\Models\User;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Str; use Illuminate\Support\Str;
abstract class PageHook abstract class PageHook implements \LibreNMS\Interfaces\Plugins\Hooks\SinglePageHook
{ {
public string $view = 'resources.views.page'; public string $view = 'resources.views.page';
@@ -46,7 +46,7 @@ abstract class PageHook
final public function handle(string $pluginName, array $settings, Application $app): array final public function handle(string $pluginName, array $settings, Application $app): array
{ {
return array_merge([ return array_merge([
'settings_view' => Str::start($this->view, "$pluginName::"), 'content_view' => Str::start($this->view, "$pluginName::"),
], $app->call([$this, 'data'], [ ], $app->call([$this, 'data'], [
'settings' => $settings, 'settings' => $settings,
])); ]));

View File

@@ -27,11 +27,10 @@ namespace App\Plugins\Hooks;
use App\Models\Port; use App\Models\Port;
use App\Models\User; use App\Models\User;
use App\Plugins\Hook;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Str; use Illuminate\Support\Str;
abstract class PortTabHook implements Hook abstract class PortTabHook implements \LibreNMS\Interfaces\Plugins\Hooks\PortTabHook
{ {
/** @var string */ /** @var string */
public $view = 'resources.views.port-tab'; public $view = 'resources.views.port-tab';

View File

@@ -29,7 +29,7 @@ use App\Models\User;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Str; use Illuminate\Support\Str;
abstract class SettingsHook abstract class SettingsHook implements \LibreNMS\Interfaces\Plugins\Hooks\SettingsHook
{ {
public string $view = 'resources.views.settings'; public string $view = 'resources.views.settings';
@@ -48,7 +48,7 @@ abstract class SettingsHook
final public function handle(string $pluginName, array $settings, Application $app): array final public function handle(string $pluginName, array $settings, Application $app): array
{ {
return array_merge([ return array_merge([
'settings_view' => Str::start($this->view, "$pluginName::"), 'content_view' => Str::start($this->view, "$pluginName::"),
], $this->data($app->call([$this, 'data'], [ ], $this->data($app->call([$this, 'data'], [
'settings' => $settings, 'settings' => $settings,
]))); ])));

View File

@@ -30,10 +30,11 @@ use App\Models\Plugin;
use Exception; use Exception;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
use LibreNMS\Util\Notifications; use LibreNMS\Util\Notifications;
use Log; use Log;
class PluginManager class PluginManager implements PluginManagerInterface
{ {
/** @var Collection */ /** @var Collection */
private $hooks; private $hooks;
@@ -104,9 +105,9 @@ class PluginManager
* @param string $hookType * @param string $hookType
* @param array $args * @param array $args
* @param string|null $plugin only for this plugin if set * @param string|null $plugin only for this plugin if set
* @return \Illuminate\Support\Collection * @return array
*/ */
public function call(string $hookType, array $args = [], ?string $plugin = null): Collection public function call(string $hookType, array $args = [], ?string $plugin = null): array
{ {
return $this->hooksFor($hookType, $args, $plugin) return $this->hooksFor($hookType, $args, $plugin)
->map(function ($hook) use ($args, $hookType) { ->map(function ($hook) use ($args, $hookType) {
@@ -127,7 +128,7 @@ class PluginManager
} }
})->filter(function ($hook) { })->filter(function ($hook) {
return $hook !== 'HOOK FAILED'; return $hook !== 'HOOK FAILED';
}); })->values()->all();
} }
/** /**

View File

@@ -26,28 +26,28 @@
namespace App\Providers; namespace App\Providers;
use App\Exceptions\PluginDoesNotImplementHookException; use App\Exceptions\PluginDoesNotImplementHookException;
use App\Plugins\PluginManager;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
class PluginProvider extends ServiceProvider class PluginProvider extends ServiceProvider
{ {
public function register(): void public function register(): void
{ {
$this->app->singleton(PluginManager::class, function ($app) { $this->app->singleton(PluginManagerInterface::class, function ($app) {
return new PluginManager; return new \App\Plugins\PluginManager;
}); });
} }
public function boot(): void public function boot(): void
{ {
$this->loadLocalPlugins($this->app->make(PluginManager::class)); $this->loadLocalPlugins($this->app->make(PluginManagerInterface::class));
} }
/** /**
* Load any local plugins these plugins must implement only one hook. * Load any local plugins these plugins must implement only one hook.
*/ */
protected function loadLocalPlugins(PluginManager $manager): void protected function loadLocalPlugins(PluginManagerInterface $manager): void
{ {
$plugin_view_location_registered = []; $plugin_view_location_registered = [];
@@ -83,8 +83,8 @@ class PluginProvider extends ServiceProvider
*/ */
protected function hookType(string $class): string protected function hookType(string $class): string
{ {
foreach (class_parents($class) as $parent) { foreach (class_implements($class) as $parent) {
if (Str::startsWith($parent, 'App\Plugins\Hooks\\')) { if (Str::startsWith($parent, 'LibreNMS\Interfaces\Plugins\Hooks\\')) {
return $parent; return $parent;
} }
} }

View File

@@ -42,6 +42,7 @@
"laravel/tinker": "^2.8", "laravel/tinker": "^2.8",
"laravel/ui": "^4.2", "laravel/ui": "^4.2",
"librenms/laravel-vue-i18n-generator": "dev-master", "librenms/laravel-vue-i18n-generator": "dev-master",
"librenms/plugin-interfaces": "^1.0",
"mews/purifier": "^3.4", "mews/purifier": "^3.4",
"nunomaduro/laravel-console-summary": "^1.9", "nunomaduro/laravel-console-summary": "^1.9",
"pear/console_color2": "^0.1", "pear/console_color2": "^0.1",

37
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "277d3c3cae41b8c97cf6e330393f124a", "content-hash": "dabb9a7876ed5d206fc8278729d2d417",
"packages": [ "packages": [
{ {
"name": "amenadiel/jpgraph", "name": "amenadiel/jpgraph",
@@ -3180,6 +3180,41 @@
}, },
"time": "2024-07-26T10:48:47+00:00" "time": "2024-07-26T10:48:47+00:00"
}, },
{
"name": "librenms/plugin-interfaces",
"version": "1.0",
"source": {
"type": "git",
"url": "https://github.com/librenms/plugin-interfaces.git",
"reference": "7a196c3e47c5c5eb140f895dde6ceac998cf7b48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/librenms/plugin-interfaces/zipball/7a196c3e47c5c5eb140f895dde6ceac998cf7b48",
"reference": "7a196c3e47c5c5eb140f895dde6ceac998cf7b48",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"autoload": {
"psr-4": {
"LibreNMS\\Interfaces\\Plugins\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"0BSD"
],
"description": "Interfaces required to create a LibreNMS Plugin",
"homepage": "https://www.librenms.org/",
"support": {
"issues": "https://github.com/librenms/plugin-interfaces/issues",
"source": "https://github.com/librenms/plugin-interfaces/tree/1.0"
},
"time": "2024-08-15T15:23:53+00:00"
},
{ {
"name": "mews/purifier", "name": "mews/purifier",
"version": "3.4.2", "version": "3.4.2",

View File

@@ -1,6 +1,6 @@
<?php <?php
use App\Plugins\Hooks\DeviceOverviewHook; use LibreNMS\Interfaces\Plugins\Hooks\DeviceOverviewHook;
$overview = 1; $overview = 1;
@@ -20,9 +20,9 @@ require 'includes/html/dev-groups-overview-data.inc.php';
require 'overview/puppet_agent.inc.php'; require 'overview/puppet_agent.inc.php';
echo LibreNMS\Plugins::call('device_overview_container', [$device]); echo LibreNMS\Plugins::call('device_overview_container', [$device]);
PluginManager::call(DeviceOverviewHook::class, ['device' => DeviceCache::getPrimary()])->each(function ($view) { foreach (PluginManager::call(DeviceOverviewHook::class, ['device' => DeviceCache::getPrimary()]) as $view) {
echo $view; echo $view;
}); }
require 'overview/ports.inc.php'; require 'overview/ports.inc.php';

View File

@@ -13,7 +13,7 @@
* @author PipoCanaja <pipocanaja@gmail.com> * @author PipoCanaja <pipocanaja@gmail.com>
*/ */
use App\Plugins\Hooks\PortTabHook; use LibreNMS\Interfaces\Plugins\Hooks\PortTabHook;
$pagetitle[] = 'Plugins'; $pagetitle[] = 'Plugins';
$no_refresh = true; $no_refresh = true;
@@ -23,6 +23,6 @@ $no_refresh = true;
<hr> <hr>
<?php <?php
echo \LibreNMS\Plugins::call('port_container', [$device, $port]); echo \LibreNMS\Plugins::call('port_container', [$device, $port]);
PluginManager::call(PortTabHook::class, ['port' => $portModel])->each(function ($view) { foreach (PluginManager::call(PortTabHook::class, ['port' => $portModel]) as $view) {
echo $view; echo $view;
}); };

View File

@@ -3,5 +3,5 @@
@section('title', $title) @section('title', $title)
@section('content') @section('content')
@include($settings_view, $settings) @include($content_view, $settings)
@endsection @endsection