From 378d27d0a9e2bb080b8cacfb49d663c4b10a69fc Mon Sep 17 00:00:00 2001 From: Flaviu Mates Date: Fri, 29 Mar 2019 19:46:57 +0200 Subject: [PATCH] TT#33114 Implement DELETE method to terminate BillingProfiles and BillingNetworks Change-Id: I5cb2beee5c8edd8efe4b1435a5f4f67d6737be19 --- .../Controller/API/BillingNetworksItem.pm | 57 +++++++++++-------- .../Controller/API/BillingProfilesItem.pm | 36 +++++++++++- t/api-rest/api-billingnetworks.t | 9 +-- t/api-rest/api-billingprofiles.t | 15 ++--- 4 files changed, 73 insertions(+), 44 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm b/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm index f2fdd5f56d..9ae79d244f 100644 --- a/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm @@ -11,12 +11,13 @@ use HTTP::Status qw(:constants); use NGCP::Panel::Utils::ValidateJSON qw(); use NGCP::Panel::Utils::Reseller qw(); +use NGCP::Panel::Utils::BillingNetworks qw /check_network_update_item/; require Catalyst::ActionRole::ACL; require NGCP::Panel::Role::HTTPMethods; require Catalyst::ActionRole::RequireSSL; sub allowed_methods{ - return [qw/GET OPTIONS HEAD PATCH PUT/]; + return [qw/GET OPTIONS HEAD PATCH PUT DELETE/]; } use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::BillingNetworks/; @@ -133,30 +134,36 @@ sub PUT :Allow { return; } -#sub DELETE :Allow { -# my ($self, $c, $id) = @_; -# my $guard = $c->model('DB')->txn_scope_guard; -# { -# my $bn = $self->item_by_id($c, $id); -# last unless $self->resource_exists($c, billingnetwork => $bn); -# last unless NGCP::Panel::Utils::Reseller::check_reseller_delete_item($c,$bn->reseller_id,sub { -# my ($err) = @_; -# $self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err); -# }); -# try { -# $bn->delete; -# } catch($e) { -# $c->log->error("Failed to delete billingnetwork with id '$id': $e"); -# $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error"); -# last; -# } -# $guard->commit; -# -# $c->response->status(HTTP_NO_CONTENT); -# $c->response->body(q()); -# } -# return; -#} +sub DELETE :Allow { + my ($self, $c, $id) = @_; + my $guard = $c->model('DB')->txn_scope_guard; + { + my $billing_network = $self->item_by_id($c, $id); + last unless $self->resource_exists($c, billingnetwork => $billing_network); + last unless NGCP::Panel::Utils::Reseller::check_reseller_delete_item($c, $billing_network->reseller_id, sub { + my ($err) = @_; + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err); + }); + return unless NGCP::Panel::Utils::BillingNetworks::check_network_update_item($c,undef,$billing_network,sub { + my ($err) = @_; + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err); + }); + try { + $billing_network->update({ + status => 'terminated' + }); + } catch($e) { + $c->log->error("Failed to terminate billingnetwork with id '$id': $e"); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error"); + last; + } + $guard->commit; + + $c->response->status(HTTP_NO_CONTENT); + $c->response->body(q()); + } + return; +} sub get_journal_methods{ return [qw/handle_item_base_journal handle_journals_get handle_journalsitem_get handle_journals_options handle_journalsitem_options handle_journals_head handle_journalsitem_head/]; diff --git a/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm b/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm index cc02907a10..84288ea4c9 100644 --- a/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm @@ -7,12 +7,13 @@ use HTTP::Headers qw(); use HTTP::Status qw(:constants); use NGCP::Panel::Utils::ValidateJSON qw(); +use NGCP::Panel::Utils::Billing qw /check_profile_update_item/; require Catalyst::ActionRole::ACL; require NGCP::Panel::Role::HTTPMethods; require Catalyst::ActionRole::RequireSSL; sub allowed_methods{ - return [qw/GET OPTIONS HEAD PATCH PUT/]; + return [qw/GET OPTIONS HEAD PATCH PUT DELETE/]; } use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::BillingProfiles/; @@ -131,8 +132,37 @@ sub PUT :Allow { return; } -# we don't allow to DELETE a billing profile - +sub DELETE :Allow { + my ($self, $c, $id) = @_; + my $guard = $c->model('DB')->txn_scope_guard; + { + my $billing_profile = $self->item_by_id($c, $id); + last unless $self->resource_exists($c, billingprofile => $billing_profile); + last unless NGCP::Panel::Utils::Reseller::check_reseller_delete_item($c, $billing_profile->reseller_id, sub { + my ($err) = @_; + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err); + }); + return unless NGCP::Panel::Utils::Billing::check_profile_update_item($c,undef,$billing_profile,sub { + my ($err) = @_; + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err); + }); + try { + $billing_profile->update({ + status => 'terminated', + terminate_timestamp => NGCP::Panel::Utils::DateTime::current_local + }); + } catch($e) { + $c->log->error("Failed to terminate billingprofile with id '$id': $e"); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error"); + last; + } + $guard->commit; + + $c->response->status(HTTP_NO_CONTENT); + $c->response->body(q()); + } + return; +} sub get_journal_methods{ return [qw/handle_item_base_journal handle_journals_get handle_journalsitem_get handle_journals_options handle_journalsitem_options handle_journals_head handle_journalsitem_head/]; diff --git a/t/api-rest/api-billingnetworks.t b/t/api-rest/api-billingnetworks.t index 118a939b0f..30453d0470 100644 --- a/t/api-rest/api-billingnetworks.t +++ b/t/api-rest/api-billingnetworks.t @@ -122,14 +122,9 @@ my $default_reseller_id = 1; is($res->code, 200, "fetch PATCHed test billingnetwork"); $billingnetwork = JSON::from_json($res->decoded_content); - $req = HTTP::Request->new('PATCH', $billingnetwork_uri); - $req->header('Content-Type' => 'application/json-patch+json'); - $req->header('Prefer' => 'return=representation'); - $req->content(JSON::to_json( - [ { op => 'replace', path => '/status', value => "terminated" } ] - )); + $req = HTTP::Request->new('DELETE', $billingnetwork_uri); $res = $ua->request($req); - is($res->code, 200, "terminate test billingnetwork"); + is($res->code, 204, "terminate test billingnetwork"); $req = HTTP::Request->new('GET', $billingnetwork_uri); $res = $ua->request($req); is($res->code, 404, "try to fetch terminated test billingnetwork"); diff --git a/t/api-rest/api-billingprofiles.t b/t/api-rest/api-billingprofiles.t index a1fd4f2663..aada794d23 100644 --- a/t/api-rest/api-billingprofiles.t +++ b/t/api-rest/api-billingprofiles.t @@ -159,14 +159,13 @@ my @allprofiles = (); my @hopts = split /\s*,\s*/, $res->header('Allow'); my $opts = JSON::from_json($res->decoded_content); ok(exists $opts->{methods} && ref $opts->{methods} eq "ARRAY", "check for valid 'methods' in body"); - foreach my $opt(qw( GET HEAD OPTIONS PUT PATCH )) { + foreach my $opt(qw( GET HEAD OPTIONS PUT PATCH DELETE )) { ok(grep { /^$opt$/ } @hopts, "check for existence of '$opt' in Allow header"); ok(grep { /^$opt$/ } @{ $opts->{methods} }, "check for existence of '$opt' in body"); } - foreach my $opt(qw( POST DELETE )) { - ok(!grep { /^$opt$/ } @hopts, "check for absence of '$opt' in Allow header"); - ok(!grep { /^$opt$/ } @{ $opts->{methods} }, "check for absence of '$opt' in body"); - } + + ok(!grep { /^POST$/ } @hopts, "check for absence of 'POST' in Allow header"); + ok(!grep { /^POST$/ } @{ $opts->{methods} }, "check for absence of 'POST' in body"); $req = HTTP::Request->new('GET', $uri.'/'.$firstprofile); $res = $ua->request($req); @@ -250,11 +249,9 @@ my @allprofiles = (); # TODO: invalid handle etc - $req->content(JSON::to_json( - [ { op => 'replace', path => '/status', value => 'terminated' } ] - )); + $req = HTTP::Request->new('DELETE', $uri.'/'.$firstprofile); $res = $ua->request($req); - is($res->code, 200, "terminated profile successful"); + is($res->code, 204, "terminated profile successful"); $req = HTTP::Request->new('GET', $uri.'/'.$firstprofile); $res = $ua->request($req); is($res->code, 404, "try to fetch terminated profile");