MT#59806 adapt /api/cfdestinationsets to Entities

* Entites logic is used for GET/POST/PUT/PATCH/DELETE
* Utils::CallForwards::check_destinations() do not obfuscate
  destinations that are returned in the response as all
  logged data is obfuscated anyways

Change-Id: Ia79f9e236c966410e2640d719c3a7f5784cc4c2a
(cherry picked from commit b2a1bc00d1)
mr12.3.1
Kirill Solomko 1 year ago
parent ab5a172e15
commit 88612f33d2

@ -62,151 +62,78 @@ __PACKAGE__->set_config({
allowed_roles => [qw/admin reseller ccareadmin ccare subscriberadmin subscriber/],
});
sub GET :Allow {
my ($self, $c) = @_;
my $page = $c->request->params->{page} // 1;
my $rows = $c->request->params->{rows} // 10;
{
my $dsets = $self->item_rs($c);
(my $total_count, $dsets, my $dsets_rows) = $self->paginate_order_collection($c, $dsets);
my (@embedded, @links);
for my $dset (@$dsets_rows) {
push @embedded, $self->hal_from_item($c, $dset, "cfdestinationsets");
push @links, Data::HAL::Link->new(
relation => 'ngcp:'.$self->resource_name,
href => sprintf('%s%d', $self->dispatch_path, $dset->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/'),
$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,
sub create_item {
my ($self, $c, $resource, $form, $process_extras) = @_;
my $schema = $c->model('DB');
my $dset;
if($c->user->roles eq "subscriberadmin") {
$resource->{subscriber_id} //= $c->user->voip_subscriber->id;
} elsif($c->user->roles eq "subscriber") {
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
}
my $b_subscriber = $schema->resultset('voip_subscribers')->find({
id => $resource->{subscriber_id},
});
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);
unless($b_subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'subscriber_id'.");
return;
}
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,
);
my $dset;
if($c->user->roles eq "subscriberadmin") {
$resource->{subscriber_id} //= $c->user->voip_subscriber->id;
} elsif($c->user->roles eq "subscriber") {
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
my $subscriber = $b_subscriber->provisioning_voip_subscriber;
unless($subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
return;
}
if (! exists $resource->{destinations} ) {
$resource->{destinations} = [];
}
if (!NGCP::Panel::Utils::CallForwards::check_destinations(
c => $c,
resource => $resource,
err_code => sub {
my ($err) = @_;
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err);
},
)) {
return;
}
try {
my $primary_nr_rs = $b_subscriber->primary_number;
my $number;
if ($primary_nr_rs) {
$number = $primary_nr_rs->cc . ($primary_nr_rs->ac //'') . $primary_nr_rs->sn;
} else {
$number = ''
}
my $domain = $subscriber->domain->domain // '';
my $b_subscriber = $schema->resultset('voip_subscribers')->find({
id => $resource->{subscriber_id},
$dset = $schema->resultset('voip_cf_destination_sets')->create({
name => $resource->{name},
subscriber_id => $subscriber->id,
});
unless($b_subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'subscriber_id'.");
last;
for my $d ( @{$resource->{destinations}} ) {
delete $d->{destination_set_id};
delete $d->{simple_destination};
$d->{destination} = NGCP::Panel::Utils::Subscriber::field_to_destination(
destination => $d->{destination},
number => $number,
domain => $domain,
uri => $d->{destination},
);
$dset->create_related("voip_cf_destinations", $d);
}
#if($c->user->roles eq "subscriberadmin" &&
# $b_subscriber->contract_id != $c->user->account_id) {
# $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
# last;
#}
my $subscriber = $b_subscriber->provisioning_voip_subscriber;
unless($subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
last;
}
if (! exists $resource->{destinations} ) {
$resource->{destinations} = [];
}
if (!NGCP::Panel::Utils::CallForwards::check_destinations(
c => $c,
resource => $resource,
err_code => sub {
my ($err) = @_;
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err);
},
)) {
last;
}
try {
my $primary_nr_rs = $b_subscriber->primary_number;
my $number;
if ($primary_nr_rs) {
$number = $primary_nr_rs->cc . ($primary_nr_rs->ac //'') . $primary_nr_rs->sn;
} else {
$number = ''
}
my $domain = $subscriber->domain->domain // '';
$dset = $schema->resultset('voip_cf_destination_sets')->create({
name => $resource->{name},
subscriber_id => $subscriber->id,
});
for my $d ( @{$resource->{destinations}} ) {
delete $d->{destination_set_id};
delete $d->{simple_destination};
$d->{destination} = NGCP::Panel::Utils::Subscriber::field_to_destination(
destination => $d->{destination},
number => $number,
domain => $domain,
uri => $d->{destination},
);
$dset->create_related("voip_cf_destinations", $d);
}
} catch($e) {
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create cfdestinationset.", $e);
last;
}
last unless $self->add_create_journal_item_hal($c,sub {
my $self = shift;
my ($c) = @_;
my $_dset = $self->item_by_id($c, $dset->id);
return $self->hal_from_item($c, $_dset, "cfdestinationsets"); });
$guard->commit;
$c->response->status(HTTP_CREATED);
$c->response->header(Location => sprintf('/%s%d', $c->request->path, $dset->id));
$c->response->body(q());
} catch($e) {
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create cfdestinationset.", $e);
return;
}
return;
return $dset;
}
1;

@ -44,121 +44,21 @@ __PACKAGE__->set_config({
}
});
sub GET :Allow {
my ($self, $c, $id) = @_;
{
last unless $self->valid_id($c, $id);
my $dset = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, destinationset => $dset);
my $hal = $self->hal_from_item($c, $dset, "cfdestinationsets");
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;
sub delete_item {
my ($self, $c, $item) = @_;
return unless $self->check_subscriber_can_update_item($c, $item);
try {
$item->delete;
} catch($e) {
my $id = $item->id;
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error",
"Failed to delete cfdestinationset with id '$id'", $e);
last;
}
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',
ops => [qw/add replace remove copy/],
);
last unless $json;
my $dset = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, destinationset => $dset);
my $old_resource = $self->hal_from_item($c, $dset, "cfdestinationsets")->resource;
my $resource = $self->apply_patch($c, $old_resource, $json);
last unless $resource;
my $form = $self->get_form($c);
$dset = $self->update_item($c, $dset, $old_resource, $resource, $form);
last unless $dset;
my $hal = $self->hal_from_item($c, $dset, "cfdestinationsets");
last unless $self->add_update_journal_item_hal($c,$hal);
$guard->commit;
$self->return_representation($c, 'hal' => $hal, 'preference' => $preference );
}
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 $dset = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, destinationset => $dset);
my $resource = $self->get_valid_put_data(
c => $c,
id => $id,
media_type => 'application/json',
);
last unless $resource;
my $old_resource = { $dset->get_inflated_columns };
my $form = $self->get_form($c);
$dset = $self->update_item($c, $dset, $old_resource, $resource, $form);
last unless $dset;
my $hal = $self->hal_from_item($c, $dset, "cfdestinationsets");
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 $dset = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, destinationset => $dset);
last unless $self->check_subscriber_can_update_item($c, $dset);
last unless $self->add_delete_journal_item_hal($c,sub {
my $self = shift;
my ($c) = @_;
return $self->hal_from_item($c, $dset, "cfdestinationsets"); });
try {
$dset->delete;
} catch($e) {
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error",
"Failed to delete cfdestinationset with id '$id'", $e);
last;
}
$guard->commit;
$c->response->status(HTTP_NO_CONTENT);
$c->response->body(q());
}
return;
return 1 ;
}
sub get_journal_methods{

@ -26,8 +26,7 @@ sub get_form {
}
sub hal_from_item {
my ($self, $c, $item, $type) = @_;
my $form;
my ($self, $c, $item, $form, $params) = @_;
my %resource = $item->get_inflated_columns;
my @destinations;
@ -132,6 +131,33 @@ sub check_subscriber_can_update_item {
return 1;
}
sub resource_from_item {
my ($self, $c, $item) = @_;
my $resource = { $item->get_inflated_columns };
$resource->{subscriber_id} = $item->subscriber->voip_subscriber->id;
$resource->{destinations} = [];
for my $dest ($item->voip_cf_destinations->all) {
my ($d, $duri) = NGCP::Panel::Utils::Subscriber::destination_to_field($dest->destination);
my $deflated;
if($d eq "uri") {
$deflated = NGCP::Panel::Utils::Subscriber::uri_deflate($c, $duri, $item->subscriber->voip_subscriber);
$d = $dest->destination;
}
my $destelem = {$dest->get_inflated_columns,
destination => $dest->destination,
$deflated ? (simple_destination => $deflated) : (),
};
delete @{$destelem}{'id', 'destination_set_id'};
push @{$resource->{destinations}}, $destelem;
}
return $resource;
}
sub update_item {
my ($self, $c, $item, $old_resource, $resource, $form) = @_;

@ -407,10 +407,12 @@ sub resource_from_item {
my $resource = { $item->get_inflated_columns };
$resource->{subscriber_id} = $item->subscriber->voip_subscriber->id;
$resource->{times} //= [];
$resource->{times} = [];
foreach my $period ($item->voip_cf_periods->all) {
push @{$resource->{times}}, { $period->get_inflated_columns };
foreach my $row ($item->voip_cf_periods->all) {
my %period = $row->get_inflated_columns;
delete $period{id};
push @{$resource->{times}}, \%period;
}
return $resource;

@ -461,19 +461,19 @@ sub check_destinations {
}
if (exists $d->{timeout} && ! is_int($d->{timeout})) {
$c->log->error("Invalid timeout for the destination '".$c->qs($d->{destination})."'");
&{$err_code}("Invalid timeout for the destination '".$c->qs($d->{destination})."'");
&{$err_code}("Invalid timeout for the destination '".$d->{destination}."'");
return;
}
if (exists $d->{priority} && ! is_int($d->{priority})) {
$c->log->error("Invalid priority for the destination '".$c->qs($d->{destination})."'");
&{$err_code}("Invalid priority for the destination '".$c->qs($d->{destination})."'");
&{$err_code}("Invalid priority for the destination '".$d->{destination}."'");
return;
}
if (defined $d->{announcement_id}) {
#todo: I think that user expects that put and get will be the same
if(('customhours' ne $d->{destination}) && ('sip:custom-hours@app.local' ne $d->{destination}) ){
$c->log->error("Invalid parameter 'announcement_id' for the destination '".$c->qs($d->{destination})."'");
&{$err_code}("Invalid parameter 'announcement_id' for the destination '".$c->qs($d->{destination})."'");
&{$err_code}("Invalid parameter 'announcement_id' for the destination '".$d->{destination}."'");
return;
}elsif(! is_int($d->{announcement_id})){
$c->log->error("Invalid announcement_id");

Loading…
Cancel
Save