%doc>
-- Operations Worksheet --
Interface (similar to device worksheet) for viewing/updating
NOC relevant infomation. This includes customer contacts,
devices, sites, circuits.
%doc>
%
%
<%args>
$id => undef
$table => undef
$search => undef
$_action => undef
$status => undef
$view => "Basics"
$edit => undef
$user => $ui->get_current_user($r)
$only_show_available_contacts => 1
%args>
%
%
<%attr>
title => 'Operations'
section => 'Operations'
%attr>
%
%
<%init>
use Netdot::Operations;
my $DEBUG = 0;
my $obj = undef;
my $list;
my @tables;
my %results;
my %stables;
my $caller_args = $m->caller_args(-1);
@{ $list } = ();
if( exists( $caller_args->{page} ) ) {
$user->setAttribute($r, "OPERATIONS_PAGE", $caller_args->{page});
}
my $page = $user->getAttribute("OPERATIONS_PAGE");
print '%ARGS is
', Dumper(%ARGS), '
' if $DEBUG;
if( $search ) {
@tables = qw( Connection Device Entity Person Site RR );
if( defined( $search ) && $search =~ /\w+/ ) {
# walk through a set of tables and search each column
foreach my $tbl ( @tables ) {
my @columns = $tbl->_essential();
if( $tbl ne "Connection" && $tbl ne "RR" ) {
push @columns, "aliases";
}
my %linksto = $ui->meta->get_links_to($tbl);
foreach my $col ( @columns ) {
if( $col eq "id" || $linksto{$col} ) {
next;
} else {
$stables{$tbl}{$col} = 1;
}
}
}
foreach my $tbl ( keys %stables ) {
foreach my $col ( keys %{ $stables{$tbl} } ) {
my $q = "%" . $search . "%";
map {
$results{$tbl}{$_->id} = $_
} $tbl->search_like( $col => $q );
}
}
} elsif( defined( $search ) && $search !~ /\w+/ ) {
print "No search criteria";
$m->abort;
} elsif( defined( $id ) && defined( $table ) ) {
$obj = $table->retrieve($id);
if( ! defined( $obj) ) {
$m->comp( 'error.mhtml', error => "Could not retrieve $table with id $id" );
}
}
} elsif( $status ) {
@tables = qw( BGPPeering Device Interface IpService );
} elsif( defined( $id ) && defined( $table ) ) {
$obj = $table->retrieve($id);
if( ! defined( $obj) ) {
$m->comp( 'error.mhtml', error => "Could not retrieve $table with id $id" );
}
}
if( %results ) {
# Tables with entity column: Connection Device Person
# Site must use EntitySite to look up the corresponding Entity
foreach my $tbl ( keys %results ) {
foreach my $id ( keys %{ $results{$tbl} } ) {
if( $tbl eq "RR" ) {
my $s = ( Device->search( name => $results{$tbl}{$id} ) )[0];
if( $s ) {
$results{"Device"}{$s->id()} = $s;
}
delete( $results{$tbl}{$id} );
}
}
}
delete( $results{"RR"} );
if( %results && scalar( keys %results ) == 1 ) {
my $tbl = ( keys %results )[0];
if( scalar( keys %{ $results{$tbl} } ) == 1 ) {
undef( $search );
$obj = ( values %{ $results{$tbl} } )[0];
$table = $tbl;
$id = $obj->id();
}
}
if( defined( $search ) ) {
foreach my $tbl ( keys %results ) {
map {
push @{ $list }, $results{$tbl}{$_}
} keys %{ $results{$tbl} };
}
}
} elsif( $obj ) {
; # do nothing
} else {
print "
No results";
$m->abort;
}
%init>
%
<%once>
my $names = 0;
my $dispatch = sub {
# Each $table type will have specific ``call chains''
# (e.g. Device->interfaces->nearcircuits->cid is the chain to circuit
# ids for a device)
my $key = shift;
my %table = (
Device => '.DeviceHandler',
# Interface => '.InterfaceHandler',
Circuit => '.CircuitHandler',
Entity => '.EntityHandler',
# ContactList => '.ContactListHandler',
Site => '.SiteHandler',
Person => '.PersonHandler',
);
die "Don't know how to dispatch \"$key\"s" unless exists $table{$key};
return $table{$key};
};
%once>
%
%
% if( $search ) {
%
<&| .MakeContainerOutside,
lhs => scalar( @{$list} ) . " results for
$search" &>
% foreach my $tbl ( sort keys %results ) {
% my @list = values %{ $results{$tbl} };
<&| .MakeContainer, lhs => $tbl, &>
<& /generic/sortresults.mhtml, table => $tbl, object => \@list, view => "row", page => "operations.html", withedit => 1 &>
&>
% }
&>
%
% } elsif( $obj ) { # Displaying a single thing
%
% my $lbl = $ui->getobjlabel($obj, ", ");
<% $table %>:
<% $obj->view_link %>
View:
% if( $view eq "Basics" ) { # The default view
[Basics]
% } else {
[Basics]
% }
% $m->comp( $dispatch->($table) , obj => $obj, only_show_available_contacts => $only_show_available_contacts); #, dispatch => $dispatch );
%
% } elsif( $status ) {
print "
Not yet implemented.";
% }
%
<%def .PersonHandler >
<%args>
$obj => 0
$accumulate_contact_lists => 0
$only_show_available_contacts
%args>
<%init>
my $contact_lists = [map {$_->contactlist} $obj->roles];
%init>
<% $obj->table %>:<% $obj->view_link %>
Contact List: <% map {$_->name} @$contact_lists %>
<&| .MakeContainer, lhs => "Devices @{[ $obj->label ]} is responsible for:" &>
% foreach my $device ($obj->devices) {
<& .DeviceHandler, obj => $device,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
% }
&>
<&| .MakeContainer, lhs => $obj->location->table &>
<& .SiteHandler, obj => $obj->location,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
&>
<&| .MakeContainer, lhs => $obj->entity->table &>
<& .EntityHandler, obj => $obj->entity,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
&>
<& .DisplayAvailableContacts, contact_lists => $contact_lists,
only_show_available_contacts => $only_show_available_contacts, obj => $obj &>
%def>
<%def .EntityHandler >
<%args>
$obj => 0
$accumulate_contact_lists => 0
$only_show_available_contacts
%args>
<%init>
my $contact_lists = [$obj->contactlist];
%init>
<% $obj->table %>:<% $obj->view_link %>
Contact List: <% map {$_->name} @$contact_lists %>
% if (scalar $obj->sites) {
<&| .MakeContainer, lhs => "Sites" &>
% foreach my $site (map {$_->site} $obj->sites) {
<& .SiteHandler, obj => $site,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
% }
&>
% }
% if (scalar $obj->devices) {
<&| .MakeContainer, lhs => "Devices" &>
% foreach my $device ($obj->devices) {
<& .DeviceHandler, obj => $device,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
% }
&>
% }
% if (scalar $obj->all_circuits) {
<&| .MakeContainer, lhs => "@{[$obj->table]} Circuits" &>
<& .DisplayCircuits, obj => $obj,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
&>
% }
% if (ref $accumulate_contact_lists eq "ARRAY") {
% @$accumulate_contact_lists = @$contact_lists;
% } else {
<& .DisplayAvailableContacts, contact_lists => $contact_lists,
only_show_available_contacts => $only_show_available_contacts, obj => $obj &>
% }
%def>
<%def .SiteHandler>
<%args>
$obj => 0
$accumulate_contact_lists => 0
$only_show_available_contacts
%args>
<%init>
#$m->comp('info', table => $obj->contactlist->table, id => $obj->contactlist->id);
# *** Still need the city (and contact list).
# my $lhs = $obj->view_link . ':' . $obj->city . " " . $obj->state;
my $contact_lists = [$obj->contactlist];
%init>
Site:<% $obj->view_link %>
Contact List: <% map {$_->name} @$contact_lists %>
<&| '.MakeContainer', lhs => "Devices", &>
% foreach my $device ($obj->devices) {
<& .DeviceHandler, obj => $device,
only_show_available_contacts => $only_show_available_contacts,
accumulate_contact_lists => $contact_lists &>
% }
&>
% if (ref $accumulate_contact_lists eq "ARRAY") {
% @$accumulate_contact_lists = @$contact_lists;
% } else {
<& .DisplayAvailableContacts, contact_lists => $contact_lists,
only_show_available_contacts => $only_show_available_contacts, obj => $obj &>
% }
%def>
%# When you read calling code the `.' indicates it is a mason
%# subroutine (as opposed to a module from a file).
<%def .DeviceHandler>
<%doc>
%doc>
<%args>
$obj => 0
# If a list ref is passed for this parameter then, instead of
# passing this devices contact lists to .DisplayAvailableContacts,
# this devices contact lists will be pushed onto
# @$accumulate_contact_lists. This is used to prevent the same
# contact list from being printed multiple times when showing the
# operations page for something like a site which may have
# multiple devices.
$accumulate_contact_lists => 0
$only_show_available_contacts
%args>
<%init>
my @contact_lists = map { $_->contactlist } $obj->contacts;
my $lhs = $obj->view_link . ':' . $obj->productname->name . " " . $obj->productname->type->name;
%init>
<&| '.MakeContainer', lhs => $lhs,
rhs => "Contact List(s): @{[map {$_->name } @contact_lists]}" &>
% if (scalar $obj->all_circuits != 0) {
<&| '.MakeContainer', lhs => 'Device Circuits' &>
<& .DisplayCircuits, obj => $obj &>
&>
% }
%# Display out of bound info if there is any.
% if ($obj->oobname ne "" or $obj->oobnumber ne "") {
<&| '.MakeContainer', lhs => 'OOB Info' &>
<& '/generic/attribute_table.mhtml', field_headers => ['oobname', 'oobnumber'],
data => [$obj->oobname, $obj->oobnumber] &>
&>
% }
%# Display uplinks and downlinks.
<&| '.MakeContainer', lhs => "Interface Links", &>
% foreach my $interface ($obj->interfaces) {
%# Are there any {up,down}links?
% if (scalar ($interface->children, $interface->parents)) {
%# allen-304-sw1 has multiple uplinks
<& /generic/data_table.mhtml, field_headers => ['interface', 'uplinks', 'downlinks'],
data =>
[[
$interface->view_link,
$m->scomp('/generic/data_table.mhtml',
data => [map {[$_->view_link]} $interface->parents]),
$m->scomp('/generic/data_table.mhtml',
data => [map {[$_->view_link]} $interface->children]),
]]
&>
% }
% }
&>
% if (ref $accumulate_contact_lists eq "ARRAY") {
% push @$accumulate_contact_lists, @contact_lists;
% } else {
<& .DisplayAvailableContacts, contact_lists => \@contact_lists,
obj => $obj, only_show_available_contacts=> $only_show_available_contacts &>
% }
&>
%def>
<%def .DisplayCircuits>
<%args>
$obj
%args>
<%init>
# Added in Operations.pm
my @circuits = $obj->all_circuits;
my (@field_headers, @data);
# This will fail if there aren't any circuits.
# Not any more. Was getting table names from first object in @circuits.
@field_headers = ('Circuit', 'Connection', 'Entity');
foreach my $circuit (@circuits) {
push @data, [$circuit->view_link, $circuit->connectionid->view_link, $circuit->vendor->view_link];
}
$m->comp('/generic/data_table.mhtml', field_headers => \@field_headers, data => \@data);
%init>
%def>
%# Name should just be display contacts now that availability is an option
<%def .DisplayAvailableContacts>
<%args>
@contact_lists
$obj
# If true only available contacts are displayed
$only_show_available_contacts=> 1
%args>
<%init>
# Need to ``uniqueify'' the contact lists since there might be
# many repeats (most devices at the same site have the same
# contact lists). The below works because keys are unique.
@contact_lists = values %{ { map {$_->name => $_} @contact_lists } };
my @contacts = map { $_->contacts } @contact_lists;
# Will fail if there aren't any contact_sets
# Not any more. Was getting table names from first object in @contacts.
my @field_headers = ("Person",
"Contact List",
"Contact Info",);
my @data;
if ($only_show_available_contacts) {
@contacts = Netdot::Operations::contactable_contacts(@contacts);
foreach my $contact_set (@contacts) {
my $contact = $contact_set->{contact};
push @data, [$contact->person->view_link,
$contact->contactlist->view_link,
$m->scomp('.ContactHandler', contact => $contact,
notification_modes => $contact_set->{availabilities})
];
}
} else {
foreach my $contact (@contacts) {
push @data, [$contact->person->view_link,
$contact->contactlist->view_link,
$m->scomp('.ContactHandler', contact => $contact)
];
}
}
my $current_set_of_contacts = $only_show_available_contacts? 'Available' : 'All';
my $other_set_of_contacts = $only_show_available_contacts? 'All' : 'Available';
%init>
<&| '.MakeContainer', lhs => "$current_set_of_contacts @{[ $obj->table ]} Contacts",
rhs => "id ]}&table=@{[ $obj->table ]}&only_show_available_contacts=@{[ ! $only_show_available_contacts]}\">[$other_set_of_contacts @{[ $obj->table ]} Contacts]" &>
<& '/generic/data_table.mhtml', field_headers => \@field_headers, data => \@data &>
&>
%def>
<%def .ContactHandler>
<%args>
$contact
# Optionally specify which notification modes to display. If none
# are specified then all are shown.
@notification_modes => ()
%args>
<%init>
@notification_modes = qw/notify_voice notify_pager notify_email/
if (scalar @notification_modes == 0);
my $person = $contact->person;
# For generically processing voice, pager, and email data.
my $template = {
notify_voice => {
title => "Phone",
fields => [qw/office cell home/],
},
notify_pager => {
title => "Pager",
fields => [qw/pager emailpager/],
},
notify_email => {
title => "Email",
fields => [qw/email/],
},
};
my (@field_headers, @data);
foreach my $mode (@notification_modes) {
my $values = $template->{$mode};
push @field_headers, "" . $values->{title} . "";
push @data, $contact->$mode->view_link;
foreach my $type (@{ $values->{fields} }) {
my %pair = $ui->form_field(object => $contact->person, column => $type);
if ($pair{value} ne "") {
push @field_headers, $pair{label};
push @data, $pair{value};
}
}
}
$m->comp('/generic/attribute_table.mhtml', field_headers => \@field_headers,
data => \@data);
%init>
%def>
%# Could make a meta make container method as these methods are almost
%# identical. Also, there is a containerhead(outside)? class which is
%# more appropriate for the case where no right side is specified.
<%def .MakeContainerOutside >
<%args>
$lhs
$rhs => " "
%args>
%
<% $lhs %>
<% $rhs %>
<% $m->content %>
%def>
<%def .MakeContainer >
<%args>
$lhs
$rhs => " "
%args>
%
<% $lhs %>
<% $rhs %>
<% $m->content %>
%def>
%# Debugging
<%def info>
<%args>
$table
$id
%args>
<%init>
sub pp {
my $obj = shift;
my $columns = shift || 'Essential';
eval {
my $s = $obj->pp($columns);
$m->print("$s
");
};
}
use Data::Dumper;
my $obj = $table->retrieve($id);
my $indent = " "x4;
$m->print(" ID $id, Table $table
");
pp($obj, "All");
$m->print(" Has A
");
foreach my $key (keys %{ $obj->meta_info->{has_a} }) {
eval{pp($obj->$key);};
$m->print("no $key in the obj
")
if ($@);
}
$m->print(" Has Many
");
foreach my $key (keys %{ $obj->meta_info->{has_many} }) {
eval {
# Same as $obj->$key :)
#my $accessor = $obj->meta_info->{has_many}->{$key}->{accessor};
#$m->print($key . ": " . $obj->$accessor . "
");
$m->print("Has " . $obj->$key . " $key:
");
$m->print("");
foreach my $foreign ($obj->$key) {
$m->print("$indent" . $foreign->pp . "\n");
}
$m->print("
");
};
}
%init>
Meta Info Dump
<% Dumper($obj->meta_info()) %>
%def>