Change-Id: Ia1e09771bc14cd9e8f240de5b86f17563525a565changes/28/9228/4
parent
786d934459
commit
de239d60eb
@ -0,0 +1,51 @@
|
||||
package NGCP::Panel::Controller::API::SMS;
|
||||
|
||||
use Sipwise::Base;
|
||||
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::SMS/;
|
||||
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
|
||||
__PACKAGE__->set_config();
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET POST OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
sub api_description {
|
||||
return 'Shows a journal of sent and received messages. New messages can be sent by issuing a POST request to the api collection.';
|
||||
}
|
||||
|
||||
# sub query_params {
|
||||
# return [
|
||||
# ];
|
||||
# }
|
||||
|
||||
sub create_item {
|
||||
my ($self, $c, $resource, $form, $process_extras) = @_;
|
||||
|
||||
my $error_msg = "";
|
||||
|
||||
NGCP::Panel::Utils::SMS::send_sms(
|
||||
c => $c,
|
||||
caller => $resource->{caller},
|
||||
callee => $resource->{callee},
|
||||
text => $resource->{text},
|
||||
err_code => sub {$error_msg = shift;},
|
||||
);
|
||||
|
||||
my $rs = $self->item_rs($c);
|
||||
my $item = $rs->create({
|
||||
subscriber_id => $resource->{subscriber_id},
|
||||
direction => 'out',
|
||||
caller => $resource->{caller},
|
||||
callee => $resource->{callee},
|
||||
text => $resource->{text},
|
||||
$error_msg ? (status => $error_msg) : (),
|
||||
});
|
||||
return $item;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,19 @@
|
||||
package NGCP::Panel::Controller::API::SMSItem;
|
||||
|
||||
use Sipwise::Base;
|
||||
use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::SMS/;
|
||||
|
||||
use HTTP::Status qw(:constants);
|
||||
|
||||
|
||||
__PACKAGE__->set_config();
|
||||
|
||||
sub allowed_methods{
|
||||
return [qw/GET OPTIONS HEAD/];
|
||||
}
|
||||
|
||||
use parent qw/Catalyst::Controller NGCP::Panel::Role::API::CFSourceSets/;
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,114 @@
|
||||
package NGCP::Panel::Form::SMSAPI;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
use NGCP::Panel::Field::BillingZone;
|
||||
|
||||
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 'id' => (
|
||||
type => 'Hidden',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The internal id in the sms journal'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'subscriber_id' => (
|
||||
type => 'PosInteger',
|
||||
required => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The subscriber id this journal entry belongs to'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'direction' => (
|
||||
type => 'Select',
|
||||
options => [
|
||||
{ value => 'in', label => 'inbound' },
|
||||
{ value => 'out', label => 'outbound' },
|
||||
],
|
||||
default => 'out', # FYI, default is not considered with API
|
||||
required => 0, # should be "1" actually, see above
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Whether the logged message is sent or received'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'caller' => (
|
||||
type => 'Text',
|
||||
required => 0,
|
||||
maxlength => 255,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Our CLI in case of sent messages. Must be valid according to the preferences allowed_clis, user_cli, cli'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'callee' => (
|
||||
type => 'Text',
|
||||
required => 1,
|
||||
maxlength => 255,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['A valid CLI in the E164 format'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'text' => (
|
||||
type => 'Text',
|
||||
required => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The content of the message'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'status' => (
|
||||
type => 'Text', # Readonly
|
||||
required => 0,
|
||||
maxlength => 255,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Whether the message has been sent successfully'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'reason' => (
|
||||
type => 'Text', # Readonly
|
||||
required => 0,
|
||||
maxlength => 255,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['An error message in case of a failed transmission'],
|
||||
},
|
||||
);
|
||||
|
||||
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/id subscriber_id direction caller callee text status reason/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,92 @@
|
||||
package NGCP::Panel::Role::API::SMS;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
|
||||
use Sipwise::Base;
|
||||
|
||||
use parent 'NGCP::Panel::Role::API';
|
||||
|
||||
|
||||
use Data::HAL::Link qw();
|
||||
use HTTP::Status qw(:constants);
|
||||
use NGCP::Panel::Utils::SMS;
|
||||
use NGCP::Panel::Form::SMSAPI;
|
||||
|
||||
sub item_name {
|
||||
return 'sms';
|
||||
}
|
||||
|
||||
sub resource_name{
|
||||
return 'sms';
|
||||
}
|
||||
|
||||
sub get_form {
|
||||
my ($self, $c) = @_;
|
||||
return (NGCP::Panel::Form::SMSAPI->new, ['subscriber_id']);
|
||||
}
|
||||
|
||||
sub hal_links {
|
||||
my($self, $c, $item, $resource, $form) = @_;
|
||||
my $b_subs_id = $item->provisioning_voip_subscriber->voip_subscriber->id;
|
||||
return [
|
||||
Data::HAL::Link->new(relation => "ngcp:subscribers", href => sprintf("/api/subscribers/%d", $b_subs_id)),
|
||||
];
|
||||
}
|
||||
|
||||
sub _item_rs {
|
||||
my ($self, $c) = @_;
|
||||
my $item_rs;
|
||||
|
||||
if($c->user->roles eq "admin") {
|
||||
$item_rs = $c->model('DB')->resultset('sms_journal');
|
||||
} elsif ($c->user->roles eq "reseller") {
|
||||
my $reseller_id = $c->user->reseller_id;
|
||||
$item_rs = $c->model('DB')->resultset('sms_journal')
|
||||
->search_rs({
|
||||
'reseller_id' => $reseller_id,
|
||||
} , {
|
||||
join => { provisioning_voip_subscriber => {'subscriber' => {'contract' => 'contact'} } },
|
||||
});
|
||||
} elsif ($c->user->roles eq 'subscriber' || $c->user->roles eq 'subscriberadmin') {
|
||||
my $subscriber_uuid = $c->user->uuid;
|
||||
$item_rs = $c->model('DB')->resultset('sms_journal')
|
||||
->search_rs({
|
||||
'provisioning_voip_subscriber.uuid' => $subscriber_uuid,
|
||||
} , {
|
||||
join => 'provisioning_voip_subscriber',
|
||||
});
|
||||
}
|
||||
|
||||
return $item_rs;
|
||||
}
|
||||
|
||||
sub check_resource{
|
||||
my($self, $c, $item, $old_resource, $resource, $form) = @_;
|
||||
|
||||
unless(defined $resource->{subscriber_id}) { # TODO: might check in form
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Missing mandatory field 'subscriber_id'");
|
||||
return;
|
||||
}
|
||||
my $b_subscriber = $c->model('DB')->resultset('voip_subscribers')->find({
|
||||
id => $resource->{subscriber_id},
|
||||
});
|
||||
unless($b_subscriber) {
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'subscriber_id'.");
|
||||
return;
|
||||
}
|
||||
my $subscriber = $b_subscriber->provisioning_voip_subscriber;
|
||||
unless($subscriber) {
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
|
||||
return;
|
||||
}
|
||||
$resource->{subscriber_id} = $subscriber->id;
|
||||
|
||||
return unless NGCP::Panel::Utils::SMS::check_numbers($c, $resource, $subscriber, sub {
|
||||
my ($err) = @_;
|
||||
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, $err);
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,139 @@
|
||||
package NGCP::Panel::Utils::SMS;
|
||||
|
||||
use Sipwise::Base;
|
||||
use LWP::UserAgent;
|
||||
use URI;
|
||||
|
||||
sub send_sms {
|
||||
my (%args) = @_;
|
||||
my $c = $args{c};
|
||||
my $caller = $args{caller};
|
||||
my $callee = $args{callee};
|
||||
my $text = $args{text};
|
||||
my $err_code = $args{err_code};
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return; };
|
||||
}
|
||||
|
||||
my $schema = $c->config->{sms}{schema};
|
||||
my $host = $c->config->{sms}{host};
|
||||
my $port = $c->config->{sms}{port};
|
||||
my $path = $c->config->{sms}{path};
|
||||
my $user = $c->config->{sms}{user};
|
||||
my $pass = $c->config->{sms}{pass};
|
||||
|
||||
my $fullpath = "$schema://$host:$port$path";
|
||||
my $ua = LWP::UserAgent->new(
|
||||
#ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 },
|
||||
timeout => 5,
|
||||
);
|
||||
my $uri = URI->new($fullpath);
|
||||
$uri->query_form(
|
||||
charset => "utf8",
|
||||
coding => "2",
|
||||
user => "$user",
|
||||
pass => "$pass",
|
||||
text => $text,
|
||||
to => $callee,
|
||||
from => $caller,
|
||||
);
|
||||
my $res = $ua->get($uri);
|
||||
if ($res->is_success) {
|
||||
return 1;
|
||||
} else {
|
||||
&{$err_code}("Error with send_sms: " . $res->status_line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# false if error, true if ok
|
||||
# TODOs: normalization?
|
||||
sub check_numbers {
|
||||
my ($c, $resource, $prov_subscriber, $err_code) = @_;
|
||||
|
||||
if (!defined $err_code || ref $err_code ne 'CODE') {
|
||||
$err_code = sub { return; };
|
||||
}
|
||||
|
||||
my $pref_rs_allowed_clis = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
|
||||
c => $c, attribute => "allowed_clis",
|
||||
prov_subscriber => $prov_subscriber,
|
||||
);
|
||||
my @allowed_clis = $pref_rs_allowed_clis->get_column('value')->all;
|
||||
my $pref_rs_user_cli = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
|
||||
c => $c, attribute => "user_cli",
|
||||
prov_subscriber => $prov_subscriber,
|
||||
);
|
||||
my $user_cli = defined $pref_rs_user_cli->first ? $pref_rs_user_cli->first->value : undef;
|
||||
my $pref_rs_cli = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
|
||||
c => $c, attribute => "cli",
|
||||
prov_subscriber => $prov_subscriber,
|
||||
);
|
||||
my $cli = defined $pref_rs_cli->first ? $pref_rs_cli->first->value : undef;
|
||||
|
||||
if ($resource->{caller}) {
|
||||
my $anumber_ok = 0;
|
||||
for my $number (@allowed_clis, $user_cli, $cli) {
|
||||
next unless $number;
|
||||
if ( _glob_matches($number, $resource->{caller}) ) {
|
||||
$anumber_ok = 1;
|
||||
}
|
||||
}
|
||||
unless ($anumber_ok) {
|
||||
return unless &{$err_code}("Invalid 'caller'", 'caller');
|
||||
}
|
||||
} else {
|
||||
if ($user_cli) {
|
||||
$resource->{caller} = $user_cli;
|
||||
} elsif ($cli) {
|
||||
$resource->{caller} = $cli;
|
||||
} else {
|
||||
return unless &{$err_code}("Could not set value for 'caller'", 'caller');
|
||||
}
|
||||
}
|
||||
|
||||
# done setting/checking anumber
|
||||
# checking bnumber
|
||||
for my $adm ('adm_', '') {
|
||||
my $pref_rs_block_out_list = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
|
||||
c => $c, attribute => $adm."block_out_list",
|
||||
prov_subscriber => $prov_subscriber,
|
||||
);
|
||||
my @block_out_list = $pref_rs_block_out_list->all;
|
||||
my $pref_rs_block_out_mode = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
|
||||
c => $c, attribute => $adm."block_out_mode",
|
||||
prov_subscriber => $prov_subscriber,
|
||||
);
|
||||
my $block_out_mode = defined $pref_rs_block_out_mode->first ? $pref_rs_block_out_mode->first->value : undef;
|
||||
|
||||
if ($block_out_mode) { # whitelist
|
||||
my $bnumber_ok = 0;
|
||||
for my $number (@block_out_list) {
|
||||
if (_glob_matches($number->value, $resource->{callee})) {
|
||||
$bnumber_ok = 1;
|
||||
}
|
||||
}
|
||||
unless ($bnumber_ok) {
|
||||
return unless &{$err_code}("Callee Number is not on whitelist for outgoing calls (${adm}block_out_list)", 'callee');
|
||||
}
|
||||
} else { # blacklist
|
||||
for my $number (@block_out_list) {
|
||||
if (_glob_matches($number->value, $resource->{callee})) {
|
||||
return unless &{$err_code}("Callee Number is on blocklist for outgoing calls (${adm}block_out_list)", 'callee');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _glob_matches {
|
||||
my ($glob, $string) = @_;
|
||||
|
||||
use Text::Glob;
|
||||
return !!Text::Glob::match_glob($glob, $string);
|
||||
}
|
||||
|
||||
1;
|
Loading…
Reference in new issue