diff --git a/lib/App/Netdisco/DB.pm b/lib/App/Netdisco/DB.pm index 7e864c36..abb2af1a 100644 --- a/lib/App/Netdisco/DB.pm +++ b/lib/App/Netdisco/DB.pm @@ -11,7 +11,7 @@ __PACKAGE__->load_namespaces( ); our # try to hide from kwalitee - $VERSION = 45; # schema version used for upgrades, keep as integer + $VERSION = 46; # schema version used for upgrades, keep as integer use Path::Class; use File::ShareDir 'dist_dir'; diff --git a/lib/App/Netdisco/DB/Result/NetmapPositions.pm b/lib/App/Netdisco/DB/Result/NetmapPositions.pm new file mode 100644 index 00000000..234407a8 --- /dev/null +++ b/lib/App/Netdisco/DB/Result/NetmapPositions.pm @@ -0,0 +1,23 @@ +use utf8; +package App::Netdisco::DB::Result::NetmapPositions; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; +__PACKAGE__->table("netmap_positions"); +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_nullable => 0, is_auto_increment => 1 }, + "device_groups", + { data_type => "text[]", is_nullable => 0 }, + "positions", + { data_type => "text", is_nullable => 0 }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->add_unique_constraint( + "netmap_positions_device_groups_key" => ['device_groups']); + +1; diff --git a/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm b/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm index 2ff1fde3..b1f8dea8 100644 --- a/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm +++ b/lib/App/Netdisco/Web/Plugin/Device/Neighbors.pm @@ -5,6 +5,7 @@ use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; +use List::MoreUtils (); use App::Netdisco::Web::Plugin; register_device_tab({ tag => 'netmap', label => 'Neighbors' }); @@ -14,10 +15,33 @@ ajax '/ajax/content/device/netmap' => require_login sub { template 'ajax/device/netmap.tt', {}, { layout => undef }; }; -# TODO ajax '/ajax/data/device/netmappositions' => require_login sub { - my $x = from_json param('positions'); - use DDP; p $x; + my $p = param('positions') or send_error('Missing positions', 400); + my $positions = from_json($p) or send_error('Bad positions', 400); + send_error('Bad positions', 400) unless ref [] eq ref $positions; + + my %clean = (); + POSITION: foreach my $pos (@$positions) { + next unless ref {} eq ref $pos; + foreach my $k (qw/ID x y/) { + next POSITION unless exists $pos->{$k}; + next POSITION unless $pos->{$k} =~ m/^[[:word:]\.-]+$/; + } + $clean{$pos->{ID}} = { x => $pos->{x}, y => $pos->{y} }; + } + + return unless scalar keys %clean; + my $posrow = schema('netdisco')->resultset('NetmapPositions')->find({ + device_groups => \[ '= ?', [device_groups => [sort (List::MoreUtils::uniq( '__ANY__' )) ]] ]}); + if ($posrow) { + $posrow->update({ positions => to_json(\%clean) }); + } + else { + schema('netdisco')->resultset('NetmapPositions')->create({ + device_groups => [sort (List::MoreUtils::uniq( '__ANY__' )) ], + positions => to_json(\%clean), + }); + } }; ajax '/ajax/data/device/netmap' => require_login sub { @@ -28,6 +52,10 @@ ajax '/ajax/data/device/netmap' => require_login sub { my $vlan = param('vlan'); undef $vlan if (defined $vlan and $vlan !~ m/^\d+$/); + my $posrow = schema('netdisco')->resultset('NetmapPositions')->find({ + device_groups => \[ '= ?', [device_groups => [sort (List::MoreUtils::uniq( '__ANY__' )) ]] ]}); + my $pos_for = from_json( $posrow ? $posrow->positions : '{}' ); + my @devices = schema('netdisco')->resultset('Device')->search({}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator', columns => ['ip', 'dns', 'name'], @@ -44,15 +72,26 @@ ajax '/ajax/data/device/netmap' => require_login sub { (my $name = ($device->{dns} || lc($device->{name}) || $device->{ip})) =~ s/$domain$//; $v3data{nodes}->{ ($device->{row_number} - 1) } = { - ID => $device->{row_number}, + ID => $device->{ip}, SIZEVALUE => 3000, COLORVALUE => 10, LABEL => $name, }; - push @{$v4data{'nodes'}}, { index => ($device->{row_number} - 1) }; - $v3data{'centernode'} = $device->{row_number} + if (exists $pos_for->{$device->{ip}}) { + my $node = $v3data{nodes}->{ ($device->{row_number} - 1) }; + $node->{'fixed'} = 1; + $node->{'x'} = $pos_for->{$device->{ip}}->{'x'}; + $node->{'y'} = $pos_for->{$device->{ip}}->{'y'}; + } + else { + ++$v3data{'newnodes'}; + } + + $v3data{'centernode'} = $device->{ip} if $qdev and $qdev->in_storage and $device->{ip} eq $qdev->ip; + + push @{$v4data{'nodes'}}, { index => ($device->{row_number} - 1) }; } my $rs = schema('netdisco')->resultset('Virtual::DeviceLinks')->search({}, { @@ -71,8 +110,8 @@ ajax '/ajax/data/device/netmap' => require_login sub { while (my $l = $rs->next) { push @{$v3data{'links'}}, { - FROMID => $id_for{$l->{left_ip}}, - TOID => $id_for{$l->{right_ip}}, + FROMID => $l->{left_ip}, + TOID => $l->{right_ip}, }; push @{$v4data{'links'}}, { source => ($id_for{$l->{left_ip}} - 1), diff --git a/share/config.yml b/share/config.yml index d79ab2af..2b705812 100644 --- a/share/config.yml +++ b/share/config.yml @@ -172,6 +172,8 @@ login_logo: "" # mibhome is discovered from environment # mibdirs defaults to contents of mibhome host_groups: + __ANY__: + - 'any' __LOCAL_ADDRESSES__: - '::1' - 'fe80::/10' diff --git a/share/schema_versions/App-Netdisco-DB-45-46-PostgreSQL.sql b/share/schema_versions/App-Netdisco-DB-45-46-PostgreSQL.sql new file mode 100644 index 00000000..78854aec --- /dev/null +++ b/share/schema_versions/App-Netdisco-DB-45-46-PostgreSQL.sql @@ -0,0 +1,9 @@ +BEGIN; + +CREATE TABLE "netmap_positions" ( + "id" serial PRIMARY KEY, + "device_groups" text[] UNIQUE NOT NULL, + "positions" text NOT NULL +); + +COMMIT; diff --git a/share/views/ajax/device/netmap.tt b/share/views/ajax/device/netmap.tt index 19a1f156..52883c97 100644 --- a/share/views/ajax/device/netmap.tt +++ b/share/views/ajax/device/netmap.tt @@ -40,11 +40,12 @@ $.getJSON('[% uri_for('/ajax/data/device/netmap') %]', {q: '[% params.q %]'}, fu graph.inspect().main.force.on('end.setupfornetdisco', function() { graph.inspect().main.nodes.each(function(n) { n.fixed = true }); - // FIXME - $.post( - '[% uri_for('/ajax/data/device/netmappositions') %]' - ,'positions=' + JSON.stringify(graph.positions()) - ); + if (mapdata['v3']['newnodes']) { + $.post( + '[% uri_for('/ajax/data/device/netmappositions') %]' + ,'positions=' + JSON.stringify(graph.positions()) + ); + } graph['nd2'] = {}; graph['nd2']['dragging'] = false; @@ -89,7 +90,7 @@ $.getJSON('[% uri_for('/ajax/data/device/netmap') %]', {q: '[% params.q %]'}, fu }), 'links': mapdata['v3']['links'] }}; - graph.start(); + graph.start(netmapdata); // center on our selected device // graph.inspect().main.force.on('end.centernode', function() {