diff --git a/lib/NGCP/Panel/Controller/API/CallLists.pm b/lib/NGCP/Panel/Controller/API/CallLists.pm index 8ebfa8d306..1f89fc6e1e 100644 --- a/lib/NGCP/Panel/Controller/API/CallLists.pm +++ b/lib/NGCP/Panel/Controller/API/CallLists.pm @@ -12,6 +12,7 @@ use HTTP::Status qw(:constants); use NGCP::Panel::Utils::DateTime; use DateTime::TimeZone; use NGCP::Panel::Utils::CallList qw(); +use NGCP::Panel::Utils::API::Calllist qw(); require Catalyst::ActionRole::ACL; require Catalyst::ActionRole::CheckTrailingSlash; require NGCP::Panel::Role::HTTPMethods; @@ -31,6 +32,10 @@ sub query_params { param => 'tz', description => 'Format start_time according to the optional time zone provided here, e.g. Europe/Berlin.', }, + { + param => 'use_owner_tz', + description => 'Format start_time according to the filtered customer\'s/subscribers\'s inherited time zone.', + }, { param => 'subscriber_id', description => 'Filter for calls for a specific subscriber. Either this or customer_id is mandatory if called by admin, reseller or subscriberadmin to filter list down to a specific subscriber in order to properly determine the direction of calls.', @@ -307,12 +312,8 @@ sub GET :Allow { my $rows = $c->request->params->{rows} // 10; my $schema = $c->model('DB'); { - if($c->req->param('tz') && !DateTime::TimeZone->is_valid_name($c->req->param('tz'))) { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Query parameter 'tz' value is not a valid time zone"); - return; - } - my $owner = $self->get_owner_data($c, $schema); + my $owner = NGCP::Panel::Utils::API::Calllist::get_owner_data($self,$c, $schema); last unless $owner; $c->stash(owner => $owner); # for query_param: direction my $items = $self->item_rs($c); diff --git a/lib/NGCP/Panel/Controller/API/CallListsItem.pm b/lib/NGCP/Panel/Controller/API/CallListsItem.pm index 93a55208f4..d379c5801b 100644 --- a/lib/NGCP/Panel/Controller/API/CallListsItem.pm +++ b/lib/NGCP/Panel/Controller/API/CallListsItem.pm @@ -8,6 +8,7 @@ use HTTP::Status qw(:constants); use NGCP::Panel::Utils::ValidateJSON qw(); use DateTime::TimeZone; +use NGCP::Panel::Utils::API::Calllist qw(); require Catalyst::ActionRole::ACL; require NGCP::Panel::Role::HTTPMethods; require Catalyst::ActionRole::RequireSSL; @@ -57,17 +58,13 @@ sub auto :Private { sub GET :Allow { my ($self, $c, $id) = @_; { - if($c->req->param('tz') && !DateTime::TimeZone->is_valid_name($c->req->param('tz'))) { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Query parameter 'tz' value is not a valid time zone"); - return; - } my $schema = $c->model('DB'); last unless $self->valid_id($c, $id); - my $owner = $self->get_owner_data($c, $schema); + my $owner = NGCP::Panel::Utils::API::Calllist::get_owner_data($self,$c, $schema); last unless $owner; - my $href_data = $owner->{subscriber} ? + my $href_data = $owner->{subscriber} ? "subscriber_id=".$owner->{subscriber}->id : "customer_id=".$owner->{customer}->id; diff --git a/lib/NGCP/Panel/Controller/API/Faxes.pm b/lib/NGCP/Panel/Controller/API/Faxes.pm index 069aa265f1..ed3408b511 100644 --- a/lib/NGCP/Panel/Controller/API/Faxes.pm +++ b/lib/NGCP/Panel/Controller/API/Faxes.pm @@ -35,6 +35,14 @@ sub api_description { sub query_params { return [ + { + param => 'tz', + description => 'Format timestamp according to the optional time zone provided here, e.g. Europe/Berlin.', + }, + { + param => 'use_owner_tz', + description => 'Format timestamp according to the filtered customer\'s/subscribers\'s inherited time zone.', + }, { param => 'subscriber_id', description => 'Filter for faxes belonging to a specific subscriber', @@ -50,7 +58,7 @@ sub query_params { { param => 'time_from', - description => 'Filter for faxes performed after or at the given time stamp.', + description => 'Filter for faxes performed after or at the given timestamp.', query => { first => sub { my $q = shift; @@ -63,7 +71,7 @@ sub query_params { { param => 'time_to', - description => 'Filter for faxes performed before or at the given time stamp.', + description => 'Filter for faxes performed before or at the given timestamp.', query => { first => sub { my $q = shift; @@ -72,8 +80,7 @@ sub query_params { }, second => sub { }, }, - }, - + }, { param => 'sid', description => 'Filter for a fax with the specific session id', diff --git a/lib/NGCP/Panel/Controller/API/Voicemails.pm b/lib/NGCP/Panel/Controller/API/Voicemails.pm index b1732c7c28..95e4c04b49 100644 --- a/lib/NGCP/Panel/Controller/API/Voicemails.pm +++ b/lib/NGCP/Panel/Controller/API/Voicemails.pm @@ -24,6 +24,14 @@ sub api_description { sub query_params { return [ + { + param => 'tz', + description => 'Format timestamp according to the optional time zone provided here, e.g. Europe/Berlin.', + }, + { + param => 'use_owner_tz', + description => 'Format timestamp according to the filtered customer\'s/subscribers\'s inherited time zone.', + }, { param => 'subscriber_id', description => 'Filter for voicemails belonging to a specific subscriber', @@ -121,7 +129,7 @@ sub GET :Allow { $hal->resource({ total_count => $total_count, }); - my $response = HTTP::Response->new(HTTP_OK, undef, + 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); diff --git a/lib/NGCP/Panel/Role/API/CallLists.pm b/lib/NGCP/Panel/Role/API/CallLists.pm index fd24c3c0b3..12b32eccc3 100644 --- a/lib/NGCP/Panel/Role/API/CallLists.pm +++ b/lib/NGCP/Panel/Role/API/CallLists.pm @@ -16,6 +16,7 @@ use NGCP::Panel::Utils::DateTime; use NGCP::Panel::Utils::CallList; use NGCP::Panel::Utils::Subscriber; use NGCP::Panel::Utils::CallList qw(); +use NGCP::Panel::Utils::API::Calllist qw(); sub _item_rs { my ($self, $c) = @_; @@ -109,14 +110,10 @@ sub resource_from_item { my $datetime_fmt = DateTime::Format::Strptime->new( pattern => '%F %T', ); - if($c->req->param('tz') && DateTime::TimeZone->is_valid_name($c->req->param('tz'))) { - # valid tz is checked in the controllers' GET already, but just in case - # it passes through via POST or something, then just ignore wrong tz - $item->start_time->set_time_zone($c->req->param('tz')); - } + my $start_time = NGCP::Panel::Utils::API::Calllist::apply_owner_timezone($self,$c,$item->start_time,$owner); - $resource->{start_time} = $datetime_fmt->format_datetime($item->start_time); - $resource->{start_time} .= '.'.$item->start_time->millisecond if $item->start_time->millisecond > 0.0; + $resource->{start_time} = $datetime_fmt->format_datetime($start_time); + $resource->{start_time} .= '.'.$start_time->millisecond if $start_time->millisecond > 0.0; return $resource; } @@ -126,76 +123,5 @@ sub item_by_id { return $item_rs->find($id); } -sub get_owner_data { - my ($self, $c, $schema) = @_; - - my $ret; - if($c->user->roles eq "admin" || $c->user->roles eq "reseller") { - if($c->req->param('subscriber_id')) { - my $sub = $schema->resultset('voip_subscribers')->find($c->req->param('subscriber_id')); - unless($sub) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); - return; - } - if($c->user->roles eq "reseller" && $sub->contract->contact->reseller_id != $c->user->reseller_id) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); - return; - } - return { - subscriber => $sub, - customer => $sub->contract, - }; - } elsif($c->req->param('customer_id')) { - my $cust = $schema->resultset('contracts')->find($c->req->param('customer_id')); - unless($cust && $cust->contact->reseller_id) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'customer_id'."); - return; - } - if($c->user->roles eq "reseller" && $cust->contact->reseller_id != $c->user->reseller_id) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'customer_id'."); - return; - } - return { - subscriber => undef, - customer => $cust, - }; - } else { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Mandatory parameter 'subscriber_id' or 'customer_id' missing in request"); - return; - } - } elsif($c->user->roles eq "subscriberadmin") { - if($c->req->param('subscriber_id')) { - my $sub = $schema->resultset('voip_subscribers')->find($c->req->param('subscriber_id')); - unless($sub) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); - return; - } - if($sub->contract_id != $c->user->account_id) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); - return; - } - return { - subscriber => $sub, - customer => $sub->contract, - }; - } else { - my $cust = $schema->resultset('contracts')->find($c->user->account_id); - unless($cust && $cust->contact->reseller_id) { - $self->error($c, HTTP_NOT_FOUND, "Invalid 'customer_id'."); - return; - } - return { - subscriber => undef, - customer => $cust, - }; - } - } else { - return { - subscriber => $c->user->voip_subscriber, - customer => $c->user->voip_subscriber->contract, - }; - } -} - 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Role/API/Faxes.pm b/lib/NGCP/Panel/Role/API/Faxes.pm index e5eb9cc90d..248fb0f79b 100644 --- a/lib/NGCP/Panel/Role/API/Faxes.pm +++ b/lib/NGCP/Panel/Role/API/Faxes.pm @@ -76,7 +76,10 @@ sub resource_from_item { my %resource = (); $resource{id} = int($item->id); - $resource{time} = $datetime_fmt->format_datetime($item->time); + $resource{time} = $datetime_fmt->format_datetime( + NGCP::Panel::Utils::API::Calllist::apply_owner_timezone($self,$c,$item->time, + NGCP::Panel::Utils::API::Calllist::get_owner_data($self,$c, undef, undef, 1) + )); $resource{subscriber_id} = int($subscriber->id); foreach(qw/direction caller callee reason status quality filename/){ $resource{$_} = $item->$_; diff --git a/lib/NGCP/Panel/Role/API/Voicemails.pm b/lib/NGCP/Panel/Role/API/Voicemails.pm index 792f56a5de..b99bc8a60d 100644 --- a/lib/NGCP/Panel/Role/API/Voicemails.pm +++ b/lib/NGCP/Panel/Role/API/Voicemails.pm @@ -11,6 +11,7 @@ use NGCP::Panel::Utils::DataHal qw(); use NGCP::Panel::Utils::DataHalLink qw(); use HTTP::Status qw(:constants); use NGCP::Panel::Utils::Subscriber; +use NGCP::Panel::Utils::API::Calllist qw(); sub _item_rs { my ($self, $c) = @_; @@ -75,10 +76,16 @@ sub hal_from_item { sub resource_from_item { my ($self, $c, $item, $form) = @_; + my $datetime_fmt = DateTime::Format::Strptime->new( + pattern => '%F %T', + ); + my %resource = (); $resource{id} = int($item->id); $resource{duration} = is_int($item->duration) ? int($item->duration) : 0; - $resource{time} = "" . $item->origtime; + $resource{time} = "" . NGCP::Panel::Utils::API::Calllist::apply_owner_timezone($self,$c,$item->origtime, + NGCP::Panel::Utils::API::Calllist::get_owner_data($self,$c, undef, undef, 1) + ); $resource{caller} = $item->callerid; $resource{subscriber_id} = int($item->mailboxuser->provisioning_voip_subscriber->voip_subscriber->id); diff --git a/lib/NGCP/Panel/Utils/API/Calllist.pm b/lib/NGCP/Panel/Utils/API/Calllist.pm new file mode 100644 index 0000000000..24b031abca --- /dev/null +++ b/lib/NGCP/Panel/Utils/API/Calllist.pm @@ -0,0 +1,146 @@ +package NGCP::Panel::Utils::API::Calllist; +use strict; +use warnings; + +use HTTP::Status qw(:constants); + + +sub get_owner_data { + my ($self, $c, $schema, $source, $optional_for_admin_reseller) = @_; + + my $ret; + $source //= $c->req->params; + my $src_subscriber_id = $source->{subscriber_id}; + my $src_customer_id = $source->{customer_id}; + + $schema //= $c->model('DB'); + + if($c->user->roles eq "admin" || $c->user->roles eq "reseller") { + if($src_subscriber_id) { + my $sub = $schema->resultset('voip_subscribers')->find($src_subscriber_id); + unless($sub) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); + return; + } + if($c->user->roles eq "reseller" && $sub->contract->contact->reseller_id != $c->user->reseller_id) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); + return; + } + return { + subscriber => $sub, + customer => $sub->contract, + }; + } elsif($src_customer_id) { + my $cust = $schema->resultset('contracts')->find($src_customer_id); + unless($cust && $cust->contact->reseller_id) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'customer_id'."); + return; + } + if($c->user->roles eq "reseller" && $cust->contact->reseller_id != $c->user->reseller_id) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'customer_id'."); + return; + } + return { + subscriber => undef, + customer => $cust, + }; + } elsif (not $optional_for_admin_reseller) { + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Mandatory parameter 'subscriber_id' or 'customer_id' missing in request"); + return; + } + } elsif($c->user->roles eq "subscriberadmin") { + if($src_subscriber_id) { + my $sub = $schema->resultset('voip_subscribers')->find($src_subscriber_id); + unless($sub) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); + return; + } + if($sub->contract_id != $c->user->account_id) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'subscriber_id'."); + return; + } + return { + subscriber => $sub, + customer => $sub->contract, + }; + } else { + my $cust = $schema->resultset('contracts')->find($c->user->account_id); + unless($cust && $cust->contact->reseller_id) { + $self->error($c, HTTP_NOT_FOUND, "Invalid 'customer_id'."); + return; + } + return { + subscriber => undef, + customer => $cust, + }; + } + } elsif($c->user->roles eq "subscriber") { + return { + subscriber => $c->user->voip_subscriber, + customer => $c->user->voip_subscriber->contract, + }; + } else { + $self->error($c, HTTP_NOT_FOUND, "Unknown role '".$c->user->roles."' of the user."); + return; + } +} + +sub apply_owner_timezone { + my ($self,$c,$dt,$owner) = @_; + my $result = $dt->clone; + if($c->req->param('tz')) { + if (DateTime::TimeZone->is_valid_name($c->req->param('tz'))) { + # valid tz is checked in the controllers' GET already, but just in case + # it passes through via POST or something, then just ignore wrong tz + $result->set_time_zone($c->req->param('tz')); + } else { + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Query parameter 'tz' value is not a valid time zone"); + return; + } + } elsif ($owner and $c->req->param('use_owner_tz')) { + my $tz; + my $sub = $owner->{subscriber}; + my $cust = $owner->{customer}; + if ($owner->{subscriber}) { + $tz = $c->model('DB')->resultset('voip_subscriber_timezone')->search_rs({ + subscriber_id => $owner->{subscriber}->id + })->first; + } elsif ($owner->{customer}) { + $tz = $c->model('DB')->resultset('contract_timezone')->search_rs({ + contract_id => $owner->{customer}->id + })->first; + } else { + # shouldnt go here. + } + $result->set_time_zone($tz->name) if $tz; + } + return $result; +} + +1; + +=head1 NAME + +NGCP::Panel::Utils::API::Calllist + +=head1 DESCRIPTION + +A temporary helper to manipulate calls related data in REST API modules + +=head1 METHODS + +=head2 get_owner_data + +Check if mandatory calls list parameters customer_id or subscriber_id are presented and get proper objects. + +=head1 AUTHOR + +Irina Peshinskaya + +=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: