diff --git a/lib/NGCP/Panel/Controller/API/PeeringGroups.pm b/lib/NGCP/Panel/Controller/API/PeeringGroups.pm index 83928ec7ed..acfb352d6d 100644 --- a/lib/NGCP/Panel/Controller/API/PeeringGroups.pm +++ b/lib/NGCP/Panel/Controller/API/PeeringGroups.pm @@ -58,7 +58,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => [qw/admin reseller/], + AllowedRole => [qw/admin/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/PeeringGroupsItem.pm b/lib/NGCP/Panel/Controller/API/PeeringGroupsItem.pm index c9c9724ba8..8bf638affc 100644 --- a/lib/NGCP/Panel/Controller/API/PeeringGroupsItem.pm +++ b/lib/NGCP/Panel/Controller/API/PeeringGroupsItem.pm @@ -24,7 +24,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => [qw/admin reseller/], + AllowedRole => [qw/admin/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/PeeringInboundRules.pm b/lib/NGCP/Panel/Controller/API/PeeringInboundRules.pm new file mode 100644 index 0000000000..4dea67dbc8 --- /dev/null +++ b/lib/NGCP/Panel/Controller/API/PeeringInboundRules.pm @@ -0,0 +1,244 @@ +package NGCP::Panel::Controller::API::PeeringInboundRules; +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 NGCP::Panel::Utils::Peering; +use Path::Tiny qw(path); +use Safe::Isa qw($_isa); +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 inbound peering rules.'; +}; + +sub query_params { + return [ + { + param => 'group_id', + description => 'Filter for peering group', + query => { + first => sub { + my $q = shift; + { group_id => $q }; + }, + second => sub {}, + }, + }, + { + param => 'field', + description => 'Filter for peering rules field (wildcards possible)', + query => { + first => sub { + my $q = shift; + { field => { like => $q } }; + }, + second => sub {}, + }, + }, + { + param => 'enabled', + description => 'Filter for peering rules enabled flag', + query => { + first => sub { + my $q = shift; + { enabled => $q }; + }, + second => sub {}, + }, + }, + ]; +} + +use parent qw/Catalyst::Controller NGCP::Panel::Role::API::PeeringInboundRules/; + +sub resource_name{ + return 'peeringinboundrules'; +} +sub dispatch_path{ + return '/api/peeringinboundrules/'; +} +sub relation{ + return 'http://purl.org/sipwise/ngcp-api/#rel-peeringinboundrules'; +} + +__PACKAGE__->config( + action => { + map { $_ => { + ACLDetachTo => '/api/root/invalid_user', + AllowedRole => [qw/admin/], + 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 $resource = $self->get_valid_post_data( + c => $c, + media_type => 'application/json', + ); + last unless $resource; + my $item; + my $form = $self->get_form($c); + last unless $self->validate_form( + c => $c, + resource => $resource, + form => $form, + exceptions => [qw/group_id/], + ); + unless($c->model('DB')->resultset('voip_peer_groups')->find($resource->{group_id})) { + $c->log->error("peering group $$resource{group_id} does not exist"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "peering group $$resource{group_id} does not exist"); + last; + } + my $dup_item = $c->model('DB')->resultset('voip_peer_inbound_rules')->find({ + group_id => $resource->{group_id}, + field => $resource->{field}, + pattern => $resource->{pattern}, + reject_code => $resource->{reject_code}, + reject_reason => $resource->{reject_reason}, + enabled => $resource->{enabled}, + priority => $resource->{priority}, + }); + if($dup_item) { + $c->log->error("peering rule already exists"); # TODO: user, message, trace, ... + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "peering rule already exists"); + last; + } + my $prio_rs = $c->model('DB')->resultset('voip_peer_inbound_rules')->search({ + group_id => $resource->{group_id}, + priority => $resource->{priority}, + }, + {} + ); + if($prio_rs->count) { + $c->log->error("peering rule priority $$resource{priority} already exists for this group"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "peering rule priority $$resource{priority} already exists for this group"); + last; + } + + try { + $item = $c->model('DB')->resultset('voip_peer_inbound_rules')->create($resource); + $item->group->update({ + has_inbound_rules => 1 + }); + } catch($e) { + $c->log->error("failed to create peering rule: $e"); # TODO: user, message, trace, ... + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create peering rule."); + 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: diff --git a/lib/NGCP/Panel/Controller/API/PeeringInboundRulesItem.pm b/lib/NGCP/Panel/Controller/API/PeeringInboundRulesItem.pm new file mode 100644 index 0000000000..a061014ccb --- /dev/null +++ b/lib/NGCP/Panel/Controller/API/PeeringInboundRulesItem.pm @@ -0,0 +1,208 @@ +package NGCP::Panel::Controller::API::PeeringInboundRulesItem; +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::PeeringInboundRules/; + +sub resource_name{ + return 'peeringinboundrules'; +} +sub dispatch_path{ + return '/api/peeringinboundrules/'; +} +sub relation{ + return 'http://purl.org/sipwise/ngcp-api/#rel-peeringinboundrules'; +} + +__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(+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, peeringinboundrule => $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, peeringinboundrule => $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, peeringinboundrule => $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, peeringinboundrule => $item); + if($item->group->voip_peer_inbound_rules->count <= 1) { + $item->group->update({ + has_inbound_rules => 0 + }); + } + $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: diff --git a/lib/NGCP/Panel/Controller/API/PeeringRules.pm b/lib/NGCP/Panel/Controller/API/PeeringRules.pm index f0838db5c9..8f7d8368b6 100644 --- a/lib/NGCP/Panel/Controller/API/PeeringRules.pm +++ b/lib/NGCP/Panel/Controller/API/PeeringRules.pm @@ -23,14 +23,14 @@ sub allowed_methods{ } sub api_description { - return 'Defines peering groups.'; + return 'Defines outbound peering rules.'; }; sub query_params { return [ { param => 'group_id', - description => 'Filter for peering rule group', + description => 'Filter for peering group', query => { first => sub { my $q = shift; @@ -80,7 +80,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => [qw/admin reseller/], + AllowedRole => [qw/admin/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/PeeringRulesItem.pm b/lib/NGCP/Panel/Controller/API/PeeringRulesItem.pm index fe192fe97c..5af5198136 100644 --- a/lib/NGCP/Panel/Controller/API/PeeringRulesItem.pm +++ b/lib/NGCP/Panel/Controller/API/PeeringRulesItem.pm @@ -34,7 +34,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => [qw/admin reseller/], + AllowedRole => [qw/admin/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/PeeringServers.pm b/lib/NGCP/Panel/Controller/API/PeeringServers.pm index abc39fc793..c7675836ec 100644 --- a/lib/NGCP/Panel/Controller/API/PeeringServers.pm +++ b/lib/NGCP/Panel/Controller/API/PeeringServers.pm @@ -101,7 +101,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => [qw/admin reseller/], + AllowedRole => [qw/admin/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/PeeringServersItem.pm b/lib/NGCP/Panel/Controller/API/PeeringServersItem.pm index 05c06df347..efed7f70ed 100644 --- a/lib/NGCP/Panel/Controller/API/PeeringServersItem.pm +++ b/lib/NGCP/Panel/Controller/API/PeeringServersItem.pm @@ -34,7 +34,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => [qw/admin reseller/], + AllowedRole => [qw/admin/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Form/Peering/InboundRuleAPI.pm b/lib/NGCP/Panel/Form/Peering/InboundRuleAPI.pm new file mode 100644 index 0000000000..5d096446b4 --- /dev/null +++ b/lib/NGCP/Panel/Form/Peering/InboundRuleAPI.pm @@ -0,0 +1,31 @@ +package NGCP::Panel::Form::Peering::InboundRuleAPI; + +use HTML::FormHandler::Moose; +extends 'NGCP::Panel::Form::Peering::InboundRule'; + +has_field 'group_id' => ( + type => 'PosInteger', + required => 1, + element_attr => { + rel => ['tooltip'], + title => ['The peering group this rule belongs to.'] + }, +); + +has_field 'priority' => ( + type => 'PosInteger', + required => 1, + element_attr => { + rel => ['tooltip'], + title => ['The priority of this rule. Lower values mean higher priority.'] + }, +); + +has_block 'fields' => ( + tag => 'div', + class => [qw/modal-body/], + render_list => [qw/group_id field pattern priority enabled reject_code reject_reason/], +); + +1; +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Role/API/PeeringGroups.pm b/lib/NGCP/Panel/Role/API/PeeringGroups.pm index 878f06655f..91842959c1 100644 --- a/lib/NGCP/Panel/Role/API/PeeringGroups.pm +++ b/lib/NGCP/Panel/Role/API/PeeringGroups.pm @@ -25,7 +25,7 @@ sub _item_rs { sub get_form { my ($self, $c) = @_; - return NGCP::Panel::Form::Peering::Group->new; + return NGCP::Panel::Form::Peering::Group->new(ctx => $c); } sub hal_from_item { @@ -43,6 +43,9 @@ sub hal_from_item { 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:peeringservers', href => sprintf("/api/peeringservers/?group_id=%d", $item->id)), + Data::HAL::Link->new(relation => 'ngcp:peeringrules', href => sprintf("/api/peeringrules/?group_id=%d", $item->id)), + Data::HAL::Link->new(relation => 'ngcp:peeringinboundrules', href => sprintf("/api/peeringinboundrules/?group_id=%d", $item->id)), ], relation => 'ngcp:'.$self->resource_name, ); diff --git a/lib/NGCP/Panel/Role/API/PeeringInboundRules.pm b/lib/NGCP/Panel/Role/API/PeeringInboundRules.pm new file mode 100644 index 0000000000..5d299f3434 --- /dev/null +++ b/lib/NGCP/Panel/Role/API/PeeringInboundRules.pm @@ -0,0 +1,114 @@ +package NGCP::Panel::Role::API::PeeringInboundRules; +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::Peering::InboundRuleAPI; +use NGCP::Panel::Utils::Peering; + +sub _item_rs { + my ($self, $c) = @_; + my $item_rs = $c->model('DB')->resultset('voip_peer_inbound_rules'); + return $item_rs; +} + +sub get_form { + my ($self, $c) = @_; + return NGCP::Panel::Form::Peering::InboundRuleAPI->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:peeringgroups', href => sprintf("/api/peeringgroups/%d", $resource{group_id})), + ], + relation => 'ngcp:'.$self->resource_name, + ); + + $form //= $self->get_form($c); + + $self->validate_form( + c => $c, + resource => \%resource, + form => $form, + exceptions => [qw/group_id/], + 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, + exceptions => [qw/group_id/], + ); + unless($c->model('DB')->resultset('voip_peer_groups')->find($resource->{group_id})) { + $c->log->error("peering group $$resource{group_id} does not exist"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "peering group $$resource{group_id} does not exist"); + return; + } + my $dup_item = $c->model('DB')->resultset('voip_peer_inbound_rules')->find({ + group_id => $resource->{group_id}, + field => $resource->{field}, + pattern => $resource->{pattern}, + reject_code => $resource->{reject_code}, + reject_reason => $resource->{reject_reason}, + enabled => $resource->{enabled}, + priority => $resource->{priority}, + }); + if($dup_item && $dup_item->id != $item->id) { + $c->log->error("peering rule already exists"); # TODO: user, message, trace, ... + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "peering rule already exists"); + return; + } + if($c->model('DB')->resultset('voip_peer_inbound_rules')->search({ + id => { '!=' => $item->id }, + group_id => $resource->{group_id}, + priority => $resource->{priority}, + }, + {} + )->count) { + $c->log->error("peering rule priority $$resource{priority} already exists for this group"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "peering rule priority $$resource{priority} already exists for this group"); + return; + } + + $item->update($resource); + return $item; +} + +1; +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Role/API/PeeringRules.pm b/lib/NGCP/Panel/Role/API/PeeringRules.pm index 2939d68489..c009415cfe 100644 --- a/lib/NGCP/Panel/Role/API/PeeringRules.pm +++ b/lib/NGCP/Panel/Role/API/PeeringRules.pm @@ -21,7 +21,7 @@ sub _item_rs { sub get_form { my ($self, $c) = @_; - return NGCP::Panel::Form::Peering::RuleAPI->new; + return NGCP::Panel::Form::Peering::RuleAPI->new(ctx => $c); } sub hal_from_item { diff --git a/lib/NGCP/Panel/Role/API/PeeringServers.pm b/lib/NGCP/Panel/Role/API/PeeringServers.pm index 5179f74e4a..bf79c2d3e6 100644 --- a/lib/NGCP/Panel/Role/API/PeeringServers.pm +++ b/lib/NGCP/Panel/Role/API/PeeringServers.pm @@ -21,7 +21,7 @@ sub _item_rs { sub get_form { my ($self, $c) = @_; - return NGCP::Panel::Form::Peering::ServerAPI->new; + return NGCP::Panel::Form::Peering::ServerAPI->new(ctx => $c); } sub hal_from_item { diff --git a/t/api-rest/api-peeringinboundrules.t b/t/api-rest/api-peeringinboundrules.t new file mode 100644 index 0000000000..4c93074f13 --- /dev/null +++ b/t/api-rest/api-peeringinboundrules.t @@ -0,0 +1,160 @@ +use strict; +use warnings; + +use Test::Collection; +use Test::FakeData; +use Test::More; +use Data::Dumper; +use Clone 'clone'; +use JSON qw/from_json to_json/; + +#init test_machine +my $test_machine = Test::Collection->new( + name => 'peeringinboundrules', + embedded_resources => [qw/peeringgroups/] +); +$test_machine->methods->{collection}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS POST)}; +$test_machine->methods->{item}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS PUT PATCH DELETE)}; + +my $fake_data = Test::FakeData->new; +$fake_data->set_data_from_script({ + peeringinboundrules => { + data => { + group_id => sub { return shift->get_id('peeringgroups',@_); }, + field => 'ruri_uri', + pattern => '^111$', + reject_code => undef, + reject_reason => undef, + priority => 50, + enabled => 1, + } + }, +}); + +#for item creation test purposes /post request data/ +$test_machine->DATA_ITEM_STORE($fake_data->process('peeringinboundrules')); + +$test_machine->form_data_item( ); +# create 3 new rules from DATA_ITEM +$test_machine->check_create_correct( 3, sub{ $_[0]->{pattern} .= $_[1]->{i}; $_[0]->{priority} += $_[1]->{i}; } ); +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} .= 1; + $data->{priority} = 51; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST same peering rule code again", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} .= 20; + $data->{reject_code} = 404; + $data->{reject_reason} = undef; + $data->{priority} = 60; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST with reject code but no reject reason", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} .= 21; + $data->{reject_code} = undef; + $data->{reject_reason} = "some reason"; + $data->{priority} = 61; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST with reject reason but no reject code", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} .= 22; + $data->{reject_code} = 399; + $data->{reject_reason} = "some reason"; + $data->{priority} = 62; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST with too small code", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} .= 23; + $data->{reject_code} = 701; + $data->{reject_reason} = "some reason"; + $data->{priority} = 63; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST with too large code", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} .= 24; + $data->{reject_code} = 400; + $data->{reject_reason} = "some reason"; + $data->{priority} = 64; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(201, "POST with valid code and reason", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{group_id} = 99999; + $data->{priority} = 65; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST with invalid group_id", $res, $result_item); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} = "my_identical_prio"; + $data->{priority} = 99; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(201, "POST with specific priority", $res, $result_item); + $data = clone($test_machine->DATA_ITEM); + $data->{pattern} = "my_identical_prio_1"; + $data->{priority} = 99; + my ($res2,$result_item2,$req2) = $test_machine->request_post($data); + $test_machine->http_code_msg(422, "POST with identical priority", $res2, $result_item2); +} +{ + my $data = clone($test_machine->DATA_ITEM); + $data->{pattern} = "my_move_attempt"; + $data->{priority} = 101; + my ($res,$result_item,$req) = $test_machine->request_post($data); + $test_machine->http_code_msg(201, "POST for preparing priority move attempt", $res, $result_item); + if(defined $res->header('Location')) { + my $rule_id = $res->header('Location'); $rule_id =~ s/^.+\/(\d+)$/$1/; + my $uri = $test_machine->get_uri($rule_id); + my ($res2,$result_item2,$req2) = $test_machine->request_get($uri); + $test_machine->http_code_msg(200, "GET to fetch rule for priority move attempt", $res2, $result_item2); + my $newdata = from_json($res2->decoded_content); + delete $newdata->{_links}; + $newdata->{priority} = 99; + my ($res3,$result_item3,$req3) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(422, "PUT to existing priority", $res3, $result_item3); + $newdata->{priority} = 102; + my ($res4,$result_item4,$req4) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(200, "PUT to new priority", $res4, $result_item4); + $newdata->{reject_code} = undef; + $newdata->{reject_reason} = "some reason"; + ($res4,$result_item4,$req4) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(422, "PUT with reason but without code", $res4, $result_item4); + $newdata->{reject_code} = 401; + $newdata->{reject_reason} = undef; + ($res4,$result_item4,$req4) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(422, "PUT with code but without reason", $res4, $result_item4); + $newdata->{reject_code} = 301; + $newdata->{reject_reason} = "some reason"; + ($res4,$result_item4,$req4) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(422, "PUT with too small code", $res4, $result_item4); + $newdata->{reject_code} = 700; + $newdata->{reject_reason} = "some reason"; + ($res4,$result_item4,$req4) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(422, "PUT with too large code", $res4, $result_item4); + $newdata->{reject_code} = 404; + $newdata->{reject_reason} = "some reason"; + ($res4,$result_item4,$req4) = $test_machine->request_put($newdata, $uri); + $test_machine->http_code_msg(200, "PUT with valid code and reason", $res4, $result_item4); + } +} + + +$test_machine->check_get2put(); +$test_machine->check_bundle(); +$test_machine->clear_test_data_all(); + +done_testing; + +# vim: set tabstop=4 expandtab: diff --git a/t/api-rest/api-root.t b/t/api-rest/api-root.t index 473de8aa01..35b996654a 100644 --- a/t/api-rest/api-root.t +++ b/t/api-rest/api-root.t @@ -104,6 +104,7 @@ $ua->credentials($netloc, "api_admin_http", $user, $pass); pbxdevices => 1, peeringgroups => 1, peeringrules => 1, + peeringinboundrules => 1, peeringserverpreferencedefs => 1, peeringserverpreferences => 1, peeringservers => 1, diff --git a/t/api-rest/testrunner b/t/api-rest/testrunner index d78eb8794c..5eb9282203 100755 --- a/t/api-rest/testrunner +++ b/t/api-rest/testrunner @@ -25,10 +25,10 @@ fi if [ "${SELECT}" = "stable" ] ; then echo "Test selection: ${SELECT}" - SELECT=$(echo t/api-rest/api-{all-links,balanceintervals,billingfees,billingnetworks,billingprofiles,billingzones,calllists,calls,cert-auth,cfdestinationsets,contracts,customercontacts,customers,faxes,lnp,ncoslevels,pbxdevicemodels,pbxdevices,peeringgroups,peeringrules,peeringservers,preferences,profilepackages,resellers,rewriterules,rewriterulesets,root,soundsets,subscriberregistrations,subscribers,systemcontacts,threads,topuplogs,trustedsources,valid-patch,vouchers}.t) + SELECT=$(echo t/api-rest/api-{all-links,balanceintervals,billingfees,billingnetworks,billingprofiles,billingzones,calllists,calls,cert-auth,cfdestinationsets,contracts,customercontacts,customers,faxes,lnp,ncoslevels,pbxdevicemodels,pbxdevices,peeringgroups,peeringrules,peeringinboundrules,peeringservers,preferences,profilepackages,resellers,rewriterules,rewriterulesets,root,soundsets,subscriberregistrations,subscribers,systemcontacts,threads,topuplogs,trustedsources,valid-patch,vouchers}.t) elif [ "${SELECT}" = "fast" ] ; then echo "Test selection: ${SELECT}" - SELECT=$(echo t/api-rest/api-{billingnetworks,billingzones,calls,cert-auth,cfdestinationsets,ncoslevels,peeringgroups,peeringrules,peeringservers,resellers,rewriterules,root,soundsets,systemcontacts,valid-patch,vouchers}.t) + SELECT=$(echo t/api-rest/api-{billingnetworks,billingzones,calls,cert-auth,cfdestinationsets,ncoslevels,peeringgroups,peeringrules,peeringinboundrules,peeringservers,resellers,rewriterules,root,soundsets,systemcontacts,valid-patch,vouchers}.t) elif [ "${SELECT}" = "all" ] ; then echo "Test selection: all" SELECT=$(echo t/api-rest/*.t)