* rtcengine related logic and apps is now removed * remove /api/rtcapps endpoint * remove /api/rtcnetworks endpoint * remove rtcengine relations from resellers such as enable_rtc flags * remove rtcengine related API tests * remove rtcengine and comx related libraries * remove csc webphone ui app * remove webrtc related selenium tests * remove rtcengine flags from /api/capabilities Change-Id: I83a4b0457fac2e0df23d267f8dbc82841dfb3001mr11.0
parent
9d7990ef47
commit
d3dc152cdc
@ -1,86 +0,0 @@
|
||||
package NGCP::Panel::Controller::API::RtcApps;
|
||||
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);
|
||||
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub api_description {
|
||||
return 'Show a collection of RTC apps, belonging to a specific reseller.';
|
||||
};
|
||||
|
||||
sub query_params {
|
||||
return [];
|
||||
}
|
||||
|
||||
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::RtcApps/;
|
||||
|
||||
sub resource_name{
|
||||
return 'rtcapps';
|
||||
}
|
||||
|
||||
sub dispatch_path{
|
||||
return '/api/rtcapps/';
|
||||
}
|
||||
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-rtcapps';
|
||||
}
|
||||
|
||||
__PACKAGE__->set_config({
|
||||
allowed_roles => [qw/admin reseller/],
|
||||
});
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $page = $c->request->params->{page} // 1;
|
||||
my $rows = $c->request->params->{rows} // 10;
|
||||
{
|
||||
my $resellers = $self->item_rs($c);
|
||||
(my $total_count, $resellers, my $resellers_rows) = $self->paginate_order_collection($c, $resellers);
|
||||
my (@embedded, @links);
|
||||
for my $reseller (@$resellers_rows) {
|
||||
push @embedded, $self->hal_from_item($c, $reseller);
|
||||
push @links, Data::HAL::Link->new(
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
href => sprintf('%s%d', $self->dispatch_path, $reseller->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,
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,194 +0,0 @@
|
||||
package NGCP::Panel::Controller::API::RtcAppsItem;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD PATCH PUT/];
|
||||
}
|
||||
use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::RtcApps/;
|
||||
|
||||
sub resource_name{
|
||||
return 'rtcapps';
|
||||
}
|
||||
|
||||
sub dispatch_path{
|
||||
return '/api/rtcapps/';
|
||||
}
|
||||
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-rtcapps';
|
||||
}
|
||||
|
||||
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/],
|
||||
Journal => [qw/admin reseller/],
|
||||
}
|
||||
});
|
||||
|
||||
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, reseller => $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 PUT :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $schema = $c->model('DB');
|
||||
my $guard = $schema->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $reseller = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, reseller => $reseller);
|
||||
my $resource = $self->get_valid_put_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json',
|
||||
);
|
||||
last unless $resource;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
my $old_resource = $self->hal_from_item($c, $reseller, 1)->resource;
|
||||
$reseller = $self->update_item($c, $reseller, $old_resource, $resource, $form);
|
||||
last unless $reseller;
|
||||
|
||||
my $hal = $self->hal_from_item($c, $reseller);
|
||||
last unless $self->add_update_journal_item_hal($c,{ hal => $hal, id => $reseller->id });
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
#my $hal = $self->hal_from_item($c, $reseller);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub PATCH :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $schema = $c->model('DB');
|
||||
my $guard = $schema->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $reseller = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, reseller => $reseller);
|
||||
my $json = $self->get_valid_patch_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json-patch+json',
|
||||
ops => ["add", "replace", "copy", "remove"],
|
||||
);
|
||||
last unless $json;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
my $old_resource = $self->hal_from_item($c, $reseller, 1)->resource;
|
||||
my $resource = $self->apply_patch($c, $old_resource, $json);
|
||||
last unless $resource;
|
||||
|
||||
$reseller = $self->update_item($c, $reseller, $old_resource, $resource, $form);
|
||||
last unless $reseller;
|
||||
|
||||
my $hal = $self->hal_from_item($c, $reseller);
|
||||
last unless $self->add_update_journal_item_hal($c,{ hal => $hal, id => $reseller->id });
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
#my $hal = $self->hal_from_item($c, $reseller);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub item_base_journal :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_item_base_journal(@_);
|
||||
}
|
||||
|
||||
sub journals_get :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journals_get(@_);
|
||||
}
|
||||
|
||||
sub journalsitem_get :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journalsitem_get(@_);
|
||||
}
|
||||
|
||||
sub journals_options :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journals_options(@_);
|
||||
}
|
||||
|
||||
sub journalsitem_options :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journalsitem_options(@_);
|
||||
}
|
||||
|
||||
sub journals_head :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journals_head(@_);
|
||||
}
|
||||
|
||||
sub journalsitem_head :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journalsitem_head(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,86 +0,0 @@
|
||||
package NGCP::Panel::Controller::API::RtcNetworks;
|
||||
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);
|
||||
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub api_description {
|
||||
return 'Show a collection of RTC networks, belonging to a specific reseller.';
|
||||
};
|
||||
|
||||
sub query_params {
|
||||
return [];
|
||||
}
|
||||
|
||||
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::RtcNetworks/;
|
||||
|
||||
sub resource_name{
|
||||
return 'rtcnetworks';
|
||||
}
|
||||
|
||||
sub dispatch_path{
|
||||
return '/api/rtcnetworks/';
|
||||
}
|
||||
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-rtcnetworks';
|
||||
}
|
||||
|
||||
__PACKAGE__->set_config({
|
||||
allowed_roles => [qw/admin reseller/],
|
||||
});
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $page = $c->request->params->{page} // 1;
|
||||
my $rows = $c->request->params->{rows} // 10;
|
||||
{
|
||||
my $resellers = $self->item_rs($c);
|
||||
(my $total_count, $resellers, my $resellers_rows) = $self->paginate_order_collection($c, $resellers);
|
||||
my (@embedded, @links);
|
||||
for my $subscriber (@$resellers_rows) {
|
||||
push @embedded, $self->hal_from_item($c, $subscriber);
|
||||
push @links, Data::HAL::Link->new(
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
href => sprintf('%s%d', $self->dispatch_path, $subscriber->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,
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,194 +0,0 @@
|
||||
package NGCP::Panel::Controller::API::RtcNetworksItem;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD PATCH PUT/];
|
||||
}
|
||||
use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::RtcNetworks/;
|
||||
|
||||
sub resource_name{
|
||||
return 'rtcnetworks';
|
||||
}
|
||||
|
||||
sub dispatch_path{
|
||||
return '/api/rtcnetworks/';
|
||||
}
|
||||
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-rtcnetworks';
|
||||
}
|
||||
|
||||
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/],
|
||||
Journal => [qw/admin reseller/],
|
||||
}
|
||||
});
|
||||
|
||||
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, reseller => $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 PUT :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $schema = $c->model('DB');
|
||||
my $guard = $schema->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $reseller = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, reseller => $reseller);
|
||||
my $resource = $self->get_valid_put_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json',
|
||||
);
|
||||
last unless $resource;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
my $old_resource = $self->hal_from_item($c, $reseller, 1)->resource;
|
||||
$reseller = $self->update_item($c, $reseller, $old_resource, $resource, $form);
|
||||
last unless $reseller;
|
||||
|
||||
my $hal = $self->hal_from_item($c, $reseller);
|
||||
last unless $self->add_update_journal_item_hal($c,{ hal => $hal, id => $reseller->id });
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
#my $hal = $self->hal_from_item($c, $reseller);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub PATCH :Allow {
|
||||
my ($self, $c, $id) = @_;
|
||||
my $schema = $c->model('DB');
|
||||
my $guard = $schema->txn_scope_guard;
|
||||
{
|
||||
my $preference = $self->require_preference($c);
|
||||
last unless $preference;
|
||||
|
||||
my $reseller = $self->item_by_id($c, $id);
|
||||
last unless $self->resource_exists($c, reseller => $reseller);
|
||||
my $json = $self->get_valid_patch_data(
|
||||
c => $c,
|
||||
id => $id,
|
||||
media_type => 'application/json-patch+json',
|
||||
ops => ["add", "replace", "copy", "remove"],
|
||||
);
|
||||
last unless $json;
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
my $old_resource = $self->hal_from_item($c, $reseller, 1)->resource;
|
||||
my $resource = $self->apply_patch($c, $old_resource, $json);
|
||||
last unless $resource;
|
||||
|
||||
$reseller = $self->update_item($c, $reseller, $old_resource, $resource, $form);
|
||||
last unless $reseller;
|
||||
|
||||
my $hal = $self->hal_from_item($c, $reseller);
|
||||
last unless $self->add_update_journal_item_hal($c,{ hal => $hal, id => $reseller->id });
|
||||
|
||||
$guard->commit;
|
||||
|
||||
if ('minimal' eq $preference) {
|
||||
$c->response->status(HTTP_NO_CONTENT);
|
||||
$c->response->header(Preference_Applied => 'return=minimal');
|
||||
$c->response->body(q());
|
||||
} else {
|
||||
#my $hal = $self->hal_from_item($c, $reseller);
|
||||
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
|
||||
$hal->http_headers,
|
||||
), $hal->as_json);
|
||||
$c->response->headers($response->headers);
|
||||
$c->response->header(Preference_Applied => 'return=representation');
|
||||
$c->response->body($response->content);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub item_base_journal :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_item_base_journal(@_);
|
||||
}
|
||||
|
||||
sub journals_get :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journals_get(@_);
|
||||
}
|
||||
|
||||
sub journalsitem_get :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journalsitem_get(@_);
|
||||
}
|
||||
|
||||
sub journals_options :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journals_options(@_);
|
||||
}
|
||||
|
||||
sub journalsitem_options :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journalsitem_options(@_);
|
||||
}
|
||||
|
||||
sub journals_head :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journals_head(@_);
|
||||
}
|
||||
|
||||
sub journalsitem_head :Journal {
|
||||
my $self = shift @_;
|
||||
return $self->handle_journalsitem_head(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,147 +0,0 @@
|
||||
package NGCP::Panel::Controller::API::RtcSessions;
|
||||
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);
|
||||
|
||||
|
||||
|
||||
sub api_description {
|
||||
return 'Show a collection of RTC sessions, belonging to a specific subscriber.';
|
||||
}
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET POST OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub query_params {
|
||||
return [];
|
||||
}
|
||||
|
||||
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::RtcSessions/;
|
||||
|
||||
sub resource_name{
|
||||
return 'rtcsessions';
|
||||
}
|
||||
|
||||
sub dispatch_path{
|
||||
return '/api/rtcsessions/';
|
||||
}
|
||||
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-rtcsessions';
|
||||
}
|
||||
|
||||
__PACKAGE__->set_config({
|
||||
allowed_roles => [qw/admin reseller subscriber subscriberadmin/],
|
||||
});
|
||||
|
||||
sub GET :Allow {
|
||||
my ($self, $c) = @_;
|
||||
my $page = $c->request->params->{page} // 1;
|
||||
my $rows = $c->request->params->{rows} // 10;
|
||||
{
|
||||
my $subscribers = $self->item_rs($c);
|
||||
(my $total_count, $subscribers, my $subscribers_rows) = $self->paginate_order_collection($c, $subscribers);
|
||||
my (@embedded, @links);
|
||||
for my $subscriber (@$subscribers_rows) {
|
||||
my $hal = $self->hal_from_item($c, $subscriber);
|
||||
next unless $hal;
|
||||
push @embedded, $hal;
|
||||
push @links, Data::HAL::Link->new(
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
href => sprintf('%s%d', $self->dispatch_path, $subscriber->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,
|
||||
});
|
||||
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 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;
|
||||
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$resource->{reseller_id} = $c->user->reseller_id; # TODO: ?
|
||||
} else {
|
||||
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
|
||||
}
|
||||
|
||||
my $subscriber_item = $c->model('DB')->resultset('voip_subscribers')->search_rs({
|
||||
id => $resource->{subscriber_id},
|
||||
})->first;
|
||||
|
||||
unless ($subscriber_item) {
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Subscriber invalid or not found.");
|
||||
last;
|
||||
}
|
||||
|
||||
# my $form = $self->get_form();
|
||||
# $resource->{reseller_id} //= undef;
|
||||
# last unless $self->validate_form(
|
||||
# c => $c,
|
||||
# resource => $resource,
|
||||
# form => $form,
|
||||
# );
|
||||
|
||||
my $session_item = NGCP::Panel::Utils::Rtc::create_rtc_session(
|
||||
config => $c->config,
|
||||
subscriber_item => $subscriber_item,
|
||||
resource => $resource,
|
||||
err_code => sub {
|
||||
my ($msg, $debug) = @_;
|
||||
$c->log->debug($debug) if $debug;
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, $msg);
|
||||
return;
|
||||
});
|
||||
last unless $session_item;
|
||||
|
||||
$guard->commit;
|
||||
|
||||
$c->response->status(HTTP_CREATED);
|
||||
$c->response->header(Location => sprintf('%s%d', $self->dispatch_path, $session_item->id));
|
||||
$c->response->body(q());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,80 +0,0 @@
|
||||
package NGCP::Panel::Controller::API::RtcSessionsItem;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
|
||||
use Data::HAL qw();
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Headers qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
require Catalyst::ActionRole::ACL;
|
||||
require NGCP::Panel::Role::HTTPMethods;
|
||||
require Catalyst::ActionRole::RequireSSL;
|
||||
|
||||
use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::RtcSessions/;
|
||||
|
||||
sub resource_name{
|
||||
return 'rtcsessions';
|
||||
}
|
||||
|
||||
sub dispatch_path{
|
||||
return '/api/rtcsessions/';
|
||||
}
|
||||
|
||||
sub relation{
|
||||
return 'http://purl.org/sipwise/ngcp-api/#rel-rtcsessions';
|
||||
}
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub journal_query_params {
|
||||
my($self,$query_params) = @_;
|
||||
return $self->get_journal_query_params($query_params);
|
||||
}
|
||||
|
||||
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/];
|
||||
}
|
||||
|
||||
__PACKAGE__->set_config({
|
||||
allowed_roles => {
|
||||
Default => [qw/admin reseller subscriber subscriberadmin/],
|
||||
Journal => [qw/admin reseller/],
|
||||
}
|
||||
});
|
||||
|
||||
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, rtc_session => $item);
|
||||
|
||||
my $hal = $self->hal_from_item($c, $item);
|
||||
|
||||
unless ($hal) {
|
||||
$c->log->error("Session not found. It may have expired.");
|
||||
$self->error($c, HTTP_NOT_FOUND, "Session not found. It may have expired.");
|
||||
last;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,30 +0,0 @@
|
||||
package NGCP::Panel::Form::ResellerRtc;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'NGCP::Panel::Form::Reseller';
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {[qw/submitid fields actions/]}
|
||||
sub build_form_element_class { [qw/form-horizontal/] }
|
||||
|
||||
has_field 'enable_rtc' => (
|
||||
type => 'Boolean',
|
||||
required => 0,
|
||||
default => 0,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Whether an RTC-entity should be created for this reseller.'],
|
||||
}
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/contract name status enable_rtc/],
|
||||
);
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,22 +0,0 @@
|
||||
package NGCP::Panel::Form::Rtc::AppsAdmin;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'NGCP::Panel::Form::Rtc::AppsReseller';
|
||||
|
||||
has_field 'reseller' => (
|
||||
type => '+NGCP::Panel::Field::Reseller',
|
||||
#validate_when_empty => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The reseller id this app belong to.'],
|
||||
},
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/reseller rtc_user_id apps/],
|
||||
);
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,95 +0,0 @@
|
||||
package NGCP::Panel::Form::Rtc::AppsReseller;
|
||||
use HTML::FormHandler::Moose;
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
# with 'NGCP::Panel::Render::RepeatableJs'; # only used in API currently
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {return [qw/submitid fields actions/]}
|
||||
sub build_form_element_class {return [qw(form-horizontal)]}
|
||||
|
||||
has_field 'rtc_user_id' => (
|
||||
# readonly
|
||||
type => 'Text',
|
||||
required => 0,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['ID in the backend RTC API (readonly).'],
|
||||
},
|
||||
readonly => 1,
|
||||
);
|
||||
|
||||
has_field 'apps' => (
|
||||
type => 'Repeatable',
|
||||
required => 0, #1,
|
||||
#setup_for_js => 1,
|
||||
do_wrapper => 1,
|
||||
do_label => 0,
|
||||
tags => {
|
||||
controls_div => 1,
|
||||
},
|
||||
wrapper_class => [qw/hfh-rep/],
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['An array of objects with keys "name", "domain", "secret" and "api_key" to create RTC apps for this reseller'],
|
||||
},
|
||||
num_when_empty => 1,
|
||||
add_extra => 1,
|
||||
);
|
||||
|
||||
has_field 'apps.domain' => (
|
||||
type => 'Text',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Domain where the cdk is included.'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'apps.name' => (
|
||||
type => 'Text',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Arbitrary text. Name of the app.'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'apps.secret' => (
|
||||
type => 'Text',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The secret (readonly).'],
|
||||
},
|
||||
readonly => 1,
|
||||
);
|
||||
|
||||
has_field 'apps.api_key' => (
|
||||
type => 'Text',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The API key (readonly).'],
|
||||
},
|
||||
readonly => 1,
|
||||
);
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Save',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
label => '',
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/rtc_user_id apps/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
@ -1,22 +0,0 @@
|
||||
package NGCP::Panel::Form::Rtc::NetworksAdmin;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'NGCP::Panel::Form::Rtc::NetworksReseller';
|
||||
|
||||
has_field 'reseller' => (
|
||||
type => '+NGCP::Panel::Field::Reseller',
|
||||
#validate_when_empty => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The reseller id this networks belong to.'],
|
||||
},
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/reseller rtc_user_id networks/],
|
||||
);
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,90 +0,0 @@
|
||||
package NGCP::Panel::Form::Rtc::NetworksReseller;
|
||||
use HTML::FormHandler::Moose;
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
# with 'NGCP::Panel::Render::RepeatableJs'; # only used in API currently
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {return [qw/submitid fields actions/]}
|
||||
sub build_form_element_class {return [qw(form-horizontal)]}
|
||||
|
||||
has_field 'rtc_user_id' => (
|
||||
# readonly
|
||||
type => 'Text',
|
||||
required => 0,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['ID in the backend RTC API (readonly).'],
|
||||
},
|
||||
readonly => 1,
|
||||
);
|
||||
|
||||
has_field 'networks' => (
|
||||
type => 'Repeatable',
|
||||
required => 0, #1,
|
||||
setup_for_js => 1,
|
||||
do_wrapper => 1,
|
||||
do_label => 0,
|
||||
tags => {
|
||||
controls_div => 1,
|
||||
},
|
||||
wrapper_class => [qw/hfh-rep/],
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['An array of objects with keys "config", "connector" and "tag" to create RTC networks for this reseller'],
|
||||
},
|
||||
);
|
||||
# webrtc, conference, xmpp-connector, sip-connector, sipwise-connector
|
||||
has_field 'networks.connector' => (
|
||||
type => 'Select',
|
||||
options => [
|
||||
{ value => 'webrtc', label => 'webrtc' },
|
||||
{ value => 'conference', label => 'conference' },
|
||||
{ value => 'xmpp-connector', label => 'xmpp-connector' },
|
||||
{ value => 'sip-connector', label => 'sip-connector' },
|
||||
{ value => 'sipwise-connector', label => 'sipwise-connector' },
|
||||
],
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['One of the available options. This defines, to which networks rtc subscribers will be able to connect to.'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'networks.tag' => (
|
||||
type => 'Text',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['An arbitrary name, to address that network instance'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'networks.config' => (
|
||||
type => 'Compound', # Text
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['An arbitrary hash of additional config contents; e.g. {"xms": false}'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Save',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
label => '',
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/rtc_user_id networks/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
@ -1,143 +0,0 @@
|
||||
package NGCP::Panel::Role::API::RtcApps;
|
||||
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 JSON::Types;
|
||||
|
||||
use NGCP::Panel::Utils::Subscriber;
|
||||
use NGCP::Panel::Utils::Rtc;
|
||||
|
||||
sub get_form {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
return NGCP::Panel::Form::get("NGCP::Panel::Form::Rtc::AppsAdmin", $c);
|
||||
}
|
||||
|
||||
sub hal_from_item {
|
||||
my ($self, $c, $item, $include_id) = @_;
|
||||
|
||||
my $resource = { reseller_id => $item->id };
|
||||
if ($item->rtc_user) {
|
||||
my $rtc_user_id = $item->rtc_user->rtc_user_id;
|
||||
$resource->{rtc_user_id} = $rtc_user_id if $include_id;
|
||||
$resource->{apps} = NGCP::Panel::Utils::Rtc::get_rtc_apps(
|
||||
rtc_user_id => $rtc_user_id,
|
||||
config => $c->config,
|
||||
include_id => $include_id,
|
||||
err_code => sub {
|
||||
my $rtc_error = shift;
|
||||
$c->log->warn($rtc_error);
|
||||
return;
|
||||
});
|
||||
} else {
|
||||
}
|
||||
#for get=>put compatibility
|
||||
if ('ARRAY' ne ref $resource->{apps}) {
|
||||
$resource->{apps} = [];
|
||||
}
|
||||
|
||||
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)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:resellers', href => sprintf("/api/resellers/%d", $item->id)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:resellers', href => sprintf("/api/rtcnetworks/%d", $item->id)),
|
||||
$self->get_journal_relation_link($c, $item->id),
|
||||
],
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
);
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
unless ($include_id) {
|
||||
return unless $self->validate_form(
|
||||
c => $c,
|
||||
form => $form,
|
||||
resource => $resource,
|
||||
run => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$self->expand_fields($c, $resource);
|
||||
$hal->resource($resource);
|
||||
return $hal;
|
||||
}
|
||||
|
||||
sub _item_rs {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $item_rs;
|
||||
$item_rs = $c->model('DB')->resultset('resellers')
|
||||
->search_rs(undef, {
|
||||
prefetch => 'rtc_user',
|
||||
});
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$item_rs = $item_rs->search({
|
||||
id => $c->user->reseller_id,
|
||||
});
|
||||
}
|
||||
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
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) = @_;
|
||||
|
||||
my $reseller = $item;
|
||||
|
||||
if (ref $resource->{apps} ne "ARRAY") {
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'apps'. Must be an array.");
|
||||
return;
|
||||
}
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
return unless $self->validate_form(
|
||||
c => $c,
|
||||
form => $form,
|
||||
resource => $resource,
|
||||
);
|
||||
|
||||
NGCP::Panel::Utils::Rtc::modify_rtc_apps(
|
||||
old_resource => $old_resource,
|
||||
resource => $resource,
|
||||
config => $c->config,
|
||||
reseller_item => $reseller,
|
||||
err_code => sub {
|
||||
my $rtc_error = shift;
|
||||
$c->log->warn($rtc_error);
|
||||
return;
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
} catch($e) {
|
||||
$c->log->error("failed to update rtcapps: $e");
|
||||
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update rtcapps.");
|
||||
return;
|
||||
};
|
||||
|
||||
return $reseller;
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,142 +0,0 @@
|
||||
package NGCP::Panel::Role::API::RtcNetworks;
|
||||
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 JSON::Types;
|
||||
|
||||
use NGCP::Panel::Utils::Subscriber;
|
||||
use NGCP::Panel::Utils::Rtc;
|
||||
|
||||
sub get_form {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
return NGCP::Panel::Form::get("NGCP::Panel::Form::Rtc::NetworksAdmin", $c);
|
||||
}
|
||||
|
||||
sub hal_from_item {
|
||||
my ($self, $c, $item, $include_id) = @_;
|
||||
|
||||
my $resource = { reseller_id => $item->id };
|
||||
if ($item->rtc_user) {
|
||||
my $rtc_user_id = $item->rtc_user->rtc_user_id;
|
||||
$resource->{rtc_user_id} = $rtc_user_id if $include_id;
|
||||
$resource->{networks} = NGCP::Panel::Utils::Rtc::get_rtc_networks(
|
||||
rtc_user_id => $rtc_user_id,
|
||||
config => $c->config,
|
||||
include_id => $include_id,
|
||||
err_code => sub {
|
||||
my ($msg, $debug) = @_;
|
||||
$c->log->debug($debug) if $debug;
|
||||
$c->log->warn($msg);
|
||||
return;
|
||||
});
|
||||
} else {
|
||||
}
|
||||
#for get=>put compatibility
|
||||
if ('ARRAY' ne ref $resource->{networks}) {
|
||||
$resource->{networks} = [];
|
||||
}
|
||||
|
||||
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)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:resellers', href => sprintf("/api/resellers/%d", $item->id)),
|
||||
$self->get_journal_relation_link($c, $item->id),
|
||||
],
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
);
|
||||
|
||||
my $form = $self->get_form($c);
|
||||
unless ($include_id) {
|
||||
return unless $self->validate_form(
|
||||
c => $c,
|
||||
form => $form,
|
||||
resource => $resource,
|
||||
run => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$self->expand_fields($c, $resource);
|
||||
$hal->resource($resource);
|
||||
return $hal;
|
||||
}
|
||||
|
||||
sub _item_rs {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $item_rs;
|
||||
$item_rs = $c->model('DB')->resultset('resellers')
|
||||
->search_rs(undef, {
|
||||
prefetch => 'rtc_user',
|
||||
});
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$item_rs = $item_rs->search({
|
||||
id => $c->user->reseller_id,
|
||||
});
|
||||
}
|
||||
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
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) = @_;
|
||||
|
||||
my $reseller = $item;
|
||||
|
||||
if (ref $resource->{networks} ne "ARRAY") {
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'networks'. Must be an array.");
|
||||
return;
|
||||
}
|
||||
|
||||
$form //= $self->get_form($c);
|
||||
return unless $self->validate_form(
|
||||
c => $c,
|
||||
form => $form,
|
||||
resource => $resource,
|
||||
);
|
||||
|
||||
try {
|
||||
NGCP::Panel::Utils::Rtc::modify_rtc_networks(
|
||||
old_resource => $old_resource,
|
||||
resource => $resource,
|
||||
config => $c->config,
|
||||
reseller_item => $reseller,
|
||||
err_code => sub {
|
||||
my ($msg, $debug) = @_;
|
||||
$c->log->debug($debug) if $debug;
|
||||
$c->log->warn($msg);
|
||||
return;
|
||||
});
|
||||
} catch($e) {
|
||||
$c->log->error("failed to update rtcnetworks: $e");
|
||||
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update rtcnetworks.");
|
||||
return;
|
||||
};
|
||||
|
||||
return $reseller;
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,103 +0,0 @@
|
||||
package NGCP::Panel::Role::API::RtcSessions;
|
||||
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 JSON::Types;
|
||||
|
||||
use NGCP::Panel::Utils::Subscriber;
|
||||
use NGCP::Panel::Utils::Rtc;
|
||||
|
||||
sub get_form {
|
||||
my ($self) = @_;
|
||||
|
||||
#return NGCP::Panel::Form::get("NGCP::Panel::Form::Rtc::NetworksAdmin", $c);
|
||||
return;
|
||||
}
|
||||
|
||||
sub hal_from_item {
|
||||
my ($self, $c, $item) = @_;
|
||||
|
||||
my $resource = {
|
||||
subscriber_id => $item->subscriber->voip_subscriber->id, # this may be confusing but we store the provisioning-subscriber-id but show the billing one
|
||||
rtc_network_tag => $item->rtc_network_tag,
|
||||
};
|
||||
|
||||
my $rtc_session = NGCP::Panel::Utils::Rtc::get_rtc_session(
|
||||
config => $c->config,
|
||||
item => $item,
|
||||
err_code => sub {
|
||||
my ($msg, $debug) = @_;
|
||||
$c->log->debug($debug) if $debug;
|
||||
$c->log->warn($msg);
|
||||
return;
|
||||
});
|
||||
if ($rtc_session) {
|
||||
$resource->{rtc_browser_token} = $rtc_session->{data}{token};
|
||||
$resource->{rtc_app_name} = $rtc_session->{data}{app}{name} if $rtc_session->{data}{app}{name};
|
||||
} else {
|
||||
# here either delete our DB entry, or recreate it accordingly
|
||||
$item->delete;
|
||||
return;
|
||||
}
|
||||
|
||||
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)),
|
||||
Data::HAL::Link->new(relation => 'ngcp:subscribers', href => sprintf("/api/subscribers/%d", $item->subscriber->voip_subscriber->id)),
|
||||
$self->get_journal_relation_link($c, $item->id),
|
||||
],
|
||||
relation => 'ngcp:'.$self->resource_name,
|
||||
);
|
||||
|
||||
$self->expand_fields($c, $resource);
|
||||
$hal->resource($resource);
|
||||
return $hal;
|
||||
}
|
||||
|
||||
sub item_rs {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $item_rs;
|
||||
$item_rs = $c->model('DB')->resultset('rtc_session');
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$item_rs = $item_rs->search({
|
||||
'contact.reseller_id' => $c->user->reseller_id,
|
||||
},{
|
||||
join => {subscriber => { voip_subscriber => { contract => 'contact' }}},
|
||||
});
|
||||
} else {
|
||||
$item_rs = $item_rs->search({
|
||||
'subscriber.id' => $c->user->id,
|
||||
},{
|
||||
join => 'subscriber',
|
||||
});
|
||||
}
|
||||
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
sub item_by_id {
|
||||
my ($self, $c, $id) = @_;
|
||||
|
||||
my $item_rs = $self->item_rs($c);
|
||||
return $item_rs->find($id);
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,306 +0,0 @@
|
||||
package NGCP::Panel::Utils::ComxAPIClient;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use Moo;
|
||||
# use Digest::MD5 qw/md5_hex/;
|
||||
# use HTTP::Tiny;
|
||||
# use Storable qw/freeze/;
|
||||
use Types::Standard qw(Int HashRef);
|
||||
# with 'Role::REST::Client';
|
||||
use LWP::UserAgent;
|
||||
use JSON qw/decode_json encode_json/;
|
||||
|
||||
has 'ua' => ( is => 'rw', default => sub {
|
||||
return LWP::UserAgent->new(
|
||||
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 },
|
||||
timeout => 20,
|
||||
);
|
||||
});
|
||||
|
||||
has 'host' => (is => 'rw', default => 'https://www.api-cdk.tld:8191');
|
||||
|
||||
has 'login_status' => (is => 'rw',
|
||||
#isa => 'HTTP::Response',
|
||||
default => sub {return {};},
|
||||
);
|
||||
|
||||
# returns appid or 0
|
||||
sub login {
|
||||
my ( $self, $username, $password, $netloc ) = @_;
|
||||
my $ua = $self->ua;
|
||||
$netloc //= $self->host =~ s!^https?://(.*:[0-9]*)(/.*$|$)!$1!r;
|
||||
$ua->credentials($netloc, "rtcengine", $username, $password);
|
||||
my $resp = $ua->get($self->host . '/users');
|
||||
$self->login_status( $self->_create_response($resp) );
|
||||
return;
|
||||
}
|
||||
|
||||
# outdated: only one account (with one network) for the session
|
||||
sub create_session_and_account {
|
||||
my ($self, $appid, $network_tag, $identifier, $access_token, $owner, $account_config) = @_;
|
||||
|
||||
my $session = $self->create_session($appid, $owner);
|
||||
$session->{data}{accounts} = [] if($session->{data});
|
||||
|
||||
my $account = $self->create_account(
|
||||
$session->{data}{id},
|
||||
$owner,
|
||||
$identifier,
|
||||
$network_tag,
|
||||
$access_token,
|
||||
$account_config );
|
||||
push @{ $session->{data}{accounts} }, $account->{data};
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
sub create_session {
|
||||
my ($self, $appid, $owner) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $session_content = encode_json({
|
||||
app => $appid,
|
||||
owner => $owner,
|
||||
});
|
||||
my $session = $self->_create_response(
|
||||
$ua->post($self->host . '/sessions', 'Content-Type' => 'application/json', Content => $session_content),
|
||||
);
|
||||
return $session;
|
||||
}
|
||||
|
||||
sub create_account {
|
||||
my ($self, $session_id, $owner, $identifier, $network_tag, $access_token, $account_config) = @_;
|
||||
my $ua = $self->ua;
|
||||
|
||||
my $account_content = encode_json({
|
||||
session => $session_id,
|
||||
network => $network_tag,
|
||||
identifier => $identifier,
|
||||
accessToken => $access_token,
|
||||
owner => $owner,
|
||||
$account_config ? (config => encode_json($account_config)) : (),
|
||||
});
|
||||
my $account = $self->_create_response(
|
||||
$ua->post($self->host . '/accounts', 'Content-Type' => 'application/json', Content => $account_content),
|
||||
);
|
||||
return $account;
|
||||
}
|
||||
|
||||
sub create_network {
|
||||
my ($self, $tag, $connector, $config, $owner) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $network_content = encode_json({
|
||||
tag => $tag,
|
||||
connector => $connector,
|
||||
config => encode_json($config),
|
||||
owner => $owner,
|
||||
});
|
||||
my $network = $self->_create_response(
|
||||
$ua->post($self->host . '/networks', 'Content-Type' => 'application/json', Content => $network_content),
|
||||
);
|
||||
return $network;
|
||||
}
|
||||
|
||||
sub create_user {
|
||||
my ($self, $email, $password) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $user_content = encode_json({
|
||||
email => $email,
|
||||
password => $password,
|
||||
});
|
||||
my $user = $self->_create_response(
|
||||
$ua->post($self->host . '/users', 'Content-Type' => 'application/json', Content => $user_content),
|
||||
);
|
||||
return $user;
|
||||
}
|
||||
|
||||
sub delete_network {
|
||||
my ($self, $network_id) = @_;
|
||||
my $ua = $self->ua;
|
||||
$network_id //= "";
|
||||
my $resp;
|
||||
$resp = $ua->delete($self->host . "/networks/id/$network_id");
|
||||
return $self->_create_response($resp);
|
||||
}
|
||||
|
||||
sub delete_user {
|
||||
my ($self, $user_id) = @_;
|
||||
my $ua = $self->ua;
|
||||
$user_id //= "";
|
||||
my $resp;
|
||||
$resp = $ua->delete($self->host . "/users/id/$user_id");
|
||||
return $self->_create_response($resp);
|
||||
}
|
||||
|
||||
sub delete_app {
|
||||
my ($self, $app_id) = @_;
|
||||
my $ua = $self->ua;
|
||||
$app_id //= "";
|
||||
my $resp;
|
||||
$resp = $ua->delete($self->host . "/apps/id/$app_id");
|
||||
return $self->_create_response($resp);
|
||||
}
|
||||
|
||||
sub create_app {
|
||||
my ($self, $name, $domain, $owner) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $app_content = encode_json({
|
||||
name => $name,
|
||||
domain => $domain,
|
||||
owner => $owner,
|
||||
});
|
||||
my $app = $self->_create_response(
|
||||
$ua->post($self->host . '/apps', 'Content-Type' => 'application/json', Content => $app_content),
|
||||
);
|
||||
return $app;
|
||||
}
|
||||
|
||||
sub get_sessions {
|
||||
my ($self, $max_rows) = @_;
|
||||
my $sessions = $self->_resolve_collection_fast( '/sessions', $max_rows );
|
||||
if ('ARRAY' eq ref $sessions->{data} && @{ $sessions->{data} }) {
|
||||
for my $session (@{ $sessions->{data} }) {
|
||||
$session->{accounts} = $self->_resolve_collection_fast( $session->{accounts}{href} );
|
||||
}
|
||||
}
|
||||
return $sessions;
|
||||
}
|
||||
|
||||
sub get_session {
|
||||
my ($self, $session_id) = @_;
|
||||
my $ua = $self->ua;
|
||||
|
||||
my $session = $self->_create_response(
|
||||
$ua->get($self->host . "/sessions/id/$session_id"),
|
||||
);
|
||||
if ($session->{data}) {
|
||||
my ($app_id) = $session->{data}{app}{href} =~ m!apps/id/(.*)$!;
|
||||
my $item_res = $ua->get($self->host . "/apps/id/$app_id");
|
||||
my $item_data = decode_json($item_res->content);
|
||||
$session->{data}{app} = $item_data;
|
||||
}
|
||||
return $session;
|
||||
}
|
||||
|
||||
sub delete_all_sessions {
|
||||
my ($self) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $resp;
|
||||
for my $session_data ($self->get_sessions->{data}) {
|
||||
my $session_id = $session_data->{id};
|
||||
$resp = $ua->delete($self->host . "/sessions/id/$session_id");
|
||||
last if $resp->code >= 300;
|
||||
}
|
||||
return $resp;
|
||||
}
|
||||
|
||||
sub get_users {
|
||||
my ($self, $max_rows) = @_;
|
||||
my $users = $self->_resolve_collection_fast( '/users', $max_rows );
|
||||
return $users;
|
||||
}
|
||||
|
||||
sub get_apps_by_user_id {
|
||||
my ($self, $user_id) = @_;
|
||||
my $apps = $self->_resolve_collection_fast( "/users/id/$user_id/apps" );
|
||||
return $apps;
|
||||
}
|
||||
|
||||
sub get_networks {
|
||||
my ($self) = @_;
|
||||
my $networks = $self->_resolve_collection_fast( '/networks' );
|
||||
return $networks;
|
||||
}
|
||||
|
||||
sub get_networks_by_user_id {
|
||||
my ($self, $user_id) = @_;
|
||||
my $networks = $self->_resolve_collection_fast( "/users/id/$user_id/networks" );
|
||||
return $networks;
|
||||
}
|
||||
|
||||
sub _resolve_collection {
|
||||
my ($self, $bare_url, $max_rows) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $rel_url = $self->_strip_host( $bare_url );
|
||||
my $res = $ua->get($self->host . $rel_url);
|
||||
my @result;
|
||||
return {code => $res->code, response => $res} unless $res->code == 200;
|
||||
my $collection = JSON::decode_json($res->content);
|
||||
return {code => $res->code, response => $res,
|
||||
error_detail => 'could not decode_json'} unless $collection;
|
||||
my $item_res;
|
||||
for my $item (@{ $collection->{items} }) {
|
||||
last if (defined $max_rows && $max_rows-- <= 0);
|
||||
my $url = $self->_strip_host( $item->{href} );
|
||||
$item_res = $ua->get($self->host . $url);
|
||||
my $item_data = decode_json($item_res->content);
|
||||
push @result, $item_data;
|
||||
}
|
||||
return {
|
||||
response => $item_res, # latest response
|
||||
code => $item_res->code,
|
||||
data => \@result,
|
||||
total_count => scalar(@result),
|
||||
};
|
||||
}
|
||||
|
||||
sub _resolve_collection_fast {
|
||||
my ($self, $bare_url, $max_rows) = @_;
|
||||
my $ua = $self->ua;
|
||||
my $rel_url = $self->_strip_host( $bare_url );
|
||||
$rel_url =
|
||||
$rel_url .
|
||||
( ($rel_url =~ m/\?/) ? '&' : '?' ) .
|
||||
'expand=true';
|
||||
my $res = $ua->get($self->host . $rel_url);
|
||||
my @result;
|
||||
return $self->_create_response($res) unless $res->code == 200;
|
||||
my $collection = JSON::decode_json($res->content);
|
||||
return {code => $res->code, response => $res,
|
||||
error_detail => 'could not decode_json'} unless $collection;
|
||||
if ('HASH' eq ref $collection) { # everything ok
|
||||
return {
|
||||
response => $res,
|
||||
code => $res->code,
|
||||
data => $collection->{items},
|
||||
total_count => $collection->{total} // (scalar @{ $collection->{items} }),
|
||||
};
|
||||
} else { # unknown error
|
||||
return {
|
||||
response => $res,
|
||||
code => $res->code,
|
||||
data => $collection,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
sub _strip_host {
|
||||
my ($self, $url) = @_;
|
||||
my $url_orig = $self->host;
|
||||
my $url_noip = $url_orig =~ s!:\d+!!r;
|
||||
return $url =~ s!$url_orig|$url_noip!!r;
|
||||
}
|
||||
|
||||
sub _create_response {
|
||||
my ($self, $res) = @_;
|
||||
my $data;
|
||||
my $debug;
|
||||
if ($res->is_success && $res->content) {
|
||||
$data = decode_json($res->content);
|
||||
} else {
|
||||
$debug = "RTC response: " . $res->decoded_content
|
||||
. ", RTC request: " . $res->request->as_string;
|
||||
}
|
||||
return {
|
||||
code => $res->code,
|
||||
data => $data,
|
||||
response => $res,
|
||||
$debug ? (debug => $debug) : (),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,747 +0,0 @@
|
||||
package NGCP::Panel::Utils::Rtc;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use JSON qw//;
|
||||
use UUID;
|
||||
|
||||
use NGCP::Panel::Utils::ComxAPIClient;
|
||||
use NGCP::Panel::Utils::Generic qw/compare/;
|
||||
|
||||
sub modify_reseller_rtc {
|
||||
my %params = @_;
|
||||
my ($old_resource, $resource, $config, $reseller_item, $err_code) =
|
||||
@params{qw/old_resource resource config reseller_item err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
if ((!defined $old_resource) && (defined $resource)) { # newly created reseller
|
||||
|
||||
# 1. enable_rtc is off -> do nothing
|
||||
if (!$resource->{enable_rtc}) {
|
||||
return;
|
||||
}
|
||||
|
||||
_create_rtc_user(
|
||||
resource => $resource,
|
||||
config => $config,
|
||||
reseller_item => $reseller_item,
|
||||
err_code => $err_code);
|
||||
|
||||
} elsif ((defined $old_resource) && (defined $resource)) {
|
||||
|
||||
if($old_resource->{status} ne 'terminated' &&
|
||||
$resource->{status} eq 'terminated' &&
|
||||
$old_resource->{enable_rtc}) { # just terminated
|
||||
|
||||
$resource->{enable_rtc} = JSON::false;
|
||||
_delete_rtc_user(
|
||||
config => $config,
|
||||
reseller_item => $reseller_item,
|
||||
err_code => $err_code);
|
||||
|
||||
} elsif ($old_resource->{enable_rtc} &&
|
||||
!$resource->{enable_rtc}) { # disable rtc
|
||||
|
||||
_delete_rtc_user(
|
||||
config => $config,
|
||||
reseller_item => $reseller_item,
|
||||
err_code => $err_code);
|
||||
} elsif (!$old_resource->{enable_rtc} &&
|
||||
$resource->{enable_rtc} &&
|
||||
$resource->{status} ne 'terminated') { # enable rtc
|
||||
|
||||
_create_rtc_user(
|
||||
resource => $resource,
|
||||
config => $config,
|
||||
reseller_item => $reseller_item,
|
||||
err_code => $err_code);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub _create_rtc_user {
|
||||
my %params = @_;
|
||||
my ($resource, $config, $reseller_item, $err_code) =
|
||||
@params{qw/resource config reseller_item err_code/};
|
||||
|
||||
my $rtc_networks = $resource->{rtc_networks} // [];
|
||||
if ('ARRAY' ne (ref $rtc_networks)) {
|
||||
$rtc_networks = [$rtc_networks];
|
||||
}
|
||||
|
||||
# 2. create user w reseller-name and reseller-name _ "pass"
|
||||
my $reseller_name = $resource->{name} =~ s/\s+//rg;
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
my ($uuid_bin, $uuid);
|
||||
UUID::generate($uuid_bin);
|
||||
UUID::unparse($uuid_bin, $uuid);
|
||||
my $rand = get_random(10, $err_code);
|
||||
return unless $rand;
|
||||
my $pass = unpack("H*", $rand);
|
||||
my $user = $comx->create_user(
|
||||
$uuid . '@ngcp.local',
|
||||
$pass,
|
||||
);
|
||||
if ($user->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc user failed. Error code: ' . $user->{code}, $user->{debug});
|
||||
}
|
||||
|
||||
# 3. create relation in our db
|
||||
$reseller_item->create_related('rtc_user', {
|
||||
rtc_user_id => $user->{data}{id},
|
||||
});
|
||||
|
||||
# 4. create related app
|
||||
my $app = $comx->create_app(
|
||||
$uuid . '_default_app',
|
||||
$uuid . '.sipwise.local',
|
||||
$user->{data}{id},
|
||||
);
|
||||
if ($app->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc app failed. Error code: ' . $app->{code}, $app->{debug});
|
||||
}
|
||||
|
||||
# 5. create related networks
|
||||
for my $n (@{ $rtc_networks }) {
|
||||
my $connector;
|
||||
if ($n =~ m/^(sip|xmpp)$/) {
|
||||
$connector = "$n-connector";
|
||||
} else {
|
||||
$connector = $n;
|
||||
}
|
||||
my $n_response = $comx->create_network(
|
||||
$n,
|
||||
$connector,
|
||||
{xms => JSON::false},
|
||||
$user->{data}{id},
|
||||
);
|
||||
if ($n_response->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc network failed. Error code: ' . $n_response->{code}, $n_response->{debug});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub _delete_rtc_user {
|
||||
my %params = @_;
|
||||
my ($config, $reseller_item, $err_code) =
|
||||
@params{qw/config reseller_item err_code/};
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
|
||||
my $rtc_user = $reseller_item->rtc_user;
|
||||
if (!defined $rtc_user) {
|
||||
return unless &{$err_code}(
|
||||
'No rtc user found in db for this reseller.');
|
||||
}
|
||||
# app and networks are deleted automatically
|
||||
my $delete_resp = $comx->delete_user(
|
||||
$rtc_user->rtc_user_id,
|
||||
);
|
||||
if ($delete_resp->{code} == 200) {
|
||||
$rtc_user->delete;
|
||||
} else {
|
||||
return unless &{$err_code}(
|
||||
'Deleting rtc user failed. Error code: ' . $delete_resp->{code}, $delete_resp->{debug});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub get_rtc_apps {
|
||||
my %params = @_;
|
||||
my ($rtc_user_id, $config, $include_id, $err_code) =
|
||||
@params{qw/rtc_user_id config include_id err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings.');
|
||||
}
|
||||
|
||||
my $apps_resp = $comx->get_apps_by_user_id($rtc_user_id);
|
||||
my $apps = $apps_resp->{data};
|
||||
unless (defined $apps && 'ARRAY' eq ref $apps && @{ $apps }) {
|
||||
return unless &{$err_code}(
|
||||
'Fetching apps failed. Code: ' . $apps_resp->{code});
|
||||
}
|
||||
|
||||
my $res = [map {{
|
||||
domain =>$_->{domain},
|
||||
name => $_->{name},
|
||||
secret => $_->{secret},
|
||||
api_key => $_->{apiKey}, # todo: which spelling do we use?
|
||||
$include_id ? (id => $_->{id}) : (),
|
||||
}} @{ $apps }];
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub modify_rtc_apps {
|
||||
my %params = @_;
|
||||
my ($old_resource, $resource, $config, $reseller_item, $err_code) =
|
||||
@params{qw/old_resource resource config reseller_item err_code/};
|
||||
#TODO: stub, to be done
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
if ((!defined $old_resource) || (!defined $resource)) { # can only modify (no create/delete) the whole resource
|
||||
return unless &{$err_code}(
|
||||
'Cannot Modify rtc app. Old or new resource missing.');
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
|
||||
my (@deleted, @new);
|
||||
for my $a (@{ $resource->{apps} }) {
|
||||
my $app_name = $a->{name};
|
||||
my ($old_app) = grep {$app_name eq $_->{name}} @{ $old_resource->{apps} };
|
||||
if (!defined $old_app) {
|
||||
push @new, $a;
|
||||
} else {
|
||||
if ($a->{domain} ne $old_app->{domain}) {
|
||||
push @deleted, $old_app;
|
||||
push @new, $a;
|
||||
}
|
||||
}
|
||||
}
|
||||
for my $a (@{ $old_resource->{apps} }) {
|
||||
my $app_name = $a->{name};
|
||||
|
||||
my ($new_app) = grep {$app_name eq $_->{name}} @{ $resource->{apps} };
|
||||
if (!defined $new_app) {
|
||||
push @deleted, $a;
|
||||
}
|
||||
}
|
||||
|
||||
for my $app (@deleted) {
|
||||
my $a_response = $comx->delete_app($app->{id});
|
||||
if ($a_response->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Deleting rtc app failed. Error code: ' . $a_response->{code});
|
||||
}
|
||||
}
|
||||
for my $app (@new) {
|
||||
my $a_response = $comx->create_app(
|
||||
$app->{name},
|
||||
$app->{domain},
|
||||
$old_resource->{rtc_user_id},
|
||||
);
|
||||
if ($a_response->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc app failed. Error code: ' . $a_response->{code});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub get_rtc_networks {
|
||||
my %params = @_;
|
||||
my ($rtc_user_id, $config, $reseller_item, $include_id, $err_code) =
|
||||
@params{qw/rtc_user_id config reseller_item include_id err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
|
||||
my $networks_resp = $comx->get_networks_by_user_id($rtc_user_id);
|
||||
my $networks = $networks_resp->{data};
|
||||
unless (defined $networks && 'ARRAY' eq ref $networks && @{ $networks }) {
|
||||
return unless &{$err_code}(
|
||||
'Fetching networks failed. Code: ' . $networks_resp->{code}, $networks_resp->{debug});
|
||||
}
|
||||
|
||||
my $res = [map {{
|
||||
config =>$_->{config},
|
||||
connector => $_->{connector},
|
||||
tag => $_->{tag},
|
||||
$include_id ? (id => $_->{id}) : (),
|
||||
}} @{ $networks }];
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub modify_rtc_networks {
|
||||
my %params = @_;
|
||||
my ($old_resource, $resource, $config, $reseller_item, $err_code) =
|
||||
@params{qw/old_resource resource config reseller_item err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
if ((!defined $old_resource) || (!defined $resource)) { # can only modify (no create/delete) the whole resource
|
||||
return unless &{$err_code}(
|
||||
'Cannot Modify rtc network. Old or new resource missing.');
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings.');
|
||||
}
|
||||
|
||||
my (@deleted, @new);
|
||||
for my $nw (@{ $resource->{networks} }) {
|
||||
my $nw_tag = $nw->{tag};
|
||||
my ($old_nw) = grep {$nw_tag eq $_->{tag}} @{ $old_resource->{networks} };
|
||||
if (!defined $old_nw) {
|
||||
push @new, $nw;
|
||||
} else {
|
||||
if ($nw->{connector} ne $old_nw->{connector}
|
||||
|| !compare($nw->{config}, $old_nw->{config})
|
||||
) {
|
||||
push @deleted, $old_nw;
|
||||
push @new, $nw;
|
||||
}
|
||||
}
|
||||
}
|
||||
for my $nw (@{ $old_resource->{networks} }) {
|
||||
my $nw_tag = $nw->{tag};
|
||||
|
||||
my ($new_nw) = grep {$nw_tag eq $_->{tag}} @{ $resource->{networks} };
|
||||
if (!defined $new_nw) {
|
||||
push @deleted, $nw;
|
||||
}
|
||||
}
|
||||
|
||||
for my $nw (@deleted) {
|
||||
my $n_response = $comx->delete_network($nw->{id});
|
||||
if ($n_response->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Deleting rtc network failed. Error code: ' . $n_response->{code}, $n_response->{debug});
|
||||
}
|
||||
}
|
||||
for my $nw (@new) {
|
||||
my $n_response = $comx->create_network(
|
||||
$nw->{tag},
|
||||
$nw->{connector},
|
||||
$nw->{config} // {},
|
||||
$old_resource->{rtc_user_id},
|
||||
);
|
||||
if ($n_response->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc network failed. Error code: ' . $n_response->{code}, $n_response->{debug});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
# returns enable_rtc (true|false) and rtc_browser_token (string)
|
||||
sub get_rtc_subscriber_data {
|
||||
my %params = @_;
|
||||
my ($prov_subs, $config, $err_code) =
|
||||
@params{qw/prov_subs config err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
unless ($prov_subs) {
|
||||
return unless &{$err_code}(
|
||||
"Couldn't get rtc_subscriber_data. No provisioning subscriber.");
|
||||
}
|
||||
|
||||
my $rtc_session = $prov_subs->rtc_session;
|
||||
unless ($rtc_session) {
|
||||
return {enable_rtc => 0}; # JSON::false ?
|
||||
}
|
||||
|
||||
# TODO: huh? is this the right browser token?
|
||||
return {enable_rtc => 1, rtc_browser_token => 'abcde TODO'};
|
||||
}
|
||||
|
||||
sub modify_subscriber_rtc {
|
||||
my %params = @_;
|
||||
my ($old_resource, $resource, $config, $prov_subs, $err_code) =
|
||||
@params{qw/old_resource resource config prov_subs err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
if ((!defined $old_resource) && (defined $resource)) { # newly created reseller
|
||||
|
||||
# 1. enable_rtc is off -> do nothing
|
||||
if (!$resource->{enable_rtc}) {
|
||||
return;
|
||||
}
|
||||
|
||||
_create_subscriber_rtc(
|
||||
resource => $resource,
|
||||
config => $config,
|
||||
prov_subs => $prov_subs,
|
||||
err_code => $err_code);
|
||||
|
||||
} elsif ((defined $old_resource) && (defined $resource)) {
|
||||
|
||||
if($old_resource->{status} ne 'terminated' &&
|
||||
$resource->{status} eq 'terminated' &&
|
||||
$old_resource->{enable_rtc}) { # just terminated
|
||||
|
||||
$resource->{enable_rtc} = JSON::false;
|
||||
_delete_subscriber_rtc(
|
||||
config => $config,
|
||||
prov_subs => $prov_subs,
|
||||
err_code => $err_code);
|
||||
|
||||
} elsif ($old_resource->{enable_rtc} &&
|
||||
!$resource->{enable_rtc}) { # disable rtc
|
||||
|
||||
_delete_subscriber_rtc(
|
||||
config => $config,
|
||||
prov_subs => $prov_subs,
|
||||
err_code => $err_code);
|
||||
} elsif (!$old_resource->{enable_rtc} &&
|
||||
$resource->{enable_rtc} &&
|
||||
$resource->{status} ne 'terminated') { # enable rtc
|
||||
|
||||
_create_rtc_user(
|
||||
resource => $resource,
|
||||
config => $config,
|
||||
prov_subs => $prov_subs,
|
||||
err_code => $err_code);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub _create_subscriber_rtc {
|
||||
my %params = @_;
|
||||
my ($resource, $config, $prov_subs, $err_code) =
|
||||
@params{qw/resource config prov_subs err_code/};
|
||||
|
||||
my $reseller = $prov_subs->voip_subscriber->contract->contact->reseller;
|
||||
unless ($reseller) {
|
||||
return unless &{err_code}(
|
||||
'Creating subscriber rtc data failed. Reseller not found.');
|
||||
}
|
||||
my $rtc_user = $reseller->rtc_user;
|
||||
unless ($rtc_user) {
|
||||
return unless &{err_code}(
|
||||
'Creating subscriber rtc data failed. Reseller has not enabled rtc.');
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
|
||||
my $comx_apps = $comx->get_apps_by_user_id($rtc_user->rtc_user_id);
|
||||
my $comx_app;
|
||||
if ($comx_apps->{data} && @{ $comx_apps->{data} }){
|
||||
$comx_app = $comx_apps->{data}[0];
|
||||
} else {
|
||||
return unless &{$err_code}(
|
||||
'_create_subscriber_rtc: Could not find app.');
|
||||
}
|
||||
|
||||
my $session = $comx->create_session(
|
||||
$comx_app->{id},
|
||||
$rtc_user->rtc_user_id,
|
||||
);
|
||||
if ($session->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc session failed. Error code: ' . $session->{code}, $session->{debug});
|
||||
}
|
||||
|
||||
# # 3. create relation in our db
|
||||
# $prov_subs->create_related('rtc_session', {
|
||||
# rtc_session_id => $session->{data}{id},
|
||||
# });
|
||||
|
||||
# # 4. create related app
|
||||
# my $app = $comx->create_app(
|
||||
# $reseller_name . '_app',
|
||||
# $reseller_name . 'www.sipwise.com',
|
||||
# $user->{data}{id},
|
||||
# );
|
||||
# if ($app->{code} != 201) {
|
||||
# return unless &{$err_code}(
|
||||
# 'Creating rtc app failed. Error code: ' . $app->{code});
|
||||
# }
|
||||
|
||||
# # 5. create related networks
|
||||
# for my $n (@{ $rtc_networks }) {
|
||||
# my $n_response = $comx->create_network(
|
||||
# $reseller_name . "_$n",
|
||||
# $n . '-connector',
|
||||
# {xms => JSON::false},
|
||||
# $user->{data}{id},
|
||||
# );
|
||||
# if ($n_response->{code} != 201) {
|
||||
# return unless &{$err_code}(
|
||||
# 'Creating rtc network failed. Error code: ' . $n_response->{code});
|
||||
# }
|
||||
# }
|
||||
# return;
|
||||
}
|
||||
|
||||
sub _delete_subscriber_rtc {
|
||||
# my %params = @_;
|
||||
# my ($config, $prov_subs, $err_code) =
|
||||
# @params{qw/config prov_subs err_code/};
|
||||
|
||||
# my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
# host => $config->{rtc}{schema}.'://'.
|
||||
# $config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
# $config->{rtc}{path},
|
||||
# );
|
||||
# $comx->login(
|
||||
# $config->{rtc}{user},
|
||||
# $config->{rtc}{pass},
|
||||
# $config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
# if ($comx->login_status->{code} != 200) {
|
||||
# return unless &{$err_code}(
|
||||
# 'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
# }
|
||||
|
||||
# my $rtc_user = $reseller_item->rtc_user;
|
||||
# if (!defined $rtc_user) {
|
||||
# return unless &{$err_code}(
|
||||
# 'No rtc user found in db for this reseller.');
|
||||
# }
|
||||
# # app and networks are deleted automatically
|
||||
# my $delete_resp = $comx->delete_user(
|
||||
# $rtc_user->rtc_user_id,
|
||||
# );
|
||||
# if ($delete_resp->{code} == 200) {
|
||||
# $rtc_user->delete;
|
||||
# } else {
|
||||
# return unless &{$err_code}(
|
||||
# 'Deleting rtc user failed. Error code: ' . $delete_resp->{code});
|
||||
# }
|
||||
# return;
|
||||
}
|
||||
|
||||
sub create_rtc_session {
|
||||
my %params = @_;
|
||||
my ($config, $err_code, $resource, $subscriber_item) =
|
||||
@params{qw/config err_code resource subscriber_item/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
my $reseller = $subscriber_item->contract->contact->reseller;
|
||||
unless ($reseller) {
|
||||
return unless &{$err_code}(
|
||||
'Creating subscriber rtc data failed. Reseller not found.');
|
||||
}
|
||||
|
||||
my $rtc_user = $reseller->rtc_user;
|
||||
unless ($rtc_user) {
|
||||
return unless &{$err_code}(
|
||||
'Creating subscriber rtc data failed. Reseller has not enabled rtc.');
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
|
||||
my $comx_apps = $comx->get_apps_by_user_id($rtc_user->rtc_user_id);
|
||||
my $comx_app;
|
||||
if ($comx_apps->{data} && @{ $comx_apps->{data} }){
|
||||
if ($resource->{rtc_app_name}) {
|
||||
($comx_app) = grep {$_->{name} eq $resource->{rtc_app_name}} @{ $comx_apps->{data} };
|
||||
} else { # default app
|
||||
($comx_app) = grep {$_->{name} =~ m/_default_app$/;} @{ $comx_apps->{data} };
|
||||
}
|
||||
}
|
||||
unless ($comx_app) {
|
||||
return unless &{$err_code}(
|
||||
'create_rtc_session: Could not find app.');
|
||||
}
|
||||
|
||||
my $comx_networks = $comx->get_networks_by_user_id($rtc_user->rtc_user_id);
|
||||
my $comx_network_tags = [];
|
||||
if ($comx_networks->{data} && 'ARRAY' eq ref $comx_networks->{data}) {
|
||||
$comx_network_tags = [ map { $_->{tag} } @{ $comx_networks->{data} } ];
|
||||
} else {
|
||||
return unless &{$err_code}(
|
||||
'create_rtc_session: Could not fetch networks for given rtc user.');
|
||||
}
|
||||
|
||||
my $session = $comx->create_session(
|
||||
$comx_app->{id},
|
||||
$rtc_user->rtc_user_id,
|
||||
);
|
||||
if ($session->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
'Creating rtc session failed. Error code: ' . $session->{code}, $session->{debug});
|
||||
}
|
||||
for my $n (@{ $comx_networks->{data} }) {
|
||||
my $identifier;
|
||||
if ($n->{connector} eq "sip-connector") {
|
||||
$identifier = 'sip:' . $subscriber_item->username . '@' . $subscriber_item->domain->domain;
|
||||
} elsif ($n->{connector} eq "xmpp-connector") {
|
||||
$identifier = 'xmpp:' . $subscriber_item->username . '@' . $subscriber_item->domain->domain;
|
||||
} else { # webrtc, ...
|
||||
$identifier = $subscriber_item->username;
|
||||
}
|
||||
my $account = $comx->create_account(
|
||||
$session->{data}{id},
|
||||
$rtc_user->rtc_user_id,
|
||||
$identifier,
|
||||
$n->{tag},
|
||||
$subscriber_item->provisioning_voip_subscriber->password,
|
||||
{xms => JSON::false},
|
||||
);
|
||||
if ($account->{code} != 201) {
|
||||
return unless &{$err_code}(
|
||||
"Creating rtc account ($n->{tag}) failed. Error code: " . $account->{code}, $account->{debug});
|
||||
}
|
||||
}
|
||||
|
||||
my $rtc_session_item = $subscriber_item->provisioning_voip_subscriber->create_related('rtc_session', {
|
||||
rtc_session_id => $session->{data}{id},
|
||||
});
|
||||
return $rtc_session_item;
|
||||
}
|
||||
|
||||
sub get_rtc_session {
|
||||
my %params = @_;
|
||||
my ($config, $item, $err_code) =
|
||||
@params{qw/config item err_code/};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return 0; };
|
||||
}
|
||||
|
||||
my $comx = NGCP::Panel::Utils::ComxAPIClient->new(
|
||||
host => $config->{rtc}{schema}.'://'.
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port}.
|
||||
$config->{rtc}{path},
|
||||
);
|
||||
$comx->login(
|
||||
$config->{rtc}{user},
|
||||
$config->{rtc}{pass},
|
||||
$config->{rtc}{host}.':'.$config->{rtc}{port});
|
||||
if ($comx->login_status->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
'Rtc Login failed. Check config settings. Status code: ' . $comx->login_status->{code}, $comx->login_status->{debug});
|
||||
}
|
||||
|
||||
my $session = $comx->get_session($item->rtc_session_id);
|
||||
if ($session->{code} != 200) {
|
||||
return unless &{$err_code}(
|
||||
"Couldn't find session. Error code: " . $session->{code}, $session->{debug});
|
||||
}
|
||||
return $session;
|
||||
}
|
||||
|
||||
sub get_random {
|
||||
my ($num, $err_code) = @_;
|
||||
my ($fd, $buf);
|
||||
unless(open($fd, '<', '/dev/urandom')) {
|
||||
return unless &{$err_code}("Failed to open /dev/urandom: $!");
|
||||
}
|
||||
unless(read($fd, $buf, $num) == $num) {
|
||||
return unless &{$err_code}("Failed to read $num bytes from /dev/urandom: $!");
|
||||
}
|
||||
close($fd);
|
||||
return $buf;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -1,630 +0,0 @@
|
||||
[% site_config.title = c.loc('Web Phone for ') _ subscriber.username _ '@' _ subscriber.domain.domain -%]
|
||||
|
||||
<script type="text/javascript" src="/js/libs/jssip-0.3.0.min.js"></script>
|
||||
<!--<script type="text/javascript" src="/js/libs/stanzaio.bundle.min.js"></script>-->
|
||||
<script type="text/javascript" src="/js/libs/stanzaio.bundle.js"></script>
|
||||
<script type="text/javascript" src="/js/libs/bootstrap-select.min.js"></script>
|
||||
<script type="text/javascript" src="/js/libs/bootstrap-switch.js"></script>
|
||||
<script type="text/javascript" src="/js/libs/jquery.slimscroll.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/css/bootstrap-select/bootstrap-select.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/bootstrap-switch/bootstrap-switch.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/font/font-awesome/css/font-awesome.min.css"/>
|
||||
|
||||
<style>
|
||||
#xmpp-roster {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#xmpp-roster .popover {
|
||||
max-width: 100%;
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
.xmpp-roster-entry-col1.available {
|
||||
background: #080;
|
||||
}
|
||||
.xmpp-roster-entry-col1.unavailable {
|
||||
background: #ddd;
|
||||
}
|
||||
.xmpp-roster-entry-col1.chat {
|
||||
background: #0f0;
|
||||
}
|
||||
.xmpp-roster-entry-col1.away,
|
||||
.xmpp-roster-entry-col1.xa {
|
||||
background: #fa0;
|
||||
}
|
||||
.xmpp-roster-entry-col1.dnd {
|
||||
background: #f00;
|
||||
}
|
||||
|
||||
.xmpp-roster-entry-ctrl {
|
||||
margin-right:10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-left.switch-mini, .switch-right.switch-mini {
|
||||
/* make more space on left/right */
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.has-switch {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.xmpp-chat-time {
|
||||
font-style:italic;
|
||||
color: #999;
|
||||
}
|
||||
.xmpp-chat-sent {
|
||||
float: right;
|
||||
clear: both;
|
||||
margin-right: 15px;
|
||||
margin-left: 30px;
|
||||
text-align: right;
|
||||
color: #333;
|
||||
}
|
||||
.xmpp-chat-recv {
|
||||
float: left;
|
||||
clear: both;
|
||||
margin-left: 0px;
|
||||
margin-right: 30px;
|
||||
text-align: left;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.has-switch {
|
||||
min-width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="row">
|
||||
<span class="pull-left" style="margin:0 5px 0 5px;">
|
||||
<a class="btn btn-primary btn-large" href="[% c.uri_for('/back') %]"><i class="icon-arrow-left"></i> [% c.loc('Back') %]</a>
|
||||
</span>
|
||||
</div>
|
||||
[% back_created = 1 -%]
|
||||
|
||||
<div class="ngcp-separator"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var phone = null;
|
||||
var chat = null;
|
||||
var sip_configuration = null;
|
||||
var xmpp_configuration = null;
|
||||
var xmpp_last_state = 'available';
|
||||
var orig_page_title = document.title;
|
||||
var window_focus = true;
|
||||
var window_timeout;
|
||||
var xmpp_show_offline = false;
|
||||
var xmpp_last_time = "";
|
||||
|
||||
$.ajax({
|
||||
url: "[% c.uri_for_action('/subscriber/webphone_ajax', c.req.captures) %]"
|
||||
}).done(function(data) {
|
||||
|
||||
sip_configuration = data.aaData.sip;
|
||||
sip_configuration.register = true;
|
||||
sip_configuration.trace_sip = true;
|
||||
phone = new JsSIP.UA(sip_configuration);
|
||||
|
||||
// ws connection events
|
||||
phone.on('connected', function(e){
|
||||
console.log("connected");
|
||||
$("#sip-status").html("[% c.loc('connected - registering...') %]");
|
||||
});
|
||||
phone.on('disconnected', function(e){
|
||||
console.log("disconnected");
|
||||
$("#sip-status").html("[% c.loc('disconnected.') %]");
|
||||
});
|
||||
|
||||
// in/out call event
|
||||
phone.on('newRTCSession', function(e){
|
||||
//console.log("newRTCSession", e.originator, e.session);
|
||||
console.log("newRTCSession", e);
|
||||
|
||||
var session = e.data.session;
|
||||
if(session.direction == 'incoming') {
|
||||
session.answer({
|
||||
mediaConstraints: { audio: true, video: $('#sip_toggle_video').is(':checked') }
|
||||
});
|
||||
|
||||
|
||||
// TODO: create_incall_window($(obj.target).parents("li.xmpp-roster-entry"), jidid, item.jid.bare);
|
||||
|
||||
session.on('started', function(e) {
|
||||
console.log("RTCSession session started");
|
||||
var rtcSession = e.sender;
|
||||
if(rtcSession.getLocalStreams().length > 0) {
|
||||
selfView.src = window.URL.createObjectURL(rtcSession.getLocalStreams()[0]);
|
||||
selfView.volume = 0;
|
||||
}
|
||||
if(rtcSession.getRemoteStreams().length > 0) {
|
||||
remoteView.src = window.URL.createObjectURL(rtcSession.getRemoteStreams()[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// in/out im event
|
||||
phone.on('newMessage', function(e){
|
||||
console.log("newMessage");
|
||||
});
|
||||
// registration events
|
||||
phone.on('registered', function(e){
|
||||
console.log("registered");
|
||||
$("#sip-status").html("[% c.loc('registered.') %]");
|
||||
});
|
||||
phone.on('unregistered', function(e){
|
||||
console.log("unregistered");
|
||||
$("#sip-status").html("[% c.loc('unregistered.') %]");
|
||||
});
|
||||
phone.on('registrationFailed', function(e){
|
||||
console.log("registrationFailed", e.data.response);
|
||||
$("#sip-status").html("[% c.loc('registration failed:') %] " + e.data.response.status_code + " - " + e.data.response.reason_phrase);
|
||||
});
|
||||
|
||||
phone.start();
|
||||
|
||||
xmpp_configuration = data.aaData.xmpp;
|
||||
// chat client modifies it, so make a copy to have the original
|
||||
// one later on re-connects
|
||||
var tmp_xmpp_configuration = jQuery.extend(true, {}, xmpp_configuration);
|
||||
chat = XMPP.createClient(tmp_xmpp_configuration);
|
||||
register_chat_callbacks();
|
||||
chat.connect();
|
||||
});
|
||||
|
||||
function register_chat_callbacks() {
|
||||
var timer = null;
|
||||
chat.on('disconnected', function() {
|
||||
console.log("xmpp disconnection");
|
||||
$("#xmpp-status").html("[% c.loc('disconnected.') %]");
|
||||
if(timer)
|
||||
return 1;
|
||||
console.log("prepare re-connect timer");
|
||||
$('#xmpp-roster').empty();
|
||||
var xmpp_last_state_tmp = xmpp_last_state;
|
||||
$('#xmpp-pres').val('unavailable');
|
||||
$('#xmpp-pres').change();
|
||||
xmpp_last_state = xmpp_last_state_tmp;
|
||||
timer = window.setInterval(function(){
|
||||
console.log("perform re-connect");
|
||||
window.clearInterval(timer);
|
||||
timer = null;
|
||||
chat.disconnect();
|
||||
console.log("create new client", xmpp_configuration);
|
||||
var tmp_xmpp_configuration = jQuery.extend(true, {}, xmpp_configuration);
|
||||
chat = XMPP.createClient(tmp_xmpp_configuration);
|
||||
register_chat_callbacks();
|
||||
chat.connect();
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
chat.on('chatState', function(obj) {
|
||||
console.log("got chat state", obj);
|
||||
var jid = obj.from.bare;
|
||||
var msg;
|
||||
if(obj.chatState == "composing") {
|
||||
msg = "[% c.loc('is typing...') %]";
|
||||
} else if(obj.chatState == "paused") {
|
||||
msg = "[% c.loc('has stopped typing.') %]";
|
||||
} else if(obj.chatState == "active") {
|
||||
// chat session started/closed
|
||||
return;
|
||||
}
|
||||
|
||||
var jidid = jid.replace(/[^a-zA-Z0-9_]/g, '-');
|
||||
var chat_win = $('#xmpp-roster #' + jidid).find('.popover');
|
||||
if(!chat_win.length) {
|
||||
chat_win = create_chat_window($('#xmpp-roster #' + jidid), jidid, jid);
|
||||
}
|
||||
$(chat_win).find('.xmpp-chat-history').append('<li><em>' + msg + '</em></li>')
|
||||
.slimScroll({ scrollBy: '50px' });
|
||||
});
|
||||
|
||||
chat.on('chat', function(obj) {
|
||||
console.log("got message ", obj);
|
||||
var jid = obj.from.bare;
|
||||
var jidid = jid.replace(/[^a-zA-Z0-9_]/g, '-');
|
||||
|
||||
var chat_win = $('#xmpp-roster #' + jidid).find('.popover');
|
||||
if(!chat_win.length) {
|
||||
chat_win = create_chat_window($('#xmpp-roster #' + jidid), jidid, jid);
|
||||
}
|
||||
|
||||
var now = get_time_string();
|
||||
if(now != xmpp_last_time) {
|
||||
xmpp_last_time = now;
|
||||
$(chat_win).find('.xmpp-chat-history').append('<li><span class="xmpp-chat-recv"><span class="xmpp-chat-time">' + now + '</span></span></li>')
|
||||
}
|
||||
$(chat_win).find('.xmpp-chat-history').append('<li><span class="xmpp-chat-recv">' + obj.body + '</span></li>')
|
||||
.slimScroll({ scrollBy: '50px' });
|
||||
|
||||
raise_attention('chat');
|
||||
});
|
||||
|
||||
chat.on('groupchat', function(message) {
|
||||
console.log("got group message ", message);
|
||||
});
|
||||
|
||||
chat.on('session:started', function() {
|
||||
$("#xmpp-status").html("[% c.loc('online.') %]");
|
||||
console.log("XMPP session started");
|
||||
chat.enableCarbons();
|
||||
chat.getRoster(function(err, resp) {
|
||||
console.log(err, resp);
|
||||
chat.sendPresence();
|
||||
if(err == null) {
|
||||
$.each(resp.roster.items, function(index, item) {
|
||||
console.log(item.name);
|
||||
var jidid = item.jid.bare.replace(/[^a-zA-Z0-9_]/g, '-');
|
||||
var entry = create_xmpp_entry_dom(jidid, item.jid.bare, item.name || item.jid.bare);
|
||||
$('#xmpp-roster').append(entry);
|
||||
$('#xmpp-roster li').sort(roster_asc_sort).appendTo('#xmpp-roster');
|
||||
equalHeights($('#' + jidid).find('.xmpp-roster-entry-col1'), $('#' + jidid).find('.xmpp-roster-entry-col2'));
|
||||
$('#' + jidid)
|
||||
.mouseenter(function(obj) {
|
||||
$(obj.currentTarget).find('.xmpp-roster-entry-col3').show();
|
||||
})
|
||||
.mouseleave(function(obj) {
|
||||
$(obj.currentTarget).find('.xmpp-roster-entry-col3').hide();
|
||||
})
|
||||
.find('[rel="tooltip"]').tooltip({'html': false});
|
||||
|
||||
$('#' + jidid).find('.xmpp-roster-entry-ctrl-chat').click(function(obj) {
|
||||
console.log("start chat");
|
||||
create_chat_window($(obj.target).parents("li.xmpp-roster-entry"), jidid, item.jid.bare);
|
||||
});
|
||||
$('#' + jidid).find('.xmpp-roster-entry-ctrl-phone').click(function(obj) {
|
||||
console.log("start chat");
|
||||
create_outcall_window($(obj.target).parents("li.xmpp-roster-entry"), jidid, item.jid.bare);
|
||||
var session = call(item.jid.bare);
|
||||
});
|
||||
|
||||
// we get a presence callback where we'll show it
|
||||
$(entry).hide();
|
||||
});
|
||||
}
|
||||
$('#xmpp-pres').val(xmpp_last_state);
|
||||
$('#xmpp-pres').change();
|
||||
});
|
||||
});
|
||||
chat.on('presence', function(pres) {
|
||||
if(pres.from.bare == xmpp_configuration.jid) {
|
||||
console.log("skip own presence info");
|
||||
return 1;
|
||||
}
|
||||
var type = pres.type || 'available';
|
||||
var show;
|
||||
if(type == 'available') {
|
||||
show = pres.show || 'available';
|
||||
} else {
|
||||
show = pres.show || 'unavailable';
|
||||
}
|
||||
var jidid = pres.from.bare.replace(/[^a-zA-Z0-9_]/g, '-');
|
||||
|
||||
$("#xmpp-roster #" + jidid + " .xmpp-roster-entry-col1").removeClass().addClass("xmpp-roster-entry-col1 " + show);
|
||||
console.log("xmpp-roster type=" + pres.type + ", show=" + pres.show);
|
||||
if(show != 'unavailable' || xmpp_show_offline) {
|
||||
$("#xmpp-roster #" + jidid).show();
|
||||
} else {
|
||||
$("#xmpp-roster #" + jidid).hide();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function call(dest_uri) {
|
||||
var eventHandlers = {
|
||||
'progress': function(e) {
|
||||
console.log("call in progress", e);
|
||||
$("#sip-status").html("[% c.loc('in progress...') %]");
|
||||
},
|
||||
'failed': function(e) {
|
||||
console.log("call failed");
|
||||
$("#sip-status").html("[% c.loc('call failed:') %] ", e);
|
||||
},
|
||||
'started': function(e) {
|
||||
console.log("call started");
|
||||
$("#sip-status").html("[% c.loc('call started.') %]");
|
||||
|
||||
var rtcSession = e.sender;
|
||||
|
||||
if (rtcSession.getLocalStreams().length > 0) {
|
||||
selfView.src = window.URL.createObjectURL(rtcSession.getLocalStreams()[0]);
|
||||
}
|
||||
if (rtcSession.getRemoteStreams().length > 0) {
|
||||
remoteView.src = window.URL.createObjectURL(rtcSession.getRemoteStreams()[0]);
|
||||
}
|
||||
},
|
||||
'ended': function(e){
|
||||
console.log("call ended");
|
||||
$("#sip-status").html("[% c.loc('call ended.') %]");
|
||||
}
|
||||
};
|
||||
|
||||
var options = {
|
||||
'eventHandlers': eventHandlers,
|
||||
'extraHeaders': [ 'X-Foo: foo', 'X-Bar: bar' ],
|
||||
'mediaConstraints': { 'audio': true, 'video': $('#sip_toggle_video').is(':checked') }
|
||||
};
|
||||
|
||||
phone.call('sip:' + dest_uri, options);
|
||||
}
|
||||
|
||||
function roster_asc_sort(a, b) {
|
||||
return ($(b).find('.xmpp-roster-entry-name').text().toLowerCase()) < ($(a).find('.xmpp-roster-entry-name').text().toLowerCase()) ? 1 : -1;
|
||||
}
|
||||
|
||||
function get_time_string() {
|
||||
var now = new Date();
|
||||
//return ((now.getHours() < 10)?"0":"") + now.getHours() +":"+ ((now.getMinutes() < 10)?"0":"") + now.getMinutes() +":"+ ((now.getSeconds() < 10)?"0":"") + now.getSeconds();
|
||||
return ((now.getHours() < 10)?"0":"") + now.getHours() +":"+ ((now.getMinutes() < 10)?"0":"") + now.getMinutes();
|
||||
}
|
||||
|
||||
function create_xmpp_entry_dom(jidid, jid, name) {
|
||||
var entry =
|
||||
'<li id="' + jidid + '" class="xmpp-roster-entry row span6" style="clear:both; float:left; padding:0; margin:1px; background:#f0f0f0;">' +
|
||||
' <div class="xmpp-roster-entry-col1 unavailable" style="float:left; width:10px; padding:0; margin:0; "> </div>' +
|
||||
' <div class="xmpp-roster-entry-col2 span3" style="float:left; padding:20px; margin:0;">' +
|
||||
' <div>' +
|
||||
' <span class="xmpp-roster-entry-name" style="font-size:1.3em; font-weight:bold;">' + name + '</span>' +
|
||||
' </div>' +
|
||||
' <div>' +
|
||||
' <span class="xmpp-roster-entry-details" style="font-size:1em; font-weight:normal;">' + jid + '</span>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
' <div class="xmpp-roster-entry-col3" style="float:right; padding:20px 0 20px 0; margin:0; display:none;">' +
|
||||
' <div style="float:right; font-size:1.5em">' +
|
||||
' <span class="fa fa-comment xmpp-roster-entry-ctrl xmpp-roster-entry-ctrl-chat" rel="tooltip" title="Start Chat"></span>' +
|
||||
' <span class="fa fa-phone xmpp-roster-entry-ctrl xmpp-roster-entry-ctrl-phone" rel="tooltip" title="Make Call"></span>' +
|
||||
' <span class="fa fa-file-text xmpp-roster-entry-ctrl xmpp-roster-entry-ctrl-fax" rel="tooltip" title="Send Fax"></span>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
'</li>';
|
||||
return entry;
|
||||
}
|
||||
|
||||
function create_chat_window(parent, jidid, jid) {
|
||||
$(parent).popover("destroy");
|
||||
$(parent).popover({
|
||||
placement: 'right',
|
||||
html: true,
|
||||
container: '#' + jidid,
|
||||
trigger: 'manual',
|
||||
title: '<div> <span class="pull-left">' + jid + '</span><span class="xmpp-chat-close pull-right fa fa-times"></span></div>',
|
||||
content: '<div class="span4" style="margin:10px;"><ul class="xmpp-chat-history" style="list-style-type:none; margin:0; min-height:100px;"></ul><input data-jid="'+ jid + '" type="text" class="xmpp-chat-input" style="width:100%; margin:10px 0 0 0;"/></div>'
|
||||
});
|
||||
$(parent).popover("show");
|
||||
$(parent).find(".xmpp-chat-input").focus();
|
||||
$(parent).find(".xmpp-chat-history").slimScroll({
|
||||
height: '100px',
|
||||
railVisible: true,
|
||||
alwaysVisible: true,
|
||||
start: 'bottom'
|
||||
});
|
||||
return $(parent).find(".popover");
|
||||
}
|
||||
|
||||
function create_incall_window(parent, jidid, jid) {
|
||||
$(parent).popover("destroy");
|
||||
$(parent).popover({
|
||||
placement: 'right',
|
||||
html: true,
|
||||
container: '#' + jidid,
|
||||
trigger: 'manual',
|
||||
title: '<div> <span class="pull-left">[% c.loc('Call from') %] ' + jid + '</span><span class="xmpp-chat-close pull-right fa fa-times"></span></div>',
|
||||
content: '<div class="span4" style="margin:10px;"><button class="sip-accept-call" style="margin-right:20px;">[% c.loc('Accept') %]</button><button class="sip-reject-call">[% c.loc('Reject') %]</button></div>'
|
||||
});
|
||||
$(parent).popover("show");
|
||||
$(parent).find(".sip-accept-call").click(function(){
|
||||
console.log("answering call");
|
||||
/*
|
||||
var session = ???;
|
||||
session.answer({
|
||||
mediaConstraints: { audio: true, video: $('#sip_toggle_video').is(':checked') }
|
||||
});
|
||||
*/
|
||||
});
|
||||
$(parent).find(".sip-reject-call").click(function(){
|
||||
console.log("rejecting call");
|
||||
// var session = ???; session.terminate({ status_code: 486 });
|
||||
});
|
||||
return $(parent).find(".popover");
|
||||
}
|
||||
|
||||
function create_outcall_window(parent, jidid, jid) {
|
||||
$(parent).popover("destroy");
|
||||
$(parent).popover({
|
||||
placement: 'right',
|
||||
html: true,
|
||||
container: '#' + jidid,
|
||||
trigger: 'manual',
|
||||
title: '<div> <span class="pull-left">[% c.loc('Calling') %] ' + jid + '</span><span class="xmpp-chat-close pull-right fa fa-times"></span></div>',
|
||||
content: '<div class="span4" style="margin:10px;"><button class="sip-stop-call" style="margin-right:20px;">[% c.loc('Terminate Call') %]</button></div>'
|
||||
});
|
||||
$(parent).popover("show");
|
||||
$(parent).find(".sip-stop-call").click(function(){
|
||||
console.log("stopping call");
|
||||
/*
|
||||
var session = ???;
|
||||
session.terminate();
|
||||
*/
|
||||
});
|
||||
return $(parent).find(".popover");
|
||||
}
|
||||
|
||||
|
||||
function equalHeights (element1, element2) {
|
||||
var height;
|
||||
|
||||
if (element1.outerHeight() > element2.outerHeight())
|
||||
{
|
||||
height = element1.outerHeight();
|
||||
element2.css('height', height);
|
||||
}
|
||||
else {
|
||||
height = element2.outerHeight();
|
||||
element1.css('height', height);
|
||||
}
|
||||
}
|
||||
|
||||
function raise_attention(type) {
|
||||
if(!window_focus) {
|
||||
if(type == "chat") {
|
||||
flash_title('[% c.loc('NEW MESSAGE') %]');
|
||||
} else {
|
||||
flash_title(type + '! ' + orig_page_title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function flash_title(title) {
|
||||
function step() {
|
||||
document.title = (document.title == orig_page_title) ? title : orig_page_title;
|
||||
window_timeout = setTimeout(step, 800);
|
||||
};
|
||||
|
||||
cancel_flash_title(window_timeout);
|
||||
step();
|
||||
};
|
||||
|
||||
function cancel_flash_title() {
|
||||
clearTimeout(window_timeout);
|
||||
document.title = orig_page_title;
|
||||
};
|
||||
|
||||
|
||||
$(function() {
|
||||
$('.selectpicker').selectpicker();
|
||||
|
||||
$('#xmpp-toggle-offline').bootstrapSwitch();
|
||||
$('#xmpp-toggle-offline').bootstrapSwitch('setSizeClass', 'switch-mini');
|
||||
$('#xmpp-toggle-offline').on('switch-change', function(obj) {
|
||||
if(obj.currentTarget.checked) {
|
||||
console.log("show offline entries");
|
||||
xmpp_show_offline = true;
|
||||
$('.xmpp-roster-entry').show();
|
||||
} else {
|
||||
console.log("hide offline entries");
|
||||
xmpp_show_offline = false;
|
||||
$('.xmpp-roster-entry-col1.unavailable').parent().hide();
|
||||
}
|
||||
});
|
||||
$('#sip_toggle_video').bootstrapSwitch();
|
||||
$('#sip_toggle_video').bootstrapSwitch('setSizeClass', 'switch-mini');
|
||||
|
||||
$('#xmpp-pres').change(function(obj) {
|
||||
var show = obj.currentTarget[obj.currentTarget.selectedIndex].value;
|
||||
xmpp_last_state = show;
|
||||
var type = (show == "unavailable" ? "unavailable" : "available");
|
||||
console.log("changing xmpp presence status, show=" + show + ", type=" + type);
|
||||
if(show == "available") {
|
||||
chat.sendPresence();
|
||||
} else {
|
||||
chat.sendPresence({ type: type, show: show });
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keypress(function(obj) {
|
||||
if($(obj.target).hasClass("xmpp-chat-input")) {
|
||||
// return esc and tab
|
||||
if (obj.which == 9 || obj.which == 27) {
|
||||
return false;
|
||||
}
|
||||
if(obj.which == 13 && $(obj.target).val().length) {
|
||||
obj.preventDefault();
|
||||
chat.sendMessage({ to: $(obj.target).data("jid"), body: $(obj.target).val() });
|
||||
var chat_win = $(obj.target).parent().find(".xmpp-chat-history");
|
||||
var now = get_time_string();
|
||||
if(now != xmpp_last_time) {
|
||||
xmpp_last_time = now;
|
||||
$(chat_win).append('<li><span class="xmpp-chat-sent"><span class="xmpp-chat-time">' + now + '</span></span></li>')
|
||||
}
|
||||
$(chat_win).append('<li><span class="xmpp-chat-sent">' + $(obj.target).val() + '</span></li>')
|
||||
.slimScroll({ scrollBy: '50px' });
|
||||
$(obj.target).val("");
|
||||
} else {
|
||||
// TODO: send chatState message somehow
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).click(function(obj) {
|
||||
if($(obj.target).hasClass("xmpp-chat-close")) {
|
||||
console.log("hiding chat window");
|
||||
$(obj.target).parents("li.xmpp-roster-entry").popover("destroy");
|
||||
$(obj.target).parents(".popover").remove();
|
||||
}
|
||||
});
|
||||
|
||||
$(window).focus(function() {
|
||||
window_focus = true;
|
||||
document.title = orig_page_title;
|
||||
clearTimeout(window_timeout);
|
||||
}).blur(function() {
|
||||
window_focus = false;
|
||||
});
|
||||
|
||||
window.onbeforeunload = function(obj) {
|
||||
if(phone.isRegistered()) {
|
||||
console.log("unregistering phone before leaving");
|
||||
phone.unregister({'all': true});
|
||||
}
|
||||
};
|
||||
|
||||
$('#xmpp-buddy-add').click(function(obj) {
|
||||
var jid = $('#xmpp-buddy-add-jid').val();
|
||||
console.log(">>>>>>>>> adding jid " + jid);
|
||||
chat.subscribe(jid);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
<div class="span6">[% c.loc('Phone Status:') %] <span id="sip-status">[% c.loc('connecting...') %]</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">[% c.loc('Chat Status:') %] <span id="xmpp-status">[% c.loc('connecting...') %]</span></div>
|
||||
</div>
|
||||
<div>
|
||||
<h3>[% c.loc('Buddy List') %]</h3>
|
||||
<div class="row span6" style="margin:0; clear:both; padding:10px;">
|
||||
<input id="xmpp-toggle-offline" style="float:left;" type="checkbox" data-on="success" data-off="default" data-on-label="[% c.loc('Show Offline') %]" data-off-label="[% c.loc('Hide Offline') %]">
|
||||
<input id="sip_toggle_video" checked style="float:left" type="checkbox" data-on="success" data-off="default" data-on-label="[% c.loc('Audio&Video') %]" data-off-label="[% c.loc('Audio Only') %]">
|
||||
</div>
|
||||
<div class="span6" style="margin:0; clear:both; padding:0;">
|
||||
<div class="span4" style="margin:0;">
|
||||
<input type="text" id="xmpp-buddy-add-jid" class="span4"/>
|
||||
</div>
|
||||
<div class="span2" style="margin:0; float:right;">
|
||||
<button class="btn btn-primary btn-medium" id="xmpp-buddy-add"><i class="icon-plus"></i> Add Buddy</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row span6" style="margin:0; clear:both;">
|
||||
<select id="xmpp-pres" class="selectpicker span6">
|
||||
[% FOR opt IN
|
||||
[
|
||||
{ n = "unavailable", d = c.loc('Offline') },
|
||||
{ n = "available", d = c.loc('Available') },
|
||||
{ n = "away", d = c.loc('Away') },
|
||||
{ n = "xa", d = c.loc('Extended Away') },
|
||||
{ n = "dnd", d = c.loc('Do Not Disturb') },
|
||||
]
|
||||
-%]
|
||||
<option value="[% opt.n %]" data-content="<span class='xmpp-roster-entry-col1 [% opt.n %]'> </span><span> [% opt.d %]</span>">[% opt.d %]</option>
|
||||
[% END -%]
|
||||
</select>
|
||||
</div>
|
||||
<ul id="xmpp-roster" class="span8" style="list-style-type:none; padding:0; margin:0;">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<video id="selfView" autoplay hidden=true></video>
|
||||
<video id="remoteView" autoplay hidden=true></video>
|
||||
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
@ -1,201 +0,0 @@
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use Net::Domain qw(hostfqdn);
|
||||
use JSON qw();
|
||||
use Test::More;
|
||||
use URI::Escape qw();
|
||||
|
||||
#use LWP::Debug;
|
||||
|
||||
my $is_local_env = 0;
|
||||
|
||||
unless ($ENV{TEST_RTC}) {
|
||||
plan skip_all => "not testing rtc, enable TEST_RTC=yes to run tests";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443');
|
||||
|
||||
my $domain_name = $ENV{TEST_RTC_DOMAIN};
|
||||
unless ($domain_name) {
|
||||
($domain_name) = ($uri =~ m!^https?://([^/:]*)(:[0-9]+)?/?.*$!);
|
||||
}
|
||||
|
||||
my ($ua, $req, $res, $data);
|
||||
|
||||
use Test::Collection;
|
||||
$ua = Test::Collection->new()->ua();
|
||||
|
||||
my ($domain_id);
|
||||
{
|
||||
$req = HTTP::Request->new('GET', "$uri/api/domains/?domain=$domain_name");
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "GET search domain");
|
||||
$data = JSON::from_json($res->decoded_content);
|
||||
ok($data->{total_count}, "got at least one domain") || die "we can't continue without domain";
|
||||
|
||||
my $selected_domain = ( 'ARRAY' eq ref $data->{_embedded}{'ngcp:domains'} )
|
||||
? $data->{_embedded}{'ngcp:domains'}[0]
|
||||
: $data->{_embedded}{'ngcp:domains'};
|
||||
|
||||
$domain_id = $selected_domain->{id};
|
||||
$domain_name = $selected_domain->{domain};
|
||||
|
||||
diag("domain: $selected_domain->{domain} ($domain_id)");
|
||||
}
|
||||
|
||||
my ($contract_id, $reseller_id, $customer_id, $bprof_id, $customercontact_id, $network_tag);
|
||||
{
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/contracts/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
contact_id => 2,
|
||||
status => 'active',
|
||||
type => 'reseller',
|
||||
billing_profile_id => 1,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create contract");
|
||||
($contract_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($contract_id, "got contract_id") || die "we don't continue here";
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/resellers/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
contract_id => $contract_id,
|
||||
name => 'rtc test reseller ' . time,
|
||||
enable_rtc => JSON::true,
|
||||
status => 'active',
|
||||
rtc_networks => ['sip','xmpp','webrtc'],
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create reseller");
|
||||
($reseller_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($reseller_id, "got reseller_id") || die "we don't continue here";
|
||||
|
||||
$req = HTTP::Request->new('GET', $uri . "/api/resellers/$reseller_id");
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch POSTed reseller");
|
||||
$data = JSON::from_json($res->decoded_content);
|
||||
ok($data->{enable_rtc}, "reseller has rtc enabled");
|
||||
|
||||
$req = HTTP::Request->new('GET', $uri . "/api/rtcnetworks/$reseller_id");
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "fetch rtcnetworks");
|
||||
$data = JSON::from_json($res->decoded_content);
|
||||
is($data->{networks}[0]{connector}, 'sip-connector', "rtcnetwork exists");
|
||||
$network_tag = $data->{networks}[0]{tag};
|
||||
|
||||
diag("reseller id: $reseller_id , first network_tag: $network_tag");
|
||||
|
||||
$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 => 'rtc test bprof ' . time,
|
||||
handle => 'rtc_test_bprof_' . time,
|
||||
reseller_id => $reseller_id,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create billingprofile");
|
||||
($bprof_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($bprof_id, "got bprof_id") || die "we don't continue here";
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/customercontacts/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
email => 'rtccustomer@ngcp.com',
|
||||
reseller_id => $reseller_id,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create customercontact");
|
||||
($customercontact_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($customercontact_id, "got customercontact_id") || die "we don't continue here";
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/customers/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
contact_id => $customercontact_id,
|
||||
billing_profile_id => $bprof_id,
|
||||
reseller_id => $reseller_id,
|
||||
status => 'active',
|
||||
type => 'sipaccount',
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create customer");
|
||||
($customer_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($customer_id, "got customer_id") || die "we don't continue here";
|
||||
|
||||
diag("customer id: $customer_id");
|
||||
}
|
||||
|
||||
my ($sub1_id, $sub1_name, $sub2_id, $sub2_name);
|
||||
{
|
||||
$sub1_name = 'rtcsub' .int(rand(1000));
|
||||
$sub2_name = 'rtcsub' .int(rand(1000));
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/subscribers/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
customer_id => $customer_id,
|
||||
domain_id => $domain_id,
|
||||
username => $sub1_name,
|
||||
password => $sub1_name,
|
||||
webusername => $sub1_name,
|
||||
webpassword => $sub1_name,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create subscriber 1");
|
||||
($sub1_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($sub1_id, "got sub1_id") || die "we don't continue here";
|
||||
|
||||
$req = HTTP::Request->new('PATCH', $uri."/api/subscriberpreferences/$sub1_id");
|
||||
$req->header('Content-Type' => 'application/json-patch+json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json([
|
||||
{op => 'add', path => '/use_rtpproxy', value => 'never'},
|
||||
]));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "PATCH set subscriberpreferences sub1");
|
||||
|
||||
diag("subscriber $sub1_name\@$domain_name (pass: $sub1_name, id: $sub1_id)");
|
||||
|
||||
$req = HTTP::Request->new('POST', $uri.'/api/subscribers/');
|
||||
$req->header('Content-Type' => 'application/json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json({
|
||||
customer_id => $customer_id,
|
||||
domain_id => $domain_id,
|
||||
username => $sub2_name,
|
||||
password => $sub2_name,
|
||||
webusername => $sub2_name,
|
||||
webpassword => $sub2_name,
|
||||
}));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 201, "POST create subscriber 2");
|
||||
($sub2_id) = $res->header('Location') =~ m!/(\d+)$!;
|
||||
ok($sub2_id, "got sub2_id") || die "we don't continue here";
|
||||
|
||||
$req = HTTP::Request->new('PATCH', $uri."/api/subscriberpreferences/$sub2_id");
|
||||
$req->header('Content-Type' => 'application/json-patch+json');
|
||||
$req->header('Prefer' => 'return=representation');
|
||||
$req->content(JSON::to_json([
|
||||
{op => 'add', path => '/use_rtpproxy', value => 'never'},
|
||||
]));
|
||||
$res = $ua->request($req);
|
||||
is($res->code, 200, "PATCH set subscriberpreferences sub2");
|
||||
|
||||
diag("subscriber $sub2_name\@$domain_name (pass: $sub2_name, id: $sub2_id)");
|
||||
diag("you can now create new session using:");
|
||||
my $noport_uri = ($uri =~ s/:[0-9]+//r);
|
||||
diag(" curl -XPOST -v -k --user $sub1_name\@$domain_name:$sub1_name -H'Content-Type: application/json' $noport_uri/api/rtcsessions/ --data-binary '{}'");
|
||||
diag(" curl -XPOST -v -k --user $sub2_name\@$domain_name:$sub2_name -H'Content-Type: application/json' $noport_uri/api/rtcsessions/ --data-binary '{}'");
|
||||
}
|
||||
|
||||
done_testing;
|
@ -1,91 +0,0 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Test::More;
|
||||
use Test::Collection;
|
||||
use Test::FakeData;
|
||||
use Data::Dumper;
|
||||
|
||||
|
||||
unless ($ENV{TEST_RTC}) {
|
||||
plan skip_all => "not testing rtc, enable TEST_RTC=yes to run tests";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $fake_data = Test::FakeData->new;
|
||||
$fake_data->set_data_from_script({
|
||||
'resellers' => {
|
||||
'data' => {
|
||||
name => "apitest reseller name " . time(),
|
||||
contract_id => sub { return shift->create('contracts', @_); },
|
||||
status => 'active',
|
||||
enable_rtc => 1, # JSON::false
|
||||
rtc_networks => ['sip', 'xmpp', 'sipwise'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
my $test_machine = Test::Collection->new(
|
||||
name => 'resellers',
|
||||
embedded_resources => [qw/resellers/],
|
||||
);
|
||||
$test_machine->methods->{collection}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS)};
|
||||
$test_machine->methods->{item}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS PUT PATCH DELETE)};
|
||||
# store some basic reseller data, to run tests with
|
||||
$test_machine->DATA_ITEM_STORE($fake_data->process('resellers'));
|
||||
$test_machine->form_data_item( );
|
||||
|
||||
my $reseller_id;
|
||||
|
||||
# test reseller API
|
||||
{
|
||||
my ($res, $content) = $test_machine->check_item_get('/api/resellers/?page=1&rows=10', "fetch resellers collection");
|
||||
my $req;
|
||||
($res, $content, $req) = $test_machine->check_item_post();
|
||||
is($res->code, 201, 'create test reseller successful');
|
||||
#my $reseller_id = $test_machine->get_id_from_created($res);
|
||||
($reseller_id) = $res->header('Location') =~ m/(\d+)$/;
|
||||
|
||||
cmp_ok($reseller_id, '>', 0, 'got valid reseller id');
|
||||
($res, $content) = $test_machine->check_item_get("/api/resellers/$reseller_id/", "fetch created reseller");
|
||||
is($res->code, 200, 'reseller successfully retrieved');
|
||||
ok($content->{enable_rtc}, 'rtc is enabled on created reseller');
|
||||
}
|
||||
|
||||
# test rtcnetworks API
|
||||
{
|
||||
my ($res, $content) = $test_machine->check_item_get("/api/rtcnetworks/$reseller_id", "fetch rtcnetwork");
|
||||
is($res->code, 200, 'rtcnetwork successfully retrieved');
|
||||
isa_ok($content->{networks}, 'ARRAY', 'networks arrayref exists');
|
||||
is(scalar(@{ $content->{networks} }), 3, 'should contain the 3 precreated networks');
|
||||
is($content->{networks}[0]{connector}, 'sip-connector', 'First network is of "sip-connector"');
|
||||
|
||||
($res, $content) = $test_machine->request_patch(
|
||||
[
|
||||
{ op => 'remove', path => '/networks/2'},
|
||||
{ op => 'replace', path => '/networks/1/connector', value => 'webrtc'},
|
||||
],
|
||||
"/api/rtcnetworks/$reseller_id/",
|
||||
);
|
||||
is($res->code, 200, 'PATCH operation on rtcnetworks item');
|
||||
isa_ok($content->{networks}, 'ARRAY', 'networks arrayref exists');
|
||||
is(scalar(@{ $content->{networks} }), 2, 'should be left with 2 networks');
|
||||
is($content->{networks}[1]{connector}, 'webrtc', 'Changed one network to "webrtc"');
|
||||
}
|
||||
|
||||
{
|
||||
my ($res, $content, $req) = $test_machine->request_patch(
|
||||
[
|
||||
{ op => 'replace', path => '/status', value => 'terminated' },
|
||||
],
|
||||
"/api/resellers/$reseller_id/",
|
||||
);
|
||||
is($res->code, 200, 'terminate reseller successful');
|
||||
}
|
||||
$test_machine->clear_test_data_all();
|
||||
|
||||
done_testing;
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
Loading…
Reference in new issue