+ api/events resource + removing an autoattendant via /api/callforwards: events OK + removing an autoattendant via /api/cfdestiantions: OK + removing an autoattendant via /api/cfmappings: OK Change-Id: I4c309753b9338582479dba9951f757bb2ecaad7echanges/98/9798/9
parent
776dd24f6f
commit
5633770f1f
@ -0,0 +1,195 @@
|
||||
package NGCP::Panel::Controller::API::Events;
|
||||
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 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 OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub api_description {
|
||||
return 'Browse EDRs (event data records).';
|
||||
};
|
||||
|
||||
sub query_params {
|
||||
return [
|
||||
{
|
||||
param => 'subscriber_id',
|
||||
description => 'Filter for events of a specific subscriber.',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
return { 'subscriber_id' => $q };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
{
|
||||
param => 'reseller_id',
|
||||
description => 'Filter for events for customers/subscribers of a specific reseller.',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
return { 'reseller.id' => $q };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
{
|
||||
param => 'type',
|
||||
description => 'Filter for events of a specific type.',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
{ type => { like => $q } };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
{
|
||||
param => 'timestamp_from',
|
||||
description => 'Filter for events occurred after or at the given time stamp.',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
my $dt = NGCP::Panel::Utils::DateTime::from_string($q);
|
||||
return { 'timestamp' => { '>=' => $dt->epoch } };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
{
|
||||
param => 'timestamp_to',
|
||||
description => 'Filter for events occurred before or at the given time stamp.',
|
||||
query => {
|
||||
first => sub {
|
||||
my $q = shift;
|
||||
my $dt = NGCP::Panel::Utils::DateTime::from_string($q);
|
||||
return { 'timestamp' => { '<=' => $dt->epoch } };
|
||||
},
|
||||
second => sub {},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::Events/;
|
||||
|
||||
sub resource_name{
|
||||
return 'events';
|
||||
}
|
||||
sub dispatch_path{
|
||||
return '/api/events/';
|
||||
}
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-events';
|
||||
}
|
||||
|
||||
__PACKAGE__->config(
|
||||
action => {
|
||||
map { $_ => {
|
||||
ACLDetachTo => '/api/root/invalid_user',
|
||||
AllowedRole => [qw/admin reseller/],
|
||||
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) {
|
||||
my $hal = $self->hal_from_item($c, $item, $form);
|
||||
$hal->_forcearray(1);
|
||||
push @embedded,$hal;
|
||||
my $link = Data::HAL::Link->new(
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
href => sprintf('/%s%d', $c->request->path, $item->id),
|
||||
);
|
||||
$link->_forcearray(1);
|
||||
push @links, $link;
|
||||
}
|
||||
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/');
|
||||
|
||||
push @links, $self->collection_nav_links($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);
|
||||
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 end : Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->log_response($c);
|
||||
}
|
||||
|
||||
1;
|
||||
@ -0,0 +1,102 @@
|
||||
package NGCP::Panel::Controller::API::EventsItem;
|
||||
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/];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::Events/;
|
||||
|
||||
sub resource_name{
|
||||
return 'events';
|
||||
}
|
||||
sub dispatch_path{
|
||||
return '/api/events/';
|
||||
}
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-events';
|
||||
}
|
||||
|
||||
__PACKAGE__->config(
|
||||
action => {
|
||||
map { $_ => {
|
||||
ACLDetachTo => '/api/root/invalid_user',
|
||||
AllowedRole => [qw/admin reseller/],
|
||||
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, event => $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 end : Private {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$self->log_response($c);
|
||||
}
|
||||
|
||||
1;
|
||||
@ -0,0 +1,28 @@
|
||||
package NGCP::Panel::Form::Event::Admin;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'NGCP::Panel::Form::Event::Reseller';
|
||||
|
||||
has_field 'reseller_id' => (
|
||||
type => 'PosInteger',
|
||||
label => 'The subscriber contract\'s reseller.',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has_field 'export_status' => (
|
||||
type => 'Select',
|
||||
label => 'The status of the exporting process.',
|
||||
options => [
|
||||
{ label => 'unexported', 'value' => 'unexported' },
|
||||
{ label => 'ok', 'value' => 'ok' },
|
||||
{ label => 'failed', 'value' => 'failed' },
|
||||
],
|
||||
);
|
||||
|
||||
has_field 'exported_at' => (
|
||||
type => 'Text',
|
||||
title => 'The timestamp when the exporting occured.',
|
||||
required => 0,
|
||||
);
|
||||
|
||||
1;
|
||||
@ -0,0 +1,50 @@
|
||||
package NGCP::Panel::Form::Event::Reseller;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
has_field 'id' => (
|
||||
type => 'Hidden'
|
||||
);
|
||||
|
||||
has_field 'type' => (
|
||||
type => 'Text',
|
||||
label => 'The event type.',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
#has_field 'type' => (
|
||||
# type => 'Select',
|
||||
# label => 'The top-up request type.',
|
||||
# options => [
|
||||
# { value => 'cash', label => 'Cash top-up' },
|
||||
# { value => 'voucher', label => 'Voucher top-up' },
|
||||
# ],
|
||||
# required => 1,
|
||||
#);
|
||||
|
||||
has_field 'subscriber_id' => (
|
||||
type => 'PosInteger',
|
||||
label => 'The subscriber the event is related to.',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has_field 'old_status' => (
|
||||
type => 'Text',
|
||||
label => 'Status information before the event, if applicable.',
|
||||
required => 0,
|
||||
);
|
||||
|
||||
has_field 'new_status' => (
|
||||
type => 'Text',
|
||||
label => 'Status information after the event, if applicable.',
|
||||
required => 0,
|
||||
);
|
||||
|
||||
has_field 'timestamp' => (
|
||||
type => '+NGCP::Panel::Field::DateTime',
|
||||
label => 'The timestamp of the event.',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
1;
|
||||
@ -0,0 +1,86 @@
|
||||
package NGCP::Panel::Role::API::Events;
|
||||
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::Event::Reseller;
|
||||
use NGCP::Panel::Form::Event::Admin;
|
||||
use Data::Dumper;
|
||||
|
||||
sub _item_rs {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $item_rs = $c->model('DB')->resultset('events');
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$item_rs = $item_rs->search({
|
||||
'reseller_id' => $c->user->reseller_id,
|
||||
},undef);
|
||||
}
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
sub get_form {
|
||||
my ($self, $c) = @_;
|
||||
if($c->user->roles eq "admin") {
|
||||
return NGCP::Panel::Form::Event::Admin->new;
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
return NGCP::Panel::Form::Event::Reseller->new;
|
||||
}
|
||||
}
|
||||
|
||||
sub hal_from_item {
|
||||
my ($self, $c, $item, $form) = @_;
|
||||
my %resource = $item->get_inflated_columns;
|
||||
|
||||
my $datetime_fmt = DateTime::Format::Strptime->new(
|
||||
pattern => '%F %T',
|
||||
);
|
||||
$resource{timestamp} = $datetime_fmt->format_datetime($resource{timestamp}) if defined $resource{timestamp};
|
||||
|
||||
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)),
|
||||
(defined $item->subscriber_id ? Data::HAL::Link->new(relation => 'ngcp:subscribers', href => sprintf("/api/subscribers/%d", $item->subscriber_id)) : ()),
|
||||
(defined $item->reseller_id ? Data::HAL::Link->new(relation => 'ngcp:resellers', href => sprintf("/api/resellers/%d", $item->reseller_id)) : ()),
|
||||
],
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
);
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
|
||||
$self->validate_form(
|
||||
c => $c,
|
||||
resource => \%resource,
|
||||
form => $form,
|
||||
run => 0,
|
||||
exceptions => [qw/id subscriber_id reseller_id/],
|
||||
);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
1;
|
||||
@ -0,0 +1,470 @@
|
||||
#use Sipwise::Base;
|
||||
use Net::Domain qw(hostfqdn);
|
||||
use LWP::UserAgent;
|
||||
use JSON qw();
|
||||
use Test::More;
|
||||
|
||||
my $is_local_env = 0;
|
||||
|
||||
my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443');
|
||||
my ($netloc) = ($uri =~ m!^https?://(.*)/?.*$!);
|
||||
|
||||
my ($ua, $req, $res);
|
||||
$ua = LWP::UserAgent->new;
|
||||
|
||||
$ua->ssl_opts(
|
||||
verify_hostname => 0,
|
||||
SSL_verify_mode => 0,
|
||||
);
|
||||
my $user = $ENV{API_USER} // 'administrator';
|
||||
my $pass = $ENV{API_PASS} // 'administrator';
|
||||
$ua->credentials($netloc, "api_admin_http", $user, $pass);
|
||||
|
||||
#$ua->add_handler("request_send", sub {
|
||||
# my ($request, $ua, $h) = @_;
|
||||
# print $request->method . ' ' . $request->uri . "\n" . ($request->content ? $request->content . "\n" : '') unless $request->header('authorization');
|
||||
# return undef;
|
||||
#});
|
||||
#$ua->add_handler("response_done", sub {
|
||||
# my ($response, $ua, $h) = @_;
|
||||
# print $response->decoded_content . "\n" if $response->code != 401;
|
||||
# return undef;
|
||||
#});
|
||||
|
||||
my $t = time;
|
||||
my $reseller_id = 1;
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/domains/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->content(JSON::to_json({
|
||||
domain => 'test' . $t . '.example.org',
|
||||
reseller_id => $reseller_id,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test domain");
|
||||
$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location'));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch created test domain");
|
||||
my $domain = JSON::from_json($res->decoded_content);
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/billingprofiles/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
name => "test profile $t",
|
||||
handle => "testprofile$t",
|
||||
reseller_id => $reseller_id,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test billing profile");
|
||||
my $billing_profile_id = $res->header('Location');
|
||||
$billing_profile_id =~ s/^.+\/(\d+)$/$1/;
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/customercontacts/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->content(JSON::to_json({
|
||||
firstname => "cust_contact_first",
|
||||
lastname => "cust_contact_last",
|
||||
email => "cust_contact\@custcontact.invalid",
|
||||
reseller_id => $reseller_id,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test customer contact");
|
||||
$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location'));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch test customer contact");
|
||||
my $custcontact = JSON::from_json($res->decoded_content);
|
||||
|
||||
my %subscriber_map = ();
|
||||
my %customer_map = ();
|
||||
|
||||
#goto SKIP;
|
||||
{
|
||||
my $customer = _create_customer(
|
||||
type => "sipaccount",
|
||||
);
|
||||
my $subscriber = _create_subscriber($customer,
|
||||
primary_number => { cc => 888, ac => '1'.(scalar keys %subscriber_map), sn => $t },
|
||||
);
|
||||
|
||||
my $call_forwards = set_callforwards($subscriber,{ cfu => {
|
||||
destinations => [
|
||||
{ destination => "5678" },
|
||||
{ destination => "autoattendant", },
|
||||
],
|
||||
}});
|
||||
$call_forwards = set_callforwards($subscriber,{ cfu => {
|
||||
destinations => [
|
||||
{ destination => "5678" },
|
||||
],
|
||||
}});
|
||||
_check_event_history("events generated using /api/callforwards: ",$subscriber->{id},"%ivr",[
|
||||
{ subscriber_id => $subscriber->{id}, type => "start_ivr" },
|
||||
{ subscriber_id => $subscriber->{id}, type => "end_ivr" },
|
||||
]);
|
||||
}
|
||||
|
||||
#$t = time;
|
||||
|
||||
SKIP:
|
||||
{
|
||||
|
||||
my $customer = _create_customer(
|
||||
type => "sipaccount",
|
||||
);
|
||||
my $subscriber = _create_subscriber($customer,
|
||||
primary_number => { cc => 888, ac => '2'.(scalar keys %subscriber_map), sn => $t },
|
||||
);
|
||||
|
||||
my $destinationset_1 = _create_cfdestinationset($subscriber,"dest1_$t",[{ destination => "1234",
|
||||
timeout => '10',
|
||||
priority => '1',
|
||||
simple_destination => undef },{ destination => "autoattendant",
|
||||
timeout => '10',
|
||||
priority => '1',
|
||||
simple_destination => undef }
|
||||
]);
|
||||
my $destinationset_2 = _create_cfdestinationset($subscriber,"dest2_$t",[{ destination => "1234",
|
||||
timeout => '10',
|
||||
priority => '1',
|
||||
simple_destination => undef },{ destination => "autoattendant",
|
||||
timeout => '10',
|
||||
priority => '1',
|
||||
simple_destination => undef }
|
||||
]);
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($t);
|
||||
my $timeset = _create_cftimeset($subscriber,[{ year => $year + 1900,
|
||||
month => $mon + 1,
|
||||
mday => $mday,
|
||||
wday => $wday + 1,
|
||||
hour => $hour,
|
||||
minute => $min}]);
|
||||
my $mappings = _create_cfmapping($subscriber,{
|
||||
#cfb => [{ destinationset => $cfdestinationset->{name},
|
||||
# timeset => $cftimeset->{name}}],
|
||||
#cfna => [{ destinationset => $cfdestinationset->{name},
|
||||
# timeset => $cftimeset->{name}}],
|
||||
#cft => [{ destinationset => $cfdestinationset->{name},
|
||||
# timeset => $cftimeset->{name}}],
|
||||
cfb => [],
|
||||
cfna => [],
|
||||
cft => [{ destinationset => $destinationset_1->{name},
|
||||
timeset => $timeset->{name}}],
|
||||
cfu => [{ destinationset => $destinationset_2->{name},
|
||||
timeset => $timeset->{name}}],
|
||||
});
|
||||
|
||||
#1. update destination set:
|
||||
$destinationset_1 = _update_cfdestinationset($destinationset_1,[{ destination => "1234",
|
||||
timeout => '10',
|
||||
priority => '1',
|
||||
simple_destination => undef },
|
||||
]);
|
||||
_check_event_history("events generated by updating /api/cfdestinationsets: ",$subscriber->{id},"%ivr",[
|
||||
{ subscriber_id => $subscriber->{id}, type => "start_ivr" },
|
||||
{ subscriber_id => $subscriber->{id}, type => "start_ivr" },
|
||||
{ subscriber_id => $subscriber->{id}, type => "end_ivr" },
|
||||
]);
|
||||
#2. update cfmappings:
|
||||
$mappings = _update_cfmapping($subscriber,"cfu",[]);
|
||||
_check_event_history("events generated by updating /api/cfmappings: ",$subscriber->{id},"%ivr",[
|
||||
{ subscriber_id => $subscriber->{id}, type => "start_ivr" },
|
||||
{ subscriber_id => $subscriber->{id}, type => "start_ivr" },
|
||||
{ subscriber_id => $subscriber->{id}, type => "end_ivr" },
|
||||
{ subscriber_id => $subscriber->{id}, type => "end_ivr" },
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
sub _create_cfmapping {
|
||||
my ($subscriber,$mappings) = @_;
|
||||
|
||||
my $cfmapping_uri = $uri.'/api/cfmappings/'.$subscriber->{id};
|
||||
$req = HTTP::Request->new('PUT', $cfmapping_uri); #$customer->{id});
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json($mappings));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "create test cfmappings");
|
||||
$req = HTTP::Request->new('GET', $cfmapping_uri); # . '?page=1&rows=' . (scalar keys %$put_data));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch test cfmappings");
|
||||
return JSON::from_json($res->decoded_content);
|
||||
}
|
||||
|
||||
sub _update_cfmapping {
|
||||
my ($subscriber,$cf_type,$mapping) = @_;
|
||||
my $cfmapping_uri = $uri.'/api/cfmappings/'.$subscriber->{id};
|
||||
$req = HTTP::Request->new('PATCH', $cfmapping_uri);
|
||||
$req->header('Content-Type' => 'application/json-patch+json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json(
|
||||
[ { op => 'replace', path => '/'.$cf_type, value => $mapping } ]
|
||||
));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "update test cfmappings");
|
||||
$req = HTTP::Request->new('GET', $cfmapping_uri);
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch updated test cfmappings");
|
||||
return JSON::from_json($res->decoded_content);
|
||||
}
|
||||
|
||||
sub _create_cftimeset {
|
||||
my ($subscriber,$times) = @_;
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/cftimesets/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->content(JSON::to_json({
|
||||
name => "cf_time_set_".$t,
|
||||
subscriber_id => $subscriber->{id},
|
||||
times => \@times,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test cftimeset");
|
||||
my $cftimeset_uri = $uri.'/'.$res->header('Location');
|
||||
$req = HTTP::Request->new('GET', $cftimeset_uri);
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch created test cftimeset");
|
||||
return JSON::from_json($res->decoded_content);
|
||||
|
||||
}
|
||||
|
||||
sub _create_cfdestinationset {
|
||||
my ($subscriber,$name,$destinations) = @_;
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/cfdestinationsets/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->content(JSON::to_json({
|
||||
name => $name,
|
||||
subscriber_id => $subscriber->{id},
|
||||
destinations => $destinations,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test cfdestinationset");
|
||||
my $cfdestinationset_uri = $uri.'/'.$res->header('Location');
|
||||
$req = HTTP::Request->new('GET', $cfdestinationset_uri);
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch created test cfdestinationset");
|
||||
return JSON::from_json($res->decoded_content);
|
||||
|
||||
}
|
||||
|
||||
sub _update_cfdestinationset {
|
||||
my ($destinationset,$destinations) = @_;
|
||||
my $cfdestinationset_uri = $uri.'/api/cfdestinationsets/'.$destinationset->{id};
|
||||
$req = HTTP::Request->new('PATCH', $cfdestinationset_uri);
|
||||
$req->header('Content-Type' => 'application/json-patch+json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json(
|
||||
[ { op => 'replace', path => '/destinations', value => $destinations } ]
|
||||
));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "update test cfdestinationset");
|
||||
$req = HTTP::Request->new('GET', $cfdestinationset_uri);
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch updated test cfdestinationset");
|
||||
return JSON::from_json($res->decoded_content);
|
||||
|
||||
}
|
||||
|
||||
sub set_callforwards {
|
||||
my ($subscriber,$call_forwards) = @_;
|
||||
|
||||
my $callforward_uri = $uri.'/api/callforwards/'.$subscriber->{id};
|
||||
$req = HTTP::Request->new('PUT', $callforward_uri); #$customer->{id});
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json($call_forwards));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "set test callforwards");
|
||||
$req = HTTP::Request->new('GET', $callforward_uri); # . '?page=1&rows=' . (scalar keys %$put_data));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch test callforwards");
|
||||
return JSON::from_json($res->decoded_content);
|
||||
|
||||
}
|
||||
|
||||
sub _get_subscriber {
|
||||
|
||||
my ($subscriber) = @_;
|
||||
$req = HTTP::Request->new('GET', $uri.'/api/subscribers/'.$subscriber->{id});
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch test subscriber");
|
||||
$subscriber = JSON::from_json($res->decoded_content);
|
||||
$subscriber_map{$subscriber->{id}} = $subscriber;
|
||||
return $subscriber;
|
||||
|
||||
}
|
||||
|
||||
sub _create_subscriber {
|
||||
|
||||
my ($customer,@further_opts) = @_;
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/subscribers/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->content(JSON::to_json({
|
||||
domain_id => $domain->{id},
|
||||
username => 'subscriber_' . (scalar keys %subscriber_map) . '_'.$t,
|
||||
password => 'subscriber_password',
|
||||
customer_id => $customer->{id},
|
||||
#status => "active",
|
||||
@further_opts,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test subscriber");
|
||||
$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location'));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch test subscriber");
|
||||
my $subscriber = JSON::from_json($res->decoded_content);
|
||||
$subscriber_map{$subscriber->{id}} = $subscriber;
|
||||
return $subscriber;
|
||||
|
||||
}
|
||||
|
||||
sub _update_subscriber {
|
||||
|
||||
my ($subscriber,@further_opts) = @_;
|
||||
$req = HTTP::Request->new('PUT', $uri.'/api/subscribers/'.$subscriber->{id});
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
%$subscriber,
|
||||
@further_opts,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "update test subscriber");
|
||||
$subscriber = JSON::from_json($res->decoded_content);
|
||||
$subscriber_map{$subscriber->{id}} = $subscriber;
|
||||
return $subscriber;
|
||||
|
||||
}
|
||||
|
||||
sub _create_customer {
|
||||
|
||||
my (@further_opts) = @_;
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/customers/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->content(JSON::to_json({
|
||||
status => "active",
|
||||
contact_id => $custcontact->{id},
|
||||
type => "sipaccount",
|
||||
billing_profile_id => $billing_profile_id,
|
||||
max_subscribers => undef,
|
||||
external_id => undef,
|
||||
#status => "active",
|
||||
@further_opts,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "create test customer");
|
||||
$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location'));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch test customer");
|
||||
my $customer = JSON::from_json($res->decoded_content);
|
||||
$customer_map{$customer->{id}} = $customer;
|
||||
return $customer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub _check_event_history {
|
||||
|
||||
my ($label,$subscriber_id,$type,$expected_events) = @_;
|
||||
if (defined $subscriber_id) {
|
||||
$subscriber_id = '&subscriber_id=' . $subscriber_id;
|
||||
} else {
|
||||
$subscriber_id = '';
|
||||
}
|
||||
if (defined $type) {
|
||||
$type = '&type=' . $type;
|
||||
} else {
|
||||
$type = '';
|
||||
}
|
||||
|
||||
my $total_count = (scalar @$expected_events);
|
||||
my $i = 0;
|
||||
my $ok = 1;
|
||||
my @events = ();
|
||||
my @requests = ();
|
||||
my $last_request;
|
||||
$last_request = _req_to_debug($req) if $req;
|
||||
my $nexturi = $uri.'/api/events/?page=1&rows=10&order_by_direction=asc&order_by=id'.$subscriber_id.$type;
|
||||
do {
|
||||
$req = HTTP::Request->new('GET',$nexturi);
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, $label . "fetch events collection page");
|
||||
push(@requests,_req_to_debug($req));
|
||||
my $collection = JSON::from_json($res->decoded_content);
|
||||
my $selfuri = $uri . $collection->{_links}->{self}->{href};
|
||||
my $colluri = URI->new($selfuri);
|
||||
|
||||
$ok = ok($collection->{total_count} == $total_count, $label . "check 'total_count' of collection") && $ok;
|
||||
|
||||
if($collection->{_links}->{next}->{href}) {
|
||||
$nexturi = $uri . $collection->{_links}->{next}->{href};
|
||||
} else {
|
||||
$nexturi = undef;
|
||||
}
|
||||
|
||||
$collection->{_embedded}->{'ngcp:events'} = [
|
||||
$collection->{_embedded}->{'ngcp:events'}
|
||||
] if "HASH" eq ref $collection->{_embedded}->{'ngcp:events'};
|
||||
|
||||
my $page_items = {};
|
||||
|
||||
foreach my $event (@{ $collection->{_embedded}->{'ngcp:events'} }) {
|
||||
$ok = _compare_event($event,$expected_events->[$i],$label) && $ok;
|
||||
delete $event->{'_links'};
|
||||
push(@events,$event);
|
||||
$i++
|
||||
}
|
||||
|
||||
} while($nexturi);
|
||||
|
||||
ok($i == $total_count,$label . "check if all expected items are listed");
|
||||
diag(Dumper({last_request => $last_request, collection_requests => \@requests, result => \@events})) if !$ok;
|
||||
|
||||
}
|
||||
|
||||
sub _compare_event {
|
||||
|
||||
my ($got,$expected,$label) = @_;
|
||||
|
||||
my $ok = 1;
|
||||
|
||||
if ($expected->{id}) {
|
||||
$ok = is($got->{id},$expected->{id},$label . "check event " . $got->{id} . " id") && $ok;
|
||||
}
|
||||
|
||||
if ($expected->{subscriber_id}) {
|
||||
$ok = is($got->{subscriber_id},$expected->{subscriber_id},$label . "check event " . $got->{id} . " subscriber_id") && $ok;
|
||||
}
|
||||
|
||||
if ($expected->{type}) {
|
||||
$ok = is($got->{type},$expected->{type},$label . "check event " . $got->{id} . " type '".$expected->{type}."'") && $ok;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
|
||||
}
|
||||
|
||||
sub _req_to_debug {
|
||||
my $request = shift;
|
||||
return { request => $request->method . " " . $request->uri,
|
||||
headers => $request->headers };
|
||||
}
|
||||
|
||||
sub _get_query_string {
|
||||
my ($filters) = @_;
|
||||
my $query = '';
|
||||
foreach my $param (keys %$filters) {
|
||||
if (length($query) == 0) {
|
||||
$query .= '?';
|
||||
} else {
|
||||
$query .= '&';
|
||||
}
|
||||
$query .= $param . '=' . $filters->{$param};
|
||||
}
|
||||
return $query;
|
||||
};
|
||||
|
||||
done_testing;
|
||||
Loading…
Reference in new issue