1package App::Netdisco::Web::Plugin::Search::Port;
2
3use Dancer ':syntax';
4use Dancer::Plugin::DBIC;
5use Dancer::Plugin::Auth::Extensible;
6
7use App::Netdisco::Web::Plugin;
8use App::Netdisco::Util::Web 'sql_match';
9
10use Regexp::Common 'net';
11use NetAddr::MAC ();
12
13register_search_tab({
14    tag => 'port',
15    label => 'Port',
16    provides_csv => 1,
17    api_endpoint => 1,
18    api_parameters => [
19      q => {
20        description => 'Port name or VLAN or MAC address',
21        required => 1,
22      },
23      partial => {
24        description => 'Search for a partial match on parameter "q"',
25        type => 'boolean',
26        default => 'true',
27      },
28      uplink => {
29        description => 'Include uplinks in results',
30        type => 'boolean',
31        default => 'false',
32      },
33      ethernet => {
34        description => 'Only Ethernet type interfaces in results',
35        type => 'boolean',
36        default => 'true',
37      },
38    ],
39});
40
41# device ports with a description (er, name) matching
42get '/ajax/content/search/port' => require_login sub {
43    my $q = param('q');
44    send_error( 'Missing query', 400 ) unless $q;
45    my $rs;
46
47    if ($q =~ m/^[0-9]+$/ and $q < 4096) {
48        $rs = schema('netdisco')->resultset('DevicePort')
49                ->columns( [qw/ ip port name up up_admin speed /] )->search({
50                  "port_vlans.vlan" => $q,
51                  ( param('uplink') ? () : (-or => [
52                    {-not_bool => "me.is_uplink"},
53                    {"me.is_uplink" => undef},
54                  ]) ),
55                  ( param('ethernet') ? ("me.type" => 'ethernetCsmacd') : () ),
56                },{ '+columns' => [qw/ device.dns device.name port_vlans.vlan /],
57                    join       => [qw/ port_vlans device /]
58                }
59                )->with_times;
60    }
61    else {
62        my ( $likeval, $likeclause ) = sql_match($q);
63        my $mac = NetAddr::MAC->new(mac => ($q || ''));
64
65        undef $mac if
66          ($mac and $mac->as_ieee
67          and (($mac->as_ieee eq '00:00:00:00:00:00')
68            or ($mac->as_ieee !~ m/$RE{net}{MAC}/)));
69
70        $rs = schema('netdisco')->resultset('DevicePort')
71                                ->columns( [qw/ ip port name up up_admin speed /] )
72                                ->search({
73              -and => [
74                -or => [
75                  { "me.name" => ( param('partial') ? $likeclause : $q ) },
76                  ( ((!defined $mac) or $mac->errstr)
77                      ? \[ 'me.mac::text ILIKE ?', $likeval ]
78                      : {  'me.mac' => $mac->as_ieee        }
79                  ),
80                  ( param('uplink') ? (
81                    { "me.remote_id"   => $likeclause },
82                    { "me.remote_type" => $likeclause },
83                  ) : () ),
84                ],
85                ( param('uplink') ? () : (-or => [
86                  {-not_bool => "me.is_uplink"},
87                  {"me.is_uplink" => undef},
88                ]) ),
89                ( param('ethernet') ? ("me.type" => 'ethernetCsmacd') : () ),
90              ]
91            },
92            {   '+columns' => [qw/ device.dns device.name port_vlans.vlan /],
93                join       => [qw/ port_vlans device /]
94            }
95            )->with_times;
96    }
97
98    my @results = $rs->hri->all;
99    return unless scalar @results;
100
101    if ( request->is_ajax ) {
102        my $json = to_json( \@results );
103        template 'ajax/search/port.tt', { results => $json };
104    }
105    else {
106        header( 'Content-Type' => 'text/comma-separated-values' );
107        template 'ajax/search/port_csv.tt', { results => \@results };
108    }
109};
110
1111;
112