diff --git a/debian/control b/debian/control
index 315ac70324..5d72102584 100644
--- a/debian/control
+++ b/debian/control
@@ -42,6 +42,7 @@ Depends: gettext,
libemail-sender-perl,
libemail-valid-perl,
libfcgi-procmanager-perl,
+ libfile-fnmatch-perl,
libfile-slurp-perl,
libfile-slurp-unicode-perl,
libfile-spec-perl (>= 3.4000~) | perl-base (>= 5.20.0-60~),
@@ -89,6 +90,7 @@ Depends: gettext,
libtext-csv-xs-perl,
libtext-glob-perl,
libtext-table-perl,
+ libtime-period-perl,
libtime-warp-perl,
libtypes-path-tiny-perl,
liburi-encode-perl,
diff --git a/lib/NGCP/Panel/Controller/API/CFMappings.pm b/lib/NGCP/Panel/Controller/API/CFMappings.pm
index f2fa968c00..63faf069ee 100644
--- a/lib/NGCP/Panel/Controller/API/CFMappings.pm
+++ b/lib/NGCP/Panel/Controller/API/CFMappings.pm
@@ -20,7 +20,7 @@ sub allowed_methods{
}
sub api_description {
- return 'Specifies callforward mappings of a subscriber, where multiple mappings can be specified per type (cfu, cfb, cft cfna) ' .
+ return 'Specifies callforward mappings of a subscriber, where multiple mappings can be specified per type (cfu, cfb, cft, cfna, cfs) ' .
'Each mapping consists of a destinationset name (see CFDestinationSets), a timeset name ' .
'(see CFTimeSets) and a sourceset name (see CFSourceSets).';
}
@@ -41,6 +41,7 @@ sub documentation_sample {
cft => [],
cft_ringtimeout => "200",
cfu => [],
+ cfs => [],
} ;
}
diff --git a/lib/NGCP/Panel/Controller/API/CallForwards.pm b/lib/NGCP/Panel/Controller/API/CallForwards.pm
index 7481c5a708..8286626d73 100644
--- a/lib/NGCP/Panel/Controller/API/CallForwards.pm
+++ b/lib/NGCP/Panel/Controller/API/CallForwards.pm
@@ -23,7 +23,7 @@ sub allowed_methods{
sub api_description {
return 'Specifies basic callforwards of a subscriber, where a number of destinations, times and sources ' .
- ' can be specified for each type (cfu, cfb, cft cfna). For more complex configurations with ' .
+ ' can be specified for each type (cfu, cfb, cft, cfna, cfs). For more complex configurations with ' .
' multiple combinations of Timesets, Destinationsets and SourceSets see CFMappings.';
};
@@ -45,6 +45,7 @@ sub documentation_sample {
cfna => {},
cft => { "ringtimeout" => "199" },
cfu => {},
+ cfs => {},
};
}
diff --git a/lib/NGCP/Panel/Controller/API/CallLists.pm b/lib/NGCP/Panel/Controller/API/CallLists.pm
index 80feb1231d..a2c0f6b0bc 100644
--- a/lib/NGCP/Panel/Controller/API/CallLists.pm
+++ b/lib/NGCP/Panel/Controller/API/CallLists.pm
@@ -127,7 +127,7 @@ sub query_params {
},
{
param => 'type',
- description => 'Filter for calls with a specific type. One of "call", "cfu", "cfb", "cft", "cfna".',
+ description => 'Filter for calls with a specific type. One of "call", "cfu", "cfb", "cft", "cfna", "cfs".',
query => {
first => sub {
my $q = shift;
@@ -140,7 +140,7 @@ sub query_params {
},
{
param => 'type_ne',
- description => 'Filter for calls not having a specific type. One of "call", "cfu", "cfb", "cft", "cfna".',
+ description => 'Filter for calls not having a specific type. One of "call", "cfu", "cfb", "cft", "cfna", "cfs".',
query => {
first => sub {
my $q = shift;
diff --git a/lib/NGCP/Panel/Controller/API/SMS.pm b/lib/NGCP/Panel/Controller/API/SMS.pm
index 58e3742b6a..81af468ad3 100644
--- a/lib/NGCP/Panel/Controller/API/SMS.pm
+++ b/lib/NGCP/Panel/Controller/API/SMS.pm
@@ -82,11 +82,11 @@ sub query_params {
},
{
param => 'direction',
- description => 'Filter for messages sent ("out") or received ("in").',
+ description => 'Filter for messages sent ("out"), received ("in") or forwarded ("forward").',
query => {
first => sub {
my $q = shift;
- if ($q eq "out" || $q eq "in") {
+ if ($q eq "out" || $q eq "in" || $q eq "forward") {
return { "me.direction" => $q };
} else {
return {},
diff --git a/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm b/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm
index 1a0226c4a5..5c014d0a63 100644
--- a/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm
+++ b/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm
@@ -223,7 +223,7 @@ sub POST :Allow {
expose_to_customer => 1,
},
{
- attribute => { -in => [qw/cfu cft cfna cfb/] },
+ attribute => { -in => [qw/cfu cft cfna cfb cfs/] },
},
],
});
diff --git a/lib/NGCP/Panel/Controller/InternalSms.pm b/lib/NGCP/Panel/Controller/InternalSms.pm
index 2c93d700df..5701815ff9 100644
--- a/lib/NGCP/Panel/Controller/InternalSms.pm
+++ b/lib/NGCP/Panel/Controller/InternalSms.pm
@@ -2,8 +2,9 @@ package NGCP::Panel::Controller::InternalSms;
use NGCP::Panel::Utils::Generic qw(:all);
use Sipwise::Base;
-
use parent 'Catalyst::Controller';
+use Time::Period;
+use File::FnMatch qw(:fnmatch);
#sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) {
sub auto {
@@ -38,6 +39,7 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
$to =~ s/^\+//;
$from =~ s/^\+//;
+ my $now = time;
try {
my $schema = $c->model('DB');
@@ -62,6 +64,101 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
callee => $to,
text => $text,
});
+
+ # check for cfs
+
+ my $cf_maps = $c->model('DB')->resultset('voip_cf_mappings')->search({
+ subscriber_id => $prov_dbalias->subscriber_id,
+ type => 'cfs'
+ });
+ unless($cf_maps->count) {
+ $c->log->info("No cfs for inbound sms from $from to $to found.");
+ last;
+ }
+
+ my $dset;
+ foreach my $map($cf_maps->all) {
+ # check source set
+ my $source_pass = 1;
+ if($map->source_set) {
+ $source_pass = 0;
+ foreach my $source($map->source_set->voip_cf_sources->all) {
+ $c->log->info(">>>> checking $from against ".$source->source);
+ if(fnmatch($source->source, $from)) {
+ $c->log->info(">>>> matched $from against ".$source->source.", pass");
+ $source_pass = 1;
+ last;
+ }
+ }
+ }
+ if($source_pass) {
+ $c->log->info(">>>> source check for $from passed, continue with time check");
+ } else {
+ $c->log->info(">>>> source check for $from failed, trying next map entry");
+ next;
+ }
+
+ my $time_pass = 1;
+ if($map->time_set) {
+ $time_pass = 0;
+ foreach my $time($map->time_set->voip_cf_periods->all) {
+ my $timestring = join(' ',
+ $time->year // '',
+ $time->month // '',
+ $time->mday // '',
+ $time->wday // '',
+ $time->hour // '',
+ $time->minute // ''
+ );
+ $c->log->info(">>>> checking $now against ".$timestring);
+ if(inPeriod($now, $timestring)) {
+ $c->log->info(">>>> matched $now against ".$timestring.", pass");
+ $time_pass = 1;
+ last;
+ }
+ }
+ }
+ if($time_pass) {
+ $c->log->info(">>>> time check for $now passed, use destination set");
+ $dset = $map->destination_set;
+ last;
+ } else {
+ $c->log->info(">>>> time check for $now failed, trying next map entry");
+ next;
+ }
+ }
+
+ unless($dset) {
+ $c->log->info(">>>> checks failed, bailing out without forwarding");
+ last;
+ }
+
+ $c->log->info(">>>> proceed sms forwarding");
+
+ unless($dset->voip_cf_destinations->first) {
+ $c->log->info(">>>> detected cf mapping has no destinations in destination set");
+ last;
+ }
+ my $dst = $dset->voip_cf_destinations->first->destination;
+ $dst =~ s/^sip:(.+)\@.+$/$1/;
+ $c->log->info(">>>> forward sms to $dst");
+
+ # feed back into kannel
+ my $error_msg;
+ NGCP::Panel::Utils::SMS::send_sms(
+ c => $c,
+ caller => $to, # use the original to as new from
+ callee => $dst,
+ text => $text,
+ err_code => sub {$error_msg = shift;},
+ );
+ my $fwd_item = $c->model('DB')->resultset('sms_journal')->create({
+ subscriber_id => $prov_dbalias->subscriber_id,
+ direction => "forward",
+ caller => $to,
+ callee => $dst,
+ text => $text,
+ });
});
} catch($e) {
$c->log->error("Failed to store received SMS message.");
diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm
index df6e7cfc8b..31bb4fb43c 100644
--- a/lib/NGCP/Panel/Controller/Subscriber.pm
+++ b/lib/NGCP/Panel/Controller/Subscriber.pm
@@ -624,7 +624,7 @@ sub preferences :Chained('base') :PathPart('preferences') :Args(0) {
my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber;
my $cfs = {};
- foreach my $type(qw/cfu cfna cft cfb/) {
+ foreach my $type(qw/cfu cfna cft cfb cfs/) {
my $maps = $prov_subscriber->voip_cf_mappings
->search({ type => $type });
$cfs->{$type} = [];
@@ -695,7 +695,7 @@ sub preferences :Chained('base') :PathPart('preferences') :Args(0) {
$c->stash->{pref_groups} = \@newprefgroups;
my $special_prefs = { check => 1 };
- foreach my $pref(qw/cfu cft cfna cfb
+ foreach my $pref(qw/cfu cft cfna cfb cfs
speed_dial reminder auto_attendant
voice_mail fax_server/) {
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
@@ -839,6 +839,10 @@ sub preferences_callforward :Chained('base') :PathPart('preferences/callforward'
$cf_desc = $c->loc('Call Forward Unavailable');
last SWITCH;
};
+ /^cfs$/ && do {
+ $cf_desc = $c->loc('Call Forward SMS');
+ last SWITCH;
+ };
# default
NGCP::Panel::Utils::Message::error(
c => $c,
@@ -1096,6 +1100,10 @@ sub preferences_callforward_advanced :Chained('base') :PathPart('preferences/cal
$cf_desc = $c->loc('Call Forward Unavailable');
last SWITCH;
};
+ /^cfs$/ && do {
+ $cf_desc = $c->loc('Call Forward SMS');
+ last SWITCH;
+ };
# default
NGCP::Panel::Utils::Message::error(
c => $c,
@@ -2620,7 +2628,7 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet
if(keys %old_profile_attributes) {
my $cfs = $c->model('DB')->resultset('voip_preferences')->search({
id => { -in => [ keys %old_profile_attributes ] },
- attribute => { -in => [qw/cfu cfb cft cfna/] },
+ attribute => { -in => [qw/cfu cfb cft cfna cfs/] },
});
$prov_subscriber->voip_usr_preferences->search({
attribute_id => { -in => [ keys %old_profile_attributes ] },
diff --git a/lib/NGCP/Panel/Controller/SubscriberProfile.pm b/lib/NGCP/Panel/Controller/SubscriberProfile.pm
index c7f8d204d8..ce382b2800 100644
--- a/lib/NGCP/Panel/Controller/SubscriberProfile.pm
+++ b/lib/NGCP/Panel/Controller/SubscriberProfile.pm
@@ -517,7 +517,7 @@ sub profile_edit :Chained('profile_base') :PathPart('edit') :Does(ACL) :ACLDetac
if(keys %old_attributes) {
my $cfs = $c->model('DB')->resultset('voip_preferences')->search({
id => { -in => [ keys %old_attributes ] },
- attribute => { -in => [qw/cfu cfb cft cfna/] },
+ attribute => { -in => [qw/cfu cfb cft cfna cfs/] },
});
my @subs = $c->model('DB')->resultset('provisioning_voip_subscribers')
->search({
diff --git a/lib/NGCP/Panel/Form/CFMappingsAPI.pm b/lib/NGCP/Panel/Form/CFMappingsAPI.pm
index 49474f41fa..47243f374c 100644
--- a/lib/NGCP/Panel/Form/CFMappingsAPI.pm
+++ b/lib/NGCP/Panel/Form/CFMappingsAPI.pm
@@ -64,6 +64,19 @@ has_field 'cfna' => (
},
);
+has_field 'cfs' => (
+ type => 'Repeatable',
+ do_wrapper => 1,
+ do_label => 0,
+ required => 0,
+ element_attr => {
+ rel => ['tooltip'],
+ title => ['Call Forward SMS, Number of Objects, each containing the keys ' .
+ '"destinationset", "timeset" and "sourceset". The values must be the name of ' .
+ 'a corresponding set which belongs to the same subscriber.'],
+ },
+);
+
has_field 'cfu.destinationset' => (
type => 'Text',
do_wrapper => 1,
@@ -136,6 +149,24 @@ has_field 'cfna.sourceset' => (
do_label => 0,
);
+has_field 'cfs.destinationset' => (
+ type => 'Text',
+ do_wrapper => 1,
+ do_label => 0,
+);
+
+has_field 'cfs.timeset' => (
+ type => 'Text',
+ do_wrapper => 1,
+ do_label => 0,
+);
+
+has_field 'cfs.sourceset' => (
+ type => 'Text',
+ do_wrapper => 1,
+ do_label => 0,
+);
+
has_field 'cft_ringtimeout' => (
type => 'PosInteger',
do_wrapper => 1,
@@ -145,7 +176,7 @@ has_field 'cft_ringtimeout' => (
has_block 'fields' => (
tag => 'div',
class => [qw(modal-body)],
- render_list => [qw(cfu cfb cft cfna)],
+ render_list => [qw(cfu cfb cft cfna cfs)],
);
1;
diff --git a/lib/NGCP/Panel/Form/CFSimpleAPI.pm b/lib/NGCP/Panel/Form/CFSimpleAPI.pm
index c5d594dd49..c39e315684 100644
--- a/lib/NGCP/Panel/Form/CFSimpleAPI.pm
+++ b/lib/NGCP/Panel/Form/CFSimpleAPI.pm
@@ -69,6 +69,20 @@ has_field 'cfna' => (
},
);
+has_field 'cfs' => (
+ type => 'Compound',
+ do_wrapper => 1,
+ do_label => 0,
+ required => 0,
+ element_attr => {
+ rel => ['tooltip'],
+ title => ['Call Forward SMS, Contains the keys "destinations", "times" and "sources". "destinations" is an Array of Objects ' .
+ 'having a "destination", "priority" and "timeout" field. "times" is an Array of Objects having the fields ' .
+ '"minute", "hour", "wday", "mday", "month", "year". "times" can be empty, then the CF is applied always. ' .
+ '"sources" is an Array of Objects having one field "source". "sources" can be empty.'],
+ },
+);
+
has_field 'cfu.destinations' => (
type => 'Repeatable',
do_wrapper => 1,
@@ -189,6 +203,36 @@ has_field 'cfna.sources.source' => (
type => 'Text',
);
+has_field 'cfs.destinations' => (
+ type => 'Repeatable',
+ do_wrapper => 1,
+ do_label => 0,
+);
+
+has_field 'cfs.destinations.destination' => (
+ type => 'Text',
+);
+
+has_field 'cfs.destinations.timeout' => (
+ type => 'PosInteger',
+);
+
+has_field 'cfs.times' => (
+ type => 'Repeatable',
+ do_wrapper => 1,
+ do_label => 0,
+);
+
+has_field 'cfs.sources' => (
+ type => 'Repeatable',
+ do_wrapper => 1,
+ do_label => 0,
+);
+
+has_field 'cfs.sources.source' => (
+ type => 'Text',
+);
+
has_field 'cft.ringtimeout' => (
type => 'PosInteger',
do_wrapper => 1,
@@ -198,7 +242,7 @@ has_field 'cft.ringtimeout' => (
has_block 'fields' => (
tag => 'div',
class => [qw(modal-body)],
- render_list => [qw(cfu cfb cft cfna)],
+ render_list => [qw(cfu cfb cft cfna cfs)],
);
1;
diff --git a/lib/NGCP/Panel/Form/Call/Reseller.pm b/lib/NGCP/Panel/Form/Call/Reseller.pm
index 39bfed623c..d43c32e1ea 100644
--- a/lib/NGCP/Panel/Form/Call/Reseller.pm
+++ b/lib/NGCP/Panel/Form/Call/Reseller.pm
@@ -400,10 +400,11 @@ has_field 'call_type' => (
{ label => 'cfb', value => 'cfb' },
{ label => 'cft', value => 'cft' },
{ label => 'cfna', value => 'cfna' },
+ { label => 'cfs', value => 'cfs' },
],
element_attr => {
rel => ['tooltip'],
- title => ['The type of call, one of call, cfu, cfb, cft, cfna.']
+ title => ['The type of call, one of call, cfu, cfb, cft, cfna, cfs.']
},
);
diff --git a/lib/NGCP/Panel/Form/CallList/Subscriber.pm b/lib/NGCP/Panel/Form/CallList/Subscriber.pm
index 8df3017025..209c62eef1 100644
--- a/lib/NGCP/Panel/Form/CallList/Subscriber.pm
+++ b/lib/NGCP/Panel/Form/CallList/Subscriber.pm
@@ -80,10 +80,11 @@ has_field 'type' => (
{ label => 'cfb', value => 'cfb' },
{ label => 'cft', value => 'cft' },
{ label => 'cfna', value => 'cfna' },
+ { label => 'cfs', value => 'cfs' },
],
element_attr => {
rel => ['tooltip'],
- title => ['The type of call, one of call, cfu, cfb, cft, cfna.']
+ title => ['The type of call, one of call, cfu, cfb, cft, cfna, cfs.']
},
);
diff --git a/lib/NGCP/Panel/Form/SMSAPI.pm b/lib/NGCP/Panel/Form/SMSAPI.pm
index 0571bb0789..179288fa07 100644
--- a/lib/NGCP/Panel/Form/SMSAPI.pm
+++ b/lib/NGCP/Panel/Form/SMSAPI.pm
@@ -33,12 +33,13 @@ has_field 'direction' => (
options => [
{ value => 'in', label => 'inbound' },
{ value => 'out', label => 'outbound' },
+ { value => 'forward', label => 'forwarded' },
],
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'],
+ title => ['Whether the logged message is sent, received or forwarded'],
},
);
diff --git a/lib/NGCP/Panel/Form/SubscriberProfile/Profile.pm b/lib/NGCP/Panel/Form/SubscriberProfile/Profile.pm
index 532d5c5247..543bab7522 100644
--- a/lib/NGCP/Panel/Form/SubscriberProfile/Profile.pm
+++ b/lib/NGCP/Panel/Form/SubscriberProfile/Profile.pm
@@ -76,7 +76,7 @@ sub field_list {
expose_to_customer => 1,
},
{
- attribute => { -in => [qw/cfu cft cfna cfb/] },
+ attribute => { -in => [qw/cfu cft cfna cfb cfs/] },
}
],
});
diff --git a/lib/NGCP/Panel/Role/API/CFMappings.pm b/lib/NGCP/Panel/Role/API/CFMappings.pm
index 9bc7c5f66f..a16ca26d41 100644
--- a/lib/NGCP/Panel/Role/API/CFMappings.pm
+++ b/lib/NGCP/Panel/Role/API/CFMappings.pm
@@ -24,7 +24,7 @@ sub hal_from_item {
my ($self, $c, $item, $type) = @_;
my $form;
- my $resource = { subscriber_id => $item->id, cfu => [], cfb => [], cfna => [], cft => [], };
+ my $resource = { subscriber_id => $item->id, cfu => [], cfb => [], cfna => [], cft => [], cfs => []};
my $b_subs_id = $item->id;
my $p_subs_id = $item->provisioning_voip_subscriber->id;
@@ -125,7 +125,7 @@ sub update_item {
my $tsets_rs = $c->model('DB')->resultset('voip_cf_time_sets');
my $ssets_rs = $c->model('DB')->resultset('voip_cf_source_sets');
- for my $type ( qw/cfu cfb cft cfna/) {
+ for my $type ( qw/cfu cfb cft cfna cfs/) {
if (ref $resource->{$type} ne "ARRAY") {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field '$type'. Must be an array.");
return;
@@ -174,7 +174,7 @@ sub update_item {
$autoattendant_count += NGCP::Panel::Utils::Subscriber::check_dset_autoattendant_status($map->destination_set);
}
$mappings_rs->delete;
- for my $type ( qw/cfu cfb cft cfna/) {
+ for my $type ( qw/cfu cfb cft cfna cfs/) {
$cf_preferences{$type}->delete;
}
for my $mapping ( @new_mappings ) {
diff --git a/lib/NGCP/Panel/Role/API/CallForwards.pm b/lib/NGCP/Panel/Role/API/CallForwards.pm
index f3a3e68261..b2f34ee617 100644
--- a/lib/NGCP/Panel/Role/API/CallForwards.pm
+++ b/lib/NGCP/Panel/Role/API/CallForwards.pm
@@ -46,7 +46,7 @@ sub hal_from_item {
],
relation => 'ngcp:'.$self->resource_name,
);
- @resource{qw/cfu cfb cft cfna/} = ({}) x 4;
+ @resource{qw/cfu cfb cft cfna cfs/} = ({}) x 5;
for my $item_cf ($item->provisioning_voip_subscriber->voip_cf_mappings->all) {
$resource{$item_cf->type} = $self->_contents_from_cfm($c, $item_cf, $item);
}
@@ -111,7 +111,7 @@ sub update_item {
run => 1,
);
- for my $type (qw/cfu cfb cft cfna/) {
+ for my $type (qw/cfu cfb cft cfna cfs/) {
next unless "ARRAY" eq ref $resource->{$type}{destinations};
for my $d (@{ $resource->{$type}{destinations} }) {
if (exists $d->{timeout} && ! is_int($d->{timeout})) {
@@ -122,7 +122,7 @@ sub update_item {
}
}
- for my $type (qw/cfu cfb cft cfna/) {
+ for my $type (qw/cfu cfb cft cfna cfs/) {
my $mapping = $c->model('DB')->resultset('voip_cf_mappings')->search_rs({
subscriber_id => $prov_subscriber_id,
type => $type,
diff --git a/lib/NGCP/Panel/Role/API/SubscriberProfiles.pm b/lib/NGCP/Panel/Role/API/SubscriberProfiles.pm
index a78de62f28..5e02263698 100644
--- a/lib/NGCP/Panel/Role/API/SubscriberProfiles.pm
+++ b/lib/NGCP/Panel/Role/API/SubscriberProfiles.pm
@@ -157,7 +157,7 @@ sub update_item {
expose_to_customer => 1,
},
{
- attribute => { -in => [qw/cfu cft cfna cfb/] },
+ attribute => { -in => [qw/cfu cft cfna cfb cfs/] },
},
],
});
@@ -175,7 +175,7 @@ sub update_item {
if(keys %old_attributes) {
my $cfs = $c->model('DB')->resultset('voip_preferences')->search({
id => { -in => [ keys %old_attributes ] },
- attribute => { -in => [qw/cfu cfb cft cfna/] },
+ attribute => { -in => [qw/cfu cfb cft cfna cfs/] },
});
my @subs = $c->model('DB')->resultset('provisioning_voip_subscribers')
->search({
diff --git a/lib/NGCP/Panel/Role/API/Subscribers.pm b/lib/NGCP/Panel/Role/API/Subscribers.pm
index 97471c347e..c012506a75 100644
--- a/lib/NGCP/Panel/Role/API/Subscribers.pm
+++ b/lib/NGCP/Panel/Role/API/Subscribers.pm
@@ -582,7 +582,7 @@ sub update_item {
if(keys %old_profile_attributes) {
my $cfs = $schema->resultset('voip_preferences')->search({
id => { -in => [ keys %old_profile_attributes ] },
- attribute => { -in => [qw/cfu cfb cft cfna/] },
+ attribute => { -in => [qw/cfu cfb cft cfna cfs/] },
});
$prov_subscriber->voip_usr_preferences->search({
attribute_id => { -in => [ keys %old_profile_attributes ] },
diff --git a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm
index e4540f692a..1c3697264a 100644
--- a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm
+++ b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm
@@ -299,7 +299,7 @@ sub get_dummy_data {
start_time => time,
source_customer_cost => int(rand(100000)),
duration => int(rand(7200)) + 10,
- call_type => (qw/cfu cfb cft cfna/)[int(rand 4)],
+ call_type => (qw/cfu cfb cft cfna cfs/)[int(rand 4)],
zone => "Zone $_",
zone_detail => "Detail $_",
}}(1 .. 50)
diff --git a/lib/NGCP/Panel/Widget/Dashboard/SubscriberCFOverview.pm b/lib/NGCP/Panel/Widget/Dashboard/SubscriberCFOverview.pm
index 9349a6b4ac..c1508ae4fb 100644
--- a/lib/NGCP/Panel/Widget/Dashboard/SubscriberCFOverview.pm
+++ b/lib/NGCP/Panel/Widget/Dashboard/SubscriberCFOverview.pm
@@ -21,7 +21,8 @@ sub _get_cf_type_descriptions {
return { cfu => $c->loc("Call Forward Unconditional"),
cfb => $c->loc("Call Forward Busy"),
cft => $c->loc("Call Forward Timeout"),
- cfna => $c->loc("Call Forward Unavailable") };
+ cfna => $c->loc("Call Forward Unavailable"),
+ cfs => $c->loc("Call Forward SMS"), };
}
sub cfs {
@@ -31,7 +32,7 @@ sub cfs {
my $cfs = {};
my $descriptions = $self->_get_cf_type_descriptions($c);
- foreach my $type (qw/cfu cfna cft cfb/) {
+ foreach my $type (qw/cfu cfna cft cfb cfs/) {
my $maps = $prov_subscriber->voip_cf_mappings
->search({ type => $type });
my @mappings = ();
diff --git a/sandbox/callforwards.pl b/sandbox/callforwards.pl
index 68cb26c22c..6f9bdb9f1a 100644
--- a/sandbox/callforwards.pl
+++ b/sandbox/callforwards.pl
@@ -43,7 +43,7 @@ for my $item ($item_rs->all) {
# print Dumper({$item->get_inflated_columns});
my %resource = ();
my $prov_subs = $item->provisioning_voip_subscriber;
- for my $cf_type (qw/cfu cfb cft cfna/) {
+ for my $cf_type (qw/cfu cfb cft cfna cfs/) {
my $mapping = $schema->resultset('voip_cf_mappings')->search({
subscriber_id => $prov_subs->id,
type => $cf_type,
@@ -73,7 +73,7 @@ $time = time();
for my $item ($item_rs->all) {
my %resource = ();
my $prov_subs = $item->provisioning_voip_subscriber;
- @resource{qw/cfu cfb cft cfna/} = ({}) x 4;
+ @resource{qw/cfu cfb cft cfna cfs/} = ({}) x 5;
for my $item_cf ($item->provisioning_voip_subscriber->voip_cf_mappings->all){
$resource{$item_cf->type} = _contents_from_cfm($item_cf, $item);
}
@@ -247,4 +247,4 @@ sub validate_fields {
return 1;
}
-1;
\ No newline at end of file
+1;
diff --git a/share/templates/subscriber/preferences.tt b/share/templates/subscriber/preferences.tt
index bef9b4233b..5a4ffb97bf 100644
--- a/share/templates/subscriber/preferences.tt
+++ b/share/templates/subscriber/preferences.tt
@@ -77,7 +77,8 @@
[% FOR cf IN [ { type = "cfu", desc = c.loc("Call Forward Unconditional") },
{ type = "cfb", desc = c.loc("Call Forward Busy") },
{ type = "cft", desc = c.loc("Call Forward Timeout") },
- { type = "cfna", desc = c.loc("Call Forward Unavailable") } ] -%]
+ { type = "cfna", desc = c.loc("Call Forward Unavailable") },
+ { type = "cfs", desc = c.loc("Call Forward SMS") } ] -%]
[% IF c.user.roles == "subscriber" || c.user.roles == "subscriberadmin" -%]
[% NEXT IF special_prefs.check && !special_prefs.callforward.${cf.type} -%]
[% END -%]
diff --git a/t/api-rest/api-callforwards.t b/t/api-rest/api-callforwards.t
index d36959a03b..1cc1da159b 100644
--- a/t/api-rest/api-callforwards.t
+++ b/t/api-rest/api-callforwards.t
@@ -89,6 +89,7 @@ SKIP:{
ok(exists $cf1single->{cfb}, "cf should have key cfb");
ok(exists $cf1single->{cft}, "cf should have key cft");
ok(exists $cf1single->{cfna}, "cf should have key cfna");
+ ok(exists $cf1single->{cfs}, "cf should have key cfs");
#write cf and check written values
my($cf1_put,$cf1_get) = $test_machine->check_put2get({data_in => $test_machine->DATA_ITEM, uri => $cf1single_uri},undef, 1 );
diff --git a/t/api-rest/api-journals.t b/t/api-rest/api-journals.t
index 442bc05353..06435c3b96 100644
--- a/t/api-rest/api-journals.t
+++ b/t/api-rest/api-journals.t
@@ -891,6 +891,8 @@ sub test_callforwards {
times => $cftimeset->{times}},
cfu => { destinations => $cfdestinationset->{destinations},
times => $cftimeset->{times}},
+ cfs => { destinations => $cfdestinationset->{destinations},
+ times => $cftimeset->{times}},
}));
$res = $ua->request($req);
is($res->code, 200, _get_request_test_message("PUT test callforwards"));
@@ -952,6 +954,8 @@ sub test_cfmapping {
timeset => $cftimeset->{name}}],
cfu => [{ destinationset => $cfdestinationset->{name},
timeset => $cftimeset->{name}}],
+ cfs => [{ destinationset => $cfdestinationset->{name},
+ timeset => $cftimeset->{name}}],
}));
$res = $ua->request($req);
is($res->code, 200, _get_request_test_message("PUT test cfmappings"));