App-Netdisco
view release on metacpan or search on metacpan
lib/App/Netdisco/Web.pm view on Meta::CPAN
*Dancer::send_error = sub {
my ($body, $status) = @_;
if (request_is_api) {
status $status || 400;
$body = '' unless defined $body;
Dancer::Continuation::Route::ErrorSent->new(
return_value => to_json { error => $body, return_url => param('return_url') }
)->throw;
}
Dancer::Continuation::Route::ErrorSent->new(
return_value => Dancer::Error->new(
message => $body,
code => $status || 500)->render()
)->throw;
};
#Â to insert /t/$tenant if set
#Â which is fine for building links, but not fine for
#Â comparison to request->path, because when is_forward() the
#Â request->path is changed...
*Dancer::Request::uri_for = sub {
my ($self, $part, $params, $dont_escape) = @_;
my $uri = $self->base;
if (vars->{'tenant'}) {
$part = '/t/'. vars->{'tenant'} . $part;
}
# Make sure there's exactly one slash between the base and the new part
my $base = $uri->path;
$base =~ s|/$||;
$part =~ s|^/||;
$uri->path("$base/$part");
$uri->query_form($params) if $params;
return $dont_escape ? uri_unescape($uri->canonical) : $uri->canonical;
};
#Â ...so here we are monkeypatching request->path as well
*Dancer::Request::path = sub {
die "path is accessor not mutator" if scalar @_ > 1;
my $self = shift;
$self->_build_path() unless $self->{path};
if (vars->{'tenant'} and $self->{path} !~ m{/t/}) {
my $path = $self->{path};
my $base = setting('path');
my $tenant = '/t/' . vars->{'tenant'};
$tenant = ($base . $tenant) if $base ne '/';
$tenant .= '/' if $base eq '/';
$path =~ s/^$base/$tenant/;
return $path;
}
return $self->{path};
};
# implement same_site
#Â from https://github.com/PerlDancer/Dancer-Session-Cookie/issues/20
*Dancer::Session::Cookie::_cookie_params = sub {
my $self = shift;
my $name = $self->session_name;
my $duration = $self->_session_expires_as_duration;
my %cookie = (
name => $name,
value => $self->_cookie_value,
path => setting('session_cookie_path') || '/',
domain => setting('session_domain'),
secure => setting('session_secure'),
http_only => setting("session_is_http_only") // 1,
same_site => setting("session_same_site"),
);
if ( defined $duration ) {
$cookie{expires} = time + $duration;
}
return %cookie;
};
}
use App::Netdisco::Web::AuthN;
use App::Netdisco::Web::Static;
use App::Netdisco::Web::Search;
use App::Netdisco::Web::Device;
use App::Netdisco::Web::Report;
use App::Netdisco::Web::API::Objects;
use App::Netdisco::Web::API::Queue;
use App::Netdisco::Web::API::Statistics;
use App::Netdisco::Web::API::User;
use App::Netdisco::Web::Health;
use App::Netdisco::Web::Metrics;
use App::Netdisco::Web::AdminTask;
use App::Netdisco::Web::TypeAhead;
use App::Netdisco::Web::PortControl;
use App::Netdisco::Web::Statistics;
use App::Netdisco::Web::Password;
use App::Netdisco::Web::CustomFields;
use App::Netdisco::Web::GenericReport;
sub _load_web_plugins {
my $plugin_list = shift;
foreach my $plugin (@$plugin_list) {
$plugin =~ s/^X::/+App::NetdiscoX::Web::Plugin::/;
$plugin = 'App::Netdisco::Web::Plugin::'. $plugin
if $plugin !~ m/^\+/;
$plugin =~ s/^\+//;
$ENV{ND2_LOG_PLUGINS} && debug "loading web plugin $plugin";
Module::Load::load $plugin;
}
}
if (setting('web_plugins') and ref [] eq ref setting('web_plugins')) {
_load_web_plugins( setting('web_plugins') );
}
if (setting('extra_web_plugins') and ref [] eq ref setting('extra_web_plugins')) {
unshift @INC, dir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'site_plugins')->stringify;
_load_web_plugins( setting('extra_web_plugins') );
}
foreach my $tag (keys %{ setting('_admin_tasks') }) {
my $code = sub {
# trick the ajax into working as if this were a tabbed page
params->{tab} = $tag;
var(nav => 'admin');
template 'admintask', {
task => setting('_admin_tasks')->{ $tag },
}, { layout => 'main' };
};
if (setting('_admin_tasks')->{ $tag }->{ 'roles' }) {
get "/admin/$tag" => require_any_role setting('_admin_tasks')->{ $tag }->{ 'roles' } => $code;
}
else {
get "/admin/$tag" => require_role admin => $code;
}
}
# after plugins are loaded, add our own template path
push @{ config->{engines}->{netdisco_template_toolkit}->{INCLUDE_PATH} },
setting('views');
#Â sort the reports which have been loaded, by their label
foreach my $cat (@{ setting('_report_order') }) {
setting('_reports_menu')->{ $cat } ||= [];
setting('_reports_menu')->{ $cat }
= [ sort { setting('_reports')->{$a}->{'label'}
cmp
setting('_reports')->{$b}->{'label'} }
@{ setting('_reports_menu')->{ $cat } } ];
}
# any template paths in deployment.yml (should override plugins)
if (setting('template_paths') and ref [] eq ref setting('template_paths')) {
if (setting('site_local_files')) {
push @{setting('template_paths')},
dir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'nd-site-local', 'share')->stringify,
dir(($ENV{NETDISCO_HOME} || $ENV{HOME}), 'nd-site-local', 'share', 'views')->stringify;
}
unshift @{ config->{engines}->{netdisco_template_toolkit}->{INCLUDE_PATH} },
@{setting('template_paths')};
}
# load cookie key from database
setting('session_cookie_key' => undef);
setting('session_cookie_key' => 'this_is_for_testing_only')
if $ENV{HARNESS_ACTIVE};
eval {
my $sessions = schema('netdisco')->resultset('Session');
my $skey = $sessions->find({id => 'dancer_session_cookie_key'});
setting('session_cookie_key' => $skey->get_column('a_session')) if $skey;
};
Dancer::Session::Cookie::init(session);
# workaround for https://github.com/PerlDancer/Dancer/issues/935
hook after_error_render => sub { setting('layout' => 'main') };
# build list of port detail columns
{
my @port_columns =
sort { $a->{idx} <=> $b->{idx} }
map {{ name => $_, %{ setting('sidebar_defaults')->{'device_ports'}->{$_} } }}
grep { $_ =~ m/^c_/ } keys %{ setting('sidebar_defaults')->{'device_ports'} };
splice @port_columns, setting('device_port_col_idx_right') + 1, 0,
grep {$_->{position} eq 'right'} @{ setting('_extra_device_port_cols') };
splice @port_columns, setting('device_port_col_idx_mid') + 1, 0,
grep {$_->{position} eq 'mid'} @{ setting('_extra_device_port_cols') };
splice @port_columns, setting('device_port_col_idx_left') + 1, 0,
grep {$_->{position} eq 'left'} @{ setting('_extra_device_port_cols') };
set('port_columns' => \@port_columns);
# update sidebar_defaults so hooks scanning params see new plugin cols
setting('sidebar_defaults')->{'device_ports'}->{ $_->{name} } = $_
for @port_columns;
}
#Â build lookup for tenancies
{
set('tenant_data' => {
map { ( $_->{tag} => { displayname => $_->{'displayname'},
tag => $_->{'tag'},
path => config->{'url_base'}->with("/t/$_->{tag}")->path } ) }
@{ setting('tenant_databases') },
{ tag => 'netdisco', displayname => (setting('database')->{displayname} || 'Default') }
});
config->{'tenant_data'}->{'netdisco'}->{'path'}
= URI::Based->new((config->{path} eq '/') ? '' : config->{path})->path;
set('tenant_tags' => [ map { $_->{'tag'} }
sort { $a->{'displayname'} cmp $b->{'displayname'} }
values %{ config->{'tenant_data'} } ]);
}
hook 'before' => sub {
my $key = request->path;
if (param('tab') and ($key !~ m/ajax/)) {
$key .= ('/' . param('tab'));
}
$key =~ s|.*/(\w+)/(\w+)$|${1}_${2}|;
var(sidebar_key => $key);
# trim whitespace
params->{'q'} =~ s/^\s+|\s+$//g if param('q');
# copy sidebar defaults into vars so we can mess about with it
foreach my $sidebar (keys %{setting('sidebar_defaults')}) {
vars->{'sidebar_defaults'}->{$sidebar} = { map {
($_ => setting('sidebar_defaults')->{$sidebar}->{$_}->{'default'})
} keys %{setting('sidebar_defaults')->{$sidebar}} };
}
};
( run in 0.739 second using v1.01-cache-2.11-cpan-e1769b4cff6 )