interval_to_daterange
request_is_api
request_is_api_report
request_is_api_search
/
;
BEGIN {
no
warnings
'redefine'
;
*Dancer::_redirect
=
sub
{
my
(
$destination
,
$status
) =
@_
;
my
$response
= Dancer::SharedData->response;
$response
->status(
$status
|| 302);
$response
->headers(
'Location'
=>
$destination
);
};
*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;
};
*Dancer::Request::uri_for
=
sub
{
my
(
$self
,
$part
,
$params
,
$dont_escape
) =
@_
;
my
$uri
=
$self
->base;
if
(vars->{
'tenant'
}) {
$part
=
'/t/'
. vars->{
'tenant'
} .
$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;
};
*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};
};
}
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'
) );
}
push
@{ config->{engines}->{netdisco_template_toolkit}->{INCLUDE_PATH} },
setting(
'views'
);
foreach
my
$cat
(@{ setting(
'_report_order'
) }) {
setting(
'_reports_menu'
)->{
$cat
}
= [
sort
{ setting(
'_reports'
)->{
$a
}->{
'label'
}
cmp
setting(
'_reports'
)->{
$b
}->{
'label'
} }
@{ setting(
'_reports_menu'
)->{
$cat
} } ];
}
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'
)};
}
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);
hook
after_error_render
=>
sub
{ setting(
'layout'
=>
'main'
) };
{
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
);
setting(
'sidebar_defaults'
)->{
'device_ports'
}->{
$_
->{name} } =
$_
for
@port_columns
;
}
{
set(
'tenant_data'
=> {
map
{ (
$_
->{tag} => {
displayname
=>
$_
->{
'displayname'
},
tag
=>
$_
->{
'tag'
},
path
=> config->{
'url_base'
}->
with
(
"/t/$_->{tag}"
)->path } ) }
@{ setting(
'tenant_databases'
) },
{
tag
=>
'netdisco'
,
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
);
params->{
'q'
} =~ s/^\s+|\s+$//g
if
param(
'q'
);
foreach
my
$sidebar
(
keys
%{setting(
'sidebar_defaults'
)}) {
vars->{
'sidebar_defaults'
}->{
$sidebar
} = {
map
{
(
$_
=> setting(
'sidebar_defaults'
)->{
$sidebar
}->{
$_
}->{
'default'
})
}
keys
%{setting(
'sidebar_defaults'
)->{
$sidebar
}} };
}
};
hook
'before'
=>
sub
{
return
unless
request_is_api_report or request_is_api_search;
map
{
delete
params->{
$_
}
if
params->{
$_
} eq
'false'
}
keys
%{params()};
};
hook
'before_template'
=>
sub
{
return
if
param(
'firstsearch'
)
or var(
'sidebar_key'
) !~ m/^\w+_\w+$/;
var(
'sidebar_defaults'
)->{var(
'sidebar_key'
)}->{
$_
} = param(
$_
)
for
keys
%{ var(
'sidebar_defaults'
)->{var(
'sidebar_key'
)} || {} };
};
hook
'before_template'
=>
sub
{
my
$tokens
=
shift
;
$tokens
->{uri_base} = request->base->path
if
request->base->path ne
'/'
;
$tokens
->{uri_base} .= (
'/t/'
. vars->{
'tenant'
})
if
vars->{
'tenant'
};
$tokens
->{uri_for} =
sub
{ uri_for(
@_
)->path_query };
my
$queryuri
= URI->new();
$queryuri
->query_param(
$_
=> param(
$_
))
for
grep
{
$_
ne
'return_url'
}
keys
%{params()};
$tokens
->{my_query} =
$queryuri
->query();
$tokens
->{user_has_role} =
sub
{ user_has_role(
@_
) };
$tokens
->{to_daterange} =
sub
{ interval_to_daterange(
@_
) };
$tokens
->{table_showrecordsmenu} =
to_json( setting(
'table_showrecordsmenu'
) );
foreach
my
$sidebar_key
(
keys
%{ var(
'sidebar_defaults'
) }) {
my
(
$mode
,
$report
) = (
$sidebar_key
=~ m/(\w+)_(\w+)/);
if
(
$mode
=~ m/^(?:search|device)$/) {
$tokens
->{
$sidebar_key
} = uri_for(
"/$mode"
, {
tab
=>
$report
});
}
elsif
(
$mode
=~ m/^report$/) {
$tokens
->{
$sidebar_key
} = uri_for(
"/$mode/$report"
);
}
foreach
my
$col
(
keys
%{ var(
'sidebar_defaults'
)->{
$sidebar_key
} }) {
$tokens
->{
$sidebar_key
}->query_param(
$col
,
var(
'sidebar_defaults'
)->{
$sidebar_key
}->{
$col
});
}
$tokens
->{
$sidebar_key
} =
$tokens
->{
$sidebar_key
}->path_query;
}
$tokens
->{mac_format_call} =
'as_'
.
lc
(param(
'mac_format'
))
if
param(
'mac_format'
);
$Template::Directive::WHILE_MAX
= 10_000;
$Template::Stash::PRIVATE
=
undef
;
};
hook
'before_template'
=>
sub
{
my
$template_engine
= engine
'template'
;
if
(not request->is_ajax
and header(
'Content-Type'
)
and header(
'Content-Type'
) eq
'text/comma-separated-values'
) {
$template_engine
->{config}->{AUTO_FILTER} =
'none'
;
$template_engine
->init();
}
};
hook
'after_template_render'
=>
sub
{
my
$template_engine
= engine
'template'
;
if
(not request->is_ajax
and header(
'Content-Type'
)
and header(
'Content-Type'
) eq
'text/comma-separated-values'
) {
$template_engine
->{config}->{AUTO_FILTER} =
'html_entity'
;
$template_engine
->init();
}
};
hook
before_layout_render
=>
sub
{
my
(
$tokens
,
$html_ref
) =
@_
;
return
unless
request_is_api_report or request_is_api_search;
if
(
ref
{} eq
ref
$tokens
and
exists
$tokens
->{results}) {
${
$html_ref
} = to_json
$tokens
->{results};
}
elsif
(
ref
{} eq
ref
$tokens
) {
map
{
delete
$tokens
->{
$_
}}
grep
{not blessed
$tokens
->{
$_
} or not
$tokens
->{
$_
}->isa(
'App::Netdisco::DB::ResultSet'
)}
keys
%$tokens
;
visit(
$tokens
,
sub
{
my
(
$key
,
$valueref
) =
@_
;
$$valueref
= [
$$valueref
->hri->all]
if
blessed
$$valueref
and
$$valueref
->isa(
'App::Netdisco::DB::ResultSet'
);
});
${
$html_ref
} = to_json
$tokens
;
}
else
{
${
$html_ref
} =
'[]'
;
}
};
hook
'after'
=>
sub
{
my
$r
=
shift
;
if
(request->path eq uri_for(
'/swagger.json'
)->path
and
ref
{} eq
ref
$r
->content) {
my
$spec
= dclone
$r
->content;
if
(vars->{
'tenant'
}) {
my
$base
= setting(
'path'
);
my
$tenant
=
'/t/'
. vars->{
'tenant'
};
$tenant
= (
$base
.
$tenant
)
if
$base
ne
'/'
;
$tenant
.=
'/'
if
$base
eq
'/'
;
foreach
my
$path
(
sort
keys
%{
$spec
->{paths} }) {
(
my
$newpath
=
$path
) =~ s/^
$base
/
$tenant
/;
$spec
->{paths}->{
$newpath
} =
delete
$spec
->{paths}->{
$path
};
}
}
$r
->content( to_json(
$spec
) );
header(
'Content-Type'
=>
'application/json'
);
}
if
(request_is_api) {
header(
'Content-Type'
=>
'application/json'
);
$r
->content(
$r
->content ||
'[]'
);
}
};
my
$swagger
= Dancer::Plugin::Swagger->instance;
my
$swagger_doc
=
$swagger
->doc;
$swagger_doc
->{consumes} =
'application/json'
;
$swagger_doc
->{produces} =
'application/json'
;
$swagger_doc
->{tags} = [
{
name
=>
'General'
,
description
=>
'Log in and Log out'
},
{
name
=>
'Search'
,
description
=>
'Search Operations'
},
{
name
=>
'Objects'
,
description
=>
'Device, Port, and associated Node Data'
},
{
name
=>
'Reports'
,
description
=>
'Canned and Custom Reports'
},
];
$swagger_doc
->{securityDefinitions} = {
APIKeyHeader
=>
{
type
=>
'apiKey'
,
name
=>
'Authorization'
,
in
=>
'header'
},
BasicAuth
=>
{
type
=>
'basic'
},
};
$swagger_doc
->{security} = [ {
APIKeyHeader
=> [] } ];
my
$swagger_base
= config->{plugins}->{Swagger}->{ui_url};
get
$swagger_base
=>
sub
{
Dancer::Plugin::Swagger->instance->doc->{schemes} = [ request->scheme ];
redirect uri_for(
$swagger_base
)->path
.
'/?url='
. uri_for(
'/swagger.json'
)->path;
};
get
$swagger_base
.
'/'
=>
sub
{
Dancer::Plugin::Swagger->instance->doc->{schemes} = [ request->scheme ];
params->{url} or redirect uri_for(
$swagger_base
)->path;
send_file(
'swagger-ui/index.html'
);
};
get
$swagger_base
.
'/**'
=>
sub
{
Dancer::Plugin::Swagger->instance->doc->{schemes} = [ request->scheme ];
send_file(
join
'/'
,
'swagger-ui'
, @{ (splat())[0] } );
};
hook
'after'
=>
sub
{
my
$r
=
shift
;
if
(
$r
->content_type and
$r
->content_type eq
'text/comma-separated-values'
) {
my
@newlines
= ();
my
@lines
=
split
m/\n/,
$r
->content;
foreach
my
$line
(
@lines
) {
push
@newlines
,
$line
if
$line
!~ m/^\s*$/;
}
$r
->content(
join
"\n"
,
@newlines
);
}
};
any
qr{^/t/(?<tenant>[^/]+)/?$}
=>
sub
{
my
$capture
= captures;
var
tenant
=>
$capture
->{
'tenant'
};
forward
'/'
;
};
any
'/t/*/**'
=>
sub
{
my
(
$tenant
,
$path
) = splat;
var
tenant
=>
$tenant
;
forward (
join
'/'
,
''
,
@$path
, (request->path =~ m{/$} ?
''
: ()));
};
any
qr{.*}
=>
sub
{
var(
'notfound'
=> true);
status
'not_found'
;
template
'index'
, {}, {
layout
=>
'main'
};
};
true;