[#75] Device module inventory report / search
This commit is contained in:
107
Netdisco/lib/App/Netdisco/DB/ResultSet/DeviceModule.pm
Normal file
107
Netdisco/lib/App/Netdisco/DB/ResultSet/DeviceModule.pm
Normal file
@@ -0,0 +1,107 @@
|
||||
package App::Netdisco::DB::ResultSet::DeviceModule;
|
||||
use base 'App::Netdisco::DB::ResultSet';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
|
||||
=head1 ADDITIONAL METHODS
|
||||
|
||||
=head2 search_by_field( \%cond, \%attrs? )
|
||||
|
||||
This variant of the standard C<search()> method returns a ResultSet of Device
|
||||
Module entries. It is written to support web forms which accept fields that
|
||||
match and locate Device Modules in the database.
|
||||
|
||||
The hashref parameter should contain fields from the Device Module table
|
||||
which will be intelligently used in a search query.
|
||||
|
||||
In addition, you can provide the key C<matchall> which, given a True or False
|
||||
value, controls whether fields must all match or whether any can match, to
|
||||
select a row.
|
||||
|
||||
Supported keys:
|
||||
|
||||
=over 4
|
||||
|
||||
=item matchall
|
||||
|
||||
If a True value, fields must all match to return a given row of the Device
|
||||
table, otherwise any field matching will cause the row to be included in
|
||||
results.
|
||||
|
||||
=item description
|
||||
|
||||
Can match the C<description> field as a substring.
|
||||
|
||||
=item name
|
||||
|
||||
Can match the C<name> field as a substring.
|
||||
|
||||
=item type
|
||||
|
||||
Can match the C<type> field as a substring.
|
||||
|
||||
=item model
|
||||
|
||||
Can match the C<model> field as a substring.
|
||||
|
||||
=item serial
|
||||
|
||||
Can match the C<serial> field as a substring.
|
||||
|
||||
=item class
|
||||
|
||||
Will match exactly the C<class> field.
|
||||
|
||||
=item ips
|
||||
|
||||
List of Device IPs containing modules.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub search_by_field {
|
||||
my ( $rs, $p, $attrs ) = @_;
|
||||
|
||||
die "condition parameter to search_by_field must be hashref\n"
|
||||
if ref {} ne ref $p
|
||||
or 0 == scalar keys %$p;
|
||||
|
||||
my $op = $p->{matchall} ? '-and' : '-or';
|
||||
|
||||
return $rs->search_rs( {}, $attrs )->search(
|
||||
{ $op => [
|
||||
( $p->{description}
|
||||
? ( 'me.description' =>
|
||||
{ '-ilike' => "\%$p->{description}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{name}
|
||||
? ( 'me.name' => { '-ilike' => "\%$p->{name}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{type}
|
||||
? ( 'me.type' => { '-ilike' => "\%$p->{type}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{model}
|
||||
? ( 'me.model' => { '-ilike' => "\%$p->{model}\%" } )
|
||||
: ()
|
||||
),
|
||||
( $p->{serial}
|
||||
? ( 'me.serial' => { '-ilike' => "\%$p->{serial}\%" } )
|
||||
: ()
|
||||
),
|
||||
|
||||
( $p->{class}
|
||||
? ( 'me.class' => { '-in' => $p->{class} } )
|
||||
: ()
|
||||
),
|
||||
( $p->{ips} ? ( 'me.ip' => { '-in' => $p->{ips} } ) : () ),
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
109
Netdisco/lib/App/Netdisco/Web/Plugin/Report/ModuleInventory.pm
Normal file
109
Netdisco/lib/App/Netdisco/Web/Plugin/Report/ModuleInventory.pm
Normal file
@@ -0,0 +1,109 @@
|
||||
package App::Netdisco::Web::Plugin::Report::ModuleInventory;
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::DBIC;
|
||||
use Dancer::Plugin::Auth::Extensible;
|
||||
|
||||
use App::Netdisco::Web::Plugin;
|
||||
use List::MoreUtils ();
|
||||
|
||||
register_report(
|
||||
{ category => 'Device',
|
||||
tag => 'moduleinventory',
|
||||
label => 'Module Inventory',
|
||||
provides_csv => 1,
|
||||
}
|
||||
);
|
||||
|
||||
hook 'before' => sub {
|
||||
|
||||
# view settings
|
||||
var('module_options' => [
|
||||
{ name => 'matchall',
|
||||
label => 'Match All Options',
|
||||
default => 'on'
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
return
|
||||
unless (
|
||||
request->path eq uri_for('/report/moduleinventory')->path
|
||||
or index( request->path,
|
||||
uri_for('/ajax/content/report/moduleinventory')->path ) == 0
|
||||
);
|
||||
|
||||
params->{'limit'} ||= 1024;
|
||||
|
||||
foreach my $col ( @{ var('module_options') } ) {
|
||||
next unless $col->{default} eq 'on';
|
||||
params->{ $col->{name} } = 'checked';
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
hook 'before_template' => sub {
|
||||
my $tokens = shift;
|
||||
|
||||
return
|
||||
unless (
|
||||
request->path eq uri_for('/report/moduleinventory')->path
|
||||
or index( request->path,
|
||||
uri_for('/ajax/content/report/moduleinventory')->path ) == 0
|
||||
);
|
||||
|
||||
# used in the search sidebar template to set selected items
|
||||
foreach my $opt (qw/class/) {
|
||||
my $p = (
|
||||
ref [] eq ref param($opt)
|
||||
? param($opt)
|
||||
: ( param($opt) ? [ param($opt) ] : [] )
|
||||
);
|
||||
$tokens->{"${opt}_lkp"} = { map { $_ => 1 } @$p };
|
||||
}
|
||||
};
|
||||
|
||||
get '/ajax/content/report/moduleinventory' => require_login sub {
|
||||
|
||||
my $has_opt = List::MoreUtils::any { param($_) }
|
||||
qw/device description name type model serial class/;
|
||||
|
||||
my $rs = schema('netdisco')->resultset('DeviceModule');
|
||||
|
||||
if ($has_opt) {
|
||||
|
||||
if ( param('device') ) {
|
||||
my @ips = schema('netdisco')->resultset('Device')
|
||||
->search_fuzzy( param('device') )->get_column('ip')->all;
|
||||
|
||||
params->{'ips'} = \@ips;
|
||||
}
|
||||
|
||||
$rs = $rs->search_by_field( scalar params )->prefetch('device')
|
||||
->limit( param('limit') )->hri;
|
||||
|
||||
}
|
||||
else {
|
||||
$rs = $rs->search(
|
||||
{},
|
||||
{ select => [ 'class', { count => 'class' } ],
|
||||
as => [qw/ class count /],
|
||||
group_by => [qw/ class /]
|
||||
}
|
||||
)->order_by( { -desc => 'count' } )->hri;
|
||||
|
||||
}
|
||||
|
||||
return unless $rs->has_rows;
|
||||
if ( request->is_ajax ) {
|
||||
template 'ajax/report/moduleinventory.tt', { results => $rs, },
|
||||
{ layout => undef };
|
||||
}
|
||||
else {
|
||||
header( 'Content-Type' => 'text/comma-separated-values' );
|
||||
template 'ajax/report/moduleinventory_csv.tt', { results => $rs, },
|
||||
{ layout => undef };
|
||||
}
|
||||
};
|
||||
|
||||
1;
|
||||
@@ -12,6 +12,8 @@ get '/report/*' => require_login sub {
|
||||
= [
|
||||
schema('netdisco')->resultset('NodeNbt')->get_distinct_col('domain')
|
||||
];
|
||||
my $class_list = [ schema('netdisco')->resultset('DeviceModule')
|
||||
->get_distinct_col('class') ];
|
||||
|
||||
# trick the ajax into working as if this were a tabbed page
|
||||
params->{tab} = $tag;
|
||||
@@ -21,6 +23,7 @@ get '/report/*' => require_login sub {
|
||||
{
|
||||
report => setting('_reports')->{$tag},
|
||||
domain_list => $domain_list,
|
||||
class_list => $class_list,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user