Files
netdisco/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Ports.pm
2014-10-11 13:01:03 +01:00

156 lines
4.9 KiB
Perl

package App::Netdisco::Web::Plugin::Device::Ports;
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_device_tab(
{ tag => 'ports', label => 'Ports', provides_csv => 1 } );
# device ports with a description (er, name) matching
get '/ajax/content/device/ports' => require_login sub {
my $q = param('q');
my $prefer = param('prefer');
$prefer = ''
unless defined $prefer and $prefer =~ m/^(?:port|name|vlan)$/;
my $device
= schema('netdisco')->resultset('Device')->search_for_device($q)
or send_error( 'Bad device', 400 );
my $rs = $device->ports_flattened;
# refine by ports if requested
my $f = param('f');
if ($f) {
if ( ( $prefer eq 'vlan' ) or not $prefer and $f =~ m/^\d+$/ ) {
if ( param('invert') ) {
$rs = $rs->search(
{ 'me.vlan' => { '!=' => $f },
'-or' => [
-not_bool => {
'me.vlan_membership' =>
{ '@>' => { -value => [$f] } }
},
'me.vlan_membership' => { '=' => undef },
]
}
);
}
else {
$rs = $rs->search(
{ -or => {
'me.vlan' => $f,
'me.vlan_membership' =>
{ '@>' => { -value => [$f] } },
},
}
);
}
return unless $rs->count;
}
else {
if ( param('partial') ) {
# change wildcard chars to SQL
$f =~ s/\*/%/g;
$f =~ s/\?/_/g;
# set wilcards at param boundaries
if ( $f !~ m/[%_]/ ) {
$f =~ s/^\%*/%/;
$f =~ s/\%*$/%/;
}
# enable ILIKE op
$f = { ( param('invert') ? '-not_ilike' : '-ilike' ) => $f };
}
elsif ( param('invert') ) {
$f = { '!=' => $f };
}
if ( ( $prefer eq 'port' )
or not $prefer and $rs->search( { 'me.port' => $f } )->count )
{
$rs = $rs->search(
{ -or => [
'me.port' => $f,
'me.slave_of' => $f,
],
}
);
}
else {
$rs = $rs->search( { 'me.name' => $f } );
return unless $rs->count;
}
}
}
# filter for port status if asked
my %port_state = map { $_ => 1 } (
ref [] eq ref param('port_state') ? @{ param('port_state') }
: param('port_state') ? param('port_state')
: ()
);
# user deseleted all port states. that means no ports.
return unless scalar keys %port_state;
# if four keys, that's shorthand for everything.
# so only add these filters if user deselected something.
if (scalar keys %port_state != 4) {
my @combi = ();
if ( exists $port_state{free} ) {
my $age_num = ( param('age_num') || 3 );
my $age_unit = ( param('age_unit') || 'months' );
my $interval = "$age_num $age_unit";
push @combi, { -and => [
{ 'me.up_admin' => 'up', 'me.up' => { '!=' => 'up' } },
\[ "age(now(), to_timestamp(extract(epoch from me.device_last_discover) "
. "- (me.device_uptime - me.lastchange)/100)) "
. "> ?::interval",
[ {} => $interval ] ],
]};
}
push @combi, { 'me.up' => 'up' }
if exists $port_state{up};
push @combi, { 'me.up_admin' => 'up', 'me.up' => { '!=' => 'up' } }
if exists $port_state{down};
push @combi, { 'me.up_admin' => { '!=' => 'up' } }
if exists $port_state{shut};
$rs = $rs->search( { -or => \@combi } );
}
# retrieve active/all connected nodes, if asked for
$rs = $rs->search_rs( {},
{ prefetch => 'nodes', bind => [ $device->ip ],
order_by => [
{ -desc => 'nodes.active' },
{ -asc => 'nodes.mac' },
{ -asc => 'nodes.ip' },
] });
my @results = $rs->hri->all;
return unless scalar @results;
if ( request->is_ajax ) {
template 'ajax/device/ports.tt',
{ results => to_json( \@results ), }, { layout => undef };
}
else {
header( 'Content-Type' => 'text/comma-separated-values' );
template 'ajax/device/ports_csv.tt', { results => \@results, },
{ layout => undef };
}
};
1;