Implemented web UI. Implemented api. Change-Id: Ieec8a8a60ace4b6c5fe0842532b5ae58964cbe9fchanges/09/7309/3
parent
9264a41ac5
commit
a6264ed34c
@ -0,0 +1,218 @@
|
||||
package NGCP::Panel::Controller::API::EmergencyMappingContainers;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use boolean qw(true);
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
use NGCP::Panel::Utils::Reseller qw();
|
||||
use Path::Tiny qw(path);
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require Catalyst::ActionRole::CheckTrailingSlash;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET POST OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub api_description {
|
||||
return 'Defines a container which holds a collection of <a href="#emergencymappings">Emergency Mappings</a>.';
|
||||
};
|
||||
|
||||
sub query_params {
|
||||
return [
|
||||
{
|
||||
param => 'name',
|
||||
description => 'Filter for emergency mapping containers with a specific name (wildcards possible)',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
{ name => { like => $q } };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
{
|
||||
param => 'reseller_id',
|
||||
description => 'Filter for emergency mapping containers for a specific reseller',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
{ reseller_id => $q };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::EmergencyMappingContainers/;
|
||||
|
||||
sub resource_name{
|
||||
return 'emergencymappingcontainers';
|
||||
}
|
||||
sub dispatch_path{
|
||||
return '/api/emergencymappingcontainers/';
|
||||
}
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-emergencymappingcontainers';
|
||||
}
|
||||
|
||||
__PACKAGE__->config(
|
||||
action => {
|
||||
map { $_ => {
|
||||
ACLDetachTo => '/api/root/invalid_user',
|
||||
AllowedRole => [qw/admin reseller/],
|
||||
Args => 0,
|
||||
Does => [qw(ACL CheckTrailingSlash RequireSSL)],
|
||||
Method => $_,
|
||||
Path => __PACKAGE__->dispatch_path,
|
||||
} } @{ __PACKAGE__->allowed_methods }
|
||||
},
|
||||
action_roles => [qw(+NGCP::Panel::Role::HTTPMethods)],
|
||||
);
|
||||
|
||||
sub auto :Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->set_body($c);
|
||||
$self->log_request($c);
|
||||
}
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $page = $c->request->params->{page} // 1;
|
||||
my $rows = $c->request->params->{rows} // 10;
|
||||
{
|
||||
my $items = $self->item_rs($c);
|
||||
(my $total_count, $items) = $self->paginate_order_collection($c, $items);
|
||||
my (@embedded, @links);
|
||||
my $form = $self->get_form($c);
|
||||
for my $item($items->all) {
|
||||
push @embedded, $self->hal_from_item($c, $item, $form);
|
||||
push @links, Data::HAL::Link->new(
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
href => sprintf('/%s%d', $c->request->path, $item->id),
|
||||
);
|
||||
}
|
||||
push @links,
|
||||
Data::HAL::Link->new(
|
||||
relation => 'curies',
|
||||
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
|
||||
name => 'ngcp',
|
||||
templated => true,
|
||||
),
|
||||
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
|
||||
Data::HAL::Link->new(relation => 'self', href => sprintf('/%s?page=%s&rows=%s', $c->request->path, $page, $rows));
|
||||
|
||||
if(($total_count / $rows) > $page ) {
|
||||
push @links, Data::HAL::Link->new(relation => 'next', href => sprintf('/%s?page=%d&rows=%d', $c->request->path, $page + 1, $rows));
|
||||
}
|
||||
if($page > 1) {
|
||||
push @links, Data::HAL::Link->new(relation => 'prev', href => sprintf('/%s?page=%d&rows=%d', $c->request->path, $page - 1, $rows));
|
||||
}
|
||||
|
||||
my $hal = Data::HAL->new(
|
||||
embedded => [@embedded],
|
||||
links => [@links],
|
||||
);
|
||||
$hal->resource({
|
||||
total_count => $total_count,
|
||||
});
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef,
|
||||
HTTP::Headers->new($hal->http_headers(skip_links => 1)), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->body($response->content);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub HEAD :Allow {
|
||||
my ($self, $c) = @_;
|
||||
$c->forward(qw(GET));
|
||||
$c->response->body(q());
|
||||
return;
|
||||
}
|
||||
|
||||
sub OPTIONS :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $allowed_methods = $self->allowed_methods_filtered($c);
|
||||
$c->response->headers(HTTP::Headers->new(
|
||||
Allow => join(', ', @{ $allowed_methods }),
|
||||
Accept_Post => 'application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-'.$self->resource_name,
|
||||
));
|
||||
$c->response->content_type('application/json');
|
||||
$c->response->body(JSON::to_json({ methods => $allowed_methods })."\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sub POST :Allow {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $schema = $c->model('DB');
|
||||
my $resource = $self->get_valid_post_data(
|
||||
c => $c,
|
||||
media_type => 'application/json',
|
||||
);
|
||||
last unless $resource;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
last unless $self->validate_form(
|
||||
c => $c,
|
||||
resource => $resource,
|
||||
form => $form,
|
||||
);
|
||||
if($c->user->roles eq "reseller") {
|
||||
$resource->{reseller_id} = $c->user->reseller_id;
|
||||
}
|
||||
my $dup_item = $c->model('DB')->resultset('emergency_containers')->find({
|
||||
reseller_id => $resource->{reseller_id},
|
||||
name => $resource->{name},
|
||||
});
|
||||
if($dup_item) {
|
||||
$c->log->error("emergency mapping container with name '$$resource{name}' already exists for this reseller");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "emergency mapping container with this name already exists for this reseller");
|
||||
return;
|
||||
}
|
||||
|
||||
my $item;
|
||||
try {
|
||||
$item = $schema->resultset('emergency_containers')->create($resource);
|
||||
} catch($e) {
|
||||
$c->log->error("failed to create emergency mapping container: $e");
|
||||
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create emergency mapping container.");
|
||||
last;
|
||||
}
|
||||
|
||||
last unless $self->add_create_journal_item_hal($c,sub {
|
||||
my $self = shift;
|
||||
my ($c) = @_;
|
||||
my $_item = $self->item_by_id($c, $item->id);
|
||||
return $self->hal_from_item($c, $_item,$form); });
|
||||
|
||||
$guard->commit;
|
||||
|
||||
$c->response->status(HTTP_CREATED);
|
||||
$c->response->header(Location => sprintf('%s%d', $self->dispatch_path, $item->id));
|
||||
$c->response->body(q());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub end : Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->log_response($c);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,210 @@
|
||||
package NGCP::Panel::Controller::API::EmergencyMappingContainersItem;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
use NGCP::Panel::Utils::DateTime;
|
||||
use NGCP::Panel::Utils::ValidateJSON qw();
|
||||
use Path::Tiny qw(path);
|
||||
use Safe::Isa qw($_isa);
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD PATCH PUT DELETE/];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::EmergencyMappingContainers/;
|
||||
|
||||
sub resource_name{
|
||||
return 'emergencymappingcontainers';
|
||||
}
|
||||
sub dispatch_path{
|
||||
return '/api/emergencymappingcontainers/';
|
||||
}
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-emergencymappingcontainers';
|
||||
}
|
||||
|
||||
__PACKAGE__->config(
|
||||
action => {
|
||||
map { $_ => {
|
||||
ACLDetachTo => '/api/root/invalid_user',
|
||||
AllowedRole => [qw/admin reseller/],
|
||||
Args => 1,
|
||||
Does => [qw(ACL RequireSSL)],
|
||||
Method => $_,
|
||||
Path => __PACKAGE__->dispatch_path,
|
||||
} } @{ __PACKAGE__->allowed_methods }
|
||||
},
|
||||
action_roles => [qw(+NGCP::Panel::Role::HTTPMethods)],
|
||||
);
|
||||
|
||||
sub auto :Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->set_body($c);
|
||||
$self->log_request($c);
|
||||
}
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
{
|
||||
last unless $self->valid_id($c, $id);
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymappingcontainer => $item);
|
||||
|
||||
my $hal = $self->hal_from_item($c, $item);
|
||||
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
(map { # XXX Data::HAL must be able to generate links with multiple relations
|
||||
s|rel="(http://purl.org/sipwise/ngcp-api/#rel-resellers)"|rel="item $1"|;
|
||||
s/rel=self/rel="item self"/;
|
||||
$_
|
||||
} $hal->http_headers),
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->body($response->content);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub HEAD :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
$c->forward(qw(GET));
|
||||
$c->response->body(q());
|
||||
return;
|
||||
}
|
||||
|
||||
sub OPTIONS :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $allowed_methods = $self->allowed_methods_filtered($c);
|
||||
$c->response->headers(HTTP::Headers->new(
|
||||
Allow => join(', ', @{ $allowed_methods }),
|
||||
Accept_Patch => 'application/json-patch+json',
|
||||
));
|
||||
$c->response->content_type('application/json');
|
||||
$c->response->body(JSON::to_json({ methods => $allowed_methods })."\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sub PATCH :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $json = $self->get_valid_patch_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json-patch+json',
|
||||
);
|
||||
last unless $json;
|
||||
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymappingcontainer => $item);
|
||||
my $old_resource = { $item->get_inflated_columns };
|
||||
my $resource = $self->apply_patch($c, $old_resource, $json);
|
||||
last unless $resource;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
|
||||
last unless $item;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
my $hal = $self->hal_from_item($c, $item, $form);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub PUT :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymappingcontainer => $item);
|
||||
my $resource = $self->get_valid_put_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json',
|
||||
);
|
||||
last unless $resource;
|
||||
my $old_resource = { $item->get_inflated_columns };
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
|
||||
last unless $item;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
my $hal = $self->hal_from_item($c, $item, $form);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub DELETE :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymappingcontainer => $item);
|
||||
my $mapping_count = $item->emergency_mappings->count;
|
||||
if ($mapping_count > 0) {
|
||||
$c->log->error("failed to delete emergency mapping container, there are still $mapping_count emergency mappings linked to it.");
|
||||
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to delete emergency mapping container.");
|
||||
last;
|
||||
}
|
||||
$item->delete;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->body(q());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub end : Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->log_response($c);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,268 @@
|
||||
package NGCP::Panel::Controller::API::EmergencyMappings;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use boolean qw(true);
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
use NGCP::Panel::Utils::DateTime;
|
||||
use Path::Tiny qw(path);
|
||||
use Safe::Isa qw($_isa);
|
||||
|
||||
use NGCP::Panel::Utils::EmergencyMapping;
|
||||
use NGCP::Panel::Utils::MySQL;
|
||||
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require Catalyst::ActionRole::CheckTrailingSlash;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET POST OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
|
||||
sub api_description {
|
||||
return 'Defines emergency mappings for an <a href="#emergencymappingscontainer">Emergency Mapping Container</a>. You can POST mappings individually one-by-one using json. To bulk-upload mappings, specify the Content-Type as "text/csv" and POST the CSV in the request body to the collection with an optional parameter "purge_existing=true", like "/api/emergencymappings/?purge_existing=true"';
|
||||
};
|
||||
|
||||
sub query_params {
|
||||
return [
|
||||
{
|
||||
param => 'emergency_container_id',
|
||||
description => 'Filter for emergency mappings belonging to a specific emergency mapping container',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
{ emergency_container_id => $q };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
{
|
||||
param => 'code',
|
||||
description => 'Filter for mappings with a specific code (wildcards possible)',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
{ code => { like => $q } };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::EmergencyMappings/;
|
||||
|
||||
sub resource_name{
|
||||
return 'emergencymappings';
|
||||
}
|
||||
sub dispatch_path{
|
||||
return '/api/emergencymappings/';
|
||||
}
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-emergencymappings';
|
||||
}
|
||||
|
||||
__PACKAGE__->config(
|
||||
action => {
|
||||
map { $_ => {
|
||||
ACLDetachTo => '/api/root/invalid_user',
|
||||
AllowedRole => [qw/admin reseller/],
|
||||
Args => 0,
|
||||
Does => [qw(ACL CheckTrailingSlash RequireSSL)],
|
||||
Method => $_,
|
||||
Path => __PACKAGE__->dispatch_path,
|
||||
} } @{ __PACKAGE__->allowed_methods }
|
||||
},
|
||||
action_roles => [qw(+NGCP::Panel::Role::HTTPMethods)],
|
||||
);
|
||||
|
||||
sub auto :Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->set_body($c);
|
||||
$self->log_request($c);
|
||||
}
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $page = $c->request->params->{page} // 1;
|
||||
my $rows = $c->request->params->{rows} // 10;
|
||||
{
|
||||
my $items = $self->item_rs($c);
|
||||
(my $total_count, $items) = $self->paginate_order_collection($c, $items);
|
||||
my (@embedded, @links);
|
||||
my $form = $self->get_form($c);
|
||||
for my $item ($items->all) {
|
||||
push @embedded, $self->hal_from_item($c, $item, $form);
|
||||
push @links, Data::HAL::Link->new(
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
href => sprintf('/%s%d', $c->request->path, $item->id),
|
||||
);
|
||||
}
|
||||
push @links,
|
||||
Data::HAL::Link->new(
|
||||
relation => 'curies',
|
||||
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
|
||||
name => 'ngcp',
|
||||
templated => true,
|
||||
),
|
||||
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
|
||||
Data::HAL::Link->new(relation => 'self', href => sprintf('/%s?page=%s&rows=%s', $c->request->path, $page, $rows));
|
||||
if(($total_count / $rows) > $page ) {
|
||||
push @links, Data::HAL::Link->new(relation => 'next', href => sprintf('/%s?page=%d&rows=%d', $c->request->path, $page + 1, $rows));
|
||||
}
|
||||
if($page > 1) {
|
||||
push @links, Data::HAL::Link->new(relation => 'prev', href => sprintf('/%s?page=%d&rows=%d', $c->request->path, $page - 1, $rows));
|
||||
}
|
||||
|
||||
my $hal = Data::HAL->new(
|
||||
embedded => [@embedded],
|
||||
links => [@links],
|
||||
);
|
||||
$hal->resource({
|
||||
total_count => $total_count,
|
||||
});
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef,
|
||||
HTTP::Headers->new($hal->http_headers(skip_links => 1)), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->body($response->content);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub HEAD :Allow {
|
||||
my ($self, $c) = @_;
|
||||
$c->forward(qw(GET));
|
||||
$c->response->body(q());
|
||||
return;
|
||||
}
|
||||
|
||||
sub OPTIONS :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $allowed_methods = $self->allowed_methods_filtered($c);
|
||||
$c->response->headers(HTTP::Headers->new(
|
||||
Allow => join(', ', @{ $allowed_methods }),
|
||||
Accept_Post => 'application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-'.$self->resource_name,
|
||||
));
|
||||
$c->response->content_type('application/json');
|
||||
$c->response->body(JSON::to_json({ methods => $allowed_methods })."\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sub POST :Allow {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $schema = $c->model('DB');
|
||||
my $resource;
|
||||
my $data = $self->get_valid_raw_post_data(
|
||||
c => $c,
|
||||
media_type => [qw#application/json text/csv#],
|
||||
);
|
||||
last unless $data;
|
||||
|
||||
if($c->request->header('Content-Type') eq 'text/csv') {
|
||||
$resource = $c->req->query_params;
|
||||
} else {
|
||||
last unless $self->require_wellformed_json($c, 'application/json', $data);
|
||||
$resource = JSON::from_json($data, { utf8 => 1 });
|
||||
$data = undef;
|
||||
}
|
||||
|
||||
if ($data) {
|
||||
my($mappings, $fails, $text_success);
|
||||
try {
|
||||
if ($resource->{purge_existing} eq 'true') {
|
||||
my ($start, $end);
|
||||
$start = time;
|
||||
NGCP::Panel::Utils::MySQL::truncate_table(
|
||||
c => $c,
|
||||
schema => $schema,
|
||||
do_transaction => 0,
|
||||
table => 'provisioning.emergency_mappings',
|
||||
);
|
||||
$schema->resultset('emergency_containers')->delete;
|
||||
$end = time;
|
||||
$c->log->debug("API Purging emergency mappings entries took " . ($end - $start) . "s");
|
||||
}
|
||||
|
||||
( $mappings, $fails, $text_success ) = NGCP::Panel::Utils::EmergencyMapping::upload_csv(
|
||||
c => $c,
|
||||
data => \$data,
|
||||
schema => $schema,
|
||||
);
|
||||
|
||||
$c->log->info( $$text_success );
|
||||
|
||||
$guard->commit;
|
||||
|
||||
$c->response->status(HTTP_CREATED);
|
||||
$c->response->body(q());
|
||||
|
||||
} catch($e) {
|
||||
$c->log->error("failed to upload csv: $e");
|
||||
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error");
|
||||
last;
|
||||
};
|
||||
} else {
|
||||
delete $resource->{purge_existing};
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
last unless $self->validate_form(
|
||||
c => $c,
|
||||
resource => $resource,
|
||||
form => $form,
|
||||
);
|
||||
|
||||
my $container = $c->model('DB')->resultset('emergency_containers')->find($resource->{emergency_container_id});
|
||||
unless($container) {
|
||||
$c->log->error("invalid emergency container id '$$resource{emergency_container_id}'");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "emergency container id does not exist");
|
||||
last;
|
||||
}
|
||||
if ($c->model('DB')->resultset('emergency_mappings')->search({
|
||||
emergency_container_id => $container->id,
|
||||
code => $resource->{code}
|
||||
},undef)->count > 0) {
|
||||
$c->log->error("Emergency mapping code '$$resource{code}' already defined for emergency container id '$$resource{emergency_container_id}'");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "emergency mapping code already exists for emergency container");
|
||||
last;
|
||||
}
|
||||
|
||||
my $item;
|
||||
try {
|
||||
$item = $c->model('DB')->resultset('emergency_mappings')->create($resource);
|
||||
} catch($e) {
|
||||
$c->log->error("failed to create emergency mapping: $e");
|
||||
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create emergency mapping.");
|
||||
last;
|
||||
}
|
||||
|
||||
$guard->commit;
|
||||
|
||||
$c->response->status(HTTP_CREATED);
|
||||
$c->response->header(Location => sprintf('/%s%d', $c->request->path, $item->id));
|
||||
$c->response->body(q());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub end : Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->log_response($c);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,204 @@
|
||||
package NGCP::Panel::Controller::API::EmergencyMappingsItem;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
use NGCP::Panel::Utils::DateTime;
|
||||
use NGCP::Panel::Utils::ValidateJSON qw();
|
||||
use Path::Tiny qw(path);
|
||||
use Safe::Isa qw($_isa);
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD PATCH PUT DELETE/];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::EmergencyMappings/;
|
||||
|
||||
sub resource_name{
|
||||
return 'emergencymappings';
|
||||
}
|
||||
sub dispatch_path{
|
||||
return '/api/emergencymappings/';
|
||||
}
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-emergencymappings';
|
||||
}
|
||||
|
||||
__PACKAGE__->config(
|
||||
action => {
|
||||
map { $_ => {
|
||||
ACLDetachTo => '/api/root/invalid_user',
|
||||
AllowedRole => [qw/admin reseller/],
|
||||
Args => 1,
|
||||
Does => [qw(ACL RequireSSL)],
|
||||
Method => $_,
|
||||
Path => __PACKAGE__->dispatch_path,
|
||||
} } @{ __PACKAGE__->allowed_methods }
|
||||
},
|
||||
action_roles => [qw(+NGCP::Panel::Role::HTTPMethods)],
|
||||
);
|
||||
|
||||
sub auto :Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->set_body($c);
|
||||
$self->log_request($c);
|
||||
}
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
{
|
||||
last unless $self->valid_id($c, $id);
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymapping => $item);
|
||||
|
||||
my $hal = $self->hal_from_item($c, $item);
|
||||
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
(map { # XXX Data::HAL must be able to generate links with multiple relations
|
||||
s|rel="(http://purl.org/sipwise/ngcp-api/#rel-resellers)"|rel="item $1"|;
|
||||
s/rel=self/rel="item self"/;
|
||||
$_
|
||||
} $hal->http_headers),
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->body($response->content);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub HEAD :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
$c->forward(qw(GET));
|
||||
$c->response->body(q());
|
||||
return;
|
||||
}
|
||||
|
||||
sub OPTIONS :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $allowed_methods = $self->allowed_methods_filtered($c);
|
||||
$c->response->headers(HTTP::Headers->new(
|
||||
Allow => join(', ', @{ $allowed_methods }),
|
||||
Accept_Patch => 'application/json-patch+json',
|
||||
));
|
||||
$c->response->content_type('application/json');
|
||||
$c->response->body(JSON::to_json({ methods => $allowed_methods })."\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sub PATCH :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $json = $self->get_valid_patch_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json-patch+json',
|
||||
);
|
||||
last unless $json;
|
||||
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymapping => $item);
|
||||
my $old_resource = $self->resource_from_item($c, $item);
|
||||
my $resource = $self->apply_patch($c, $old_resource, $json);
|
||||
last unless $resource;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
|
||||
last unless $item;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
my $hal = $self->hal_from_item($c, $item, $form);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub PUT :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymapping => $item);
|
||||
my $resource = $self->get_valid_put_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json',
|
||||
);
|
||||
last unless $resource;
|
||||
my $old_resource = $self->resource_from_item($c, $item);
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
|
||||
last unless $item;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
my $hal = $self->hal_from_item($c, $item, $form);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub DELETE :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
|
||||
my $guard = $c->model('DB')->txn_scope_guard;
|
||||
{
|
||||
my $item = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, emergencymapping => $item);
|
||||
$item->delete;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->body(q());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub end : Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->log_response($c);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,566 @@
|
||||
package NGCP::Panel::Controller::EmergencyMapping;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
use Sipwise::Base;
|
||||
|
||||
use parent 'Catalyst::Controller';
|
||||
|
||||
use NGCP::Panel::Utils::Message;
|
||||
use NGCP::Panel::Utils::Navigation;
|
||||
use NGCP::Panel::Utils::Datatables;
|
||||
use NGCP::Panel::Utils::EmergencyMapping;
|
||||
use NGCP::Panel::Utils::MySQL;
|
||||
|
||||
use NGCP::Panel::Form::EmergencyMapping::Container;
|
||||
use NGCP::Panel::Form::EmergencyMapping::ContainerAdmin;
|
||||
use NGCP::Panel::Form::EmergencyMapping::Mapping;
|
||||
use NGCP::Panel::Form::EmergencyMapping::Upload;
|
||||
|
||||
sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
||||
my ($self, $c) = @_;
|
||||
$c->log->debug(__PACKAGE__ . '::auto');
|
||||
NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub list :Chained('/') :PathPart('emergencymapping') :CaptureArgs(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
|
||||
my $emergency_container_rs = $c->model('DB')->resultset('emergency_containers');
|
||||
if($c->user->roles eq "reseller") {
|
||||
$emergency_container_rs = $emergency_container_rs->search({
|
||||
reseller_id => $c->user->reseller_id
|
||||
});
|
||||
}
|
||||
$c->stash(emergency_container_rs => $emergency_container_rs);
|
||||
$c->stash->{emergency_container_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
||||
{ name => "id", "search" => 1, "title" => $c->loc("#") },
|
||||
{ name => "reseller.name", "search" => 1, "title" => $c->loc("Reseller") },
|
||||
{ name => "name", "search" => 1, "title" => $c->loc("Name") },
|
||||
]);
|
||||
|
||||
my $emergency_mapping_rs = $c->model('DB')->resultset('emergency_mappings');
|
||||
$c->stash(emergency_mapping_rs => $emergency_mapping_rs);
|
||||
$c->stash->{emergency_mapping_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
||||
{ name => "id", "search" => 1, "title" => $c->loc("#") },
|
||||
{ name => "emergency_container.name", "search" => 1, "title" => $c->loc("Container") },
|
||||
{ name => "emergency_container.reseller.name", "search" => 1, "title" => $c->loc("Reseller") },
|
||||
{ name => "code", "search" => 1, "title" => $c->loc("Emergency Number") },
|
||||
{ name => "prefix", "search" => 1, "title" => $c->loc("Emergency Prefix") },
|
||||
]);
|
||||
|
||||
$c->stash(template => 'emergencymapping/list.tt');
|
||||
}
|
||||
|
||||
sub root :Chained('list') :PathPart('') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
}
|
||||
|
||||
sub emergency_container_ajax :Chained('list') :PathPart('emergency_container_ajax') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $resultset = $c->stash->{emergency_container_rs};
|
||||
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{emergency_container_dt_columns});
|
||||
|
||||
$c->detach( $c->view("JSON") );
|
||||
}
|
||||
|
||||
sub emergency_mapping_ajax :Chained('list') :PathPart('emergency_mapping_ajax') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $resultset = $c->stash->{emergency_mapping_rs};
|
||||
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{emergency_mapping_dt_columns});
|
||||
|
||||
$c->detach( $c->view("JSON") );
|
||||
}
|
||||
|
||||
sub emergency_container_base :Chained('list') :PathPart('emergency_container') :CaptureArgs(1) {
|
||||
my ($self, $c, $emergency_container_id) = @_;
|
||||
|
||||
unless($emergency_container_id && is_int($emergency_container_id)) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { id => $emergency_container_id },
|
||||
desc => $c->loc('Invalid emergency mapping container id detected!'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
$c->response->redirect($c->uri_for());
|
||||
return;
|
||||
}
|
||||
|
||||
my $res = $c->stash->{emergency_container_rs}->find($emergency_container_id);
|
||||
unless(defined($res)) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { id => $emergency_container_id },
|
||||
desc => $c->loc('Emergency mapping container does not exist!'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
$c->response->redirect($c->uri_for());
|
||||
return;
|
||||
}
|
||||
$c->stash(emergency_container => {$res->get_inflated_columns});
|
||||
$c->stash(emergency_container_result => $res);
|
||||
}
|
||||
|
||||
sub emergency_container_edit :Chained('emergency_container_base') :PathPart('edit') {
|
||||
my ($self, $c ) = @_;
|
||||
|
||||
my $posted = ($c->request->method eq 'POST');
|
||||
my $form;
|
||||
my $params = $c->stash->{emergency_container};
|
||||
$params->{reseller}{id} = delete $params->{reseller_id};
|
||||
$params = merge($params, $c->session->{created_objects});
|
||||
if($c->user->roles eq "reseller") {
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::Container->new(ctx => $c);
|
||||
} else {
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::ContainerAdmin->new(ctx => $c);
|
||||
}
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => $c->request->params,
|
||||
item => $params,
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
||||
c => $c,
|
||||
form => $form,
|
||||
fields => {},
|
||||
back_uri => $c->req->uri,
|
||||
);
|
||||
if($posted && $form->validated) {
|
||||
if($c->user->roles eq "reseller") {
|
||||
$form->values->{reseller_id} = $c->user->reseller_id;
|
||||
} else {
|
||||
$form->values->{reseller_id} = $form->values->{reseller}{id};
|
||||
}
|
||||
delete $form->values->{reseller};
|
||||
try {
|
||||
my $schema = $c->model('DB');
|
||||
|
||||
if ($c->model('DB')->resultset('emergency_containers')->search({
|
||||
reseller_id => $form->values->{reseller_id},
|
||||
name => $form->values->{name}
|
||||
},undef)->count > 0) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { name => $form->values->{name} },
|
||||
desc => $c->loc("Emergency mapping container with this name already exists for this reseller!"),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$schema->txn_do(sub {
|
||||
$c->stash->{emergency_container_result}->update($form->values);
|
||||
});
|
||||
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
desc => $c->loc('Emergency mapping container successfully updated'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to update emergency mapping container'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
}
|
||||
$c->stash( 'emergency_container_edit_flag' => 1 );
|
||||
$c->stash( 'emergency_container_form' => $form );
|
||||
}
|
||||
|
||||
sub emergency_container_create :Chained('list') :PathPart('emergency_container_create') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $schema = $c->model('DB');
|
||||
my $posted = ($c->request->method eq 'POST');
|
||||
my $form;
|
||||
my $params = {};
|
||||
$params = merge($params, $c->session->{created_objects});
|
||||
if($c->user->roles eq "reseller") {
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::Container->new(ctx => $c);
|
||||
} else {
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::ContainerAdmin->new(ctx => $c);
|
||||
}
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => $c->request->params,
|
||||
item => $params,
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
||||
c => $c,
|
||||
form => $form,
|
||||
fields => {},
|
||||
back_uri => $c->req->uri,
|
||||
);
|
||||
if($posted && $form->validated) {
|
||||
if($c->user->roles eq "reseller") {
|
||||
$form->values->{reseller_id} = $c->user->reseller_id;
|
||||
} else {
|
||||
$form->values->{reseller_id} = $form->values->{reseller}{id};
|
||||
}
|
||||
delete $form->values->{reseller};
|
||||
try {
|
||||
if ($c->model('DB')->resultset('emergency_containers')->search({
|
||||
reseller_id => $form->values->{reseller_id},
|
||||
name => $form->values->{name}
|
||||
},undef)->count > 0) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { name => $form->values->{name} },
|
||||
desc => $c->loc("Emergency mapping container with this name already exists for this reseller!"),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
my $emergency_container = $c->model('DB')->resultset('emergency_containers')->create($form->values);
|
||||
|
||||
$c->session->{created_objects}->{emergency_container} = { id => $emergency_container->id };
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
desc => $c->loc('Emergency mapping container successfully created'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to create emergency mapping container'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
}
|
||||
|
||||
$c->stash(emergency_container_create_flag => 1);
|
||||
$c->stash(emergency_container_form => $form);
|
||||
}
|
||||
|
||||
sub emergency_container_delete :Chained('emergency_container_base') :PathPart('delete') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
my $emergency_container = $c->stash->{emergency_container_result};
|
||||
|
||||
my $emergency_mapping_count = $emergency_container->emergency_mappings->count;
|
||||
if ($emergency_mapping_count > 0) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
desc => $c->loc("Emergency mapping container still linked to emergency mappings."),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
my $schema = $c->model('DB');
|
||||
$schema->txn_do(sub {
|
||||
$emergency_container->delete;
|
||||
});
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
data => $c->stash->{emergency_container},
|
||||
desc => $c->loc('Emergency mapping container successfully deleted'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
} catch ($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
data => $c->stash->{emergency_container},
|
||||
desc => $c->loc('Failed to delete emergency mapping container'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
};
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
}
|
||||
|
||||
sub emergency_mapping_base :Chained('list') :PathPart('emergency_mapping') :CaptureArgs(1) {
|
||||
my ($self, $c, $emergency_mapping_id) = @_;
|
||||
|
||||
unless($emergency_mapping_id && is_int($emergency_mapping_id)) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { id => $emergency_mapping_id },
|
||||
desc => $c->loc('Invalid emergency mapping id detected!'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
$c->response->redirect($c->uri_for());
|
||||
return;
|
||||
}
|
||||
|
||||
my $res = $c->stash->{emergency_mapping_rs}->find($emergency_mapping_id);
|
||||
unless(defined($res)) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { id => $emergency_mapping_id },
|
||||
desc => $c->loc('Emergency mapping does not exist!'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
$c->response->redirect($c->uri_for());
|
||||
return;
|
||||
}
|
||||
$c->stash(emergency_mapping => {$res->get_inflated_columns});
|
||||
$c->stash(emergency_mapping_result => $res);
|
||||
}
|
||||
|
||||
sub emergency_mapping_edit :Chained('emergency_mapping_base') :PathPart('edit') {
|
||||
my ($self, $c ) = @_;
|
||||
|
||||
my $posted = ($c->request->method eq 'POST');
|
||||
my $form;
|
||||
my $params = $c->stash->{emergency_mapping};
|
||||
$params->{emergency_container}{id} = delete $params->{emergency_container_id};
|
||||
$params = merge($params, $c->session->{created_objects});
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::Mapping->new(ctx => $c);
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => $c->request->params,
|
||||
item => $params,
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
||||
c => $c,
|
||||
form => $form,
|
||||
fields => { 'emergency_container.create' => $c->uri_for('/emergencymapping/emergency_container_create') },
|
||||
back_uri => $c->req->uri,
|
||||
);
|
||||
if($posted && $form->validated) {
|
||||
$form->values->{emergency_container_id} = $form->values->{emergency_container}{id};
|
||||
delete $form->values->{emergency_container};
|
||||
my $emergency_container = $c->model('DB')->resultset('emergency_containers')->find($form->values->{emergency_container_id});
|
||||
unless($emergency_container) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { id => $form->values->{emergency_container_id} },
|
||||
desc => $c->loc('Invalid emergency mapping container id detected!'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
if ($c->model('DB')->resultset('emergency_mappings')->search({
|
||||
emergency_container_id => $emergency_container->id,
|
||||
code => $form->values->{code}
|
||||
},undef)->count > 0) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { code => $form->values->{code} },
|
||||
desc => $c->loc("Emergency code already defined for emergency mapping container!"),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
my $schema = $c->model('DB');
|
||||
$schema->txn_do(sub {
|
||||
$form->values->{prefix} = undef unless(length $form->values->{prefix});
|
||||
$c->stash->{emergency_mapping_result}->update($form->values);
|
||||
});
|
||||
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
desc => $c->loc('Emergency mapping successfully updated'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to update emergency mapping'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
}
|
||||
$c->stash( 'emergency_mapping_edit_flag' => 1 );
|
||||
$c->stash( 'emergency_mapping_form' => $form );
|
||||
}
|
||||
|
||||
sub emergency_mapping_create :Chained('list') :PathPart('emergency_mapping_create') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $schema = $c->model('DB');
|
||||
my $posted = ($c->request->method eq 'POST');
|
||||
my $form;
|
||||
my $params = {};
|
||||
$params = merge($params, $c->session->{created_objects});
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::Mapping->new(ctx => $c);
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => $c->request->params,
|
||||
item => $params,
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
||||
c => $c,
|
||||
form => $form,
|
||||
fields => { 'emergency_container.create' => $c->uri_for('/emergencymapping/emergency_container_create') },
|
||||
back_uri => $c->req->uri,
|
||||
);
|
||||
if($posted && $form->validated) {
|
||||
$form->values->{emergency_container_id} = $form->values->{emergency_container}{id};
|
||||
delete $form->values->{emergency_container};
|
||||
my $emergency_container = $c->model('DB')->resultset('emergency_containers')->find($form->values->{emergency_container_id});
|
||||
unless($emergency_container) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { id => $form->values->{emergency_container_id} },
|
||||
desc => $c->loc('Invalid emergency container id detected!'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
if ($c->model('DB')->resultset('emergency_mappings')->search({
|
||||
emergency_container_id => $emergency_container->id,
|
||||
code => $form->values->{code}
|
||||
},undef)->count > 0) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
data => { code => $form->values->{code} },
|
||||
desc => $c->loc("Emergency mapping already exists for this emergency mapping container!"),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
my $emergency_mapping = $emergency_container->emergency_mappings->create($form->values);
|
||||
$c->session->{created_objects}->{emergency_mapping} = { id => $emergency_mapping->id };
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
desc => $c->loc('Emergency mapping successfully created'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to create emergency mapping'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
}
|
||||
|
||||
$c->stash(emergency_mapping_create_flag => 1);
|
||||
$c->stash(emergency_mapping_form => $form);
|
||||
}
|
||||
|
||||
sub emergency_mapping_delete :Chained('emergency_mapping_base') :PathPart('delete') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
my $emergency_mapping = $c->stash->{emergency_mapping_result};
|
||||
|
||||
try {
|
||||
$emergency_mapping->delete;
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
data => $c->stash->{emergency_mapping},
|
||||
desc => $c->loc('Emergency mapping successfully deleted'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
} catch ($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
data => $c->stash->{emergency_mapping},
|
||||
desc => $c->loc('Failed to delete emergency mapping'),
|
||||
);
|
||||
$c->flash(emergency_mapping_messages => delete $c->flash->{messages});
|
||||
};
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emergencymapping'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub emergency_mappings_upload :Chained('list') :PathPart('upload') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $form = NGCP::Panel::Form::EmergencyMapping::Upload->new(ctx => $c);
|
||||
my $upload = $c->req->upload('upload_mapping');
|
||||
my $posted = $c->req->method eq 'POST';
|
||||
my @params = ( upload_mapping => $posted ? $upload : undef, );
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => { @params },
|
||||
action => $c->uri_for('/emergencymapping/upload'),
|
||||
);
|
||||
if($form->validated) {
|
||||
|
||||
# TODO: check by formhandler?
|
||||
unless($upload) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
desc => $c->loc('No emergency mapping file specified!'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
$c->response->redirect($c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
my $data = $upload->slurp;
|
||||
my($emergency_mappings, $fails, $text_success);
|
||||
try {
|
||||
my $schema = $c->model('DB');
|
||||
$schema->txn_do(sub {
|
||||
if($c->req->params->{purge_existing}) {
|
||||
my ($start, $end);
|
||||
$start = time;
|
||||
NGCP::Panel::Utils::MySQL::truncate_table(
|
||||
c => $c,
|
||||
schema => $schema,
|
||||
do_transaction => 0,
|
||||
table => 'provisioning.emergency_mappings',
|
||||
);
|
||||
$c->stash->{emergency_container_rs}->delete;
|
||||
$end = time;
|
||||
$c->log->debug("Purging emergency mappings took " . ($end - $start) . "s");
|
||||
}
|
||||
( $emergency_mappings, $fails, $text_success ) = NGCP::Panel::Utils::EmergencyMapping::upload_csv(
|
||||
c => $c,
|
||||
data => \$data,
|
||||
schema => $schema,
|
||||
);
|
||||
});
|
||||
|
||||
NGCP::Panel::Utils::Message::info(
|
||||
c => $c,
|
||||
desc => $$text_success,
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message::error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to upload emergency mappings'),
|
||||
);
|
||||
$c->flash(emergency_container_messages => delete $c->flash->{messages});
|
||||
}
|
||||
|
||||
$c->response->redirect($c->uri_for('/emergencymapping'));
|
||||
return;
|
||||
}
|
||||
|
||||
$c->stash(emergency_container_create_flag => 1);
|
||||
$c->stash(emergency_container_form => $form);
|
||||
}
|
||||
|
||||
sub emergency_mappings_download :Chained('list') :PathPart('download') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
my $schema = $c->model('DB');
|
||||
$c->response->header ('Content-Disposition' => 'attachment; filename="emergency_mapping_list.csv"');
|
||||
$c->response->content_type('text/csv');
|
||||
$c->response->status(200);
|
||||
NGCP::Panel::Utils::EmergencyMapping::create_csv(
|
||||
c => $c,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
|
||||
1;
|
||||
@ -0,0 +1,33 @@
|
||||
package NGCP::Panel::Field::EmergencyMappingContainer;
|
||||
use Moose;
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler::Field::Compound';
|
||||
|
||||
has_field 'id' => (
|
||||
type => '+NGCP::Panel::Field::DataTable',
|
||||
label => 'Emergency Mapping Container',
|
||||
do_label => 0,
|
||||
do_wrapper => 0,
|
||||
required => 1,
|
||||
template => 'helpers/datatables_field.tt',
|
||||
ajax_src => '/emergencymapping/emergency_container_ajax',
|
||||
table_titles => ['#', 'Reseller', 'Name'],
|
||||
table_fields => ['id', 'reseller.name', 'name'],
|
||||
);
|
||||
|
||||
has_field 'create' => (
|
||||
type => 'Button',
|
||||
do_label => 0,
|
||||
value => 'Create Emergency Mapping Container',
|
||||
element_class => [qw/btn btn-tertiary pull-right/],
|
||||
);
|
||||
|
||||
sub validate {
|
||||
my ( $self ) = @_;
|
||||
my $value = $self->value;
|
||||
$self->add_error('Emergency mapping container id must be a positive integer')
|
||||
if(!$self->has_errors && $value->{id} !~ /^\d+$/);
|
||||
}
|
||||
|
||||
no Moose;
|
||||
1;
|
||||
@ -0,0 +1,47 @@
|
||||
package NGCP::Panel::Form::EmergencyMapping::Container;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {[qw/submitid fields actions/]}
|
||||
sub build_form_element_class { [qw/form-horizontal/] }
|
||||
|
||||
has_field 'id' => (
|
||||
type => 'Hidden'
|
||||
);
|
||||
|
||||
has_field 'name' => (
|
||||
type => 'Text',
|
||||
required => 1,
|
||||
maxlength => 31,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['A human readable name of the emergency mapping container.']
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Save',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
label => '',
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/name/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,22 @@
|
||||
package NGCP::Panel::Form::EmergencyMapping::ContainerAdmin;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'NGCP::Panel::Form::EmergencyMapping::Container';
|
||||
|
||||
has_field 'reseller' => (
|
||||
type => '+NGCP::Panel::Field::Reseller',
|
||||
validate_when_empty => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The reseller id to assign this emergency mapping container to.']
|
||||
},
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/reseller name/],
|
||||
);
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,73 @@
|
||||
package NGCP::Panel::Form::EmergencyMapping::Mapping;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {[qw/submitid fields actions/]}
|
||||
sub build_form_element_class { [qw/form-horizontal/] }
|
||||
|
||||
has_field 'emergency_container' => (
|
||||
type => '+NGCP::Panel::Field::EmergencyMappingContainer',
|
||||
label => 'Emergency Mapping Container',
|
||||
validate_when_empty => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The emergency mapping container this mapping entry belongs to.']
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'code' => (
|
||||
type => 'Text',
|
||||
required => 1,
|
||||
maxlength => 31,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The emergency code.']
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'prefix' => (
|
||||
type => 'Text',
|
||||
required => 0,
|
||||
maxlength => 31,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['An optional emergency prefix the emergency code is mapped to.']
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Save',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
label => '',
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/emergency_container code prefix/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
sub validate_code {
|
||||
my ( $self, $field ) = @_;
|
||||
|
||||
unless($field->value =~ /^\d+$/) {
|
||||
$field->add_error($field->label . " must be a number");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,45 @@
|
||||
package NGCP::Panel::Form::EmergencyMapping::Upload;
|
||||
use Sipwise::Base;
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
use NGCP::Panel::Field::BillingZone;
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has '+enctype' => ( default => 'multipart/form-data');
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {[qw/submitid fields actions/]}
|
||||
sub build_form_element_class { [qw/form-horizontal/] }
|
||||
|
||||
has_field 'upload_mapping' => (
|
||||
type => 'Upload',
|
||||
max_size => '2097152000', # 2GB
|
||||
);
|
||||
|
||||
has_field 'purge_existing' => (
|
||||
type => 'Boolean',
|
||||
);
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Upload',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
do_label => 0,
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/upload_mapping purge_existing/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,114 @@
|
||||
package NGCP::Panel::Role::API::EmergencyMappingContainers;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use parent 'NGCP::Panel::Role::API';
|
||||
|
||||
|
||||
use boolean qw(true);
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
use NGCP::Panel::Form::EmergencyMapping::Container;
|
||||
use NGCP::Panel::Form::EmergencyMapping::ContainerAdmin;
|
||||
|
||||
sub _item_rs {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $item_rs = $c->model('DB')->resultset('emergency_containers');
|
||||
if($c->user->roles eq "reseller") {
|
||||
$item_rs = $item_rs->search({
|
||||
reseller_id => $c->user->reseller_id,
|
||||
});
|
||||
}
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
sub get_form {
|
||||
my ($self, $c) = @_;
|
||||
my $form;
|
||||
|
||||
if($c->user->roles eq "reseller") {
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::Container->new(ctx => $c);
|
||||
} else {
|
||||
$form = NGCP::Panel::Form::EmergencyMapping::ContainerAdmin->new(ctx => $c);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
sub hal_from_item {
|
||||
my ($self, $c, $item, $form) = @_;
|
||||
my %resource = $item->get_inflated_columns;
|
||||
|
||||
my $hal = Data::HAL->new(
|
||||
links => [
|
||||
Data::HAL::Link->new(
|
||||
relation => 'curies',
|
||||
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
|
||||
name => 'ngcp',
|
||||
templated => true,
|
||||
),
|
||||
Data::HAL::Link->new(relation => 'collection', href => sprintf("/api/%s/", $self->resource_name)),
|
||||
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
|
||||
Data::HAL::Link->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:emergencymappings', href => sprintf("/api/emergencymappings/?emergency_container_id=%d", $item->id)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:reseller', href => sprintf("/api/resellers/%d", $item->reseller_id)),
|
||||
],
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
);
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
|
||||
$self->validate_form(
|
||||
c => $c,
|
||||
resource => \%resource,
|
||||
form => $form,
|
||||
run => 0,
|
||||
);
|
||||
|
||||
$resource{id} = int($item->id);
|
||||
$hal->resource({%resource});
|
||||
return $hal;
|
||||
}
|
||||
|
||||
sub item_by_id {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $item_rs = $self->item_rs($c);
|
||||
return $item_rs->find($id);
|
||||
}
|
||||
|
||||
sub update_item {
|
||||
my ($self, $c, $item, $old_resource, $resource, $form) = @_;
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
return unless $self->validate_form(
|
||||
c => $c,
|
||||
form => $form,
|
||||
resource => $resource,
|
||||
);
|
||||
|
||||
my $reseller_item = $c->model('DB')->resultset('resellers')->find($resource->{reseller_id});
|
||||
unless($reseller_item) {
|
||||
$c->log->error("reseller id '$$resource{reseller_id}' does not exist");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Reseller id does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
my $dup_item = $c->model('DB')->resultset('emergency_containers')->find({
|
||||
reseller_id => $resource->{reseller_id},
|
||||
name => $resource->{name},
|
||||
});
|
||||
if($dup_item && $dup_item->id != $item->id) {
|
||||
$c->log->error("emergency mapping container with name '$$resource{name}' already exists for this reseller");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Emergency mapping container with this name already exists for this reseller");
|
||||
return;
|
||||
}
|
||||
|
||||
$item->update($resource);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,112 @@
|
||||
package NGCP::Panel::Role::API::EmergencyMappings;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use parent 'NGCP::Panel::Role::API';
|
||||
|
||||
|
||||
use boolean qw(true);
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
use NGCP::Panel::Form::EmergencyMapping::Mapping;
|
||||
|
||||
sub _item_rs {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $item_rs = $c->model('DB')->resultset('emergency_mappings');
|
||||
if($c->user->roles eq "reseller") {
|
||||
$item_rs = $item_rs->search({
|
||||
'emergency_container.reseller_id' => $c->user->reseller_id,
|
||||
},{
|
||||
'join' => 'emergency_container',
|
||||
});
|
||||
}
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
sub get_form {
|
||||
my ($self, $c) = @_;
|
||||
return NGCP::Panel::Form::EmergencyMapping::Mapping->new(ctx => $c);
|
||||
}
|
||||
|
||||
sub hal_from_item {
|
||||
my ($self, $c, $item, $form) = @_;
|
||||
my %resource = $item->get_inflated_columns;
|
||||
|
||||
my $hal = Data::HAL->new(
|
||||
links => [
|
||||
Data::HAL::Link->new(
|
||||
relation => 'curies',
|
||||
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
|
||||
name => 'ngcp',
|
||||
templated => true,
|
||||
),
|
||||
Data::HAL::Link->new(relation => 'collection', href => sprintf("/api/%s/", $self->resource_name)),
|
||||
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
|
||||
Data::HAL::Link->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:emergencymappingcontainers', href => sprintf("/api/emergencymappingcontainers/%d", $item->emergency_container_id)),
|
||||
],
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
);
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
|
||||
$self->validate_form(
|
||||
c => $c,
|
||||
resource => \%resource,
|
||||
form => $form,
|
||||
run => 0,
|
||||
);
|
||||
|
||||
$resource{id} = int($item->id);
|
||||
$hal->resource({%resource});
|
||||
return $hal;
|
||||
}
|
||||
|
||||
sub resource_from_item {
|
||||
my ($self, $c, $item) = @_;
|
||||
my $r = { $item->get_inflated_columns };
|
||||
return $r;
|
||||
}
|
||||
|
||||
sub item_by_id {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $item_rs = $self->item_rs($c);
|
||||
return $item_rs->find($id);
|
||||
}
|
||||
|
||||
sub update_item {
|
||||
my ($self, $c, $item, $old_resource, $resource, $form) = @_;
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
$resource->{lnp_provider_id} = delete $resource->{carrier_id};
|
||||
return unless $self->validate_form(
|
||||
c => $c,
|
||||
form => $form,
|
||||
resource => $resource,
|
||||
);
|
||||
|
||||
my $container = $c->model('DB')->resultset('emergency_containers')->find($resource->{emergency_container_id});
|
||||
unless($container) {
|
||||
$c->log->error("invalid emergency container id '$$resource{emergency_container_id}'");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Emergency container id does not exist");
|
||||
return;
|
||||
}
|
||||
if ($old_resource->{code} ne $resource->{code} && $c->model('DB')->resultset('emergency_mappings')->search({
|
||||
emergency_container_id => $container->id,
|
||||
code => $resource->{code}
|
||||
},undef)->count > 0) {
|
||||
$c->log->error("Emergency mapping code '$$resource{code}' already exists for container id '$$resource{emergency_container_id}'");
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "emergency mapping code already exists for emergency container");
|
||||
return;
|
||||
}
|
||||
|
||||
$item->update($resource);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,109 @@
|
||||
package NGCP::Panel::Utils::EmergencyMapping;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Text::CSV_XS;
|
||||
use NGCP::Panel::Utils::MySQL;
|
||||
|
||||
sub _insert_batch {
|
||||
my ($c, $schema, $mappings, $chunk_size) = @_;
|
||||
NGCP::Panel::Utils::MySQL::bulk_insert(
|
||||
c => $c,
|
||||
schema => $schema,
|
||||
do_transaction => 0,
|
||||
query => "REPLACE INTO provisioning.emergency_mappings(emergency_container_id, code, prefix)",
|
||||
data => $mappings,
|
||||
chunk_size => $chunk_size
|
||||
);
|
||||
}
|
||||
|
||||
sub upload_csv {
|
||||
my(%params) = @_;
|
||||
my ($c,$data,$schema) = @params{qw/c data schema/};
|
||||
my ($start, $end);
|
||||
|
||||
# csv bulk upload
|
||||
my $csv = Text::CSV_XS->new({ allow_whitespace => 1, binary => 1, keep_meta_info => 1 });
|
||||
#my @cols = @{ $c->config->{lnp_csv}->{element_order} };
|
||||
my @cols = qw/name reseller_id code prefix/;
|
||||
|
||||
my @fields ;
|
||||
my @fails = ();
|
||||
my $linenum = 0;
|
||||
my @mappings = ();
|
||||
my %containers = ();
|
||||
open(my $fh, '<:encoding(utf8)', $data);
|
||||
$start = time;
|
||||
my $chunk_size = 2000;
|
||||
while ( my $line = $csv->getline($fh)) {
|
||||
++$linenum;
|
||||
unless (scalar @{ $line } == scalar @cols) {
|
||||
push @fails, $linenum;
|
||||
next;
|
||||
}
|
||||
my $row = {};
|
||||
@{$row}{@cols} = @{ $line };
|
||||
my $k = $row->{name};
|
||||
my $r = $row->{reseller_id};
|
||||
unless(exists $containers{$k}) {
|
||||
my $container = $schema->resultset('emergency_containers')->find_or_create({
|
||||
name => $k,
|
||||
reseller_id => $r,
|
||||
});
|
||||
$containers{$k} = $container->id;
|
||||
}
|
||||
push @mappings, [$containers{$k}, $row->{code}, $row->{prefix}];
|
||||
|
||||
if($linenum % $chunk_size == 0) {
|
||||
_insert_batch($c, $schema, \@mappings, $chunk_size);
|
||||
@mappings = ();
|
||||
}
|
||||
}
|
||||
if(@mappings) {
|
||||
_insert_batch($c, $schema, \@mappings, $chunk_size);
|
||||
}
|
||||
$end = time;
|
||||
close $fh;
|
||||
$c->log->debug("Parsing and uploading Emergency Mappings CSV took " . ($end - $start) . "s");
|
||||
|
||||
my $text = $c->loc('Emergency Mappings successfully uploaded');
|
||||
if(@fails) {
|
||||
$text .= $c->loc(", but skipped the following line numbers: ") . (join ", ", @fails);
|
||||
}
|
||||
|
||||
return ( \@mappings, \@fails, \$text );
|
||||
}
|
||||
|
||||
sub create_csv {
|
||||
my(%params) = @_;
|
||||
my($c) = @params{qw/c/};
|
||||
|
||||
#my @cols = @{ $c->config->{emergency_mapping_csv}->{element_order} };
|
||||
my @cols = qw/name reseller_id code prefix/;
|
||||
|
||||
my $mapping_rs = $c->stash->{emergency_mapping_rs}->search_rs(
|
||||
undef,
|
||||
{
|
||||
'+select' => ['emergency_container.name', 'emergency_container.reseller_id'],
|
||||
'+as' => ['name', 'reseller_id'],
|
||||
'join' => 'emergency_container',
|
||||
}
|
||||
);
|
||||
|
||||
my ($start, $end);
|
||||
$start = time;
|
||||
while(my $mapping_row = $mapping_rs->next) {
|
||||
my %mapping = $mapping_row->get_inflated_columns;
|
||||
delete $mapping{id};
|
||||
$c->res->write_fh->write(join (",", @mapping{@cols}) );
|
||||
$c->res->write_fh->write("\n");
|
||||
}
|
||||
$c->res->write_fh->close;
|
||||
$end = time;
|
||||
$c->log->debug("Creating Emergency Mapping CSV for download took " . ($end - $start) . "s");
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,68 @@
|
||||
[% site_config.title = c.loc('Emergency Mappings') -%]
|
||||
|
||||
<div class="row">
|
||||
<span>
|
||||
<a class="btn btn-primary btn-large" href="[% c.uri_for('/back') %]"><i class="icon-arrow-left"></i> [% c.loc('Back') %]</a>
|
||||
<a class="btn btn-primary btn-large" href="[% c.uri_for('/emergencymapping/download') %]"><i class="icon-star"></i> [% c.loc('Download CSV') %]</a>
|
||||
<a class="btn btn-primary btn-large" href="[% c.uri_for('/emergencymapping/upload') %]"><i class="icon-star"></i> [% c.loc('Upload CSV') %]</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
[% back_created = 1 -%]
|
||||
|
||||
<h3>[% c.loc('Emergency Containers') %]</h3>
|
||||
[%
|
||||
helper.name = c.loc('Emergency Containers');
|
||||
helper.identifier = 'emergency_containers';
|
||||
helper.messages = emergency_container_messages;
|
||||
helper.dt_columns = emergency_container_dt_columns;
|
||||
helper.length_change = 1;
|
||||
|
||||
helper.close_target = emergency_container_close_target;
|
||||
helper.create_flag = emergency_container_create_flag;
|
||||
helper.edit_flag = emergency_container_edit_flag;
|
||||
helper.form_object = emergency_container_form;
|
||||
helper.ajax_uri = c.uri_for('emergency_container_ajax');
|
||||
|
||||
UNLESS c.user.read_only;
|
||||
helper.dt_buttons = [
|
||||
{ name = c.loc('Delete'), uri = "/emergencymapping/emergency_container/'+full[\"id\"]+'/delete", class = 'btn-small btn-secondary', icon = 'icon-remove' },
|
||||
{ name = c.loc('Edit'), uri = "/emergencymapping/emergency_container/'+full[\"id\"]+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' },
|
||||
];
|
||||
helper.top_buttons = [
|
||||
{ name = c.loc('Create Emergency Container'), uri = c.uri_for('/emergencymapping/emergency_container_create'), icon = 'icon-star' },
|
||||
];
|
||||
END;
|
||||
|
||||
PROCESS 'helpers/datatables.tt';
|
||||
-%]
|
||||
|
||||
<div class="ngcp-separator"></div>
|
||||
|
||||
<h3>[% c.loc('Emergency Mappings') %]</h3>
|
||||
[%
|
||||
helper.name = c.loc('Emergency Mappings');
|
||||
helper.identifier = 'emergency_mappings';
|
||||
helper.messages = emergency_mapping_messages;
|
||||
helper.dt_columns = emergency_mapping_dt_columns;
|
||||
helper.length_change = 1;
|
||||
|
||||
helper.close_target = emergency_mapping_close_target;
|
||||
helper.create_flag = emergency_mapping_create_flag;
|
||||
helper.edit_flag = emergency_mapping_edit_flag;
|
||||
helper.form_object = emergency_mapping_form;
|
||||
helper.ajax_uri = c.uri_for('emergency_mapping_ajax');
|
||||
|
||||
UNLESS c.user.read_only;
|
||||
helper.dt_buttons = [
|
||||
{ name = c.loc('Delete'), uri = "/emergencymapping/emergency_mapping/'+full[\"id\"]+'/delete", class = 'btn-small btn-secondary', icon = 'icon-remove' },
|
||||
{ name = c.loc('Edit'), uri = "/emergencymapping/emergency_mapping/'+full[\"id\"]+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' },
|
||||
];
|
||||
helper.top_buttons = [
|
||||
{ name = c.loc('Create Emergency Mapping'), uri = c.uri_for('/emergencymapping/emergency_mapping_create'), icon = 'icon-star' },
|
||||
];
|
||||
END;
|
||||
|
||||
PROCESS 'helpers/datatables.tt';
|
||||
-%]
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
||||
Loading…
Reference in new issue