From 1084bd6d1a418d70593dee9c96390b3850c6936f Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Sun, 19 Sep 2021 18:26:33 -0500 Subject: [PATCH] Convert all ports backend to Laravel style ajax table (#13184) * port ports to Laravel style ajax table * fix style * cleanups+fixes * correct column name * correct port formatter Co-authored-by: Jellyfrog * always filter deleted Co-authored-by: Jellyfrog --- .../Controllers/Table/PortsController.php | 166 ++++++++++++++ includes/html/pages/ports/list.inc.php | 16 +- includes/html/table/ports.inc.php | 209 ------------------ resources/views/port/actions.blade.php | 12 + routes/web.php | 1 + 5 files changed, 188 insertions(+), 216 deletions(-) create mode 100644 app/Http/Controllers/Table/PortsController.php delete mode 100644 includes/html/table/ports.inc.php create mode 100644 resources/views/port/actions.blade.php diff --git a/app/Http/Controllers/Table/PortsController.php b/app/Http/Controllers/Table/PortsController.php new file mode 100644 index 0000000000..00f648925d --- /dev/null +++ b/app/Http/Controllers/Table/PortsController.php @@ -0,0 +1,166 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2021 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Table; + +use App\Models\Port; +use DB; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Arr; +use LibreNMS\Util\Number; +use LibreNMS\Util\Rewrite; +use LibreNMS\Util\Url; + +class PortsController extends TableController +{ + protected function rules() + { + return [ + 'device_id' => 'nullable|integer', + 'deleted' => 'boolean', + 'disabled' => 'boolean', + 'errors' => 'nullable|boolean', + 'hostname' => 'nullable|ip_or_hostname', + 'ifAlias' => 'nullable|string', + 'ifType' => 'nullable|string', + 'ifSpeed' => 'nullable|integer', + 'ignore' => 'boolean', + 'location' => 'nullable|integer', + 'port_descr_type' => 'nullable|string', + 'state' => 'nullable|in:up,down,admindown', + ]; + } + + protected function filterFields($request) + { + return [ + 'ports.device_id' => 'device_id', + 'location_id' => 'location', + 'ifSpeed', + 'ifType', + 'port_descr_type', + 'ports.disabled' => 'disabled', + 'ports.ignore' => 'ignore', + ]; + } + + protected function sortFields($request) + { + return [ + 'hostname', + 'ifIndex', + 'ifDescr', + 'secondsIfLastChange', + 'ifConnectorPresent', + 'ifInErrors_delta', + 'ifOutErrors_delta', + 'ifInOctets_rate', + 'ifOutOctets_rate', + 'ifInUcastPkts_rate', + 'ifOutUcastPkts_rate', + 'ifType', + 'ifAlias', + 'ifMtu', + 'ifSpeed', + ]; + } + + protected function baseQuery($request) + { + $query = Port::hasAccess($request->user()) + ->with('device') + ->leftJoin('devices', 'ports.device_id', 'devices.device_id') + ->where('deleted', $request->get('deleted', 0)) // always filter deleted + ->when($request->get('hostname'), function (Builder $query, $hostname) { + $query->where(function (Builder $query) use ($hostname) { + $query->where('hostname', 'like', "%$hostname%") + ->orWhere('sysName', 'like', "%$hostname%"); + }); + }) + ->when($request->get('ifAlias'), function (Builder $query, $ifAlias) { + return $query->where('ifAlias', 'like', "%$ifAlias%"); + }) + ->when($request->get('errors'), function (Builder $query) { + $query->where(function (Builder $query) { + return $query->where('ifInErrors_delta', '>', 0) + ->orWhere('ifOutErrors_delta', '>', 0); + }); + }) + ->when($request->get('state'), function (Builder $query, $state) { + switch ($state) { + case 'down': + return $query->where('ifAdminStatus', 'up')->where('ifOperStatus', 'down'); + case 'up': + return $query->where('ifAdminStatus', 'up')->where('ifOperStatus', 'up'); + case 'admindown': + return $query->where('ifAdminStatus', 'down')->where('ports.ignore', 0); + default: + return $query; + } + }); + + $select = [ + 'ports.*', + 'hostname', + ]; + + if (array_key_exists('secondsIfLastChange', Arr::wrap($request->get('sort')))) { + // for sorting + $select[] = DB::raw('`devices`.`uptime` - `ports`.`ifLastChange` / 100 as secondsIfLastChange'); + } + + return $query->select($select); + } + + /** + * @param \App\Models\Port $port + * @return array + */ + public function formatItem($port) + { + $status = $port->ifOperStatus == 'down' + ? ($port->ifAdminStatus == 'up' ? 'label-danger' : 'label-warning') + : 'label-success'; + + return [ + 'status' => $status, + 'device' => Url::deviceLink($port->device), + 'port' => Url::portLink($port), + 'secondsIfLastChange' => ceil($port->device->uptime - ($port->ifLastChange / 100)), + 'ifConnectorPresent' => ($port->ifConnectorPresent == 'true') ? 'yes' : 'no', + 'ifSpeed' => $port->ifSpeed, + 'ifMtu' => $port->ifMtu, + 'ifInOctets_rate' => $port->ifInOctets_rate * 8, + 'ifOutOctets_rate' => $port->ifOutOctets_rate * 8, + 'ifInUcastPkts_rate' => $port->ifInUcastPkts_rate, + 'ifOutUcastPkts_rate' => $port->ifOutUcastPkts_rate, + 'ifInErrors_delta' => $port->poll_period ? Number::formatSi($port->ifInErrors_delta / $port->poll_period, 2, 3, 'EPS') : '', + 'ifOutErrors_delta' => $port->poll_period ? Number::formatSi($port->ifOutErrors_delta / $port->poll_period, 2, 3, 'EPS') : '', + 'ifType' => Rewrite::normalizeIfType($port->ifType), + 'ifAlias' => $port->ifAlias, + 'actions' => (string) view('port.actions', ['port' => $port]), + ]; + } +} diff --git a/includes/html/pages/ports/list.inc.php b/includes/html/pages/ports/list.inc.php index cb9db077c3..0d6b5e921b 100644 --- a/includes/html/pages/ports/list.inc.php +++ b/includes/html/pages/ports/list.inc.php @@ -33,9 +33,9 @@ if ($vars['errors']) { - - - + + + @@ -53,10 +53,10 @@ if ($vars['errors']) { data-visible="" data-css-class="blue" data-converter="human-pps"> Packets Out - - @@ -98,6 +98,9 @@ var grid = $("#ports").bootgrid({ formatters: { 'device': function (column, row) { return "" + row.device + ""; + }, + 'port': function (column, row) { + return row.port } }, templates: { @@ -106,7 +109,6 @@ var grid = $("#ports").bootgrid({ post: function () { return { - id: "ports", device_id: '', hostname: '', state: '', @@ -121,7 +123,7 @@ var grid = $("#ports").bootgrid({ errors: '', }; }, - url: "ajax_table.php" + url: '' }); $(".actionBar").append(""); diff --git a/includes/html/table/ports.inc.php b/includes/html/table/ports.inc.php deleted file mode 100644 index f2755e60d9..0000000000 --- a/includes/html/table/ports.inc.php +++ /dev/null @@ -1,209 +0,0 @@ -. - * - * @link https://www.librenms.org - * - * @copyright 2016 Tony Murray - * @author Tony Murray - */ -$where = "`D`.`hostname` != '' "; -$param = []; -$sql = 'FROM `ports`'; - -if (! Auth::user()->hasGlobalRead()) { - $port_ids = Permissions::portsForUser()->toArray() ?: [0]; - $device_ids = Permissions::devicesForUser()->toArray() ?: [0]; - $where .= ' AND (`ports`.`port_id` IN ' . dbGenPlaceholders(count($port_ids)); - $where .= ' OR `D`.`device_id` IN ' . dbGenPlaceholders(count($device_ids)); - $where .= ')'; - $param = array_merge($param, $port_ids, $device_ids); -} - -$sql .= ' LEFT JOIN `devices` AS `D` ON `ports`.`device_id` = `D`.`device_id`'; - -if (! empty($vars['hostname'])) { - $where .= ' AND (D.hostname LIKE ? OR D.sysName LIKE ?)'; - $param += array_fill(count($param), 2, '%' . $vars['hostname'] . '%'); -} - -if (! empty($vars['location'])) { - $where .= ' AND `D`.`location_id` = ?'; - $param[] = $vars['location']; -} - -$sql .= " WHERE $where "; - -if (! empty($vars['errors'])) { - $sql .= ' AND (`ports`.`ifInErrors_delta` > 0 OR `ports`.`ifOutErrors_delta` > 0)'; -} - -if (! empty($vars['device_id'])) { - $sql .= ' AND `ports`.`device_id`=?'; - $param[] = $vars['device_id']; -} - -if (! empty($vars['state'])) { - switch ($vars['state']) { - case 'down': - $sql .= ' AND `ports`.`ifAdminStatus` = ? AND `ports`.`ifOperStatus` = ?'; - $param[] = 'up'; - $param[] = 'down'; - break; - case 'up': - $sql .= ' AND `ports`.`ifAdminStatus` = ? AND `ports`.`ifOperStatus` = ?'; - $param[] = 'up'; - $param[] = 'up'; - break; - case 'admindown': - $sql .= ' AND `ports`.`ifAdminStatus` = ? AND `D`.`ignore` = 0'; - $param[] = 'down'; - break; - } -} - -if (! empty($vars['ifSpeed'])) { - $sql .= ' AND `ports`.`ifSpeed`=?'; - $param[] = $vars['ifSpeed']; -} - -if (! empty($vars['ifType'])) { - $sql .= ' AND `ports`.`ifType`=?'; - $param[] = $vars['ifType']; -} - -if (! empty($vars['port_descr_type'])) { - $sql .= ' AND `ports`.`port_descr_type`=?'; - $param[] = $vars['port_descr_type']; -} - -if (! empty($vars['ifAlias'])) { - $sql .= ' AND `ports`.`ifAlias` LIKE ?'; - $param[] = '%' . $vars['ifAlias'] . '%'; -} - -$sql .= ' AND `ports`.`disabled`=?'; -$param[] = (int) (isset($vars['disabled']) && $vars['disabled']); - -$sql .= ' AND `ports`.`ignore`=?'; -$param[] = (int) (isset($vars['ignore']) && $vars['ignore']); - -$sql .= ' AND `ports`.`deleted`=?'; -$param[] = (int) (isset($vars['deleted']) && $vars['deleted']); - -$count_sql = "SELECT COUNT(`ports`.`port_id`) $sql"; -$total = (int) dbFetchCell($count_sql, $param); - -if (isset($sort) && ! empty($sort)) { - [$sort_column, $sort_order] = explode(' ', trim($sort)); - if ($sort_column == 'device') { - $sql .= " ORDER BY `D`.`hostname` $sort_order"; - } elseif ($sort_column == 'port') { - $sql .= " ORDER BY `ifDescr` $sort_order"; - } elseif ($sort_column == 'ifLastChange') { - $sql .= " ORDER BY `secondsIfLastChange` $sort_order"; - } else { - $sql .= " ORDER BY `$sort_column` $sort_order"; - } -} - -if (isset($current)) { - $limit_low = (($current * $rowCount) - ($rowCount)); - $limit_high = $rowCount; -} - -if ($rowCount != -1) { - $sql .= " LIMIT $limit_low,$limit_high"; -} - -$query = 'SELECT DISTINCT(`ports`.`port_id`),`ports`.*'; -// calculate ifLastChange as seconds ago -$query .= ',`D`.`uptime` - `ports`.`ifLastChange` / 100 as secondsIfLastChange '; -$query .= $sql; - -foreach (dbFetchRows($query, $param) as $port) { - $device = device_by_id_cache($port['device_id']); - $port = cleanPort($port, $device); - - switch ($port['ifOperStatus']) { - case 'up': - $status = 'label-success'; - break; - case 'down': - switch ($port['ifAdminStatus']) { - case 'up': - $status = 'label-danger'; - break; - case 'down': - $status = 'label-warning'; - break; - } - break; - } - - // FIXME what actions should we have? - $actions = '
'; - - if ($vars['deleted'] !== 'yes') { - $actions .= '
'; - - if (Auth::user()->hasGlobalAdmin()) { - $actions .= '
'; - } - } - - if ($vars['deleted'] === 'yes') { - if (port_permitted($port['port_id'], $device['device_id'])) { - $actions .= '
'; - } - } - - $actions .= '
'; - - $response[] = [ - 'status' => $status, - 'device' => generate_device_link($device), - 'port' => generate_port_link($port), - 'ifLastChange' => ceil($port['secondsIfLastChange']), - 'ifConnectorPresent' => ($port['ifConnectorPresent'] == 'true') ? 'yes' : 'no', - 'ifSpeed' => $port['ifSpeed'], - 'ifMtu' => $port['ifMtu'], - 'ifInOctets_rate' => $port['ifInOctets_rate'] * 8, - 'ifOutOctets_rate' => $port['ifOutOctets_rate'] * 8, - 'ifInUcastPkts_rate' => $port['ifInUcastPkts_rate'], - 'ifOutUcastPkts_rate' => $port['ifOutUcastPkts_rate'], - 'ifInErrors' => $port['poll_period'] ? \LibreNMS\Util\Number::formatSi($port['ifInErrors_delta'] / $port['poll_period'], 2, 3, 'EPS') : '', - 'ifOutErrors' => $port['poll_period'] ? \LibreNMS\Util\Number::formatSi($port['ifOutErrors_delta'] / $port['poll_period'], 2, 3, 'EPS') : '', - 'ifType' => \LibreNMS\Util\Rewrite::normalizeIfType($port['ifType']), - 'ifAlias' => $port['ifAlias'], - 'actions' => $actions, - ]; -} - -$output = [ - 'current' => $current, - 'rowCount' => $rowCount, - 'rows' => $response, - 'total' => $total, -]; - -echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/resources/views/port/actions.blade.php b/resources/views/port/actions.blade.php new file mode 100644 index 0000000000..9a095d8ab8 --- /dev/null +++ b/resources/views/port/actions.blade.php @@ -0,0 +1,12 @@ +
+
+ @if(request('deleted') === 'yes') +
+ @else +
+ @admin +
+ @endadmin + @endif +
+
diff --git a/routes/web.php b/routes/web.php index 1c07e5fcce..770eef7490 100644 --- a/routes/web.php +++ b/routes/web.php @@ -137,6 +137,7 @@ Route::group(['middleware' => ['auth'], 'guard' => 'auth'], function () { Route::post('mempools', 'MempoolsController'); Route::post('outages', 'OutagesController'); Route::post('port-nac', 'PortNacController'); + Route::post('ports', 'PortsController')->name('table.ports'); Route::post('routes', 'RoutesTablesController'); Route::post('syslog', 'SyslogController'); Route::post('vminfo', 'VminfoController');
Device>PortStatus ChangedDevice data-formatter="port">PortStatus Changed Connected Speed MTU>Errors In Errors Out Media