From 74882e39504674c4f16726c069f0d9ceaffcc5c9 Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Sun, 16 Dec 2018 15:18:17 -0600 Subject: [PATCH] Dashboard widget update (#9515) Implemented in Laravel Doesn't use legacy PHP session Several widgets have new features and settings, for example: - Multiple ports in one graph - Maps settings are configurable and override system settings but default to system settings - Graylog stream and/or device selection - Much improved graph widget selection - Many more DO NOT DELETE THIS TEXT #### Please note > Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting. - [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/) #### Testers If you would like to test this pull request then please run: `./scripts/github-apply `, i.e `./scripts/github-apply 5926` After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert. --- LibreNMS/Util/Colors.php | 71 +++ LibreNMS/Util/Graph.php | 84 ++++ LibreNMS/Util/Html.php | 56 +++ LibreNMS/Util/Rewrite.php | 1 + LibreNMS/Util/StringHelpers.php | 81 ++++ LibreNMS/Util/Time.php | 51 +++ LibreNMS/Util/Url.php | 51 ++- app/ApiClients/GraylogApi.php | 145 ++++++ .../Form/WidgetSettingsController.php | 61 +++ .../Controllers/PaginatedAjaxController.php | 8 +- .../Select/ApplicationController.php | 65 +++ .../Controllers/Select/BillController.php | 48 ++ .../Controllers/Select/DeviceController.php | 17 +- .../Select/DeviceGroupController.php | 49 ++ .../Controllers/Select/EventlogController.php | 6 +- .../Select/GraphAggregateController.php | 74 +++ .../Controllers/Select/GraphController.php | 152 +++++++ .../Select/GraylogStreamsController.php | 71 +++ .../Select/MuninPluginController.php | 55 +++ .../Controllers/Select/PortController.php | 94 ++++ .../Select/PortFieldController.php | 74 +++ .../Controllers/Select/SelectController.php | 2 +- .../Controllers/Select/SyslogController.php | 6 +- .../Controllers/Table/GraylogController.php | 134 ++++++ .../Table/SimpleTableController.php | 72 +++ .../Controllers/Table/TableController.php | 11 +- .../Controllers/Widgets/AlertsController.php | 74 +++ .../Widgets/AvailabilityMapController.php | 174 +++++++ .../Widgets/ComponentStatusController.php | 69 +++ .../Widgets/DeviceSummaryController.php | 88 ++++ .../Widgets/DeviceSummaryHorizController.php | 41 ++ .../Widgets/DeviceSummaryVertController.php | 41 ++ .../Widgets/EventlogController.php | 53 +++ .../Controllers/Widgets/GlobeController.php | 111 +++++ .../Controllers/Widgets/GraphController.php | 270 +++++++++++ .../Controllers/Widgets/GraylogController.php | 62 +++ .../Controllers/Widgets/ImageController.php | 79 ++++ .../Controllers/Widgets/NotesController.php | 63 +++ .../Widgets/PlaceholderController.php | 38 ++ .../Widgets/ServerStatsController.php | 93 ++++ .../Controllers/Widgets/SyslogController.php | 52 +++ .../Widgets/TopDevicesController.php | 305 +++++++++++++ .../Widgets/TopInterfacesController.php | 73 +++ .../Controllers/Widgets/WidgetController.php | 105 +++++ .../Widgets/WorldMapController.php | 99 ++++ app/Models/Bill.php | 53 +++ app/Models/Dashboard.php | 30 +- app/Models/Device.php | 36 +- app/Models/DeviceGroup.php | 5 + app/Models/Mempool.php | 7 + app/Models/MuninPlugin.php | 46 ++ app/Models/Port.php | 11 +- app/Models/Service.php | 49 ++ app/Models/Storage.php | 7 + app/Models/UserWidget.php | 11 +- app/Models/Widget.php | 35 ++ app/Providers/RouteServiceProvider.php | 13 - html/ajax_dash.php | 65 +-- html/css/jquery.gridster.min.css | 2 +- html/css/styles.css | 20 +- html/includes/common/availability-map.inc.php | 20 +- html/includes/common/component-status.inc.php | 38 -- html/includes/common/generic-graph.inc.php | 427 ------------------ html/includes/common/generic-image.inc.php | 72 --- html/includes/common/graylog.inc.php | 61 ++- html/includes/common/notes.inc.php | 44 -- html/includes/common/server-stats.inc.php | 139 ------ html/includes/common/top-devices.inc.php | 343 -------------- html/includes/common/top-interfaces.inc.php | 165 ------- html/includes/common/worldmap.inc.php | 202 +++------ html/includes/forms/widget-settings.inc.php | 69 --- html/includes/functions.inc.php | 151 +------ html/js/jquery.gridster.min.js | 4 +- html/js/librenms.js | 51 ++- html/legacy/ajax_dash.php | 64 --- html/legacy_index.php | 2 +- html/pages/device/logs/graylog.inc.php | 2 +- html/pages/front/tiles.php | 47 +- includes/common.php | 28 +- resources/views/layouts/librenmsv1.blade.php | 42 +- resources/views/widgets/alerts.blade.php | 73 +++ .../views/widgets/availability-map.blade.php | 51 +++ .../views/widgets/component-status.blade.php | 18 + .../widgets/device-summary-horiz.blade.php | 54 +++ .../widgets/device-summary-vert.blade.php | 66 +++ resources/views/widgets/eventlog.blade.php | 27 ++ resources/views/widgets/globe.blade.php | 29 ++ resources/views/widgets/graph.blade.php | 9 + resources/views/widgets/graylog.blade.php | 39 ++ resources/views/widgets/image.blade.php | 3 + resources/views/widgets/placeholder.blade.php | 5 + .../views/widgets/server-stats.blade.php | 50 ++ .../views/widgets/settings/alerts.blade.php | 65 +++ .../settings/availability-map.blade.php | 74 +++ .../views/widgets/settings/base.blade.php | 13 + .../widgets/settings/device-summary.blade.php | 19 + .../views/widgets/settings/eventlog.blade.php | 38 ++ .../views/widgets/settings/globe.blade.php | 27 ++ .../views/widgets/settings/graph.blade.php | 126 ++++++ .../views/widgets/settings/graylog.blade.php | 57 +++ .../views/widgets/settings/image.blade.php | 18 + .../views/widgets/settings/notes.blade.php | 19 + .../widgets/settings/server-stats.blade.php | 35 ++ .../views/widgets/settings/syslog.blade.php | 22 + .../widgets/settings/top-devices.blade.php | 35 ++ .../widgets/settings/top-interfaces.blade.php | 26 ++ .../views/widgets/settings/worldmap.blade.php | 42 ++ resources/views/widgets/syslog.blade.php | 28 ++ resources/views/widgets/top-devices.blade.php | 25 + .../views/widgets/top-interfaces.blade.php | 21 + resources/views/widgets/worldmap.blade.php | 61 +++ routes/legacy.php | 6 - routes/web.php | 34 ++ 113 files changed, 5103 insertions(+), 1902 deletions(-) create mode 100644 LibreNMS/Util/Colors.php create mode 100644 LibreNMS/Util/Graph.php create mode 100644 LibreNMS/Util/StringHelpers.php create mode 100644 LibreNMS/Util/Time.php create mode 100644 app/ApiClients/GraylogApi.php create mode 100644 app/Http/Controllers/Form/WidgetSettingsController.php create mode 100644 app/Http/Controllers/Select/ApplicationController.php create mode 100644 app/Http/Controllers/Select/BillController.php create mode 100644 app/Http/Controllers/Select/DeviceGroupController.php create mode 100644 app/Http/Controllers/Select/GraphAggregateController.php create mode 100644 app/Http/Controllers/Select/GraphController.php create mode 100644 app/Http/Controllers/Select/GraylogStreamsController.php create mode 100644 app/Http/Controllers/Select/MuninPluginController.php create mode 100644 app/Http/Controllers/Select/PortController.php create mode 100644 app/Http/Controllers/Select/PortFieldController.php create mode 100644 app/Http/Controllers/Table/GraylogController.php create mode 100644 app/Http/Controllers/Table/SimpleTableController.php create mode 100644 app/Http/Controllers/Widgets/AlertsController.php create mode 100644 app/Http/Controllers/Widgets/AvailabilityMapController.php create mode 100644 app/Http/Controllers/Widgets/ComponentStatusController.php create mode 100644 app/Http/Controllers/Widgets/DeviceSummaryController.php create mode 100644 app/Http/Controllers/Widgets/DeviceSummaryHorizController.php create mode 100644 app/Http/Controllers/Widgets/DeviceSummaryVertController.php create mode 100644 app/Http/Controllers/Widgets/EventlogController.php create mode 100644 app/Http/Controllers/Widgets/GlobeController.php create mode 100644 app/Http/Controllers/Widgets/GraphController.php create mode 100644 app/Http/Controllers/Widgets/GraylogController.php create mode 100644 app/Http/Controllers/Widgets/ImageController.php create mode 100644 app/Http/Controllers/Widgets/NotesController.php create mode 100644 app/Http/Controllers/Widgets/PlaceholderController.php create mode 100644 app/Http/Controllers/Widgets/ServerStatsController.php create mode 100644 app/Http/Controllers/Widgets/SyslogController.php create mode 100644 app/Http/Controllers/Widgets/TopDevicesController.php create mode 100644 app/Http/Controllers/Widgets/TopInterfacesController.php create mode 100644 app/Http/Controllers/Widgets/WidgetController.php create mode 100644 app/Http/Controllers/Widgets/WorldMapController.php create mode 100644 app/Models/Bill.php create mode 100644 app/Models/MuninPlugin.php create mode 100644 app/Models/Widget.php delete mode 100644 html/includes/common/component-status.inc.php delete mode 100644 html/includes/common/generic-graph.inc.php delete mode 100644 html/includes/common/generic-image.inc.php delete mode 100644 html/includes/common/notes.inc.php delete mode 100644 html/includes/common/server-stats.inc.php delete mode 100644 html/includes/common/top-devices.inc.php delete mode 100644 html/includes/common/top-interfaces.inc.php delete mode 100644 html/includes/forms/widget-settings.inc.php delete mode 100644 html/legacy/ajax_dash.php create mode 100644 resources/views/widgets/alerts.blade.php create mode 100644 resources/views/widgets/availability-map.blade.php create mode 100644 resources/views/widgets/component-status.blade.php create mode 100644 resources/views/widgets/device-summary-horiz.blade.php create mode 100644 resources/views/widgets/device-summary-vert.blade.php create mode 100644 resources/views/widgets/eventlog.blade.php create mode 100644 resources/views/widgets/globe.blade.php create mode 100644 resources/views/widgets/graph.blade.php create mode 100644 resources/views/widgets/graylog.blade.php create mode 100644 resources/views/widgets/image.blade.php create mode 100644 resources/views/widgets/placeholder.blade.php create mode 100644 resources/views/widgets/server-stats.blade.php create mode 100644 resources/views/widgets/settings/alerts.blade.php create mode 100644 resources/views/widgets/settings/availability-map.blade.php create mode 100644 resources/views/widgets/settings/base.blade.php create mode 100644 resources/views/widgets/settings/device-summary.blade.php create mode 100644 resources/views/widgets/settings/eventlog.blade.php create mode 100644 resources/views/widgets/settings/globe.blade.php create mode 100644 resources/views/widgets/settings/graph.blade.php create mode 100644 resources/views/widgets/settings/graylog.blade.php create mode 100644 resources/views/widgets/settings/image.blade.php create mode 100644 resources/views/widgets/settings/notes.blade.php create mode 100644 resources/views/widgets/settings/server-stats.blade.php create mode 100644 resources/views/widgets/settings/syslog.blade.php create mode 100644 resources/views/widgets/settings/top-devices.blade.php create mode 100644 resources/views/widgets/settings/top-interfaces.blade.php create mode 100644 resources/views/widgets/settings/worldmap.blade.php create mode 100644 resources/views/widgets/syslog.blade.php create mode 100644 resources/views/widgets/top-devices.blade.php create mode 100644 resources/views/widgets/top-interfaces.blade.php create mode 100644 resources/views/widgets/worldmap.blade.php delete mode 100644 routes/legacy.php diff --git a/LibreNMS/Util/Colors.php b/LibreNMS/Util/Colors.php new file mode 100644 index 0000000000..fa90727cb5 --- /dev/null +++ b/LibreNMS/Util/Colors.php @@ -0,0 +1,71 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Util; + +class Colors +{ + public static function percentage($percentage, $component_perc_warn = null) + { + $perc_warn = 75; + + if (isset($component_perc_warn)) { + $perc_warn = round($component_perc_warn, 0); + } + + if ($percentage > $perc_warn) { + return [ + 'left' => 'c4323f', + 'right' => 'c96a73' + ]; + } + + if ($percentage > 75) { + return [ + 'left' => 'bf5d5b', + 'right' => 'd39392' + ]; + } + + if ($percentage > 50) { + return [ + 'left' => 'bf875b', + 'right' => 'd3ae92' + ]; + } + + if ($percentage > 25) { + return [ + 'left' => '5b93bf', + 'right' => '92b7d3' + ]; + } + + return [ + 'left' => '9abf5b', + 'right' => 'bbd392' + ]; + } +} diff --git a/LibreNMS/Util/Graph.php b/LibreNMS/Util/Graph.php new file mode 100644 index 0000000000..7062340a26 --- /dev/null +++ b/LibreNMS/Util/Graph.php @@ -0,0 +1,84 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Util; + +use App\Models\Device; +use LibreNMS\Config; + +class Graph +{ + public static function getTypes() + { + return ['device', 'port', 'application', 'munin']; + } + + /** + * Get an array of all graph subtypes for the given type + * @param $type + * @param Device $device + * @return array + */ + public static function getSubtypes($type, $device = null) + { + $types = []; + + // find the subtypes defined in files + foreach (glob(base_path("/html/includes/graphs/$type/*.inc.php")) as $file) { + $type = basename($file, '.inc.php'); + if ($type != 'auth') { + $types[] = $type; + } + } + + if ($device != null) { + // find the MIB subtypes + $graphs = $device->graphs(); + + foreach (Config::get('graph_types') as $type => $type_data) { + foreach (array_keys($type_data) as $subtype) { + if ($graphs->contains($subtype) && self::isMibGraph($type, $subtype)) { + $types[] = $subtype; + } + } + } + } + + sort($types); + return $types; + } + + /** + * Check if the given graph is a mib graph + * + * @param $type + * @param $subtype + * @return bool + */ + public static function isMibGraph($type, $subtype) + { + return Config::get("graph_types.$type.$subtype.section") == 'mib'; + } +} diff --git a/LibreNMS/Util/Html.php b/LibreNMS/Util/Html.php index 6a1399987c..ab6bce8c1d 100644 --- a/LibreNMS/Util/Html.php +++ b/LibreNMS/Util/Html.php @@ -25,6 +25,8 @@ namespace LibreNMS\Util; +use HTMLPurifier; +use HTMLPurifier_Config; use LibreNMS\Config; class Html @@ -95,4 +97,58 @@ class Html return $graph_data; } + + public static function percentageBar($width, $height, $percent, $left_text, $left_colour, $left_background, $right_text, $right_colour, $right_background) + { + if ($percent > '100') { + $size_percent = '100'; + } else { + $size_percent = $percent; + } + + $output = ' +
+
+
+
+
+ '.$left_text.' + '.$right_text.' +
+ '; + + return $output; + } + + /** + * Clean a string for display in an html page. + * + * @param $value + * @param array $purifier_config (key, value pair) + * @return string + */ + public static function display($value, $purifier_config = []) + { + /** @var HTMLPurifier $purifier */ + static $purifier; + + // If $purifier_config is non-empty then we don't want + // to convert html tags and allow these to be controlled + // by purifier instead. + if (empty($purifier_config)) { + $value = htmlentities($value); + } + + if (!isset($purifier)) { + // initialize HTML Purifier here since this is the only user + $p_config = HTMLPurifier_Config::createDefault(); + $p_config->set('Cache.SerializerPath', Config::get('temp_dir', '/tmp')); + foreach ($purifier_config as $k => $v) { + $p_config->set($k, $v); + } + $purifier = new HTMLPurifier($p_config); + } + + return $purifier->purify(stripslashes($value)); + } } diff --git a/LibreNMS/Util/Rewrite.php b/LibreNMS/Util/Rewrite.php index 3fd5e0f26b..eaa3e7a6eb 100644 --- a/LibreNMS/Util/Rewrite.php +++ b/LibreNMS/Util/Rewrite.php @@ -103,6 +103,7 @@ class Rewrite 'serviceinstance' => 'SI', 'dwdm' => 'DWDM', 'bundle-ether' => 'BE', + 'bridge-aggregation' => 'BA', ]; return str_ireplace(array_keys($rewrite_shortif), array_values($rewrite_shortif), $name); diff --git a/LibreNMS/Util/StringHelpers.php b/LibreNMS/Util/StringHelpers.php new file mode 100644 index 0000000000..8972a92b4d --- /dev/null +++ b/LibreNMS/Util/StringHelpers.php @@ -0,0 +1,81 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Util; + +class StringHelpers +{ + /** + * Shorten text over 50 chars, if shortened, add ellipsis + * + * @param $string + * @param int $max + * @return string + */ + public static function shortenText($string, $max = 30) + { + if (strlen($string) > 50) { + return substr($string, 0, $max) . "..."; + } + + return $string; + } + + public static function niceCase($string) + { + $replacements = [ + 'dbm' => 'dBm', + 'entropy' => 'Random entropy', + 'mysql' => 'MySQL', + 'powerdns' => 'PowerDNS', + 'bind' => 'BIND', + 'nfs-stats' => 'NFS Stats', + 'nfs-v3-stats' => 'NFS v3 Stats', + 'nfs-server' => 'NFS Server', + 'ntp' => 'NTP', + 'ntp-client' => 'NTP Client', + 'ntp-server' => 'NTP Server', + 'os-updates' => 'OS Updates', + 'smart' => 'SMART', + 'powerdns-recursor' => 'PowerDNS Recursor', + 'powerdns-dnsdist' => 'PowerDNS dnsdist', + 'dhcp-stats' => 'DHCP Stats', + 'ups-nut' => 'UPS nut', + 'ups-apcups' => 'UPS apcups', + 'gpsd' => 'GPSD', + 'exim-stats' => 'EXIM Stats', + 'fbsd-nfs-client' => 'FreeBSD NFS Client', + 'fbsd-nfs-server' => 'FreeBSD NFS Server', + 'php-fpm' => 'PHP-FPM', + 'opengridscheduler' => 'Open Grid Scheduler', + 'sdfsinfo' => 'SDFS info', + 'freeradius' => 'FreeRADIUS', + 'pi-hole' => 'pi-hole', + 'zfs' => 'ZFS', + ]; + + return isset($replacements[$string]) ? $replacements[$string] : ucfirst($string); + } +} diff --git a/LibreNMS/Util/Time.php b/LibreNMS/Util/Time.php new file mode 100644 index 0000000000..f8c524dc43 --- /dev/null +++ b/LibreNMS/Util/Time.php @@ -0,0 +1,51 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Util; + +class Time +{ + public static function legacyTimeSpecToSecs($description) + { + $conversion = [ + 'now' => 0, + 'onehour' => 3600, + 'fourhour' => 14400, + 'sixhour' => 21600, + 'twelvehour' => 43200, + 'day' => 86400, + 'twoday' => 172800, + 'week' => 604800, + 'twoweek' => 1209600, + 'month' => 2678400, + 'twomonth' => 5356800, + 'threemonth' => 8035200, + 'year' => 31536000, + 'twoyear' => 63072000, + ]; + + return isset($conversion[$description]) ? $conversion[$description] : 0; + } +} diff --git a/LibreNMS/Util/Url.php b/LibreNMS/Util/Url.php index b8e62cfd13..4d3cd84c40 100644 --- a/LibreNMS/Util/Url.php +++ b/LibreNMS/Util/Url.php @@ -102,8 +102,7 @@ class Url if ($overlib == 0) { $link = $contents; } else { - // escape quotes - $contents = str_replace(["'", '"'], "\'", $contents); + $contents = self::escapeBothQuotes($contents); $link = Url::overlibLink($url, $text, $contents, $class); } @@ -177,6 +176,33 @@ class Url return self::generate(['page' => 'device', 'device' => $port->device_id, 'tab' => 'port', 'port' => $port->port_id], $vars); } + /** + * @param Port $port + * @return string + */ + public static function portThumbnail($port) + { + $graph_array = [ + 'port_id' => $port->port_id, + 'graph_type' => 'port_bits', + 'from' => Carbon::now()->subDay()->timestamp, + 'to' => Carbon::now()->timestamp, + 'width' => 150, + 'height' => 21, + ]; + + return self::portImage($graph_array); + } + + public static function portImage($args) + { + if (empty($args['bg'])) { + $args['bg'] = 'FFFFFF00'; + } + + return ""; + } + public static function generate($vars, $new_vars = []) { $vars = array_merge($vars, $new_vars); @@ -245,6 +271,22 @@ class Url return $output; } + public static function overlibContent($graph_array, $text) + { + $overlib_content = '
' . $text . '
'; + + $now = Carbon::now(); + + foreach ([1, 7, 30, 365] as $days) { + $graph_array['from'] = $now->subDays($days)->timestamp; + $overlib_content .= self::escapeBothQuotes(self::graphTag($graph_array)); + } + + $overlib_content .= '
'; + + return $overlib_content; + } + /** * Generate minigraph image url * @@ -321,4 +363,9 @@ class Url return "interface-upup"; } + + private static function escapeBothQuotes($string) + { + return str_replace(["'", '"'], "\'", $string); + } } diff --git a/app/ApiClients/GraylogApi.php b/app/ApiClients/GraylogApi.php new file mode 100644 index 0000000000..9111622e75 --- /dev/null +++ b/app/ApiClients/GraylogApi.php @@ -0,0 +1,145 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\ApiClients; + +use App\Models\Device; +use GuzzleHttp\Client; +use LibreNMS\Config; + +class GraylogApi +{ + private $client; + private $api_prefix = ''; + + public function __construct(array $config = []) + { + if (version_compare(Config::get('graylog.version', '2.4'), '2.1', '>=')) { + $this->api_prefix = '/api'; + } + + if (empty($config)) { + $base_uri = Config::get('graylog.server'); + if ($port = Config::get('graylog.port')) { + $base_uri .= ':' . $port; + } + + $config = [ + 'base_uri' => $base_uri, + 'auth' => [Config::get('graylog.username'), Config::get('graylog.password')], + 'headers' => ['Accept' => 'application/json'], + ]; + } + + $this->client = new Client($config); + } + + public function getStreams() + { + if (!$this->isConfigured()) { + return []; + } + + $uri = $this->api_prefix . '/streams'; + + $response = $this->client->get($uri); + $data = json_decode($response->getBody(), true); + + return $data ?: []; + } + + /** + * Query the Graylog server + * + * @param string $query + * @param int $range + * @param int $limit + * @param int $offset + * @param string $sort field:asc or field:desc + * @param string $filter + * @return array + */ + public function query($query = '*', $range = 0, $limit = 0, $offset = 0, $sort = null, $filter = null) + { + if (!$this->isConfigured()) { + return []; + } + + $uri = Config::get('graylog.base_uri'); + if (!$uri) { + $uri = $this->api_prefix . '/search/universal/relative'; + } + + $data = [ + 'query' => $query, + 'range' => $range, + 'limit' => $limit, + 'offset' => $offset, + 'sort' => $sort, + 'filter' => $filter, + ]; + + $response = $this->client->get($uri, ['query' => $data]); + $data = json_decode($response->getBody(), true); + + return $data ?: []; + } + + /** + * Build a simple query string that searches the messages field and/or filters by device + * + * @param string $search Search the message field for this string + * @param Device $device + * @return string + */ + public function buildSimpleQuery($search = null, $device = null) + { + $query = []; + if ($search) { + $query[] = 'message:"' . $search . '"'; + } + + if ($device) { + $ip = gethostbyname($device->hostname); + $device_query = 'source:"' . $device->hostname . '" || source:"' . $ip . '"'; + if ($device->ip && $ip != $device->ip) { + $query .= ' || source:"' . $device->ip . '"'; + } + + $query[] = '(' . $device_query . ')'; + } + + if (empty($query)) { + return '*'; + } + + return implode('&&', $query); + } + + public function isConfigured() + { + return isset($this->client->getConfig()['base_uri']); + } +} diff --git a/app/Http/Controllers/Form/WidgetSettingsController.php b/app/Http/Controllers/Form/WidgetSettingsController.php new file mode 100644 index 0000000000..e0de21339b --- /dev/null +++ b/app/Http/Controllers/Form/WidgetSettingsController.php @@ -0,0 +1,61 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Form; + +use App\Http\Controllers\Controller; +use App\Models\UserWidget; +use Illuminate\Http\Request; + +class WidgetSettingsController extends Controller +{ + public function update(Request $request, $widget_settings) + { + $this->validate($request, ['settings' => 'array']); + + $widget = UserWidget::with('dashboard')->findOrFail($widget_settings); + $widget_settings = (array)$request->get('settings', []); + + if (!$widget->dashboard->canWrite($request->user())) { + return response()->json([ + 'status' => 'error', + 'message' => 'ERROR: You have no write-access to this dashboard' + ]); + } + + $widget->settings = $widget_settings; + if ($widget->save()) { + return response()->json([ + 'status' => 'ok', + 'message' => 'Updated widget settings' + ]); + } + + return response()->json([ + 'status' => 'error', + 'message' => 'ERROR: Could not update' + ]); + } +} diff --git a/app/Http/Controllers/PaginatedAjaxController.php b/app/Http/Controllers/PaginatedAjaxController.php index 9965017e33..4de057b072 100644 --- a/app/Http/Controllers/PaginatedAjaxController.php +++ b/app/Http/Controllers/PaginatedAjaxController.php @@ -46,7 +46,7 @@ abstract class PaginatedAjaxController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder */ - abstract public function baseQuery($request); + abstract protected function baseQuery($request); /** * @param Paginator $paginator @@ -59,7 +59,7 @@ abstract class PaginatedAjaxController extends Controller * * @return array */ - public function rules() + protected function rules() { return []; } @@ -71,7 +71,7 @@ abstract class PaginatedAjaxController extends Controller * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function searchFields($request) + protected function searchFields($request) { return []; } @@ -82,7 +82,7 @@ abstract class PaginatedAjaxController extends Controller * @param Model $model * @return array|Collection|Model */ - public function formatItem($model) + protected function formatItem($model) { return $model; } diff --git a/app/Http/Controllers/Select/ApplicationController.php b/app/Http/Controllers/Select/ApplicationController.php new file mode 100644 index 0000000000..9d1b40dfe3 --- /dev/null +++ b/app/Http/Controllers/Select/ApplicationController.php @@ -0,0 +1,65 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Models\Application; + +class ApplicationController extends SelectController +{ + protected function rules() + { + return [ + 'type' => 'nullable|string', + ]; + } + + /** + * Defines the base query for this resource + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder + */ + protected function baseQuery($request) + { + $query = Application::hasAccess($request->user())->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName'); + }]); + + if ($type = $request->get('type')) { + $query->where('app_type', $type); + } + + return $query; + } + + public function formatItem($app) + { + return [ + 'id' => $app->app_id, + 'text' => $app->displayName() . ' - ' . $app->device->displayName(), + ]; + } +} diff --git a/app/Http/Controllers/Select/BillController.php b/app/Http/Controllers/Select/BillController.php new file mode 100644 index 0000000000..8b6514daa3 --- /dev/null +++ b/app/Http/Controllers/Select/BillController.php @@ -0,0 +1,48 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Models\Bill; + +class BillController extends SelectController +{ + protected function searchFields($request) + { + return ['bill_name', 'bill_notes']; + } + + /** + * Defines the base query for this resource + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder + */ + protected function baseQuery($request) + { + return Bill::hasAccess($request->user()) + ->select('bill_id', 'bill_name'); + } +} diff --git a/app/Http/Controllers/Select/DeviceController.php b/app/Http/Controllers/Select/DeviceController.php index 67d46824c3..df52aa7be2 100644 --- a/app/Http/Controllers/Select/DeviceController.php +++ b/app/Http/Controllers/Select/DeviceController.php @@ -29,13 +29,24 @@ use App\Models\Device; class DeviceController extends SelectController { - public function searchFields($request) + private $id = 'device_id'; + + protected function rules() + { + return [ + 'id' => 'nullable|in:device_id,hostname' + ]; + } + + protected function searchFields($request) { return ['hostname', 'sysName']; } - public function baseQuery($request) + protected function baseQuery($request) { + $this->id = $request->get('id', 'device_id'); + return Device::hasAccess($request->user())->select('device_id', 'hostname', 'sysName'); } @@ -43,7 +54,7 @@ class DeviceController extends SelectController { /** @var Device $device */ return [ - 'id' => $device->device_id, + 'id' => $device->{$this->id}, 'text' => $device->displayName(), ]; } diff --git a/app/Http/Controllers/Select/DeviceGroupController.php b/app/Http/Controllers/Select/DeviceGroupController.php new file mode 100644 index 0000000000..29132092b3 --- /dev/null +++ b/app/Http/Controllers/Select/DeviceGroupController.php @@ -0,0 +1,49 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Models\DeviceGroup; + +class DeviceGroupController extends SelectController +{ + protected function searchFields($request) + { + return ['name']; + } + + protected function baseQuery($request) + { + return DeviceGroup::hasAccess($request->user())->select('id', 'name'); + } + + public function formatItem($device_group) + { + return [ + 'id' => $device_group->id, + 'text' => $device_group->name, + ]; + } +} diff --git a/app/Http/Controllers/Select/EventlogController.php b/app/Http/Controllers/Select/EventlogController.php index d0385f4e3e..383e94e829 100644 --- a/app/Http/Controllers/Select/EventlogController.php +++ b/app/Http/Controllers/Select/EventlogController.php @@ -34,7 +34,7 @@ class EventlogController extends SelectController * * @return array */ - public function rules() + protected function rules() { return [ 'field' => 'required|in:type', @@ -48,7 +48,7 @@ class EventlogController extends SelectController * @param \Illuminate\Http\Request $request * @return array */ - public function searchFields($request) + protected function searchFields($request) { return [$request->get('field')]; } @@ -59,7 +59,7 @@ class EventlogController extends SelectController * @param \Illuminate\Http\Request $request * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder */ - public function baseQuery($request) + protected function baseQuery($request) { /** @var \Illuminate\Database\Eloquent\Builder $query */ $query = Eventlog::hasAccess($request->user()) diff --git a/app/Http/Controllers/Select/GraphAggregateController.php b/app/Http/Controllers/Select/GraphAggregateController.php new file mode 100644 index 0000000000..74db977191 --- /dev/null +++ b/app/Http/Controllers/Select/GraphAggregateController.php @@ -0,0 +1,74 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Http\Controllers\Controller; +use Illuminate\Http\Request; +use LibreNMS\Config; + +class GraphAggregateController extends Controller +{ + private $rules = [ + 'limit' => 'int', + 'page' => 'int', + 'term' => 'nullable|string', + ]; + + public function __invoke(Request $request) + { + $this->validate($request, $this->rules); + + $types = [ + 'transit', + 'peering', + 'core', + ]; + + foreach ((array)Config::get('custom_descr', []) as $custom) { + if ($custom) { + $types[] = $custom; + } + } + + // handle search + if ($search = strtolower($request->get('term'))) { + $types = array_filter($types, function ($type) use ($search) { + return !str_contains(strtolower($type), $search); + }); + } + + // format results + return response()->json([ + 'results' => array_map(function ($type) { + return [ + 'id' => $type, + 'text' => ucwords($type), + ]; + }, $types), + 'pagination' => ['more' => false] + ]); + } +} diff --git a/app/Http/Controllers/Select/GraphController.php b/app/Http/Controllers/Select/GraphController.php new file mode 100644 index 0000000000..50455237c1 --- /dev/null +++ b/app/Http/Controllers/Select/GraphController.php @@ -0,0 +1,152 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Http\Controllers\Controller; +use App\Models\Device; +use Illuminate\Http\Request; +use Illuminate\Support\Collection; +use LibreNMS\Util\Graph; +use LibreNMS\Util\StringHelpers; + +class GraphController extends Controller +{ + private $rules = [ + 'limit' => 'int', + 'page' => 'int', + 'term' => 'nullable|string', + 'device' => 'nullable|int', + ]; + + public function __invoke(Request $request) + { + $this->validate($request, $this->rules); + + $data = []; + $search = $request->get('term'); + $device_id = $request->get('device'); + $device = $device_id ? Device::find($device_id) : null; + + foreach (Graph::getTypes() as $type) { + $graphs = $this->filterTypeGraphs(collect(Graph::getSubtypes($type, $device)), $type, $search); + + if ($graphs->isNotEmpty()) { + $data[] = [ + 'text' => StringHelpers::niceCase($type), + 'children' => $graphs->map(function ($graph) use ($type) { + return $this->formatGraph($type, $graph); + })->values() + ]; + } + } + + $aggregators = $this->filterTypeGraphs(collect([ + 'transit' => 'Transit', + 'peering' => 'Peering', + 'core' => 'Core', + 'custom' => 'Custom', + 'ports' => 'Manual Ports' + ]), 'aggregators', $search); + if ($aggregators->isNotEmpty()) { + $data[] = [ + 'text' => 'Aggregators', + 'children' => $aggregators->map(function ($text, $id) { + return compact('id', 'text'); + })->values() + ]; + } + + $billing = $this->filterTypeGraphs(collect([ + 'bill_bits' => 'Bill Bits' + ]), 'bill', $search); + if ($billing->isNotEmpty()) { + $data[] = [ + 'text' => 'Bill', + 'children' => $billing->map(function ($text, $id) { + return compact('id', 'text'); + })->values() + ]; + } + + return response()->json([ + 'results' => $data, + 'pagination' => ['more' => false] + ]); + } + + private function formatGraph($top, $graph) + { + $text = $graph; + if (str_contains('_', $graph)) { + list($type, $subtype) = explode('_', $graph, 2); + } else { + $type = $graph; + $subtype = ''; + } + + if (!Graph::isMibGraph($type, $subtype)) { + $text = ucwords($top . ' ' . str_replace(['_', '-'], ' ', $text)); + } + + return [ + 'id' => $top . '_' . $graph, + 'text' => $text, + ]; + } + + /** + * @param Collection $graphs + * @param string $type + * @param string $search + * @return Collection + */ + private function filterTypeGraphs($graphs, $type, $search) + { + $search = strtolower($search); + + if ($search) { + $terms = preg_split('/[ _-]/', $search, 2); + $first = array_shift($terms); + + if (str_contains($type, $first)) { + // search matches type, show all unless there are more terms. + if (!empty($terms)) { + $sub_search = array_shift($terms); + $graphs = $graphs->filter(function ($graph) use ($sub_search) { + return str_contains(strtolower($graph), $sub_search); + }); + } + } else { + // if the type matches, don't filter the sub values + $graphs = $graphs->filter(function ($graph) use ($search) { + return str_contains(strtolower($graph), $search); + }); + } + } + + return $graphs; + } +} diff --git a/app/Http/Controllers/Select/GraylogStreamsController.php b/app/Http/Controllers/Select/GraylogStreamsController.php new file mode 100644 index 0000000000..ee64d76ef9 --- /dev/null +++ b/app/Http/Controllers/Select/GraylogStreamsController.php @@ -0,0 +1,71 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\ApiClients\GraylogApi; +use App\Http\Controllers\Controller; +use Illuminate\Http\Request; +use Log; + +class GraylogStreamsController extends Controller +{ + /** + * The default method called by the route handler + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function __invoke(Request $request, GraylogApi $api) + { + $this->validate($request, [ + 'limit' => 'int', + 'page' => 'int', + 'term' => 'nullable|string', + ]); + $search = strtolower($request->get('term')); + + $streams = []; + try { + $streams = collect($api->getStreams()['streams'])->filter(function ($stream) use ($search) { + return !$search || str_contains(strtolower($stream['title']), $search) || str_contains(strtolower($stream['description']), $search); + })->map(function ($stream) { + $text = $stream['title']; + if ($stream['description']) { + $text .= " ({$stream['description']})"; + } + + return ['id' => $stream['id'], 'text' => $text]; + }); + } catch (\Exception $e) { + Log::error($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]); + } + + return response()->json([ + 'results' => $streams, + 'pagination' => ['more' => false] + ]); + } +} diff --git a/app/Http/Controllers/Select/MuninPluginController.php b/app/Http/Controllers/Select/MuninPluginController.php new file mode 100644 index 0000000000..260bd4e570 --- /dev/null +++ b/app/Http/Controllers/Select/MuninPluginController.php @@ -0,0 +1,55 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Models\MuninPlugin; + +class MuninPluginController extends SelectController +{ + + /** + * Defines the base query for this resource + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder + */ + protected function baseQuery($request) + { + return MuninPlugin::hasAccess($request->user()) + ->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName'); + }]) + ->select('mplug_id', 'mplug_type'); + } + + public function formatItem($munin_plugin) + { + return [ + 'id' => $munin_plugin->mplug_id, + 'text' => $munin_plugin->device->shortDisplayName() . ' - ' . $munin_plugin->mplug_type + ]; + } +} diff --git a/app/Http/Controllers/Select/PortController.php b/app/Http/Controllers/Select/PortController.php new file mode 100644 index 0000000000..2651f445f3 --- /dev/null +++ b/app/Http/Controllers/Select/PortController.php @@ -0,0 +1,94 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Models\Port; + +class PortController extends SelectController +{ + /** + * Defines validation rules (will override base validation rules for select2 responses too) + * + * @return array + */ + protected function rules() + { + return [ + 'device' => 'nullable|int', + ]; + } + + /** + * Defines search fields will be searched in order + * + * @param \Illuminate\Http\Request $request + * @return array + */ + protected function searchFields($request) + { + return (array)$request->get('field', ['ifAlias', 'ifName', 'ifDescr', 'devices.hostname', 'devices.sysName']); + } + + /** + * Defines the base query for this resource + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder + */ + protected function baseQuery($request) + { + /** @var \Illuminate\Database\Eloquent\Builder $query */ + $query = Port::hasAccess($request->user()) + ->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName'); + }]) + ->select('ports.device_id', 'port_id', 'ifAlias', 'ifName', 'ifDescr') + ->groupBy(['ports.device_id', 'port_id', 'ifAlias', 'ifName', 'ifDescr']); + + if ($request->get('term')) { + // join with devices for searches + $query->leftJoin('devices', 'devices.device_id', 'ports.device_id'); + } + + if ($device_id = $request->get('device')) { + $query->where('ports.device_id', $device_id); + } + + return $query; + } + + public function formatItem($port) + { + /** @var Port $port */ + $label = $port->getShortLabel(); + $description = ($label == $port->ifAlias ? '' : ' - ' . $port->ifAlias); + + return [ + 'id' => $port->port_id, + 'text' => $label . ' - ' . $port->device->shortDisplayName() . $description, + ]; + } +} diff --git a/app/Http/Controllers/Select/PortFieldController.php b/app/Http/Controllers/Select/PortFieldController.php new file mode 100644 index 0000000000..318764a286 --- /dev/null +++ b/app/Http/Controllers/Select/PortFieldController.php @@ -0,0 +1,74 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Select; + +use App\Models\Port; + +class PortFieldController extends SelectController +{ + /** + * Defines validation rules (will override base validation rules for select2 responses too) + * + * @return array + */ + protected function rules() + { + return [ + 'field' => 'required|in:ifType', + 'device' => 'nullable|int', + ]; + } + + /** + * Defines search fields will be searched in order + * + * @param \Illuminate\Http\Request $request + * @return array + */ + protected function searchFields($request) + { + return [$request->get('field')]; + } + + /** + * Defines the base query for this resource + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder + */ + protected function baseQuery($request) + { + /** @var \Illuminate\Database\Eloquent\Builder $query */ + $query = Port::hasAccess($request->user()) + ->select($request->get('field'))->distinct(); + + if ($device_id = $request->get('device')) { + $query->where('ports.device_id', $device_id); + } + + return $query; + } +} diff --git a/app/Http/Controllers/Select/SelectController.php b/app/Http/Controllers/Select/SelectController.php index b35696f854..9812337418 100644 --- a/app/Http/Controllers/Select/SelectController.php +++ b/app/Http/Controllers/Select/SelectController.php @@ -50,7 +50,7 @@ abstract class SelectController extends PaginatedAjaxController public function __invoke(Request $request) { $this->validate($request, $this->rules()); - $limit = $request->get('limit', 20); + $limit = $request->get('limit', 50); $query = $this->search($request->get('term'), $this->baseQuery($request), $this->searchFields($request)); $paginator = $query->simplePaginate($limit); diff --git a/app/Http/Controllers/Select/SyslogController.php b/app/Http/Controllers/Select/SyslogController.php index c83a9707c9..3ddfe533eb 100644 --- a/app/Http/Controllers/Select/SyslogController.php +++ b/app/Http/Controllers/Select/SyslogController.php @@ -32,7 +32,7 @@ class SyslogController extends SelectController * * @return array */ - public function rules() + protected function rules() { return [ 'field' => 'required|in:program,priority', @@ -46,7 +46,7 @@ class SyslogController extends SelectController * @param \Illuminate\Http\Request $request * @return array */ - public function searchFields($request) + protected function searchFields($request) { return [$request->get('field')]; } @@ -57,7 +57,7 @@ class SyslogController extends SelectController * @param \Illuminate\Http\Request $request * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder */ - public function baseQuery($request) + protected function baseQuery($request) { /** @var \Illuminate\Database\Eloquent\Builder $query */ $query = \App\Models\Syslog::hasAccess($request->user()) diff --git a/app/Http/Controllers/Table/GraylogController.php b/app/Http/Controllers/Table/GraylogController.php new file mode 100644 index 0000000000..36295b74bc --- /dev/null +++ b/app/Http/Controllers/Table/GraylogController.php @@ -0,0 +1,134 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Table; + +use App\ApiClients\GraylogApi; +use App\Models\Device; +use DateInterval; +use DateTime; +use DateTimeZone; +use Illuminate\Http\Request; +use LibreNMS\Config; +use LibreNMS\Util\Url; + +class GraylogController extends SimpleTableController +{ + private $timezone; + + public function __construct() + { + $timezone = Config::get('graylog.timezone'); + $this->timezone = $timezone ? new DateTimeZone($timezone) : null; + } + + public function __invoke(Request $request, GraylogApi $api) + { + if (!$api->isConfigured()) { + return response()->json([ + 'error' => 'Graylog is not configured', + ], 503); + } + + $this->validate($request, [ + 'stream' => 'nullable|alpha_num', + 'device' => 'nullable|int', + 'range' => 'nullable|int', + ]); + + $search = $request->get('searchPhrase'); + $device_id = $request->get('device'); + $device = $device_id ? Device::find($device_id) : null; + $range = $request->get('range', 0) ; + $limit = $request->get('rowCount', 10); + $page = $request->get('current', 1); + $offset = ($page - 1) * $limit; + $query = $api->buildSimpleQuery($search, $device); + + $sort = null; + foreach ($request->get('sort', []) as $field => $direction) { + $sort = "$field:$direction"; + } + + $stream = $request->get('stream'); + $filter = $stream ? "streams:$stream" : null; + + try { + $data = $api->query($query, $range, $limit, $offset, $sort, $filter); + return $this->formatResponse( + array_map([$this, 'formatMessage'], $data['messages']), + $page, + count($data['messages']), + $data['total_results'] + ); + } catch (\Exception $se) { + $error = $se->getMessage(); + } + + return response()->json([ + 'error' => $error, + ], 500); + } + + private function formatMessage($message) + { + if ($this->timezone) { + $graylogTime = new DateTime($message['message']['timestamp']); + $offset = $this->timezone->getOffset($graylogTime); + + $timeInterval = DateInterval::createFromDateString((string)$offset . 'seconds'); + $graylogTime->add($timeInterval); + $displayTime = $graylogTime->format('Y-m-d H:i:s'); + } else { + $displayTime = $message['message']['timestamp']; + } + + return [ + 'severity' => $this->severityLabel($message['message']['level']), + 'timestamp' => $displayTime, + 'source' => ''.$message['message']['source'].'', + 'message' => $message['message']['message'], + 'facility' => isset($message['message']['facility']) ? $message['message']['facility'] : '', + 'level' => $message['message']['level'], + ]; + } + + private function severityLabel($severity) + { + $map = [ + "0" => "label-danger", + "1" => "label-danger", + "2" => "label-danger", + "3" => "label-danger", + "4" => "label-warning", + "5" => "label-info", + "6" => "label-info", + "7" => "label-default", + "" => "label-info", + ]; + $barColor = isset($map[$severity]) ? $map[$severity] : 'label-info'; + return ''; + } +} diff --git a/app/Http/Controllers/Table/SimpleTableController.php b/app/Http/Controllers/Table/SimpleTableController.php new file mode 100644 index 0000000000..cc4e012449 --- /dev/null +++ b/app/Http/Controllers/Table/SimpleTableController.php @@ -0,0 +1,72 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Table; + +use App\Http\Controllers\Controller; +use Illuminate\Http\Request; +use Illuminate\Support\Collection; + +abstract class SimpleTableController extends Controller +{ + public static $base_rules = [ + 'current' => 'int', + 'rowCount' => 'int', + 'searchPhrase' => 'nullable|string', + 'sort.*' => 'in:asc,desc', + ]; + + /** + * Validate the given request with the given rules. + * + * @param \Illuminate\Http\Request $request + * @param array $rules + * @param array $messages + * @param array $customAttributes + * @return void + */ + public function validate(Request $request, array $rules = [], array $messages = [], array $customAttributes = []) + { + $full_rules = array_replace(self::$base_rules, $rules); + parent::validate($request, $full_rules, $messages, $customAttributes); + } + + /** + * @param array|Collection $rows + * @param int $page + * @param int $currentCount + * @param int $total + * @return \Illuminate\Http\JsonResponse + */ + protected function formatResponse($rows, $page, $currentCount, $total) + { + return response()->json([ + 'current' => $page, + 'rowCount' => $currentCount, + 'rows' => $rows, + 'total' => $total, + ]); + } +} diff --git a/app/Http/Controllers/Table/TableController.php b/app/Http/Controllers/Table/TableController.php index 731ae047c1..f00d92964a 100644 --- a/app/Http/Controllers/Table/TableController.php +++ b/app/Http/Controllers/Table/TableController.php @@ -34,14 +34,13 @@ abstract class TableController extends PaginatedAjaxController { final protected function baseRules() { - return [ - 'current' => 'int', - 'rowCount' => 'int', - 'searchPhrase' => 'nullable|string', - 'sort.*' => 'in:asc,desc', - ]; + return SimpleTableController::$base_rules; } + /** + * @param Request $request + * @return \Illuminate\Http\JsonResponse + */ public function __invoke(Request $request) { $this->validate($request, $this->rules()); diff --git a/app/Http/Controllers/Widgets/AlertsController.php b/app/Http/Controllers/Widgets/AlertsController.php new file mode 100644 index 0000000000..8322aaa794 --- /dev/null +++ b/app/Http/Controllers/Widgets/AlertsController.php @@ -0,0 +1,74 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\DeviceGroup; +use Illuminate\Http\Request; + +class AlertsController extends WidgetController +{ + protected $title = 'Alerts'; + protected $defaults = [ + 'device' => null, + 'acknowledged' => null, + 'fired' => null, + 'min_severity' => null, + 'state' => null, + 'group' => null, + 'proc' => 0, + 'sort' => 1, + ]; + + public function getView(Request $request) + { + return view('widgets.alerts', $this->getSettings()); + } + + public function getSettingsView(Request $request) + { + $data = $this->getSettings(); + $data['severities'] = [ + // alert_rules.status is enum('ok','warning','critical') + 'ok' => 1, + 'warning' => 2, + 'critical' => 3, + 'ok only' => 4, + 'warning only' => 5, + 'critical only' => 6, + ]; + $data['states'] = [ + // divined from librenms/alerts.php + 'recovered' => '0', + 'alerted' => '1', + 'acknowledged' => '2', + 'worse' => '3', + 'better' => '4', + ]; + $data['device_group'] = DeviceGroup::find($data['group']); + + return view('widgets.settings.alerts', $data); + } +} diff --git a/app/Http/Controllers/Widgets/AvailabilityMapController.php b/app/Http/Controllers/Widgets/AvailabilityMapController.php new file mode 100644 index 0000000000..7ce4fd11cb --- /dev/null +++ b/app/Http/Controllers/Widgets/AvailabilityMapController.php @@ -0,0 +1,174 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use App\Models\DeviceGroup; +use App\Models\Service; +use App\Models\UserWidget; +use Illuminate\Http\Request; +use LibreNMS\Config; + +class AvailabilityMapController extends WidgetController +{ + protected $title = 'Availability Map'; + + public function __construct() + { + $this->defaults = [ + 'title' => null, + 'type' => (int)Config::get('webui.availability_map_compact', 0), + 'tile_size' => 12, + 'color_only_select' => 0, + 'show_disabled_and_ignored' => 0, + 'mode_select' => 0, + 'device_group' => 0, + ]; + } + + public function getView(Request $request) + { + $data = $this->getSettings(); + + $devices = []; + $device_totals = []; + $services = []; + $services_totals = []; + + $mode = $data['mode_select']; + if ($mode == 0 || $mode == 2) { + list($devices, $device_totals) = $this->getDevices($request); + } + if ($mode > 0) { + list($services, $services_totals) = $this->getServices($request); + } + + $data['device'] = Device::first(); + + $data['devices'] = $devices; + $data['device_totals'] = $device_totals; + $data['services'] = $services; + $data['services_totals'] = $services_totals; + + return view('widgets.availability-map', $data); + } + + + + public function getSettingsView(Request $request) + { + $settings = $this->getSettings(); + $settings['device_group'] = DeviceGroup::find($settings['device_group']); + + return view('widgets.settings.availability-map', $settings); + } + + /** + * @param Request $request + * @return array + */ + private function getDevices(Request $request) + { + $settings = $this->getSettings(); + + // filter for by device group or show all + if ($group_id = $settings['device_group']) { + $device_query = DeviceGroup::find($group_id)->devices()->hasAccess($request->user()); + } else { + $device_query = Device::hasAccess($request->user()); + } + + if (!$settings['show_disabled_and_ignored']) { + $device_query->where('disabled', 0); + } + $devices = $device_query->select('devices.device_id', 'hostname', 'sysName', 'status', 'uptime')->get(); + + // process status + $uptime_warn = Config::get('uptime_warning', 84600); + $totals = ['warn' => 0, 'up' => 0, 'down' => 0, 'ignored' => 0, 'disabled' => 0]; + foreach ($devices as $device) { + if ($device->disabled) { + $totals['disabled']++; + $device->stateName = "disabled"; + $device->labelClass = "blackbg"; + } elseif ($device->ignore) { + $totals['ignored']++; + $device->stateName = "ignored"; + $device->labelClass = "label-default"; + } elseif ($device->status == 1) { + if (($device->uptime < $uptime_warn) && ($device->uptime != 0)) { + $totals['warn']++; + $device->stateName = 'warn'; + $device->labelClass = 'label-warning'; + } else { + $totals['up']++; + $device->stateName = 'up'; + $device->labelClass = 'label-success'; + } + } else { + $totals['down']++; + $device->stateName = 'down'; + $device->labelClass = 'label-danger'; + } + } + return [$devices, $totals]; + } + + private function getServices($request) + { + $settings = $this->getSettings(); + + // filter for by device group or show all + if ($group_id = $settings['device_group']) { + $services_query = DeviceGroup::find($group_id)->services()->hasAccess($request->user()); + } else { + $services_query = Service::hasAccess($request->user()); + } + + $services = $services_query->with(['device' => function ($query) { + $query->select('devices.device_id', 'hostname', 'sysName'); + }])->select('service_id', 'device_id', 'service_type', 'service_desc', 'service_status')->get(); + + // process status + $totals = ['warn' => 0, 'up' => 0, 'down' => 0]; + foreach ($services as $service) { + if ($service->service_status == 0) { + $service->labelClass = "label-success"; + $service->stateName = "up"; + $totals['up']++; + } elseif ($service->service_status == 1) { + $service->labelClass = "label-warning"; + $service->stateName = "warn"; + $totals['warn']++; + } else { + $service->labelClass = "label-danger"; + $service->stateName = "down"; + $totals['down']++; + } + } + return [$services, $totals]; + } +} diff --git a/app/Http/Controllers/Widgets/ComponentStatusController.php b/app/Http/Controllers/Widgets/ComponentStatusController.php new file mode 100644 index 0000000000..ba3c177cef --- /dev/null +++ b/app/Http/Controllers/Widgets/ComponentStatusController.php @@ -0,0 +1,69 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Component; +use DB; +use Illuminate\Http\Request; +use Illuminate\View\View; + +class ComponentStatusController extends WidgetController +{ + protected $title = 'Component Status'; + + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + $status = [ + [ + 'color' => 'text-success', + 'text' => __('Ok'), + ], + [ + 'color' => 'grey', + 'text' => __('Warning'), + ], + [ + 'color' => 'text-danger', + 'text' => __('Critical'), + ] + ]; + + $component_status = Component::query() + ->select('status', DB::raw("count('status') as total")) + ->groupBy('status') + ->get()->pluck('total', 'status')->toArray(); + + foreach ($status as $key => $value) { + $status[$key]['total'] = isset($component_status[$key]) ? $component_status[$key] : 0; + } + + return view('widgets.component-status', compact('status')); + } +} diff --git a/app/Http/Controllers/Widgets/DeviceSummaryController.php b/app/Http/Controllers/Widgets/DeviceSummaryController.php new file mode 100644 index 0000000000..b2f86a259b --- /dev/null +++ b/app/Http/Controllers/Widgets/DeviceSummaryController.php @@ -0,0 +1,88 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use App\Models\Port; +use App\Models\Service; +use Illuminate\Http\Request; +use LibreNMS\Config; + +abstract class DeviceSummaryController extends WidgetController +{ + protected $title = 'Device Summary'; + + public function __construct() + { + // init defaults we need to check config, so do it in construct + $this->defaults = [ + 'show_services' => (int)Config::get('show_services', 1), + 'summary_errors' => (int)Config::get('summary_errors', 0) + ]; + } + + public function getSettingsView(Request $request) + { + $settings = $this->getSettings(); + + return view('widgets.settings.device-summary', $settings); + } + + protected function getData(Request $request) + { + $data = $this->getSettings(); + $user = $request->user(); + + $data['devices'] = [ + 'count' => Device::hasAccess($user)->count(), + 'up' => Device::hasAccess($user)->isUp()->count(), + 'down' => Device::hasAccess($user)->isDown()->count(), + 'ignored' => Device::hasAccess($user)->isIgnored()->count(), + 'disabled' => Device::hasAccess($user)->isDisabled()->count(), + ]; + + $data['ports'] = [ + 'count' => Port::hasAccess($user)->count(), + 'up' => Port::hasAccess($user)->isUp()->count(), + 'down' => Port::hasAccess($user)->isDown()->count(), + 'ignored' => Port::hasAccess($user)->isIgnored()->count(), + 'shutdown' => Port::hasAccess($user)->isShutdown()->count(), + 'errored' => $data['summary_errors'] ? Port::hasAccess($user)->hasErrors()->count() : -1, + ]; + + if ($data['show_services']) { + $data['services'] = [ + 'count' => Service::hasAccess($user)->count(), + 'up' => Service::hasAccess($user)->isUp()->count(), + 'down' => Service::hasAccess($user)->isDown()->count(), + 'ignored' => Service::hasAccess($user)->isIgnored()->count(), + 'disabled' => Service::hasAccess($user)->isDisabled()->count(), + ]; + } + + return $data; + } +} diff --git a/app/Http/Controllers/Widgets/DeviceSummaryHorizController.php b/app/Http/Controllers/Widgets/DeviceSummaryHorizController.php new file mode 100644 index 0000000000..1c9cd1332a --- /dev/null +++ b/app/Http/Controllers/Widgets/DeviceSummaryHorizController.php @@ -0,0 +1,41 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use Illuminate\Http\Request; +use Illuminate\View\View; + +class DeviceSummaryHorizController extends DeviceSummaryController +{ + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + return view('widgets.device-summary-horiz', $this->getData($request)); + } +} diff --git a/app/Http/Controllers/Widgets/DeviceSummaryVertController.php b/app/Http/Controllers/Widgets/DeviceSummaryVertController.php new file mode 100644 index 0000000000..b97218b047 --- /dev/null +++ b/app/Http/Controllers/Widgets/DeviceSummaryVertController.php @@ -0,0 +1,41 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use Illuminate\Http\Request; +use Illuminate\View\View; + +class DeviceSummaryVertController extends DeviceSummaryController +{ + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + return view('widgets.device-summary-vert', $this->getData($request)); + } +} diff --git a/app/Http/Controllers/Widgets/EventlogController.php b/app/Http/Controllers/Widgets/EventlogController.php new file mode 100644 index 0000000000..edd2a4146c --- /dev/null +++ b/app/Http/Controllers/Widgets/EventlogController.php @@ -0,0 +1,53 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use Illuminate\Http\Request; + +class EventlogController extends WidgetController +{ + protected $title = 'Eventlog'; + protected $defaults = [ + 'title' => null, + 'device' => null, + 'eventtype' => null, + ]; + + public function getSettingsView(Request $request) + { + $data = $this->getSettings(); + + $data['device'] = Device::hasAccess($request->user())->find($data['device']); + + return view('widgets.settings.eventlog', $data); + } + + public function getView(Request $request) + { + return view('widgets.eventlog', $this->getSettings()); + } +} diff --git a/app/Http/Controllers/Widgets/GlobeController.php b/app/Http/Controllers/Widgets/GlobeController.php new file mode 100644 index 0000000000..9a46f32732 --- /dev/null +++ b/app/Http/Controllers/Widgets/GlobeController.php @@ -0,0 +1,111 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Location; +use Illuminate\Http\Request; +use Illuminate\View\View; +use LibreNMS\Config; + +class GlobeController extends WidgetController +{ + protected $title = 'Globe'; + + public function __construct() + { + // init defaults we need to check config, so do it in construct + $this->defaults = [ + 'title' => null, + 'markers' => Config::get('frontpage_globe.markers', 'devices'), + 'region' => Config::get('frontpage_globe.region', 'world'), + 'resolution' => Config::get('frontpage_globe.resolution', 'countries'), + ]; + } + + public function getSettingsView(Request $request) + { + return view('widgets.settings.globe', $this->getSettings()); + } + + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + $data = $this->getSettings(); + $locations = collect(); + + $eager_load = $data['markers'] == 'ports' ? ['devices.ports'] : ['devices']; + + /** @var Location $location */ + foreach (Location::hasAccess($request->user())->with($eager_load)->get() as $location) { + $count = 0; + $up = 0; + $down_items = collect(); + + if ($data['markers'] == 'devices') { + $count = $location->devices->count(); + list($devices_down, $devices_up) = $location->devices->partition(function ($device) { + return $device->disable = 0 && $device->ignore = 0 && $device->status = 0; + }); + $up = $devices_up->count(); + $down_items = $devices_down->map(function ($device) { + return $device->displayName() . ' DOWN'; + }); + } elseif ($data['markers'] == 'ports') { + foreach ($location->devices as $device) { + list($ports_down, $ports_up) = $device->ports->partition(function ($port) { + return $port->ifOperStatus == 'down' && $port->ifAdminStatus == 'up'; + }); + $count += $device->ports->count(); + $up += $ports_up->count(); + $down_items = $ports_down->map(function ($port) use ($device) { + return $device->displayName() . '/' . $port->getShortLabel() . ' DOWN'; + }); + } + } + + // indicate the number of up items before the itemized down + $down_items->prepend($up . ' ' . ucfirst($data['markers']) . ' OK'); + + if ($count > 0) { + $locations->push([ + $location->lat, + $location->lng, + $location->location, + $count ? (1 - $up / $count) * 100 : 0, // percent down + $count, + $down_items->implode(',
'), + ]); + } + } + + $data['locations'] = $locations->toJson(); + + return view('widgets.globe', $data); + } +} diff --git a/app/Http/Controllers/Widgets/GraphController.php b/app/Http/Controllers/Widgets/GraphController.php new file mode 100644 index 0000000000..22e9d95caf --- /dev/null +++ b/app/Http/Controllers/Widgets/GraphController.php @@ -0,0 +1,270 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Application; +use App\Models\Bill; +use App\Models\Device; +use App\Models\MuninPlugin; +use App\Models\Port; +use App\Models\UserWidget; +use Carbon\Carbon; +use Illuminate\Http\Request; +use Illuminate\View\View; +use LibreNMS\Config; +use LibreNMS\Util\Graph; +use LibreNMS\Util\Time; + +class GraphController extends WidgetController +{ + protected $title = 'Graph'; + protected $defaults = [ + 'title' => null, + 'graph_type' => null, + 'graph_range' => 'oneday', + 'graph_legend' => 'yes', + 'graph_device' => null, + 'graph_port' => null, + 'graph_application' => null, + 'graph_munin' => null, + 'graph_ports' => [], + 'graph_custom' => [], + 'graph_manual' => null, + 'graph_bill' => null, + ]; + + public function title() + { + $settings = $this->getSettings(); + + if (!empty($settings['title'])) { + return $settings['title']; + } + + // automatic title + $type = $this->getGraphType(); + if ($type == 'device') { + $device = Device::find($settings['graph_device']); + return ($device ? $device->displayName() : 'Device') . ' / ' . $settings['graph_type']; + } elseif ($type == 'aggregate') { + return 'Overall ' . $this->getGraphType(false) . ' Bits (' . $settings['graph_range'] . ')'; + } elseif ($type == 'port') { + if ($port = Port::find($settings['graph_port'])) { + return $port->device->displayName() . ' / ' . $port->getShortLabel() . ' / ' . $settings['graph_type']; + } + } elseif ($type == 'application') { + if ($application = Application::find($settings['graph_application'])) { + return $application->device->displayName() . ' / ' . $application->app_type . ' / ' . $settings['graph_type']; + } + } elseif ($type == 'bill') { + if ($bill = Bill::find($settings['graph_bill'])) { + return 'Bill: ' . $bill->bill_name; + } + } elseif ($type == 'munin') { + if ($munin = MuninPlugin::find($settings['graph_munin'])) { + return $munin->device->displayName() . ' / ' . $munin->mplug_type . ' / ' . $settings['graph_type']; + } + } + + // fall back for types where we couldn't find the item + if ($settings['graph_type']) { + return 'Device / ' . ucfirst($type) . ' / ' . $settings['graph_type']; + } + + return $this->title; + } + + public function getSettingsView(Request $request) + { + $data = $this->getSettings(); + + // format display name for selected graph type + $type_parts = explode('_', $data['graph_type']); + $primary = array_shift($type_parts); + $secondary = implode('_', $type_parts); + $name = $primary . ' ' . (Graph::isMibGraph($primary, $secondary) ? $secondary : implode(' ', $type_parts)); + + // format display for selected items + if ($primary == 'device' && $data['graph_device']) { + $device = Device::find($data['graph_device']); + } + $data['device_text'] = isset($device) ? $device->displayName() : __('Device does not exist'); + + if ($primary == 'port' && $data['graph_port']) { + $port = Port::find($data['graph_port']); + } + $data['port_text'] = isset($port) ? $port->getLabel() : __('Port does not exist'); + + if ($primary == 'application' && $data['graph_application']) { + $app = Application::find($data['graph_application']); + } + $data['application_text'] = isset($app) ? $app->displayName() . ' - ' . $app->device->displayName() : __('App does not exist'); + + if ($primary == 'bill' && $data['graph_bill']) { + $bill = Bill::find($data['graph_bill']); + } + $data['bill_text'] = isset($bill) ? $bill->bill_name : __('Bill does not exist'); + + if ($primary == 'munin' && $data['graph_munin']) { + $mplug = MuninPlugin::with('device')->find($data['graph_munin']); + } + $data['munin_text'] = isset($mplug) ? $mplug->device->displayName() . ' - ' . $mplug->mplug_type : __('Munin plugin does not exist'); + + $data['graph_ports'] = Port::whereIn('port_id', $data['graph_ports']) + ->select('ports.device_id', 'port_id', 'ifAlias', 'ifName', 'ifDescr') + ->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName'); + }])->get(); + + $data['graph_port_ids'] = $data['graph_ports']->pluck('port_id')->toJson(); + + $data['graph_text'] = ucwords($name); + + return view('widgets.settings.graph', $data); + } + + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + $settings = $this->getSettings(); + + // get type + $type = $this->getGraphType(); + + // force settings if not initialized + if (is_null($type) || empty($settings['graph_' . $this->getGraphType(false)])) { + return $this->getSettingsView($request); + } + + $param = ''; + + if ($type == 'device') { + $param = 'device='.$settings['graph_device']; + } elseif ($type == 'application') { + $param = 'id='.$settings['graph_application']; + } elseif ($type == 'munin') { + if ($mplug = MuninPlugin::find($settings['graph_munin'])) { + $param = 'device='.$mplug->device_id.'&plugin='.$mplug->mplug_type; + } + } elseif ($type == 'aggregate') { + $aggregate_type = $this->getGraphType(false); + if ($aggregate_type == 'custom') { + $aggregate_type = $settings['graph_custom']; + } + + if ($aggregate_type == 'ports') { + $port_ids = $settings['graph_ports']; + } else { + $port_types = collect((array)$aggregate_type)->map(function ($type) { + // check for config definitions + if (Config::has("{$type}_descr")) { + return Config::get("{$type}_descr", []); + } + + return $type; + })->flatten(); + + $port_ids = Port::hasAccess($request->user())->where(function ($query) use ($port_types) { + foreach ($port_types as $port_type) { + $port_type = str_replace('@', '%', $port_type); + $query->orWhere('port_descr_type', 'LIKE', $port_type); + } + })->pluck('port_id')->all(); + } + + $param = 'id=' . implode(',', $port_ids); + $settings['graph_type'] = 'multiport_bits_separate'; + } else { + $param = 'id='.$settings['graph_'.$type]; + } + + $data = $settings; + $data['param'] = $param; + $data['dimensions'] = $request->get('dimensions'); + $data['from'] = Carbon::now()->subSeconds(Time::legacyTimeSpecToSecs($settings['graph_range']))->timestamp; + $data['to'] = Carbon::now()->timestamp; + + return view('widgets.graph', $data); + } + + private function getGraphType($summarize = true) + { + $type = explode('_', $this->getSettings()['graph_type'], 2)[0]; + + if ($summarize && in_array($type, ['transit', 'peering', 'core', 'ports', 'custom'])) { + return 'aggregate'; + } + + return $type; + } + + public function getSettings() + { + if (is_null($this->settings)) { + $id = \Request::get('id'); + $widget = UserWidget::findOrFail($id); + $settings = array_replace($this->defaults, (array)$widget->settings); + $settings['id'] = $id; + + // legacy data conversions + if ($settings['graph_type'] == 'manual') { + $settings['graph_type'] = 'custom'; + $settings['graph_custom'] = explode(',', $settings['graph_manual']); + } + if ($settings['graph_type'] == 'transpeer') { + $settings['graph_type'] = 'custom'; + $settings['graph_custom'] = ['transit', 'peer']; + } + + $settings['graph_device'] = $this->convertLegacySettingId($settings['graph_device'], 'device_id'); + $settings['graph_port'] = $this->convertLegacySettingId($settings['graph_port'], 'port_id'); + $settings['graph_application'] = $this->convertLegacySettingId($settings['graph_application'], 'app_id'); + $settings['graph_munin'] = $this->convertLegacySettingId($settings['graph_munin'], 'mplug_id'); + $settings['graph_bill'] = $this->convertLegacySettingId($settings['graph_bill'], 'bill_id'); + + $settings['graph_custom'] = (array)$settings['graph_custom']; + $settings['graph_ports'] = (array)$settings['graph_ports']; + + + $this->settings = $settings; + } + + return $this->settings; + } + + private function convertLegacySettingId($setting, $key) + { + if ($setting && !is_numeric($setting)) { + $data = json_decode($setting, true); + return isset($data[$key]) ? $data[$key] : 0; + } + + return $setting; + } +} diff --git a/app/Http/Controllers/Widgets/GraylogController.php b/app/Http/Controllers/Widgets/GraylogController.php new file mode 100644 index 0000000000..dbc4713c2a --- /dev/null +++ b/app/Http/Controllers/Widgets/GraylogController.php @@ -0,0 +1,62 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use Illuminate\Http\Request; +use Illuminate\View\View; + +class GraylogController extends WidgetController +{ + protected $title = 'Graylog'; + protected $defaults = [ + 'title' => null, + 'stream' => null, + 'device' => null, + 'range' => null, + 'limit' => 15, + ]; + + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + return view('widgets.graylog', $this->getSettings()); + } + + public function getSettingsView(Request $request) + { + $data = $this->getSettings(); + + if ($data['device']) { + $data['device'] = Device::find($data['device']); + } + + return view('widgets.settings.graylog', $data); + } +} diff --git a/app/Http/Controllers/Widgets/ImageController.php b/app/Http/Controllers/Widgets/ImageController.php new file mode 100644 index 0000000000..52cd03b1d4 --- /dev/null +++ b/app/Http/Controllers/Widgets/ImageController.php @@ -0,0 +1,79 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use Illuminate\Http\Request; + +class ImageController extends WidgetController +{ + protected $title = 'Custom Image'; + protected $defaults = [ + 'title' => null, + 'image_url' => null, + 'target_url' => null, + ]; + + public function getView(Request $request) + { + $data = $this->getSettings(); + + if (is_null($data['image_url'])) { + return $this->getSettingsView($request); + } + + $dimensions = $request->get('dimensions'); + $data['dimensions'] = $dimensions; + + // send size so generated images can generate the proper size + $data['image_url'] = str_replace(['@AUTO_HEIGHT@', '@AUTO_WIDTH@'], [$dimensions['y'], $dimensions['x']], $data['image_url']); + + // bust cache + if (str_contains($data['image_url'], '?')) { + $data['image_url'] .= '&' . mt_rand(); + } else { + $data['image_url'] .= '?' . mt_rand(); + } + + return view('widgets.image', $data); + } + + public function getSettingsView(Request $request) + { + return view('widgets.settings.image', $this->getSettings()); + } + + public function getSettings() + { + if (is_null($this->settings)) { + parent::getSettings(); + if (!empty($this->settings['image_title'])) { + $this->settings['title'] = $this->settings['image_title']; + } + } + + return $this->settings; + } +} diff --git a/app/Http/Controllers/Widgets/NotesController.php b/app/Http/Controllers/Widgets/NotesController.php new file mode 100644 index 0000000000..c2b11b3b45 --- /dev/null +++ b/app/Http/Controllers/Widgets/NotesController.php @@ -0,0 +1,63 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use Illuminate\Http\Request; +use Illuminate\View\View; +use LibreNMS\Util\Html; + +class NotesController extends WidgetController +{ + protected $title = 'Notes'; + protected $defaults = [ + 'title' => null, + 'notes' => null, + ]; + + public function getView(Request $request) + { + $settings = $this->getSettings(); + + if (is_null($settings['notes'])) { + return $this->getSettingsView($request); + } + + $purifier_config = [ + 'HTML.Allowed' => 'b,iframe[frameborder|src|width|height],i,ul,ol,li,h1,h2,h3,h4,br,p,pre', + 'HTML.Trusted' => true, + 'HTML.SafeIframe' => true, + 'URI.SafeIframeRegexp' => '%^(https?:)?//%', + ]; + $output = Html::display(nl2br($settings['notes']), $purifier_config); + + return $output; + } + + public function getSettingsView(Request $request) + { + return view('widgets.settings.notes', $this->getSettings()); + } +} diff --git a/app/Http/Controllers/Widgets/PlaceholderController.php b/app/Http/Controllers/Widgets/PlaceholderController.php new file mode 100644 index 0000000000..4b9fc82c8e --- /dev/null +++ b/app/Http/Controllers/Widgets/PlaceholderController.php @@ -0,0 +1,38 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use Illuminate\Http\Request; + +class PlaceholderController extends WidgetController +{ + protected $title = 'Placeholder'; + + public function getView(Request $request) + { + return view('widgets.placeholder'); + } +} diff --git a/app/Http/Controllers/Widgets/ServerStatsController.php b/app/Http/Controllers/Widgets/ServerStatsController.php new file mode 100644 index 0000000000..96fd90e9d6 --- /dev/null +++ b/app/Http/Controllers/Widgets/ServerStatsController.php @@ -0,0 +1,93 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use Illuminate\Http\Request; + +class ServerStatsController extends WidgetController +{ + protected $title = 'Server Stats'; + protected $defaults = [ + 'title' => null, + 'columnsize' => 3, + 'device' => null, + 'cpu' => 0, + 'mempools' => [], + 'disks' => [], + ]; + + public function title(Request $request) + { + $settings = $this->getSettings(); + if ($settings['title']) { + return $settings['title']; + } + + /** @var Device $device */ + $device = Device::hasAccess($request->user())->find($settings['device']); + if ($device) { + return $device->displayName() . ' Stats'; + } + + return $this->title; + } + + public function getView(Request $request) + { + $data = $this->getSettings(); + + if (is_null($data['device'])) { + return $this->getSettingsView($request); + } + + /** @var Device $device */ + $device = Device::hasAccess($request->user())->find($data['device']); + if ($device) { + $data['cpu'] = $device->processors()->avg('processor_usage'); + $data['mempools'] = $device->mempools()->select(\DB::raw('mempool_descr, ROUND(mempool_used / (1024*1024), 0) as used, ROUND(mempool_total /(1024*1024), 0) as total'))->get(); + $data['disks'] = $device->storage()->select(\DB::raw('storage_descr, ROUND(storage_used / (1024*1024), 0) as used, ROUND(storage_size / (1024*1024), 0) as total'))->get(); + } + + return view('widgets.server-stats', $data); + } + + public function getSettingsView(Request $request) + { + $settings = $this->getSettings(); + $settings['device'] = Device::hasAccess($request->user())->find($settings['device']) ?: null; + + return view('widgets.settings.server-stats', $settings); + } + + public function getSettings() + { + $settings = parent::getSettings(); + $settings['columns'] = 12 / $settings['columnsize']; + + return $settings; + } +} diff --git a/app/Http/Controllers/Widgets/SyslogController.php b/app/Http/Controllers/Widgets/SyslogController.php new file mode 100644 index 0000000000..6bff46ff80 --- /dev/null +++ b/app/Http/Controllers/Widgets/SyslogController.php @@ -0,0 +1,52 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use Illuminate\Http\Request; + +class SyslogController extends WidgetController +{ + protected $title = 'Syslog'; + protected $defaults = [ + 'title' => null, + 'device' => null, + ]; + + public function getSettingsView(Request $request) + { + $data = $this->getSettings(); + + $data['device'] = Device::hasAccess($request->user())->find($data['device']); + + return view('widgets.settings.syslog', $data); + } + + public function getView(Request $request) + { + return view('widgets.syslog', $this->getSettings()); + } +} diff --git a/app/Http/Controllers/Widgets/TopDevicesController.php b/app/Http/Controllers/Widgets/TopDevicesController.php new file mode 100644 index 0000000000..22affe24e2 --- /dev/null +++ b/app/Http/Controllers/Widgets/TopDevicesController.php @@ -0,0 +1,305 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use App\Models\Mempool; +use App\Models\Port; +use App\Models\Processor; +use App\Models\Storage; +use Auth; +use Carbon\Carbon; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\Request; +use Illuminate\Support\Collection; +use Illuminate\View\View; +use LibreNMS\Util\Colors; +use LibreNMS\Util\Html; +use LibreNMS\Util\StringHelpers; +use LibreNMS\Util\Url; + +class TopDevicesController extends WidgetController +{ + protected $title = 'Top Devices'; + protected $defaults = [ + 'title' => null, + 'top_query' => 'traffic', + 'sort_order' => 'asc', + 'device_count' => 5, + 'time_interval' => 15, + ]; + + public function title() + { + $settings = $this->getSettings(); + return isset($settings['title']) ? $settings['title'] : $this->title; + } + + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + $settings = $this->getSettings(); + $sort = $settings['sort_order']; + + switch ($settings['top_query']) { + case 'traffic': + $data = $this->getTrafficData($sort); + break; + case 'uptime': + $data = $this->getUptimeData($sort); + break; + case 'ping': + $data = $this->getPingData($sort); + break; + case 'cpu': + $data = $this->getProcessorData($sort); + break; + case 'ram': + $data = $this->getMemoryData($sort); + break; + case 'poller': + $data = $this->getPollerData($sort); + break; + case 'storage': + $data = $this->getStorageData($sort); + break; + default: + $data = []; + } + + return view('widgets.top-devices', $data); + } + + public function getSettingsView(Request $request) + { + return view('widgets.settings.top-devices', $this->getSettings()); + } + + /** + * @param array|string $headers + * @param Collection $rows + * @return array + */ + private function formatData($headers, $rows) + { + return [ + 'headers' => (array)$headers, + 'rows' => $rows, + ]; + } + + /** + * @param Builder $query + * @param string $left_table + * @return Builder + */ + private function withDeviceQuery($query, $left_table) + { + $settings = $this->getSettings(); + + /** @var Builder $query */ + return $query->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName', 'status'); + }]) + ->select("$left_table.device_id") + ->leftJoin('devices', "$left_table.device_id", 'devices.device_id') + ->groupBy("$left_table.device_id") + ->where('devices.last_polled', '>', Carbon::now()->subMinutes($settings['time_interval'])); + } + + /** + * @param Builder $query + * @return Builder + */ + private function deviceQuery() + { + $settings = $this->getSettings(); + + return Device::hasAccess(Auth::user())->select('device_id', 'hostname', 'sysName', 'status') + ->where('devices.last_polled', '>', Carbon::now()->subMinutes($settings['time_interval'])) + ->limit($settings['device_count']); + } + + /** + * @param Device $device + * @param string $graph_type + * @param array $graph_params + * @return array + */ + private function standardRow($device, $graph_type, $graph_params = []) + { + return [ + Url::deviceLink($device, $device->shortDisplayName()), + Url::deviceLink($device, Url::minigraphImage( + $device, + Carbon::now()->subDays(1)->timestamp, + Carbon::now()->timestamp, + $graph_type, + 'no', + 150, + 21 + ), $graph_params, 0, 0, 0), + ]; + } + + private function getTrafficData($sort) + { + $settings = $this->getSettings(); + + /** @var Builder $query */ + $query = Port::hasAccess(Auth::user())->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName', 'status'); + }]) + ->select('device_id') + ->groupBy('device_id') + ->where('poll_time', '>', Carbon::now()->subMinutes($settings['time_interval'])->timestamp) + ->has('device') + ->orderByRaw('SUM(ifInOctets_rate + ifOutOctets_rate) ' . $sort) + ->limit($settings['device_count']); + + $results = $query->get()->map(function ($port) { + return $this->standardRow($port->device, 'device_bits'); + }); + + return $this->formatData('Traffic', $results); + } + + private function getUptimeData($sort) + { + /** @var Builder $query */ + $query = $this->deviceQuery()->orderBy('uptime', $sort); + + $results = $query->get()->map(function ($device) { + return $this->standardRow($device, 'device_uptime', ['tab' => 'graphs', 'group' => 'system']); + }); + + return $this->formatData('Uptime', $results); + } + + private function getPingData($sort) + { + /** @var Builder $query */ + $query = $this->deviceQuery()->orderBy('last_ping_timetaken', $sort); + + $results = $query->get()->map(function ($device) { + return $this->standardRow($device, 'device_ping_perf', ['tab' => 'graphs', 'group' => 'poller']); + }); + + return $this->formatData('Response time', $results); + } + + private function getProcessorData($sort) + { + /** @var Builder $query */ + $query = $this->withDeviceQuery(Processor::hasAccess(Auth::user()), (new Processor)->getTable()) + ->orderByRaw('AVG(`processor_usage`) ' . $sort); + + $results = $query->get()->map(function ($port) { + return $this->standardRow($port->device, 'device_processor', ['tab' => 'health', 'metric' => 'processor']); + }); + + return $this->formatData('CPU Load', $results); + } + + private function getMemoryData($sort) + { + /** @var Builder $query */ + $query = $this->withDeviceQuery(Mempool::hasAccess(Auth::user()), (new Mempool)->getTable()) + ->orderBy('mempool_perc', $sort); + + $results = $query->get()->map(function ($port) { + return $this->standardRow($port->device, 'device_mempool', ['tab' => 'health', 'metric' => 'mempool']); + }); + + return $this->formatData('Memory usage', $results); + } + + private function getPollerData($sort) + { + /** @var Builder $query */ + $query = $this->deviceQuery()->orderBy('last_polled_timetaken', $sort); + + $results = $query->get()->map(function ($device) { + return $this->standardRow($device, 'device_poller_perf', ['tab' => 'graphs', 'group' => 'poller']); + }); + + return $this->formatData('Poller duration', $results); + } + + private function getStorageData($sort) + { + $settings = $this->getSettings(); + + /** @var Builder $query */ + $query = Storage::hasAccess(Auth::user())->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName', 'status'); + }]) + ->leftJoin('devices', 'storage.device_id', 'devices.device_id') + ->select('storage.device_id', 'storage_id', 'storage_descr', 'storage_perc', 'storage_perc_warn') + ->where('devices.last_polled', '>', Carbon::now()->subMinutes($settings['time_interval'])) + ->orderBy('storage_perc', $sort) + ->limit($settings['device_count']); + + + $results = $query->get()->map(function ($storage) { + $device = $storage->device; + + $graph_array = [ + 'height' => 100, + 'width' => 210, + 'to' => Carbon::now()->timestamp, + 'from' => Carbon::now()->subDay()->timestamp, + 'id' => $storage->storage_id, + 'type' => 'device_storage', + 'legend' => 'no', + ]; + $overlib_content = Url::overlibContent($graph_array, $device->displayName() . ' - ' . $storage->storage_descr); + + $link_array = $graph_array; + $link_array['page'] = 'graphs'; + unset($link_array['height'], $link_array['width'], $link_array['legend']); + $link = Url::generate($link_array); + + $percent = $storage->storage_perc; + $background = Colors::percentage($percent, $storage->storage_perc_warn); + + return [ + Url::deviceLink($device, $device->shortDisplayName()), + StringHelpers::shortenText($storage->storage_descr, 50), + Url::overlibLink( + $link, + Html::percentageBar(150, 20, $percent, null, 'ffffff', $background['left'], $percent.'%', 'ffffff', $background['right']), + $overlib_content + ) + ]; + }); + + return $this->formatData(['Storage Device', 'Disk usage'], $results); + } +} diff --git a/app/Http/Controllers/Widgets/TopInterfacesController.php b/app/Http/Controllers/Widgets/TopInterfacesController.php new file mode 100644 index 0000000000..e4c50764ee --- /dev/null +++ b/app/Http/Controllers/Widgets/TopInterfacesController.php @@ -0,0 +1,73 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Port; +use Carbon\Carbon; +use Illuminate\Http\Request; +use Illuminate\View\View; + +class TopInterfacesController extends WidgetController +{ + protected $title = 'Top Interfaces'; + protected $defaults = [ + 'interface_count' => 5, + 'time_interval' => 15, + 'interface_filter' => null, + ]; + + /** + * @param Request $request + * @return View + */ + public function getView(Request $request) + { + $data = $this->getSettings(); + + $query = Port::hasAccess($request->user())->with(['device' => function ($query) { + $query->select('device_id', 'hostname', 'sysName', 'status'); + }]) + ->select('port_id', 'device_id', 'ifName', 'ifDescr', 'ifAlias') + ->groupBy('port_id', 'device_id', 'ifName', 'ifDescr', 'ifAlias') + ->where('poll_time', '>', Carbon::now()->subMinutes($data['time_interval'])) + ->orderByRaw('SUM(ifInOctets_rate + ifOutOctets_rate) DESC') + ->limit($data['interface_count']); + + if ($data['interface_filter']) { + $query->where('ifType', '=', $data['interface_filter']); + } + + $data['ports'] = $query->get(); + + return view('widgets.top-interfaces', $data); + } + + + public function getSettingsView(Request $request) + { + return view('widgets.settings.top-interfaces', $this->getSettings()); + } +} diff --git a/app/Http/Controllers/Widgets/WidgetController.php b/app/Http/Controllers/Widgets/WidgetController.php new file mode 100644 index 0000000000..c54216edb0 --- /dev/null +++ b/app/Http/Controllers/Widgets/WidgetController.php @@ -0,0 +1,105 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Http\Controllers\Controller; +use App\Models\UserWidget; +use Illuminate\Http\Request; +use Illuminate\View\View; + +abstract class WidgetController extends Controller +{ + /** @var string sets the title for this widget, use title() function if you need to dynamically generate */ + protected $title = 'Widget'; + + /** @var array Set default values for settings */ + protected $defaults = []; + + private $show_settings = false; + protected $settings = null; + + /** + * @param Request $request + * @return View + */ + abstract public function getView(Request $request); + + /** + * @param Request $request + * @return View + */ + public function getSettingsView(Request $request) + { + return view('widgets.settings.base'); + } + + public function __invoke(Request $request) + { + $this->show_settings = (bool)$request->get('settings'); + + if ($this->show_settings) { + $view = $this->getSettingsView($request); + } else { + $view = $this->getView($request); + } + + $settings = $this->getSettings(); + if (!empty($settings['title'])) { + $title = $settings['title']; + } else { + $title = __(method_exists($this, 'title') ? app()->call([$this, 'title']) : $this->title); + } + + return $this->formatResponse($view, $title, $settings); + } + + /** + * Get the settings (with defaults applied) + * + * @return array + */ + public function getSettings() + { + if (is_null($this->settings)) { + $id = \Request::get('id'); + $widget = UserWidget::find($id); + $this->settings = array_replace($this->defaults, $widget ? (array)$widget->settings : []); + $this->settings['id'] = $id; + } + + return $this->settings; + } + + private function formatResponse($view, $title, $settings, $status = 'ok') + { + return response()->json([ + 'status' => $status, + 'title' => __($title), + 'html' => is_string($view) ? $view : $view->__toString(), + 'settings' => $settings, + ]); + } +} diff --git a/app/Http/Controllers/Widgets/WorldMapController.php b/app/Http/Controllers/Widgets/WorldMapController.php new file mode 100644 index 0000000000..89c3458b72 --- /dev/null +++ b/app/Http/Controllers/Widgets/WorldMapController.php @@ -0,0 +1,99 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Widgets; + +use App\Models\Device; +use App\Models\Location; +use Illuminate\Http\Request; +use Illuminate\Support\Collection; +use LibreNMS\Config; + +class WorldMapController extends WidgetController +{ + protected $title = 'World Map'; + + public function __construct() + { + $this->defaults = [ + 'title' => null, + 'title_url' => Config::get('leaflet.tile_url', '{s}.tile.openstreetmap.org'), + 'init_lat' => Config::get('leaflet.default_lat', 51.4800), + 'init_lng' => Config::get('leaflet.default_lng', 0), + 'init_zoom' => Config::get('leaflet.default_zoom', 2), + 'group_radius' => Config::get('leaflet.group_radius', 80), + 'status' => '0,1', + ]; + } + + + public function getView(Request $request) + { + $settings = $this->getSettings(); + $status = explode(',', $settings['status']); + + $settings['dimensions'] = $request->get('dimensions'); + + $devices = Device::hasAccess($request->user()) + ->with('location') + ->where('disabled', 0) + ->whereIn('status', $status) + ->get() + ->filter(function ($device) use ($status) { + if (!($device->location_id && $device->location->coordinatesValid())) { + return false; + } + + // add extra data + $device->markerIcon = 'greenMarker'; + $device->zOffset = 0; + + if ($device->status == 0) { + $device->markerIcon = 'redMarker'; + $device->zOffset = 10000; + +// TODO if ($device->isUnderMaintenance()) + if (false) { + if ($status == 0) { + return false; + } + $device->markerIcon = 'blueMarker'; + $device->zOffset = 5000; + } + } + + return true; + }); + + $settings['devices'] = $devices; + + return view('widgets.worldmap', $settings); + } + + public function getSettingsView(Request $request) + { + return view('widgets.settings.worldmap', $this->getSettings()); + } +} diff --git a/app/Models/Bill.php b/app/Models/Bill.php new file mode 100644 index 0000000000..d995630959 --- /dev/null +++ b/app/Models/Bill.php @@ -0,0 +1,53 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Models; + +use Illuminate\Database\Eloquent\Model; + +class Bill extends Model +{ + public $timestamps = false; + protected $primaryKey = 'bill_id'; + + // ---- Query Scopes ---- + + public function scopeHasAccess($query, User $user) + { + if ($user->hasGlobalRead()) { + return $query; + } + + return $query->join('bill_perms', 'bill_perms.bill_id', "bills.bill_id") + ->where('bill_perms.user_id', $user->user_id); + } + + // ---- Define Relationships ---- + + public function ports() + { + return $this->belongsToMany('App\Models\Port', 'bill_ports', 'bill_id', 'bill_id'); + } +} diff --git a/app/Models/Dashboard.php b/app/Models/Dashboard.php index 9296e91c82..3b90ba2839 100644 --- a/app/Models/Dashboard.php +++ b/app/Models/Dashboard.php @@ -11,11 +11,31 @@ class Dashboard extends Model protected $primaryKey = 'dashboard_id'; protected $fillable = ['user_id', 'dashboard_name', 'access']; + // ---- Helper Functions --- + + /** + * @param User $user + * @return bool + */ + public function canRead($user) + { + return $this->user_id == $user->user_id || $this->access > 0; + } + + /** + * @param User $user + * @return bool + */ + public function canWrite($user) + { + return $this->user_id == $user->user_id || $this->access > 1; + } + // ---- Query scopes ---- /** * @param Builder $query - * @param $user + * @param User $user * @return Builder|static */ public function scopeAllAvailable(Builder $query, $user) @@ -24,19 +44,13 @@ class Dashboard extends Model ->orWhere('access', '>', 0); } - // ---- Define Reletionships ---- + // ---- Define Relationships ---- - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ public function user() { return $this->belongsTo('App\Models\User', 'user_id'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ public function widgets() { return $this->hasMany('App\Models\UserWidget', 'dashboard_id'); diff --git a/app/Models/Device.php b/app/Models/Device.php index e95d27556c..16550b036e 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -251,6 +251,18 @@ class Device extends BaseModel return asset('images/os/generic.svg'); } + /** + * Get list of enabled graphs for this device. + * + * @return \Illuminate\Support\Collection + */ + public function graphs() + { + return DB::table('device_graphs') + ->where('device_id', $this->device_id) + ->pluck('graph'); + } + /** * Update the max_depth field based on parents * Performs SQL query, so make sure all parents are saved first @@ -301,19 +313,21 @@ class Device extends BaseModel /** * @return string */ - public function statusColour() + public function statusName() { - $status = $this->status; - $ignore = $this->ignore; - $disabled = $this->disabled; - if ($disabled == 1) { - return 'teal'; - } elseif ($ignore == 1) { - return 'yellow'; - } elseif ($status == 0) { - return 'danger'; + if ($this->disabled == 1) { + return 'disabled'; + } elseif ($this->ignore == 1) { + return 'ignore'; + } elseif ($this->status == 0) { + return 'down'; } else { - return 'success'; + $warning_time = \LibreNMS\Config::get('uptime_warning', 84600); + if ($this->uptime < $warning_time && $this->uptime != 0) { + return 'warn'; + } + + return 'up'; } } diff --git a/app/Models/DeviceGroup.php b/app/Models/DeviceGroup.php index e106863b09..baa793e36f 100644 --- a/app/Models/DeviceGroup.php +++ b/app/Models/DeviceGroup.php @@ -311,4 +311,9 @@ class DeviceGroup extends BaseModel { return $this->belongsToMany('App\Models\Device', 'device_group_device', 'device_group_id', 'device_id'); } + + public function services() + { + return $this->belongsToMany('App\Models\Service', 'device_group_device', 'device_group_id', 'device_id'); + } } diff --git a/app/Models/Mempool.php b/app/Models/Mempool.php index 00406ce678..f72962d1c7 100644 --- a/app/Models/Mempool.php +++ b/app/Models/Mempool.php @@ -9,6 +9,13 @@ class Mempool extends BaseModel protected $primaryKey = 'mempool_id'; + // ---- Query Scopes ---- + + public function scopeHasAccess($query, User $user) + { + return $this->hasDeviceAccess($query, $user); + } + // ---- Define Relationships ---- public function device() diff --git a/app/Models/MuninPlugin.php b/app/Models/MuninPlugin.php new file mode 100644 index 0000000000..cabd5c3c53 --- /dev/null +++ b/app/Models/MuninPlugin.php @@ -0,0 +1,46 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Models; + +class MuninPlugin extends BaseModel +{ + public $timestamps = false; + protected $primaryKey = 'mplug_id'; + + // ---- Query scopes ---- + + public function scopeHasAccess($query, User $user) + { + return $this->hasDeviceAccess($query, $user); + } + + // ---- Define Relationships ---- + + public function device() + { + return $this->belongsTo('App\Models\Device', 'device_id'); + } +} diff --git a/app/Models/Port.php b/app/Models/Port.php index f48825517e..23ecd76ff7 100644 --- a/app/Models/Port.php +++ b/app/Models/Port.php @@ -56,7 +56,7 @@ class Port extends BaseModel */ public function getShortLabel() { - return Rewrite::shortenIfName(Rewrite::normalizeIfName($this->getLabel())); + return Rewrite::shortenIfName(Rewrite::normalizeIfName($this->ifName ?: $this->ifDescr)); } /** @@ -147,6 +147,15 @@ class Port extends BaseModel ]); } + /** + * @param Builder $query + * @return Builder + */ + public function scopeIsShutdown($query) + { + return $query->where('ifAdminStatus', 'down'); + } + /** * @param Builder $query * @return Builder diff --git a/app/Models/Service.php b/app/Models/Service.php index ac34ba940d..c820d4f971 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -2,6 +2,8 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Builder; + class Service extends BaseModel { public $timestamps = false; @@ -9,6 +11,53 @@ class Service extends BaseModel // ---- Query Scopes ---- + /** + * @param Builder $query + * @return Builder + */ + public function scopeIsUp($query) + { + return $query->where([ + ['service_ignore', '=', 0], + ['service_disabled', '=', 0], + ['service_status', '=', 0], + ]); + } + + /** + * @param Builder $query + * @return Builder + */ + public function scopeIsDown($query) + { + return $query->where([ + ['service_ignore', '=', 0], + ['service_disabled', '=', 0], + ['service_status', '=', 2], + ]); + } + + /** + * @param Builder $query + * @return Builder + */ + public function scopeIsIgnored($query) + { + return $query->where([ + ['service_ignore', '=', 1], + ['service_disabled', '=', 0], + ]); + } + + /** + * @param Builder $query + * @return Builder + */ + public function scopeIsDisabled($query) + { + return $query->where('service_disabled', 1); + } + public function scopeHasAccess($query, User $user) { return $this->hasDeviceAccess($query, $user); diff --git a/app/Models/Storage.php b/app/Models/Storage.php index faf0b85f3e..b8d74272d1 100644 --- a/app/Models/Storage.php +++ b/app/Models/Storage.php @@ -9,6 +9,13 @@ class Storage extends BaseModel protected $primaryKey = 'storage_id'; + // ---- Query Scopes ---- + + public function scopeHasAccess($query, User $user) + { + return $this->hasDeviceAccess($query, $user); + } + // ---- Define Relationships ---- public function device() diff --git a/app/Models/UserWidget.php b/app/Models/UserWidget.php index 3e2fd2f3ed..13d1fc407d 100644 --- a/app/Models/UserWidget.php +++ b/app/Models/UserWidget.php @@ -15,25 +15,16 @@ class UserWidget extends Model // ---- Define Relationships ---- - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ public function user() { return $this->belongsTo('App\Models\User', 'user_id'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasOne - */ public function widget() { - return $this->hasOne('App\Models\Widgets', 'widget_id'); + return $this->hasOne('App\Models\Widget', 'widget_id'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ public function dashboard() { return $this->belongsTo('App\Models\Dashboard', 'dashboard_id'); diff --git a/app/Models/Widget.php b/app/Models/Widget.php new file mode 100644 index 0000000000..ed23b061f7 --- /dev/null +++ b/app/Models/Widget.php @@ -0,0 +1,35 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Models; + +use Illuminate\Database\Eloquent\Model; + +class Widget extends Model +{ + public $timestamps = false; + protected $primaryKey = 'widget_id'; + protected $fillable = ['widget_title', 'widget', 'base_dimensions']; +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 51bcc9944f..5ea48d39d4 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -35,8 +35,6 @@ class RouteServiceProvider extends ServiceProvider */ public function map() { - $this->mapLegacyRoutes(); - $this->mapApiRoutes(); $this->mapWebRoutes(); @@ -44,17 +42,6 @@ class RouteServiceProvider extends ServiceProvider // } - /** - * Define legacy routes for the application. - * Only initializing minimal middleware: Cookies and Session. - */ - protected function mapLegacyRoutes() - { - Route::middleware('minimal') - ->namespace($this->namespace) - ->group(base_path('routes/legacy.php')); - } - /** * Define the "web" routes for the application. * diff --git a/html/ajax_dash.php b/html/ajax_dash.php index c8bca4750e..de612ca32f 100644 --- a/html/ajax_dash.php +++ b/html/ajax_dash.php @@ -1,61 +1,10 @@ - */ +header('Content-type: application/json'); -/* -|-------------------------------------------------------------------------- -| Register The Auto Loader -|-------------------------------------------------------------------------- -| -| Composer provides a convenient, automatically generated class loader for -| our application. We just need to utilize it! We'll simply require it -| into the script here so that we don't have to worry about manual -| loading any of our classes later on. It feels great to relax. -| -*/ - -require __DIR__.'/../bootstrap/autoload.php'; - -/* -|-------------------------------------------------------------------------- -| Turn On The Lights -|-------------------------------------------------------------------------- -| -| We need to illuminate PHP development, so let us turn on the lights. -| This bootstraps the framework and gets it ready for use, then it -| will load up this application so that we can run it and send -| the responses back to the browser and delight our users. -| -*/ - -$app = require_once __DIR__.'/../bootstrap/app.php'; - -/* -|-------------------------------------------------------------------------- -| Run The Application -|-------------------------------------------------------------------------- -| -| Once we have the application, we can handle the incoming request -| through the kernel, and send the associated response back to -| the client's browser allowing them to enjoy the creative -| and wonderful application we have prepared for them. -| -*/ - -$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); - -// rewrite the request uri -$_SERVER['REQUEST_URI'] = '/legacy_ajax_dash'; - -$response = $kernel->handle( - $request = Illuminate\Http\Request::capture() -); - -$response->send(); - -$kernel->terminate($request, $response); +// reload dashboard referencing old endpoint +exit(json_encode([ + 'html' => '', + 'status' => 'ok', + 'title' => 'Reload Dasbhoard' +])); diff --git a/html/css/jquery.gridster.min.css b/html/css/jquery.gridster.min.css index a78051fdf1..2ef7990a0f 100644 --- a/html/css/jquery.gridster.min.css +++ b/html/css/jquery.gridster.min.css @@ -1,2 +1,2 @@ -/*! gridster.js - v0.6.10 - 2015-08-05 - * https://dsmorse.github.io/gridster.js/ - Copyright (c) 2015 ducksboard; Licensed MIT */ +/*! gridster.js - v0.7.0 - 2017-03-27 - * https://dsmorse.github.io/gridster.js/ - Copyright (c) 2017 ducksboard; Licensed MIT */ .gridster{position:relative}.gridster>*{-webkit-transition:height .4s,width .4s;-moz-transition:height .4s,width .4s;-o-transition:height .4s,width .4s;-ms-transition:height .4s,width .4s;transition:height .4s,width .4s}.gridster .gs-w{z-index:2;position:absolute}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster.collapsed{height:auto!important}.gridster.collapsed .gs-w{position:static!important}.ready .gs-w:not(.preview-holder),.ready .resize-preview-holder{-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .dragging,.gridster .resizing{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}.gs-resize-handle{position:absolute;z-index:1}.gs-resize-handle-both{width:20px;height:20px;bottom:-8px;right:-8px;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=);background-position:top left;background-repeat:no-repeat;cursor:se-resize;z-index:20}.gs-resize-handle-x{top:0;bottom:13px;right:-5px;width:10px;cursor:e-resize}.gs-resize-handle-y{left:0;right:13px;bottom:-5px;height:10px;cursor:s-resize}.gs-w:hover .gs-resize-handle,.resizing .gs-resize-handle{opacity:1}.gs-resize-handle,.gs-w.dragging .gs-resize-handle{opacity:0}.gs-resize-disabled .gs-resize-handle,[data-max-sizex="1"] .gs-resize-handle-x,[data-max-sizey="1"] .gs-resize-handle-y,[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle{display:none!important} \ No newline at end of file diff --git a/html/css/styles.css b/html/css/styles.css index 181ce1edcb..72519c7680 100644 --- a/html/css/styles.css +++ b/html/css/styles.css @@ -1731,10 +1731,6 @@ tr.search:nth-child(odd) { border-top-right-radius: 4px; } -.widget_body { - padding: 0.8em; -} - .mapTooltip { position : fixed; background-color : #B2B3B1; @@ -1917,6 +1913,7 @@ label { .edit-widget, .close-widget { cursor: pointer; } .widget_body { + padding: 0.8em; overflow-y: auto; width: 100%; height: calc(100% - 38px); @@ -2063,6 +2060,21 @@ label { line-height:34px; } +.dashboard-widget-settings label { + line-height:34px; +} + +.dashboard-graph, .dashboard-graph img { + height: 100%; + width: 100%; +} + +.dashboard-image { + padding: 2px; + height: 100%; + width: auto; +} + .nav > li > a { padding-left: 10px; padding-right: 5px; diff --git a/html/includes/common/availability-map.inc.php b/html/includes/common/availability-map.inc.php index c57083f866..d274f2c8a2 100644 --- a/html/includes/common/availability-map.inc.php +++ b/html/includes/common/availability-map.inc.php @@ -14,8 +14,8 @@ use LibreNMS\Authentication\LegacyAuth; -if (isset($widget_settings['mode_select']) && $widget_settings['mode_select'] !== '') { - $mode = $widget_settings['mode_select']; +if (isset($settings['mode_select']) && $settings['mode_select'] !== '') { + $mode = $settings['mode_select']; } elseif (isset($_SESSION["map_view"]) && is_numeric($_SESSION["map_view"])) { $mode = $_SESSION["map_view"]; } else { @@ -29,10 +29,10 @@ $select_modes = array( ); if ($config['webui']['availability_map_compact'] == 1) { - $compact_tile = $widget_settings['tile_size']; + $compact_tile = $settings['tile_size']; } -$show_disabled_ignored = $widget_settings['show_disabled_and_ignored']; +$show_disabled_ignored = $settings['show_disabled_and_ignored']; if (defined('SHOW_SETTINGS')) { $common_output[] = ' @@ -42,7 +42,7 @@ if (defined('SHOW_SETTINGS')) {
- +
'; @@ -54,8 +54,8 @@ if (defined('SHOW_SETTINGS')) {
@@ -107,7 +107,7 @@ if (defined('SHOW_SETTINGS')) { $common_output[] = ''; } else { foreach ($select_modes as $mode_select => $option) { - if ($mode_select == $widget_settings["mode_select"]) { + if ($mode_select == $settings["mode_select"]) { $selected = 'selected'; } else { $selected = ''; @@ -237,7 +237,7 @@ if (defined('SHOW_SETTINGS')) { '; } else { - if ($widget_settings['color_only_select'] == 1) { + if ($settings['color_only_select'] == 1) { $deviceState = ' '; $deviceLabel .= ' widget-availability-fixed'; } @@ -295,7 +295,7 @@ if (defined('SHOW_SETTINGS')) { '; } else { $serviceText = $service['service_type'] . ' - ' . $serviceState; - if ($widget_settings['color_only_select'] == 1) { + if ($settings['color_only_select'] == 1) { $serviceText = ' '; $serviceLabel .= ' widget-availability-fixed'; } diff --git a/html/includes/common/component-status.inc.php b/html/includes/common/component-status.inc.php deleted file mode 100644 index 403c5d8b19..0000000000 --- a/html/includes/common/component-status.inc.php +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - -'; -foreach ($OBJCOMP->getComponentStatus() as $k => $v) { - if ($k == 0) { - $status = 'Ok'; - $color = 'green'; - } elseif ($k == 1) { - $status = 'Warning'; - $color = 'grey'; - } else { - $status = 'Critical'; - $color = 'red'; - } - $common_output[] .= ' - - - - -'; -} -$common_output[] .= ' - -
StatusCount

'.$status.'

'.$v.'

- -'; diff --git a/html/includes/common/generic-graph.inc.php b/html/includes/common/generic-graph.inc.php deleted file mode 100644 index 67144952e7..0000000000 --- a/html/includes/common/generic-graph.inc.php +++ /dev/null @@ -1,427 +0,0 @@ - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ - -/** - * Generic Graph Widget - * @author Daniel Preussker - * @copyright 2015-2016 Daniel Preussker, QuxLabs UG - * @license GPL - * @package LibreNMS - * @subpackage Widgets - */ - -if (defined('SHOW_SETTINGS') || empty($widget_settings)) { - $common_output[] = ' -
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
- -
-
-
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- '; - $common_output[] = '
-
-
-
- -
-
- -
-
-
-
- -
-
-
- - -'; -} else { - $type = explode('_', $widget_settings['graph_type'], 2); - $type = array_shift($type); - $widget_settings['graph_'.$type] = json_decode($widget_settings['graph_'.$type], true)?:$widget_settings['graph_'.$type]; - if ($type == 'device') { - if (empty($widget_settings['title'])) { - $widget_settings['title'] = $widget_settings['graph_device']['name']." / ".$widget_settings['graph_type']; - } - $param = 'device='.$widget_settings['graph_device']['device_id']; - } elseif ($type == 'application') { - $param = 'id='.$widget_settings['graph_'.$type]['app_id']; - } elseif ($type == 'munin') { - $param = 'device='.$widget_settings['graph_'.$type]['device_id'].'&plugin='.$widget_settings['graph_'.$type]['name']; - } elseif ($type == 'transit' || $type == 'peering' || $type == 'core' || $type == 'custom' || $type == 'manual' || $type == 'transpeer') { - if ($type == 'custom' || $type == 'manual') { - $type = $widget_settings['graph_'.$type]; - $type = explode(',', $type); - } - if ($type == 'transpeer') { - $type = array('transit','peering'); - } - - $ports = get_ports_from_type($type); - foreach ($ports as $port) { - $tmp[] = $port['port_id']; - } - $param = 'id='.implode(',', $tmp); - $widget_settings['graph_type'] = 'multiport_bits_separate'; - if (empty($widget_settings['title'])) { - $widget_settings['title'] = 'Overall '.ucfirst(htmlspecialchars($type)).' Bits ('.$widget_settings['graph_range'].')'; - } - } else { - $param = 'id='.$widget_settings['graph_'.$type][$type.'_id']; - } - if (empty($widget_settings['title'])) { - $widget_settings['title'] = $widget_settings['graph_'.$type]['hostname']." / ".$widget_settings['graph_'.$type]['name']." / ".$widget_settings['graph_type']; - } - $common_output[] = ''; -} diff --git a/html/includes/common/generic-image.inc.php b/html/includes/common/generic-image.inc.php deleted file mode 100644 index c0a9fbe586..0000000000 --- a/html/includes/common/generic-image.inc.php +++ /dev/null @@ -1,72 +0,0 @@ - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ - -/** - * Generic Image Widget - * @author Daniel Preussker - * @copyright 2015 Daniel Preussker, QuxLabs UG - * @license GPL - * @package LibreNMS - * @subpackage Widgets - */ - -if (defined('SHOW_SETTINGS') || empty($widget_settings)) { - $common_output[] = ' -
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
-
'; -} else { - $widget_settings['title'] = $widget_settings['image_title']; - if (strstr($widget_settings['image_url'], '@AUTO_HEIGHT@')) { - $widget_settings['image_url'] = str_replace('@AUTO_HEIGHT@', $widget_dimensions['y'], $widget_settings['image_url']); - } - if (strstr($widget_settings['image_url'], '@AUTO_WIDTH@')) { - $widget_settings['image_url'] = str_replace('@AUTO_WIDTH@', $widget_dimensions['x'], $widget_settings['image_url']); - } - if (strstr($widget_settings['image_url'], '?')) { - $widget_settings['image_url'] .= "&".mt_rand(); - } else { - $widget_settings['image_url'] .= "?".mt_rand(); - } - $common_output[] = ''; -} diff --git a/html/includes/common/graylog.inc.php b/html/includes/common/graylog.inc.php index c99c802bac..e340ac0a98 100644 --- a/html/includes/common/graylog.inc.php +++ b/html/includes/common/graylog.inc.php @@ -17,7 +17,7 @@ * @author LibreNMS Contributors */ -use LibreNMS\Authentication\LegacyAuth; +use App\Models\Device; if (empty($results_limit)) { $results_limit = 25; @@ -28,11 +28,12 @@ $tmp_output = ' - - - - - + + + + + +
TimestampLevelSourceMessageFacilityTimestampLevelSourceMessageFacility
@@ -45,28 +46,25 @@ searchbar = "
"Filter: "+ '; +$tmp_output .= '"
 
"+'; + if (!empty($filter_device)) { $tmp_output .= ' - ""+ + ""+ '; } else { $tmp_output .= ' - "
"+ + '; - - if (LegacyAuth::user()->hasGlobalRead()) { - $results = dbFetchRows("SELECT `hostname` FROM `devices` GROUP BY `hostname` ORDER BY `hostname`"); - } else { - $results = dbFetchRows("SELECT `D`.`hostname` FROM `devices` AS `D`, `devices_perms` AS `P` WHERE `P`.`user_id` = ? AND `P`.`device_id` = `D`.`device_id` GROUP BY `hostname` ORDER BY `hostname`", array(LegacyAuth::id())); - } - - foreach ($results as $data) { - $tmp_output .= '"" +'; + $filter_device = $device->device_id; } $tmp_output .= ' @@ -74,10 +72,6 @@ if (!empty($filter_device)) { '; } -if (empty($filter_device) && isset($_POST['hostname'])) { - $filter_device = mres($_POST['hostname']); -} - if (isset($config['graylog']['timezone'])) { $timezone = 'row.timestamp;'; } else { @@ -85,7 +79,8 @@ if (isset($config['graylog']['timezone'])) { } $tmp_output .= ' - "
"+ + ""+ ""+ ""+ ""+ @@ -98,9 +93,8 @@ $tmp_output .= ' ""+ ""+ ""+ - ""+ " 
"+ - " "+ + " "+ "
"+ "

" @@ -126,13 +120,16 @@ $tmp_output .= ' post: function () { return { - id: "graylog", - hostname: "' . (isset($filter_device) ? $filter_device : '') . '", + stream: "' . (isset($_POST['stream']) ? mres($_POST['stream']) : '') . '", + device: "' . (isset($filter_device) ? $filter_device : '') . '", range: "' . (isset($_POST['range']) ? mres($_POST['range']) : '') . '" }; }, - url: "ajax_table.php", + url: "ajax/table/graylog", }); + + init_select2("#stream", "graylog-streams", {}, "' . (isset($_POST['stream']) ? mres($_POST['stream']) : '') . '"); + init_select2("#device", "device", {limit: 100}, "' . (isset($filter_device) ? $filter_device : '') . '"); '; diff --git a/html/includes/common/notes.inc.php b/html/includes/common/notes.inc.php deleted file mode 100644 index 46b7f4e118..0000000000 --- a/html/includes/common/notes.inc.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. Please see LICENSE.txt at the top level of - * the source code distribution for details. - */ - -if (defined('SHOW_SETTINGS') || empty($widget_settings)) { - $common_output[] = ' -
-
-
- The following html tags are supported: <b>, <iframe>, <i>, <ul>, <ol>, <li>, <h1>, <h2>, <h3>, <h4>, <br>, <p>. If you want just text then wrap in <pre></pre> -
-
-
- -
- -
-
-
-
- -
-
-
'; -} else { - $tmp_config = array( - 'HTML.Allowed' => 'b,iframe[frameborder|src|width|height],i,ul,ol,li,h1,h2,h3,h4,br,p,pre', - 'HTML.Trusted' => true, - 'HTML.SafeIframe' => true, - 'URI.SafeIframeRegexp' => '%^(https?:)?//%', - ); - $common_output[] = display(nl2br($widget_settings['notes']), $tmp_config); - unset($tmp_config); -} diff --git a/html/includes/common/server-stats.inc.php b/html/includes/common/server-stats.inc.php deleted file mode 100644 index fd7f991429..0000000000 --- a/html/includes/common/server-stats.inc.php +++ /dev/null @@ -1,139 +0,0 @@ - -
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- '; -} else { - if (device_permitted($device_id)) { - $cpu = dbFetchCell("SELECT AVG(processor_usage) from processors WHERE device_id = ?", array($device_id)); - $mem = dbFetchRows("SELECT mempool_descr, - ROUND(mempool_used / (1024*1024), 0) as used, - ROUND(mempool_total /(1024*1024), 0) as total - FROM mempools WHERE device_id = ?", array($device_id)); - $disk = dbFetchRows("SELECT storage_descr, - ROUND(storage_used / (1024*1024), 0) as used, - ROUND(storage_size / (1024*1024), 0) as total - FROM storage WHERE device_id = ?", array($device_id)); - $colno = 12 / $column; - if (!$cpu) { - $cpu = 0; - } - - $common_output[] = ' -
-
-
'; - - $i = 0; - foreach ($mem as $m) { - $common_output[] = '
-
-
'; - $mem_js_output .= "var memgauge" . $i . " = new JustGage({ - id: 'mem-" . $i . "-" . $unique_id . "', - value: " . $m['used'] . ", - min: 0, - max: " . $m['total'] . ", - label: 'Mbytes', - valueFontSize: '2px', - title: '" . $m['mempool_descr'] . " Usage' - });\n"; - $i++; - } - - $i = 0; - foreach ($disk as $d) { - $common_output[] = '
-
-
'; - $disk_js_output .= "var diskgauge" . $i . " = new JustGage({ - id: 'disk-" . $i . "-" . $unique_id . "', - value: " . $d['used'] . ", - min: 0, - max: " . $d['total'] . ", - label: 'Mbytes', - valueFontSize: '2px', - title: '" . substr($d['storage_descr'], 0, 20) . " Usage' - });\n"; - $i++; - } - - $common_output[] = ''; - $common_output[] = ''; - $common_output[] = "'; - } else { - $common_output[] = 'You do not have permission to view this device'; - } -} diff --git a/html/includes/common/top-devices.inc.php b/html/includes/common/top-devices.inc.php deleted file mode 100644 index 1006d6cd7c..0000000000 --- a/html/includes/common/top-devices.inc.php +++ /dev/null @@ -1,343 +0,0 @@ - - * Copyright (C) 2016 Cercel Valentin - * - * This widget is based on legacy frontpage module created by Paul Gear. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -use LibreNMS\Authentication\LegacyAuth; - -$top_query = $widget_settings['top_query'] ?: 'traffic'; -$sort_order = $widget_settings['sort_order']; - -$selected_sort_asc = ''; -$selected_sort_desc = ''; - -if ($sort_order === 'asc') { - $selected_sort_asc = 'selected'; -} elseif ($sort_order === 'desc') { - $selected_sort_desc = 'selected'; -} - -$selected_traffic = ''; -$selected_uptime = ''; -$selected_ping = ''; -$selected_cpu = ''; -$selected_ram = ''; -$selected_poller = ''; -$selected_storage = ''; - -switch ($top_query) { - case "traffic": - $table_header = 'Traffic'; - $selected_traffic = 'selected'; - $graph_type = 'device_bits'; - $graph_params = array(); - break; - case "uptime": - $table_header = 'Uptime'; - $selected_uptime = 'selected'; - $graph_type = 'device_uptime'; - $graph_params = array('tab' => 'graphs', 'group' => 'system'); - break; - case "ping": - $table_header = 'Response time'; - $selected_ping = 'selected'; - $graph_type = 'device_ping_perf'; - $graph_params = array('tab' => 'graphs', 'group' => 'poller'); - break; - case "cpu": - $table_header = 'CPU Load'; - $selected_cpu = 'selected'; - $graph_type = 'device_processor'; - $graph_params = array('tab' => 'health', 'metric' => 'processor'); - break; - case "ram": - $table_header = 'Memory usage'; - $selected_ram = 'selected'; - $graph_type = 'device_mempool'; - $graph_params = array('tab' => 'health', 'metric' => 'mempool'); - break; - case "poller": - $table_header = 'Poller duration'; - $selected_poller = 'selected'; - $graph_type = 'device_poller_perf'; - $graph_params = array('tab' => 'graphs', 'group' => 'poller'); - break; - case "storage": - $table_header = 'Disk usage'; - $selected_storage = 'selected'; - $graph_type = 'device_storage'; - $graph_params = array('tab' => 'health', 'metric' => 'storage'); - break; -} - -$widget_settings['device_count'] = $widget_settings['device_count'] > 0 ? $widget_settings['device_count'] : 5; -$widget_settings['time_interval'] = $widget_settings['time_interval'] > 0 ? $widget_settings['time_interval'] : 15; - -if (defined('SHOW_SETTINGS') || empty($widget_settings)) { - $common_output[] = ' -
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
-
'; -} else { - $interval = $widget_settings['time_interval']; - (integer)$interval_seconds = ($interval * 60); - (integer)$device_count = $widget_settings['device_count']; - - $common_output[] = '

Top ' . $device_count . ' devices (last ' . $interval . ' minutes)

'; - - $params = ['interval' => $interval_seconds, 'count' => $device_count]; - if (!LegacyAuth::user()->hasGlobalRead()) { - $params['user'] = LegacyAuth::id(); - } - if ($top_query === 'traffic') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = ' - SELECT *, sum(p.ifInOctets_rate + p.ifOutOctets_rate) as total - FROM ports as p, devices as d - WHERE d.device_id = p.device_id - AND unix_timestamp() - p.poll_time < :interval - AND ( p.ifInOctets_rate > 0 - OR p.ifOutOctets_rate > 0 ) - GROUP BY d.device_id - ORDER BY total ' . $sort_order . ' - LIMIT :count - '; - } else { - $query = ' - SELECT *, sum(p.ifInOctets_rate + p.ifOutOctets_rate) as total - FROM ports as p, devices as d, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user AND `P`.`device_id` = `d`.`device_id` AND - d.device_id = p.device_id - AND unix_timestamp() - p.poll_time < :interval - AND ( p.ifInOctets_rate > 0 - OR p.ifOutOctets_rate > 0 ) - GROUP BY d.device_id - ORDER BY total ' . $sort_order . ' - LIMIT :count - '; - } - } elseif ($top_query === 'uptime') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = 'SELECT `uptime`, `hostname`, `last_polled`, `device_id`, `sysName` - FROM `devices` - WHERE unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `uptime` ' . $sort_order . ' - LIMIT :count'; - } else { - $query = 'SELECT `uptime`, `hostname`, `last_polled`, `d`.`device_id`, `d`.`sysName` - FROM `devices` as `d`, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user - AND `P`.`device_id` = `d`.`device_id` - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `uptime` ' . $sort_order . ' - LIMIT :count'; - } - } elseif ($top_query === 'ping') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = 'SELECT `last_ping_timetaken`, `hostname`, `last_polled`, `device_id`, `sysName` - FROM `devices` - WHERE unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `last_ping_timetaken` ' . $sort_order . ' - LIMIT :count'; - } else { - $query = 'SELECT `last_ping_timetaken`, `hostname`, `last_polled`, `d`.`device_id`, `d`.`sysName` - FROM `devices` as `d`, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user - AND `P`.`device_id` = `d`.`device_id` - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `last_ping_timetaken` ' . $sort_order . ' - LIMIT :count'; - } - } elseif ($top_query === 'cpu') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = 'SELECT `hostname`, `last_polled`, `d`.`device_id`, avg(`processor_usage`) as `cpuload`, `d`.`sysName` - FROM `processors` AS `procs`, `devices` AS `d` - WHERE `d`.`device_id` = `procs`.`device_id` - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - GROUP BY `d`.`device_id`, `d`.`hostname`, `d`.`last_polled`, `d`.`sysName` - ORDER BY `cpuload` ' . $sort_order . ' - LIMIT :count'; - } else { - $query = 'SELECT `hostname`, `last_polled`, `d`.`device_id`, avg(`processor_usage`) as `cpuload`, `d`.`sysName` - FROM `processors` AS procs, `devices` AS `d`, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user AND `P`.`device_id` = `procs`.`device_id` AND `P`.`device_id` = `d`.`device_id` - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - GROUP BY `procs`.`device_id`, `d`.`hostname`, `d`.`last_polled`, `d`.`sysName` - ORDER BY `cpuload` ' . $sort_order . ' - LIMIT :count'; - } - } elseif ($top_query === 'ram') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = 'SELECT `hostname`, `last_polled`, `d`.`device_id`, `mempool_perc`, `d`.`sysName` - FROM `mempools` as `mem`, `devices` as `d` - WHERE `d`.`device_id` = `mem`.`device_id` - AND `mempool_descr` IN (\'Physical memory\',\'Memory\') - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `mempool_perc` ' . $sort_order . ' - LIMIT :count'; - } else { - $query = 'SELECT `hostname`, `last_polled`, `d`.`device_id`, `mempool_perc`, `d`.`sysName` - FROM `mempools` as `mem`, `devices` as `d`, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user AND `P`.`device_id` = `mem`.`device_id` AND `P`.`device_id` = `d`.`device_id` - AND `mempool_descr` IN (\'Physical memory\',\'Memory\') - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `mempool_perc` ' . $sort_order . ' - LIMIT :count'; - } - } elseif ($top_query === 'storage') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = 'SELECT `hostname`, `last_polled`, `d`.`device_id`, `storage_perc`, `d`.`sysName`, `storage_descr`, `storage_perc_warn`, `storage_id` - FROM `storage` as `disk`, `devices` as `d` - WHERE `d`.`device_id` = `disk`.`device_id` - AND `d`.`type` = \'server\' - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `storage_perc` ' . $sort_order . ' - LIMIT :count'; - } else { - $query = 'SELECT `hostname`, `last_polled`, `d`.`device_id`, `storage_perc`, `d`.`sysName`, `storage_descr`, `storage_perc_warn`, `storage_id` - FROM `storage` as `disk`, `devices` as `d`, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user AND `P`.`device_id` = `disk`.`device_id` AND `P`.`device_id` = `d`.`device_id` - AND `d`.`type` = \'server\' - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `storage_perc` ' . $sort_order . ' - LIMIT :count'; - } - } elseif ($top_query === 'poller') { - if (LegacyAuth::user()->hasGlobalRead()) { - $query = 'SELECT `last_polled_timetaken`, `hostname`, `last_polled`, `device_id`, `sysName` - FROM `devices` - WHERE unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `last_polled_timetaken` ' . $sort_order . ' - LIMIT :count'; - } else { - $query = 'SELECT `last_polled_timetaken`, `hostname`, `last_polled`, `d`.`device_id`, `d`.`sysName` - FROM `devices` as `d`, `devices_perms` AS `P` - WHERE `P`.`user_id` = :user - AND `P`.`device_id` = `d`.`device_id` - AND unix_timestamp() - UNIX_TIMESTAMP(`last_polled`) < :interval - ORDER BY `last_polled_timetaken` ' . $sort_order . ' - LIMIT :count'; - } - } - - - $common_output[] = ' -
- - - - '; - if ($top_query == 'storage') { - $common_output[] = ''; - } - $common_output[] = ' - - - '; - - foreach (dbFetchRows($query, $params) as $result) { - $common_output[] = ' - - - '; - } - $common_output[] = ' - -
DeviceStorage Device' . $table_header . '
' . generate_device_link($result, shorthost($result['hostname'])) . ''; - if ($top_query == 'storage') { - $graph_array = array(); - $graph_array['height'] = '100'; - $graph_array['width'] = '210'; - $graph_array['to'] = $config['time']['now']; - $graph_array['id'] = $drive['storage_id']; - $graph_array['type'] = $graph_type; - $graph_array['from'] = $config['time']['day']; - $graph_array['legend'] = 'no'; - - $overlib_content = generate_overlib_content($graph_array, $result['hostname'].' - '.$result['storage_descr']); - - $link_array = $graph_array; - $link_array['page'] = 'graphs'; - unset($link_array['height'], $link_array['width'], $link_array['legend']); - $link = generate_url($link_array); - - $percent = $result['storage_perc']; - $background = get_percentage_colours($percent, $result['storage_perc_warn']); - $common_output[] = shorten_text($result['storage_descr'], 50).''; - $common_output[] = overlib_link($link, print_percentage_bar(150, 20, $percent, null, 'ffffff', $background['left'], $percent.'%', 'ffffff', $background['right']), $overlib_content); - } else { - $common_output[] = generate_device_link($result, generate_minigraph_image($result, $config['time']['day'], $config['time']['now'], $graph_type, 'no', 150, 21), $graph_params, 0, 0, 0); - } - $common_output[] = '
-
'; -} diff --git a/html/includes/common/top-interfaces.inc.php b/html/includes/common/top-interfaces.inc.php deleted file mode 100644 index 82b708462b..0000000000 --- a/html/includes/common/top-interfaces.inc.php +++ /dev/null @@ -1,165 +0,0 @@ - - * - * This widget is based on legacy frontpage module created by Paul Gear. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ - -/** - * Top interfaces by traffic - * @author Sergiusz Paprzycki - * @copyright 2015 Sergiusz Paprzycki - * @license GPL - * @package LibreNMS - * @subpackage Widgets - */ - -use LibreNMS\Authentication\LegacyAuth; - -if (defined('SHOW_SETTINGS') || empty($widget_settings)) { - $common_output[] = ' -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
- -
-
-
- - - '; -} else { - $interval = $widget_settings['time_interval']; - (integer) $lastpoll_seconds = ($interval * 60) ?: 300; - (integer) $interface_count = $widget_settings['interface_count'] ?: 5; - $params = ['lastpoll' => $lastpoll_seconds, 'count' => $interface_count, 'filter1' => ($widget_settings['interface_filter']?:(int)1), 'filter2' => ($widget_settings['interface_filter']?:(int)1)]; - if (!LegacyAuth::user()->hasGlobalRead()) { - $params['user1'] = LegacyAuth::id(); - $params['user2'] = LegacyAuth::id(); - } - if (LegacyAuth::user()->hasGlobalRead()) { - $query = ' - SELECT p.*, devices.*, p.ifInOctets_rate + p.ifOutOctets_rate as total - FROM ports as p - INNER JOIN devices ON p.device_id = devices.device_id - AND unix_timestamp() - p.poll_time <= :lastpoll - AND ( p.ifType = :filter1 || 1 = :filter2 ) - AND ( p.ifInOctets_rate > 0 || p.ifOutOctets_rate > 0 ) - ORDER BY total DESC - LIMIT :count - '; - } else { - $query = ' - SELECT ports.*, devices.*, ports.ifInOctets_rate + ports.ifOutOctets_rate as total - FROM ports - INNER JOIN devices ON ports.device_id = devices.device_id - LEFT JOIN ports_perms ON ports.port_id = ports_perms.port_id - LEFT JOIN devices_perms ON devices.device_id = devices_perms.device_id - WHERE ( ports_perms.user_id = :user1 || devices_perms.user_id = :user2 ) - AND unix_timestamp() - ports.poll_time <= :lastpoll - AND ( ports.ifType = :filter1 || 1 = :filter2 ) - AND ( ports.ifInOctets_rate > 0 || ports.ifOutOctets_rate > 0 ) - GROUP BY ports.port_id - ORDER BY total DESC - LIMIT :count - '; - } - $common_output[] = ' -

Top '.$interface_count.' interfaces polled within '.$interval.' minutes

-
- - - - - - - - - - '; - - foreach (dbFetchRows($query, $params) as $result) { - $result = cleanPort($result); - $common_output[] = ' - - - - - - '; - } - $common_output[] = ' - -
DeviceInterfaceTotal traffic
'.generate_device_link($result, shorthost($result['hostname'])).''.generate_port_link($result, shorten_interface_type($result['ifName'])).''.generate_port_link($result, generate_port_thumbnail($result)).'
-
- '; -} diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index 6fed0914e6..b5cbe6f642 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -22,118 +22,30 @@ * @subpackage Frontpage */ -use LibreNMS\Authentication\LegacyAuth; +use Auth; use LibreNMS\Config; -require_once $config['install_dir'] . '/includes/alerts.inc.php'; -require_once $config['install_dir'] . '/includes/device-groups.inc.php'; +$install_dir = Config::get('install_dir'); +require_once $install_dir . '/includes/alerts.inc.php'; +require_once $install_dir . '/includes/device-groups.inc.php'; -if ($config['map']['engine'] == 'leaflet') { - if (defined('SHOW_SETTINGS') && $config['front_page'] == "pages/front/tiles.php") { - $temp_output = ' -
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/availability-map.blade.php b/resources/views/widgets/settings/availability-map.blade.php new file mode 100644 index 0000000000..e6a84a4974 --- /dev/null +++ b/resources/views/widgets/settings/availability-map.blade.php @@ -0,0 +1,74 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/base.blade.php b/resources/views/widgets/settings/base.blade.php new file mode 100644 index 0000000000..e05988cac2 --- /dev/null +++ b/resources/views/widgets/settings/base.blade.php @@ -0,0 +1,13 @@ + + @yield('form') + + @hassection('form') +
+ +
+ @else + No settings for this widget + @endif + + +@yield('javascript') diff --git a/resources/views/widgets/settings/device-summary.blade.php b/resources/views/widgets/settings/device-summary.blade.php new file mode 100644 index 0000000000..af3cd804b7 --- /dev/null +++ b/resources/views/widgets/settings/device-summary.blade.php @@ -0,0 +1,19 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+
+ + +
+@endsection diff --git a/resources/views/widgets/settings/eventlog.blade.php b/resources/views/widgets/settings/eventlog.blade.php new file mode 100644 index 0000000000..80b2bcd6ab --- /dev/null +++ b/resources/views/widgets/settings/eventlog.blade.php @@ -0,0 +1,38 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+ + +
+
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/globe.blade.php b/resources/views/widgets/settings/globe.blade.php new file mode 100644 index 0000000000..f86fe885ec --- /dev/null +++ b/resources/views/widgets/settings/globe.blade.php @@ -0,0 +1,27 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+ + +
+
+ + +
+
+ + +
+@endsection diff --git a/resources/views/widgets/settings/graph.blade.php b/resources/views/widgets/settings/graph.blade.php new file mode 100644 index 0000000000..ce5332ac04 --- /dev/null +++ b/resources/views/widgets/settings/graph.blade.php @@ -0,0 +1,126 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + + + + + +@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/graylog.blade.php b/resources/views/widgets/settings/graylog.blade.php new file mode 100644 index 0000000000..99d3521f9b --- /dev/null +++ b/resources/views/widgets/settings/graylog.blade.php @@ -0,0 +1,57 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/image.blade.php b/resources/views/widgets/settings/image.blade.php new file mode 100644 index 0000000000..c739ef9c83 --- /dev/null +++ b/resources/views/widgets/settings/image.blade.php @@ -0,0 +1,18 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+ +
+ + +
+ +
+ + +
+@endsection diff --git a/resources/views/widgets/settings/notes.blade.php b/resources/views/widgets/settings/notes.blade.php new file mode 100644 index 0000000000..73ed229a55 --- /dev/null +++ b/resources/views/widgets/settings/notes.blade.php @@ -0,0 +1,19 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+ +
+ + +
+ +
+
+ The following html tags are supported: <b>, <iframe>, <i>, <ul>, <ol>, <li>, <h1>, <h2>, <h3>, <h4>, <br>, <p>.
+ If you want just text then wrap in <pre></pre> +
+@endsection diff --git a/resources/views/widgets/settings/server-stats.blade.php b/resources/views/widgets/settings/server-stats.blade.php new file mode 100644 index 0000000000..6b2e078cc6 --- /dev/null +++ b/resources/views/widgets/settings/server-stats.blade.php @@ -0,0 +1,35 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+ +
+ + +
+ +
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/syslog.blade.php b/resources/views/widgets/settings/syslog.blade.php new file mode 100644 index 0000000000..30646ebaa0 --- /dev/null +++ b/resources/views/widgets/settings/syslog.blade.php @@ -0,0 +1,22 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/top-devices.blade.php b/resources/views/widgets/settings/top-devices.blade.php new file mode 100644 index 0000000000..5cfb34c916 --- /dev/null +++ b/resources/views/widgets/settings/top-devices.blade.php @@ -0,0 +1,35 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+@endsection diff --git a/resources/views/widgets/settings/top-interfaces.blade.php b/resources/views/widgets/settings/top-interfaces.blade.php new file mode 100644 index 0000000000..d65e3dc729 --- /dev/null +++ b/resources/views/widgets/settings/top-interfaces.blade.php @@ -0,0 +1,26 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+
+ + +
+
+ + +
+@endsection + +@section('javascript') + +@endsection diff --git a/resources/views/widgets/settings/worldmap.blade.php b/resources/views/widgets/settings/worldmap.blade.php new file mode 100644 index 0000000000..e88846229d --- /dev/null +++ b/resources/views/widgets/settings/worldmap.blade.php @@ -0,0 +1,42 @@ +@extends('widgets.settings.base') + +@section('form') +
+ + +
+ +
+ + +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+@endsection diff --git a/resources/views/widgets/syslog.blade.php b/resources/views/widgets/syslog.blade.php new file mode 100644 index 0000000000..c370c9c526 --- /dev/null +++ b/resources/views/widgets/syslog.blade.php @@ -0,0 +1,28 @@ +
+ + + + + + + + + + + + +
TimestampLevelHostnameProgramMessagePriority
+
+ diff --git a/resources/views/widgets/top-devices.blade.php b/resources/views/widgets/top-devices.blade.php new file mode 100644 index 0000000000..c1047dbfe3 --- /dev/null +++ b/resources/views/widgets/top-devices.blade.php @@ -0,0 +1,25 @@ +@if($rows->isNotEmpty()) +
+ + + + + @foreach($headers as $header) + + @endforeach + + + + @foreach($rows as $row) + + @foreach($row as $column) + + @endforeach + + @endforeach + +
Device{{ $header }}
{!! $column !!}
+
+@else +

@lang('No devices found within interval.')

+@endif diff --git a/resources/views/widgets/top-interfaces.blade.php b/resources/views/widgets/top-interfaces.blade.php new file mode 100644 index 0000000000..9cb63e1657 --- /dev/null +++ b/resources/views/widgets/top-interfaces.blade.php @@ -0,0 +1,21 @@ +

Top {{ $interface_count }} interfaces polled within {{ $time_interval }} minutes

+
+ + + + + + + + + + @foreach($ports as $port) + + + + + + @endforeach + +
@lang('Device')@lang('Interface')@lang('Total traffic')
{!! \LibreNMS\Util\Url::deviceLink($port->device, $port->device->shortDisplayName()) !!}{!! \LibreNMS\Util\Url::portLink($port, $port->getShortLabel()) !!}{!! \LibreNMS\Util\Url::portLink($port, \LibreNMS\Util\Url::portThumbnail($port)) !!}
+
diff --git a/resources/views/widgets/worldmap.blade.php b/resources/views/widgets/worldmap.blade.php new file mode 100644 index 0000000000..1a20ba6dda --- /dev/null +++ b/resources/views/widgets/worldmap.blade.php @@ -0,0 +1,61 @@ +
+ + diff --git a/routes/legacy.php b/routes/legacy.php deleted file mode 100644 index 505fa248e2..0000000000 --- a/routes/legacy.php +++ /dev/null @@ -1,6 +0,0 @@ - ['auth'], 'guard' => 'auth'], function () { - Route::any('legacy_ajax_dash', 'LegacyController@dash'); -}); diff --git a/routes/web.php b/routes/web.php index 6bfd610eef..67f9020940 100644 --- a/routes/web.php +++ b/routes/web.php @@ -40,18 +40,52 @@ Route::group(['middleware' => ['auth', '2fa'], 'guard' => 'auth'], function () { Route::post('set_resolution', 'ResolutionController@set'); Route::resource('location', 'LocationController', ['only' => ['update', 'destroy']]); + Route::group(['prefix' => 'form', 'namespace' => 'Form'], function () { + Route::resource('widget-settings', 'WidgetSettingsController'); + }); + Route::group(['prefix' => 'select', 'namespace' => 'Select'], function () { + Route::get('application', 'ApplicationController'); + Route::get('bill', 'BillController'); Route::get('device', 'DeviceController'); + Route::get('device-group', 'DeviceGroupController'); Route::get('eventlog', 'EventlogController'); + Route::get('graph', 'GraphController'); + Route::get('graph-aggregate', 'GraphAggregateController'); + Route::get('graylog-streams', 'GraylogStreamsController'); Route::get('syslog', 'SyslogController'); + Route::get('munin', 'MuninPluginController'); + Route::get('port', 'PortController'); + Route::get('port-field', 'PortFieldController'); }); Route::group(['prefix' => 'table', 'namespace' => 'Table'], function () { Route::post('customers', 'CustomersController'); Route::post('eventlog', 'EventlogController'); Route::post('location', 'LocationController'); + Route::post('graylog', 'GraylogController'); Route::post('syslog', 'SyslogController'); }); + + Route::group(['prefix' => 'dash', 'namespace' => 'Widgets'], function () { + Route::post('alerts', 'AlertsController'); + Route::post('availability-map', 'AvailabilityMapController'); + Route::post('component-status', 'ComponentStatusController'); + Route::post('device-summary-horiz', 'DeviceSummaryHorizController'); + Route::post('device-summary-vert', 'DeviceSummaryVertController'); + Route::post('eventlog', 'EventlogController'); + Route::post('generic-graph', 'GraphController'); + Route::post('generic-image', 'ImageController'); + Route::post('globe', 'GlobeController'); + Route::post('graylog', 'GraylogController'); + Route::post('placeholder', 'PlaceholderController'); + Route::post('notes', 'NotesController'); + Route::post('server-stats', 'ServerStatsController'); + Route::post('syslog', 'SyslogController'); + Route::post('top-devices', 'TopDevicesController'); + Route::post('top-interfaces', 'TopInterfacesController'); + Route::post('worldmap', 'WorldMapController'); + }); }); // Debugbar routes need to be here because of catch-all