From da9d1a6e2b020954d17c984736f71b6f7faef5f2 Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Tue, 15 Dec 2015 12:10:43 +0100 Subject: [PATCH] MT#4067 Add NCOS LNP handling. Change-Id: Idd3cd1964065ad4d21ea6224ce6396f32571f72b --- .../Panel/Controller/API/NcosLnpCarriers.pm | 216 ++++++++++++++++++ .../Controller/API/NcosLnpCarriersItem.pm | 197 ++++++++++++++++ lib/NGCP/Panel/Controller/NCOS.pm | 161 +++++++++++++ lib/NGCP/Panel/Form/NCOS/Lnp.pm | 71 ++++++ lib/NGCP/Panel/Form/NCOS/LnpAPI.pm | 24 ++ lib/NGCP/Panel/Role/API/NcosLnpCarriers.pm | 115 ++++++++++ share/templates/ncos/pattern_list.tt | 37 ++- 7 files changed, 820 insertions(+), 1 deletion(-) create mode 100644 lib/NGCP/Panel/Controller/API/NcosLnpCarriers.pm create mode 100644 lib/NGCP/Panel/Controller/API/NcosLnpCarriersItem.pm create mode 100644 lib/NGCP/Panel/Form/NCOS/Lnp.pm create mode 100644 lib/NGCP/Panel/Form/NCOS/LnpAPI.pm create mode 100644 lib/NGCP/Panel/Role/API/NcosLnpCarriers.pm diff --git a/lib/NGCP/Panel/Controller/API/NcosLnpCarriers.pm b/lib/NGCP/Panel/Controller/API/NcosLnpCarriers.pm new file mode 100644 index 0000000000..9e09d2aa14 --- /dev/null +++ b/lib/NGCP/Panel/Controller/API/NcosLnpCarriers.pm @@ -0,0 +1,216 @@ +package NGCP::Panel::Controller::API::NcosLnpCarriers; +use NGCP::Panel::Utils::Generic qw(:all); +use Sipwise::Base; +use Moose; +#use namespace::sweep; +use boolean qw(true); +use Data::HAL qw(); +use Data::HAL::Link qw(); +use HTTP::Headers qw(); +use HTTP::Status qw(:constants); +use MooseX::ClassAttribute qw(class_has); +use NGCP::Panel::Utils::DateTime; +use Path::Tiny qw(path); +use Safe::Isa qw($_isa); +BEGIN { extends 'Catalyst::Controller::ActionRole'; } +require Catalyst::ActionRole::ACL; +require Catalyst::ActionRole::CheckTrailingSlash; +require Catalyst::ActionRole::HTTPMethods; +require Catalyst::ActionRole::RequireSSL; + +class_has 'api_description' => ( + is => 'ro', + isa => 'Str', + default => + 'Defines email templates to be send when new subscribers are created or when passwords are reset.', +); + +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'ncos_level_id', + description => 'Filter for NCOS LNP entries belonging to a specific NCOS level.', + query => { + first => sub { + my $q = shift; + { ncos_level_id => $q }; + }, + second => sub {}, + }, + }, + { + param => 'carrier_id', + description => 'Filter for NCOS LNP entries belonging to a specific LNP carrier.', + query => { + first => sub { + my $q = shift; + { lnp_provider_id => $q }; + }, + second => sub {}, + }, + }, + ]}, +); + +with 'NGCP::Panel::Role::API::NcosLnpCarriers'; + +class_has('resource_name', is => 'ro', default => 'ncoslnpcarriers'); +class_has('dispatch_path', is => 'ro', default => '/api/ncoslnpcarriers/'); +class_has('relation', is => 'ro', default => 'http://purl.org/sipwise/ngcp-api/#rel-ncoslnpcarriers'); + +__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(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 $resource = $self->get_valid_post_data( + c => $c, + media_type => 'application/json', + ); + last unless $resource; + + my $form = $self->get_form($c); + $resource->{lnp_provider_id} = delete $resource->{carrier_id}; + last unless $self->validate_form( + c => $c, + resource => $resource, + form => $form, + exceptions => [qw/ncos_level_id/], + ); + + my $level = $c->model('DB')->resultset('ncos_levels')->find( + $resource->{ncos_level_id}, + ); + unless($level) { + $c->log->error("invalid ncos_level_id '$$resource{ncos_level_id}'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid ncos_level_id, level does not exist"); + return; + } + + my $dup_item = $level->ncos_lnp_lists->search({ + lnp_provider_id => $resource->{lnp_provider_id}, + })->first; + if($dup_item) { + $c->log->error("ncos lnp entry with carrier '$$resource{lnp_provider_id}' already exists for ncos_level_id '$$resource{ncos_level_id}'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "NCOS lnp entry already exists for given ncos level"); + return; + } + + my $item; + try { + $item = $level->ncos_lnp_lists->create($resource); + } catch($e) { + $c->log->error("failed to create ncos lnp entry: $e"); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create ncos lnp entry."); + 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); +} + +no Moose; +1; + +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Controller/API/NcosLnpCarriersItem.pm b/lib/NGCP/Panel/Controller/API/NcosLnpCarriersItem.pm new file mode 100644 index 0000000000..7f79ed99f1 --- /dev/null +++ b/lib/NGCP/Panel/Controller/API/NcosLnpCarriersItem.pm @@ -0,0 +1,197 @@ +package NGCP::Panel::Controller::API::NcosLnpCarriersItem; +use NGCP::Panel::Utils::Generic qw(:all); +use Sipwise::Base; +use Moose; +#use namespace::sweep; +use HTTP::Headers qw(); +use HTTP::Status qw(:constants); +use MooseX::ClassAttribute qw(class_has); +use NGCP::Panel::Utils::DateTime; +use NGCP::Panel::Utils::ValidateJSON qw(); +use Path::Tiny qw(path); +use Safe::Isa qw($_isa); +BEGIN { extends 'Catalyst::Controller::ActionRole'; } +require Catalyst::ActionRole::ACL; +require Catalyst::ActionRole::HTTPMethods; +require Catalyst::ActionRole::RequireSSL; + +with 'NGCP::Panel::Role::API::NcosLnpCarriers'; + +class_has('resource_name', is => 'ro', default => 'ncoslnpcarriers'); +class_has('dispatch_path', is => 'ro', default => '/api/ncoslnpcarriers/'); +class_has('relation', is => 'ro', default => 'http://purl.org/sipwise/ngcp-api/#rel-ncoslnpcarriers'); + +__PACKAGE__->config( + action => { + map { $_ => { + ACLDetachTo => '/api/root/invalid_user', + AllowedRole => [qw/admin/], + Args => 1, + Does => [qw(ACL RequireSSL)], + Method => $_, + Path => __PACKAGE__->dispatch_path, + } } @{ __PACKAGE__->allowed_methods } + }, + action_roles => [qw(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, ncoslnpcarrier => $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, ncoslnpcarrier => $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, ncoslnpcarrier => $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, ncoslnpcarrier => $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); +} + +no Moose; +1; + +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Controller/NCOS.pm b/lib/NGCP/Panel/Controller/NCOS.pm index 6847bd9d32..ec3cc04db9 100644 --- a/lib/NGCP/Panel/Controller/NCOS.pm +++ b/lib/NGCP/Panel/Controller/NCOS.pm @@ -7,6 +7,7 @@ BEGIN { use base 'Catalyst::Controller'; } use NGCP::Panel::Form::NCOS::ResellerLevel; use NGCP::Panel::Form::NCOS::AdminLevel; use NGCP::Panel::Form::NCOS::Pattern; +use NGCP::Panel::Form::NCOS::Lnp; use NGCP::Panel::Form::NCOS::LocalAC; use NGCP::Panel::Utils::Message; use NGCP::Panel::Utils::Navigation; @@ -239,6 +240,17 @@ sub pattern_list :Chained('base') :PathPart('pattern') :CaptureArgs(0) { { name => 'pattern', search => 1, title => $c->loc('Pattern') }, { name => 'description', search => 1, title => $c->loc('Description') }, ]); + + if($c->user->roles eq "admin") { + my $lnp_rs = $c->stash->{level_result}->ncos_lnp_lists; + $c->stash(lnp_rs => $lnp_rs); + + $c->stash->{lnp_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ + { name => 'id', search => 1, title => $c->loc('#') }, + { name => 'lnp_provider.name', search => 1, title => $c->loc('LNP Carrier') }, + { name => 'description', search => 1, title => $c->loc('Description') }, + ]); + } $c->stash(local_ac_checked => $c->stash->{level_result}->local_ac, template => 'ncos/pattern_list.tt'); @@ -256,6 +268,19 @@ sub pattern_ajax :Chained('pattern_list') :PathPart('ajax') :Args(0) { $c->detach( $c->view("JSON") ); } +sub lnp_ajax :Chained('pattern_list') :PathPart('lnp_ajax') :Args(0) :AllowedRole(admin) { + my ($self, $c) = @_; + + unless($c->user->roles eq "admin") { + $c->response->body(JSON::to_json({ code => 403, message => 'Path forbidden' })."\n"); + return; + } + + my $resultset = $c->stash->{lnp_rs}; + NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{lnp_dt_columns}); + $c->detach( $c->view("JSON") ); +} + sub pattern_base :Chained('pattern_list') :PathPart('') :CaptureArgs(1) { my ($self, $c, $pattern_id) = @_; @@ -420,6 +445,142 @@ sub pattern_edit_local_ac :Chained('pattern_list') :PathPart('edit_local_ac') :A ); } +sub lnp_root :Chained('pattern_list') :PathPart('lnp') :Args(0) { + my ($self, $c) = @_; +} + +sub lnp_base :Chained('pattern_list') :PathPart('lnp') :CaptureArgs(1) :AllowedRole(admin) { + my ($self, $c, $lnp_id) = @_; + + unless($c->user->roles eq "admin") { + $c->detach('/denied_page'); + } + + unless($lnp_id && is_int($lnp_id)) { + NGCP::Panel::Utils::Message::error( + c => $c, + log => 'Invalid NCOS lnp id detected', + desc => $c->loc('Invalid NCOS lnp id detected'), + ); + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{pattern_base_uri}); + } + + my $res = $c->stash->{lnp_rs}->find($lnp_id); + unless(defined($res)) { + NGCP::Panel::Utils::Message::error( + c => $c, + log => 'NCOS lnp entry does not exist', + desc => $c->loc('NCOS lnp entry does not exist'), + ); + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{pattern_base_uri}); + } + $c->stash(lnp_result => $res); +} + +sub lnp_edit :Chained('lnp_base') :PathPart('edit') { + my ($self, $c) = @_; + + my $posted = ($c->request->method eq 'POST'); + my $form = NGCP::Panel::Form::NCOS::Lnp->new(ctx => $c); + $form->process( + posted => $posted, + params => $c->request->params, + item => $c->stash->{lnp_result}, + ); + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, + back_uri => $c->req->uri, + ); + if($posted && $form->validated) { + try { + $c->stash->{lnp_result}->update($form->values); + NGCP::Panel::Utils::Message::info( + c => $c, + data => { $c->stash->{lnp_result}->get_inflated_columns }, + desc => $c->loc('NCOS lnp entry successfully updated'), + ); + } catch($e) { + NGCP::Panel::Utils::Message::error( + c => $c, + error => $e, + desc => $c->loc('Failed to update NCOS lnp entry'), + ); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{pattern_base_uri}); + } + + $c->stash( + close_target => $c->stash->{pattern_base_uri}, + lnp_form => $form, + lnp_edit_flag => 1 + ); +} + +sub lnp_delete :Chained('lnp_base') :PathPart('delete') { + my ($self, $c) = @_; + + try { + $c->stash->{lnp_result}->delete; + NGCP::Panel::Utils::Message::info( + c => $c, + data => { $c->stash->{lnp_result}->get_inflated_columns }, + desc => $c->loc('NCOS lnp entry successfully deleted'), + ); + } catch ($e) { + NGCP::Panel::Utils::Message::error( + c => $c, + error => $e, + desc => $c->loc('Failed to delete NCOS lnp entry'), + ); + }; + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{pattern_base_uri}); +} + +sub lnp_create :Chained('pattern_list') :PathPart('lnp/create') :Args(0) :AllowedRole(admin) { + my ($self, $c) = @_; + + unless($c->user->roles eq "admin") { + $c->detach('/denied_page'); + } + + my $posted = ($c->request->method eq 'POST'); + my $form = NGCP::Panel::Form::NCOS::Lnp->new(ctx => $c); + $form->process( + posted => $posted, + params => $c->request->params, + ); + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, + back_uri => $c->req->uri, + ); + if($posted && $form->validated) { + try { + $c->stash->{lnp_rs}->create($form->values); + NGCP::Panel::Utils::Message::info( + c => $c, + desc => $c->loc('NCOS lnp entry successfully created'), + ); + } catch($e) { + NGCP::Panel::Utils::Message::error( + c => $c, + error => $e, + desc => $c->loc('Failed to create NCOS lnp entry'), + ); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{pattern_base_uri}); + } + + $c->stash( + close_target => $c->stash->{pattern_base_uri}, + lnp_form => $form, + lnp_create_flag => 1 + ); +} + __PACKAGE__->meta->make_immutable; diff --git a/lib/NGCP/Panel/Form/NCOS/Lnp.pm b/lib/NGCP/Panel/Form/NCOS/Lnp.pm new file mode 100644 index 0000000000..2fb57344ca --- /dev/null +++ b/lib/NGCP/Panel/Form/NCOS/Lnp.pm @@ -0,0 +1,71 @@ +package NGCP::Panel::Form::NCOS::Lnp; + +use HTML::FormHandler::Moose; +extends 'HTML::FormHandler'; +#use Moose::Util::TypeConstraints; + +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 'lnp_provider' => ( + type => '+NGCP::Panel::Field::LnpCarrier', + label => 'LNP Carrier', + validate_when_empty => 1, + element_attr => { + rel => ['tooltip'], + title => ['The LNP carrier to include in the NCOS list.'] + }, +); + +has_field 'description' => ( + type => 'Text', + required => 0, +); + +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/lnp_provider description/], +); + +has_block 'actions' => ( + tag => 'div', + class => [qw/modal-footer/], + render_list => [qw/save/], +); + +1; + +=head1 NAME + +NGCP::Panel::Form::NCOSPattern + +=head1 DESCRIPTION + +Form to modify a billing.ncos_pattern_list row. + +=head1 METHODS + +=head1 AUTHOR + +Gerhard Jungwirth + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/NCOS/LnpAPI.pm b/lib/NGCP/Panel/Form/NCOS/LnpAPI.pm new file mode 100644 index 0000000000..08508d05ce --- /dev/null +++ b/lib/NGCP/Panel/Form/NCOS/LnpAPI.pm @@ -0,0 +1,24 @@ +package NGCP::Panel::Form::NCOS::LnpAPI; + +use HTML::FormHandler::Moose; +extends 'NGCP::Panel::Form::NCOS::Lnp'; +#use Moose::Util::TypeConstraints; + +has_field 'ncos_level_id' => ( + type => 'PosInteger', + required => 1, + element_attr => { + rel => ['tooltip'], + title => ['The ncos level this lnp entry belongs to.'] + }, +); + +has_block 'fields' => ( + tag => 'div', + class => [qw/modal-body/], + render_list => [qw/description ncos_level_id lnp_provider_id/], +); + +1; + +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Role/API/NcosLnpCarriers.pm b/lib/NGCP/Panel/Role/API/NcosLnpCarriers.pm new file mode 100644 index 0000000000..5470ef6d96 --- /dev/null +++ b/lib/NGCP/Panel/Role/API/NcosLnpCarriers.pm @@ -0,0 +1,115 @@ +package NGCP::Panel::Role::API::NcosLnpCarriers; +use NGCP::Panel::Utils::Generic qw(:all); +use Moose::Role; +use Sipwise::Base; +with 'NGCP::Panel::Role::API' => { + -alias =>{ item_rs => '_item_rs', }, + -excludes => [ 'item_rs' ], +}; + +use boolean qw(true); +use TryCatch; +use Data::HAL qw(); +use Data::HAL::Link qw(); +use HTTP::Status qw(:constants); +use NGCP::Panel::Form::NCOS::LnpAPI; + +sub item_rs { + my ($self, $c) = @_; + + my $item_rs = $c->model('DB')->resultset('ncos_lnp_list'); + return $item_rs; +} + +sub get_form { + my ($self, $c) = @_; + return NGCP::Panel::Form::NCOS::LnpAPI->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:ncoslevels', href => sprintf("/api/ncoslevels/%d", $item->ncos_level_id)), + ], + relation => 'ngcp:'.$self->resource_name, + ); + + $form //= $self->get_form($c); + + $self->validate_form( + c => $c, + resource => \%resource, + form => $form, + run => 0, + exceptions => [qw/ncos_level_id/], + ); + + $resource{id} = int($item->id); + $resource{carrier_id} = int($item->lnp_provider_id); + delete $resource{lnp_provider_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 resource_from_item { + my ($self, $c, $item) = @_; + my $r = { $item->get_inflated_columns }; + $r->{carrier_id} = delete $r->{lnp_provider_id}; + return $r; +} + +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, + exceptions => [qw/ncos_level_id/], + ); + + my $level = $c->model('DB')->resultset('ncos_levels')->find( + $resource->{ncos_level_id}, + ); + unless($level) { + $c->log->error("invalid ncos_level_id '$$resource{ncos_level_id}'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid ncos_level_id, level does not exist"); + return; + } + + my $dup_item = $level->ncos_lnp_lists->search({ + lnp_provider_id => $resource->{lnp_provider_id}, + })->first; + if($dup_item && $dup_item->id != $item->id) { + $c->log->error("ncos lnp carrier '$$resource{lnp_provider_id}' already exists for ncos_level_id '$$resource{ncos_level_id}'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "NCOS lnp entry already exists for given ncos level"); + return; + } + + $item->update($resource); + + return $item; +} + +1; +# vim: set tabstop=4 expandtab: diff --git a/share/templates/ncos/pattern_list.tt b/share/templates/ncos/pattern_list.tt index d4dfd175a3..df87c797f1 100644 --- a/share/templates/ncos/pattern_list.tt +++ b/share/templates/ncos/pattern_list.tt @@ -1,5 +1,6 @@ -[% site_config.title = c.loc('Number Patterns for [_1]', level_result.level) -%] +[% site_config.title = c.loc('NCOS details for [_1]', level_result.level) -%] +

[% c.loc('NCOS Number Patterns') %]

[% helper.name = c.loc('Number Pattern'); helper.identifier = 'number_pattern'; @@ -28,6 +29,8 @@ PROCESS 'helpers/datatables.tt'; -%] +
+
@@ -41,4 +44,36 @@
+[% IF c.user.roles == "admin" -%] +
+

[% c.loc('NCOS LNP Carriers') %]

+[% + helper.name = c.loc('LNP Carriers'); + helper.identifier = 'lnp_carriers'; + helper.messages = lnp_messages; + helper.dt_columns = lnp_dt_columns; + helper.length_change = 1; + + helper.close_target = close_target; + helper.create_flag = lnp_create_flag; + helper.edit_flag = lnp_edit_flag; + helper.form_object = lnp_form; + helper.ajax_uri = c.uri_for_action( "/ncos/lnp_ajax", [c.req.captures.0] ); + + helper.tmpuri = c.uri_for_action( "/ncos/lnp_root", [c.req.captures.0] ); + + UNLESS c.user.read_only; + helper.dt_buttons = [ + { name = c.loc('Edit'), uri = helper.tmpuri _ "/'+full.id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, + { name = c.loc('Delete'), uri = helper.tmpuri _ "/'+full.id+'/delete", class = 'btn-small btn-secondary', icon = 'icon-trash' }, + ]; + helper.top_buttons = [ + { name = c.loc('Create LNP Entry'), uri = c.uri_for_action( "/ncos/lnp_create", [c.req.captures.0] ), icon = 'icon-star' }, + ]; + END; + + PROCESS 'helpers/datatables.tt'; +-%] +[% END -%] + [% # vim: set tabstop=4 syntax=html expandtab: -%]