From bb04e38d6599394d2b8c618f46c2744bf0b36eae Mon Sep 17 00:00:00 2001 From: Irina Peshinskaya Date: Fri, 23 Nov 2018 18:41:40 +0100 Subject: [PATCH] Revert "Revert "TT#47906 Remove unnecessary code from /api/soundsets/"" This reverts commit 04500cbc40541bb7f1c23d9d9e2d87a1c988c350. Change-Id: Id13dc9c487420371bf5e69a519fd6a135d9f0d92 --- lib/NGCP/Panel/Controller/API/SoundSets.pm | 208 +++--------------- .../Panel/Controller/API/SoundSetsItem.pm | 208 ++++++------------ lib/NGCP/Panel/Role/API/SoundSets.pm | 137 +++--------- 3 files changed, 136 insertions(+), 417 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/SoundSets.pm b/lib/NGCP/Panel/Controller/API/SoundSets.pm index 66b7ff05a4..aecbb662b7 100644 --- a/lib/NGCP/Panel/Controller/API/SoundSets.pm +++ b/lib/NGCP/Panel/Controller/API/SoundSets.pm @@ -2,13 +2,13 @@ package NGCP::Panel::Controller::API::SoundSets; 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 parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::SoundSets/; + +__PACKAGE__->set_config({ + allowed_roles => [qw/admin reseller subscriberadmin/], +}); sub allowed_methods{ return [qw/GET POST OPTIONS HEAD/]; @@ -34,189 +34,53 @@ sub query_params { { param => 'reseller_id', description => 'Filter for sound sets of a specific reseller', - query => { - first => sub { - my $q = shift; - return { 'reseller_id' => $q }; - }, - second => sub {}, - }, + type => 'string_eq', }, { param => 'name', description => 'Filter for sound sets with a specific name (wildcard pattern allowed)', - query => { - first => sub { - my $q = shift; - return { name => { like => $q } }; - }, - second => sub {}, - }, + type => 'string_like', }, ]; } -use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::SoundSets/; - -sub resource_name{ - return 'soundsets'; -} - -sub dispatch_path{ - return '/api/soundsets/'; -} -sub relation{ - return 'http://purl.org/sipwise/ngcp-api/#rel-soundsets'; -} +sub create_item { + my ($self, $c, $resource, $form, $process_extras) = @_; -__PACKAGE__->set_config({ - allowed_roles => [qw/admin reseller subscriberadmin/], -}); + my $item; + try { + my $copy_from_default_params = { map {$_ => delete $resource->{$_}} (qw/copy_from_default loopplay replace_existing language/)}; -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), + $item = $c->model('DB')->resultset('voip_sound_sets')->create($resource); + if($item->contract_id && $item->contract_default) { + $c->model('DB')->resultset('voip_sound_sets')->search({ + reseller_id => $item->reseller_id, + contract_id => $item->contract_id, + contract_default => 1, + id => { '!=' => $item->id }, + })->update({ contract_default => 0 }); + } + if ($copy_from_default_params->{copy_from_default}) { + my $error; + my $handles_rs = NGCP::Panel::Utils::Sounds::get_handles_rs(c => $c, set_rs => $item); + NGCP::Panel::Utils::Sounds::apply_default_soundset_files( + c => $c, + lang => $copy_from_default_params->{language}, + set_id => $item->id, + handles_rs => $handles_rs, + loopplay => $copy_from_default_params->{loopplay}, + override => $copy_from_default_params->{replace_existing}, + error_ref => \$error, ); } - 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/'), - $self->collection_nav_links($c, $page, $rows, $total_count, $c->request->path, $c->request->query_params); - - 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); + } catch($e) { + $c->log->error("failed to create soundset: $e"); # TODO: user, message, trace, ... + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create soundset."); return; } - 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 $customer_id = delete $resource->{customer_id}; - $resource->{contract_id} //= $customer_id; - my $form = $self->get_form($c); - last unless $self->validate_form( - c => $c, - resource => $resource, - form => $form, - ); - if ($c->user->roles eq "admin") { - } elsif ($c->user->roles eq "reseller") { - $resource->{reseller_id} = $c->user->reseller_id; - } elsif ($c->user->roles eq "subscriberadmin") { - $resource->{contract_id} = $c->user->account_id; - $resource->{reseller_id} = $c->user->contract->contact->reseller_id; - } - - my $reseller = $c->model('DB')->resultset('resellers')->find({ - id => $resource->{reseller_id}, - }); - unless($reseller) { - $c->log->error("invalid reseller_id '$$resource{reseller_id}'"); # TODO: user, message, trace, ... - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Reseller does not exist"); - return; - } - my $customer; - if(defined $resource->{contract_id}) { - $customer = $c->model('DB')->resultset('contracts')->find({ - id => $resource->{contract_id}, - 'contact.reseller_id' => { '!=' => undef }, - },{ - join => 'contact', - }); - unless($customer) { - $c->log->error("invalid customer_id '$$resource{contract_id}'"); # TODO: user, message, trace, ... - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Customer does not exist"); - return; - } - unless($customer->contact->reseller_id == $reseller->id) { - $c->log->error("customer_id '$$resource{contract_id}' doesn't belong to reseller_id '$$resource{reseller_id}"); # TODO: user, message, trace, ... - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid reseller for customer"); - return; - } - } - $resource->{contract_default} //= 0; - - my $item; - try { - my $copy_from_default_params = { map {$_ => delete $resource->{$_}} (qw/copy_from_default loopplay replace_existing language/)}; - - $item = $c->model('DB')->resultset('voip_sound_sets')->create($resource); - if($item->contract_id && $item->contract_default) { - $c->model('DB')->resultset('voip_sound_sets')->search({ - reseller_id => $item->reseller_id, - contract_id => $item->contract_id, - contract_default => 1, - id => { '!=' => $item->id }, - })->update({ contract_default => 0 }); - } - if ($copy_from_default_params->{copy_from_default}) { - my $error; - my $handles_rs = NGCP::Panel::Utils::Sounds::get_handles_rs(c => $c, set_rs => $item); - NGCP::Panel::Utils::Sounds::apply_default_soundset_files( - c => $c, - lang => $copy_from_default_params->{language}, - set_id => $item->id, - handles_rs => $handles_rs, - loopplay => $copy_from_default_params->{loopplay}, - override => $copy_from_default_params->{replace_existing}, - error_ref => \$error, - ); - } - } catch($e) { - $c->log->error("failed to create soundset: $e"); # TODO: user, message, trace, ... - $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create soundset."); - 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); #reload is required here, otherwise description field is missing - return $self->hal_from_item($c, $_item); }); - - $guard->commit; - - $c->response->status(HTTP_CREATED); - $c->response->header(Location => sprintf('/%s%d', $c->request->path, $item->id)); - $c->response->body(q()); - } - return; + return $item; } 1; diff --git a/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm b/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm index c9e996034c..afd55f35d8 100644 --- a/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm +++ b/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm @@ -2,38 +2,10 @@ package NGCP::Panel::Controller::API::SoundSetsItem; use NGCP::Panel::Utils::Generic qw(:all); use Sipwise::Base; - -use HTTP::Headers qw(); use HTTP::Status qw(:constants); -use NGCP::Panel::Utils::ValidateJSON qw(); -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/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::SoundSets/; -sub resource_name{ - return 'soundsets'; -} - -sub dispatch_path{ - return '/api/soundsets/'; -} - -sub relation{ - return 'http://purl.org/sipwise/ngcp-api/#rel-soundsets'; -} - -sub journal_query_params { - my($self,$query_params) = @_; - return $self->get_journal_query_params($query_params); -} - __PACKAGE__->set_config({ allowed_roles => { Default => [qw/admin reseller subscriberadmin/], @@ -41,134 +13,84 @@ __PACKAGE__->set_config({ } }); -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, soundset => $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"|r =~ - s/rel=self/rel="item self"/r; - } $hal->http_headers), - ), $hal->as_json); - $c->response->headers($response->headers); - $c->response->body($response->content); - return; - } - return; +sub allowed_methods{ + return [qw/GET OPTIONS HEAD PATCH PUT DELETE/]; } -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, soundset => $item); - my $form = $self->get_form($c); - my $old_resource = $self->resource_from_item($c, $item, $form); - my $resource = $self->apply_patch($c, $old_resource, $json); - last unless $resource; - - $item = $self->update_item($c, $item, $old_resource, $resource, $form); - last unless $item; - - my $hal = $self->hal_from_item($c, $item, $form); - last unless $self->add_update_journal_item_hal($c,$hal); - - $guard->commit; - - $self->return_representation($c, 'hal' => $hal, 'preference' => $preference ); - } - return; +sub journal_query_params { + my($self,$query_params) = @_; + return $self->get_journal_query_params($query_params); } -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, soundset => $item); - my $resource = $self->get_valid_put_data( - c => $c, - id => $id, - media_type => 'application/json', +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/]; +} + +sub update_item_model { + my ($self, $c, $item, $old_resource, $resource, $form) = @_; + + my $copy_from_default_params = { map {$_ => delete $resource->{$_}} (qw/copy_from_default loopplay replace_existing language/) }; + $item->update($resource); + if ($copy_from_default_params->{copy_from_default}) { + my $error; + my $handles_rs = NGCP::Panel::Utils::Sounds::get_handles_rs(c => $c, set_rs => $item); + NGCP::Panel::Utils::Sounds::apply_default_soundset_files( + c => $c, + lang => $copy_from_default_params->{language}, + set_id => $item->id, + handles_rs => $handles_rs, + loopplay => $copy_from_default_params->{loopplay}, + override => $copy_from_default_params->{replace_existing}, + error_ref => \$error, ); - last unless $resource; - my $form = $self->get_form($c); - my $old_resource = $self->resource_from_item($c, $item, $form); - - $item = $self->update_item($c, $item, $old_resource, $resource, $form); - last unless $item; - - my $hal = $self->hal_from_item($c, $item, $form); - last unless $self->add_update_journal_item_hal($c,$hal); - - $guard->commit; - $self->return_representation($c, 'hal' => $hal, 'preference' => $preference ); } - 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, soundset => $item); - - last unless $self->add_delete_journal_item_hal($c,sub { - my $self = shift; - my ($c) = @_; - my $_form = $self->get_form($c); - return $self->hal_from_item($c, $item, $_form); }); - - if($item->contract_id) { - my $pref_rs = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, attribute => 'contract_sound_set', - ); - $pref_rs->search({ value => $item->id })->delete; + if($item->contract_id && $item->contract_default && !$old_resource->{contract_default}) { + $c->model('DB')->resultset('voip_sound_sets')->search({ + reseller_id => $item->reseller_id, + contract_id => $item->contract_id, + contract_default => 1, + id => { '!=' => $item->id }, + })->update({ contract_default => 0 }); + + foreach my $bill_subscriber($item->contract->voip_subscribers->all) { + my $prov_subscriber = $bill_subscriber->provisioning_voip_subscriber; + if($prov_subscriber) { + my $pref_rs = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( + c => $c, prov_subscriber => $prov_subscriber, attribute => 'contract_sound_set', + ); + unless($pref_rs->first) { + $pref_rs->create({ value => $item->id }); + } + } } + } - foreach my $p(qw/usr dom peer/) { - $c->model('DB')->resultset("voip_".$p."_preferences")->search({ - 'attribute.attribute' => 'sound_set', - value => $item->id, - },{ - join => 'attribute', - })->delete_all; # explicit delete_all, otherwise query fails - } - - $item->delete; + return $item; +} - $guard->commit; +sub delete_item { + my ($self, $c, $item) = @_; - $c->response->status(HTTP_NO_CONTENT); - $c->response->body(q()); + if($item->contract_id) { + my $pref_rs = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( + c => $c, attribute => 'contract_sound_set', + ); + $pref_rs->search({ value => $item->id })->delete; } - 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/]; + foreach my $p(qw/usr dom peer/) { + $c->model('DB')->resultset("voip_".$p."_preferences")->search({ + 'attribute.attribute' => 'sound_set', + value => $item->id, + },{ + join => 'attribute', + })->delete_all; # explicit delete_all, otherwise query fails + } + + $item->delete; + + return 1; } 1; diff --git a/lib/NGCP/Panel/Role/API/SoundSets.pm b/lib/NGCP/Panel/Role/API/SoundSets.pm index 10feb2679d..615f4b1d01 100644 --- a/lib/NGCP/Panel/Role/API/SoundSets.pm +++ b/lib/NGCP/Panel/Role/API/SoundSets.pm @@ -5,12 +5,15 @@ 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); +sub resource_name{ + return 'soundsets'; +} + sub _item_rs { my ($self, $c) = @_; @@ -41,73 +44,35 @@ sub get_form { } } -sub hal_from_item { - my ($self, $c, $item, $form) = @_; - - $form //= $self->get_form($c); - my $resource = $self->resource_from_item($c, $item, $form); - - 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, - ), - # nth: these should also be adapted/adaptable when using subscriber(admin) roles - 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:resellers', href => sprintf("/api/resellers/%d", $item->reseller_id)), - $item->contract_id ? Data::HAL::Link->new(relation => 'ngcp:customers', href => sprintf("/api/customers/%d", $item->contract_id)) : (), - Data::HAL::Link->new(relation => 'ngcp:soundfiles', href => sprintf("/api/soundfiles/?set_id=%d", $item->id)), - $self->get_journal_relation_link($c, $item->id), - ], - relation => 'ngcp:'.$self->resource_name, - ); - - - $self->validate_form( - c => $c, - resource => $resource, - form => $form, - run => 0, - ); - if (exists $resource->{contract_id}) { - $resource->{customer_id} = delete $resource->{contract_id}; - } - - $resource->{id} = int($item->id); - $hal->resource($resource); - return $hal; +sub hal_links { + my($self, $c, $item, $resource, $form) = @_; + my $adm = $c->user->roles eq "admin"; + return [ + Data::HAL::Link->new(relation => 'ngcp:resellers', href => sprintf("/api/resellers/%d", $item->reseller_id)), + $item->contract_id ? Data::HAL::Link->new(relation => 'ngcp:customers', href => sprintf("/api/customers/%d", $item->contract_id)) : (), + Data::HAL::Link->new(relation => 'ngcp:soundfiles', href => sprintf("/api/soundfiles/?set_id=%d", $item->id)), + ]; } -sub resource_from_item { - my ($self, $c, $item, $form) = @_; - - my $resource = { $item->get_inflated_columns }; - +sub post_process_hal_resource { + my($self, $c, $item, $resource, $form) = @_; + #Currently actual field is contract_id, as it is specified in the form and thus in the doc + #But we will keep customer_id for backward compatibility + $resource->{customer_id} = $resource->{contract_id}; return $resource; } -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) = @_; - +sub pre_process_form_resource{ + my($self,$c, $item, $old_resource, $resource, $form, $process_extras) = @_; + #For backward compatibility. We always showed contract_id in generated API docs, as we used datatable field contract + #but considered only customer_id value. + #So now we allow both, and one documented (contract_id) has higher priority my $customer_id = delete $resource->{customer_id}; $resource->{contract_id} //= $customer_id; - $form //= $self->get_form($c); - return unless $self->validate_form( - c => $c, - form => $form, - resource => $resource, - ); +} + +sub process_form_resource{ + my($self,$c, $item, $old_resource, $resource, $form, $process_extras) = @_; if ($c->user->roles eq "admin") { } elsif ($c->user->roles eq "reseller") { @@ -116,6 +81,14 @@ sub update_item { $resource->{contract_id} = $c->user->account_id; $resource->{reseller_id} = $c->user->contract->contact->reseller_id; } + $resource->{contract_default} //= 0; + return $resource; +} + +sub check_resource{ + my($self, $c, $item, $old_resource, $resource, $form, $process_extras) = @_; + my $schema = $c->model('DB'); + my $reseller = $c->model('DB')->resultset('resellers')->find({ id => $resource->{reseller_id}, }); @@ -143,47 +116,7 @@ sub update_item { return; } } - - $resource->{contract_default} //= 0; - - my $copy_from_default_params = { map {$_ => delete $resource->{$_}} (qw/copy_from_default loopplay replace_existing language/) }; - $item->update($resource); - if ($copy_from_default_params->{copy_from_default}) { - my $error; - my $handles_rs = NGCP::Panel::Utils::Sounds::get_handles_rs(c => $c, set_rs => $item); - NGCP::Panel::Utils::Sounds::apply_default_soundset_files( - c => $c, - lang => $copy_from_default_params->{language}, - set_id => $item->id, - handles_rs => $handles_rs, - loopplay => $copy_from_default_params->{loopplay}, - override => $copy_from_default_params->{replace_existing}, - error_ref => \$error, - ); - } - - if($item->contract_id && $item->contract_default && !$old_resource->{contract_default}) { - $c->model('DB')->resultset('voip_sound_sets')->search({ - reseller_id => $item->reseller_id, - contract_id => $item->contract_id, - contract_default => 1, - id => { '!=' => $item->id }, - })->update({ contract_default => 0 }); - - foreach my $bill_subscriber($item->contract->voip_subscribers->all) { - my $prov_subscriber = $bill_subscriber->provisioning_voip_subscriber; - if($prov_subscriber) { - my $pref_rs = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $prov_subscriber, attribute => 'contract_sound_set', - ); - unless($pref_rs->first) { - $pref_rs->create({ value => $item->id }); - } - } - } - } - - return $item; + return 1; } 1;