diff --git a/lib/NGCP/Panel/Controller/API/CFDestinationSets.pm b/lib/NGCP/Panel/Controller/API/CFDestinationSets.pm index 9228b61f02..63d7b9d873 100644 --- a/lib/NGCP/Panel/Controller/API/CFDestinationSets.pm +++ b/lib/NGCP/Panel/Controller/API/CFDestinationSets.pm @@ -197,8 +197,7 @@ sub POST :Allow { if (! exists $resource->{destinations} ) { $resource->{destinations} = []; } - if (ref $resource->{destinations} ne "ARRAY") { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'destinations'. Must be an array."); + if(!$self->check_destinations($c, $resource)){ last; } try { diff --git a/lib/NGCP/Panel/Controller/API/CallForwardsItem.pm b/lib/NGCP/Panel/Controller/API/CallForwardsItem.pm index f8b40c9b80..9c7e304109 100644 --- a/lib/NGCP/Panel/Controller/API/CallForwardsItem.pm +++ b/lib/NGCP/Panel/Controller/API/CallForwardsItem.pm @@ -70,7 +70,7 @@ sub GET :Allow { { last unless $self->valid_id($c, $id); my $item = $self->item_by_id($c, $id); - last unless $self->resource_exists($c, subscriber => $item); + last unless $self->resource_exists($c, 'callforward' => $item); my $hal = $self->hal_from_item($c, $item); diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index b9bc172115..4c644de16b 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -931,7 +931,13 @@ sub preferences_callforward :Chained('base') :PathPart('preferences/callforward' $params = { destination => $c->stash->{cf_tmp_params} }; $params->{destination}{destination} = $d; $params->{ringtimeout} = $ringtimeout; + $params->{destination}->{announcement_id} = $destination ? $destination->announcement_id : ''; } + $c->stash->{custom_announcements_rs} = $c->model('DB')->resultset('voip_sound_handles')->search({ + 'group.name' => 'custom_announcements', + },{ + join => 'group', + }); if($c->config->{features}->{cloudpbx}) { my $pbx_pref = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( @@ -1020,6 +1026,7 @@ sub preferences_callforward :Chained('base') :PathPart('preferences/callforward' destination => $d, timeout => $t, priority => 1, + announcement_id => (('customhours' eq $dest->field('destination')->value) and $dest->field('announcement_id')->value) || undef, }); unless(defined $map) { @@ -1322,6 +1329,11 @@ sub preferences_callforward_destinationset_create :Chained('base') :PathPart('pr $c->stash->{pbx} = 1; } } + $c->stash->{custom_announcements_rs} = $c->model('DB')->resultset('voip_sound_handles')->search({ + 'group.name' => 'custom_announcements', + },{ + join => 'group', + }); my $form = NGCP::Panel::Form::DestinationSet->new(ctx => $c); @@ -1375,6 +1387,7 @@ sub preferences_callforward_destinationset_create :Chained('base') :PathPart('pr destination => $d, timeout => $t, priority => $dest->field('priority')->value, + announcement_id => (('customhours' eq $dest->field('destination')->value) and $dest->field('announcement_id')->value) || undef, }); } } @@ -1462,14 +1475,20 @@ sub preferences_callforward_destinationset_edit :Chained('preferences_callforwar ($d, $duri) = NGCP::Panel::Utils::Subscriber::destination_to_field($d); push @destinations, { - destination => $d, - uri => {timeout => $t, destination => $duri}, - priority => $dest->priority, - id => $dest->id, + destination => $d, + uri => {timeout => $t, destination => $duri}, + priority => $dest->priority, + announcement_id => $dest->announcement_id, + id => $dest->id, }; } $params->{destination} = \@destinations; } + $c->stash->{custom_announcements_rs} = $c->model('DB')->resultset('voip_sound_handles')->search({ + 'group.name' => 'custom_announcements', + },{ + join => 'group', + }); $c->stash->{cf_tmp_params} = $params; my $form = NGCP::Panel::Form::DestinationSet->new(ctx => $c); @@ -1544,6 +1563,7 @@ sub preferences_callforward_destinationset_edit :Chained('preferences_callforwar destination => $d, timeout => $t, priority => $dest->field('priority')->value, + announcement_id => (('customhours' eq $dest->field('destination')->value) and $dest->field('announcement_id')->value) || undef, }); } $set->discard_changes; # reload (destinations may be cached) diff --git a/lib/NGCP/Panel/Form/CFDestinationSetAPI.pm b/lib/NGCP/Panel/Form/CFDestinationSetAPI.pm index 22f82f5a5c..7b8093beda 100644 --- a/lib/NGCP/Panel/Form/CFDestinationSetAPI.pm +++ b/lib/NGCP/Panel/Form/CFDestinationSetAPI.pm @@ -68,6 +68,12 @@ has_field 'destinations.priority' => ( default => 1, ); +has_field 'destinations.announcement_id' => ( + type => '+NGCP::Panel::Field::PosInteger', + label => 'Announcement ID', + default => 1, +); + 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/CFSimpleAPI.pm b/lib/NGCP/Panel/Form/CFSimpleAPI.pm index c39e315684..13fad7e20f 100644 --- a/lib/NGCP/Panel/Form/CFSimpleAPI.pm +++ b/lib/NGCP/Panel/Form/CFSimpleAPI.pm @@ -97,6 +97,10 @@ has_field 'cfu.destinations.timeout' => ( type => 'PosInteger', ); +has_field 'cfu.destinations.announcement_id' => ( + type => 'PosInteger', +); + has_field 'cfu.times' => ( type => 'Repeatable', do_wrapper => 1, @@ -127,6 +131,10 @@ has_field 'cfb.destinations.timeout' => ( type => 'PosInteger', ); +has_field 'cfb.destinations.announcement_id' => ( + type => 'PosInteger', +); + has_field 'cfb.times' => ( type => 'Repeatable', do_wrapper => 1, @@ -163,6 +171,10 @@ has_field 'cft.times' => ( do_label => 0, ); +has_field 'cft.destinations.announcement_id' => ( + type => 'PosInteger', +); + has_field 'cft.sources' => ( type => 'Repeatable', do_wrapper => 1, @@ -187,6 +199,10 @@ has_field 'cfna.destinations.timeout' => ( type => 'PosInteger', ); +has_field 'cfna.destinations.announcement_id' => ( + type => 'PosInteger', +); + has_field 'cfna.times' => ( type => 'Repeatable', do_wrapper => 1, @@ -217,6 +233,10 @@ has_field 'cfs.destinations.timeout' => ( type => 'PosInteger', ); +has_field 'cfs.destinations.announcement_id' => ( + type => 'PosInteger', +); + has_field 'cfs.times' => ( type => 'Repeatable', do_wrapper => 1, diff --git a/lib/NGCP/Panel/Form/DestinationSet.pm b/lib/NGCP/Panel/Form/DestinationSet.pm index 3ac4bab66e..25ce62de46 100644 --- a/lib/NGCP/Panel/Form/DestinationSet.pm +++ b/lib/NGCP/Panel/Form/DestinationSet.pm @@ -102,6 +102,16 @@ has_field 'destination.priority' => ( required => 1, ); +has_field 'destination.announcement_id' => ( + type => 'Select', + #widget => 'RadioGroup', + label => 'Custom announcement', + options_method => \&build_announcements, + wrapper_class => [qw/hfh-rep-field ngcp-destination ngcp-destination-customhours/], + required => 0, +); + + has_field 'destination.rm' => ( type => 'RmElement', value => 'Remove', @@ -155,6 +165,17 @@ sub validate_destination{ } return $result; } +sub build_announcements { + my ($self) = @_; + my @options = (); + my $c = $self->form->ctx; + push @options, { label => 'Select announcement', value => '' }; + foreach($c->stash->{custom_announcements_rs}->all){ + push @options, { label => $_->name, value => $_->id }; + } + return \@options; +} + 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/SubscriberCFSimple.pm b/lib/NGCP/Panel/Form/SubscriberCFSimple.pm index 82a32b26e9..2f17cad082 100644 --- a/lib/NGCP/Panel/Form/SubscriberCFSimple.pm +++ b/lib/NGCP/Panel/Form/SubscriberCFSimple.pm @@ -66,6 +66,8 @@ has_field 'destination.uri' => ( type => 'Compound', do_label => 0, ); + + has_field 'destination.uri.destination' => ( type => '+NGCP::Panel::Field::URI', label => 'URI/Number', @@ -75,6 +77,14 @@ has_field 'destination.uri.timeout' => ( label => 'for (seconds)', default => 300, ); +has_field 'destination.announcement_id' => ( + type => 'Select', + #widget => 'RadioGroup', + label => 'Custom announcement', + options_method => \&build_announcements, + wrapper_class => [qw/hfh-rep-field ngcp-destination ngcp-destination-customhours/], + required => 0, +); has_field 'cf_actions' => ( type => 'Compound', @@ -116,6 +126,18 @@ sub validate_destination{ } return $result; } + +sub build_announcements { + my ($self) = @_; + my @options = (); + my $c = $self->form->ctx; + push @options, { label => 'Select announcement', value => '' }; + foreach($c->stash->{custom_announcements_rs}->all){ + push @options, { label => $_->name, value => $_->id }; + } + return \@options; +} + 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Role/API/CFDestinationSets.pm b/lib/NGCP/Panel/Role/API/CFDestinationSets.pm index a10c6a8172..f176832d22 100644 --- a/lib/NGCP/Panel/Role/API/CFDestinationSets.pm +++ b/lib/NGCP/Panel/Role/API/CFDestinationSets.pm @@ -116,17 +116,9 @@ sub update_item { if (! exists $resource->{destinations} ) { $resource->{destinations} = []; } - if (ref $resource->{destinations} ne "ARRAY") { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'destinations'. Must be an array."); + if(!$self->check_destinations($c, $resource)){ return; } - for my $d (@{ $resource->{destinations} }) { - if (exists $d->{timeout} && ! is_int($d->{timeout})) { - $c->log->error("Invalid field 'timeout'."); - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'timeout'."); - return; - } - } my $b_subscriber = $schema->resultset('voip_subscribers')->find($resource->{subscriber_id}); unless ($b_subscriber) { @@ -136,7 +128,7 @@ sub update_item { my $subscriber = $b_subscriber->provisioning_voip_subscriber; unless($subscriber) { $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber."); - last; + return; } try { @@ -185,5 +177,46 @@ sub update_item { return $item; } +sub check_destinations{ + my($self,$c,$resource) = @_; + if (ref $resource->{destinations} ne "ARRAY") { + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'destinations'. Must be an array."); + return; + } + for my $d (@{ $resource->{destinations} }) { + if (exists $d->{timeout} && ! is_int($d->{timeout})) { + $c->log->error("Invalid timeout for the destination '".$d->{destination}."'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid timeout for the destination '".$d->{destination}."'"); + return; + } + if (exists $d->{priority} && ! is_int($d->{priority})) { + $c->log->error("Invalid priority for the destination '".$d->{destination}."'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid priority for the destination '".$d->{destination}."'"); + return; + } + if (defined $d->{announcement_id}) { + #todo: I think that user expects that put and get will be the same + if(('customhours' ne $d->{destination}) && ('sip:custom-hours@app.local' ne $d->{destination}) ){ + $c->log->error("Invalid parameter 'announcement_id' for the destination '".$d->{destination}."'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid parameter 'announcement_id' for the destination '".$d->{destination}."'"); + return; + }elsif(! is_int($d->{announcement_id})){ + $c->log->error("Invalid announcement_id"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid announcement_id"); + return; + }elsif(! $c->model('DB')->resultset('voip_sound_handles')->search_rs({ + 'me.id' => $d->{announcement_id}, + 'group.name' => 'custom_announcements', + },{ + 'join' => 'group', + })->first() ){ + $c->log->error("Unknown announcement_id: ".$d->{announcement_id}); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown announcement_id:".$d->{announcement_id}); + return; + } + } + } + return 1; +} 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Role/API/CallForwards.pm b/lib/NGCP/Panel/Role/API/CallForwards.pm index ca62739ae5..2c0a578d1f 100644 --- a/lib/NGCP/Panel/Role/API/CallForwards.pm +++ b/lib/NGCP/Panel/Role/API/CallForwards.pm @@ -119,6 +119,27 @@ sub update_item { $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid timeout in '$type'"); return; } + if (defined $d->{announcement_id}) { + if('customhours' ne $d->{destination}){ + $c->log->error("Invalid parameter 'announcement_id' for the destination '".$d->{destination}."' in '$type'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid parameter 'announcement_id' for the destination '".$d->{destination}."' in '$type'"); + return; + }elsif(! is_int($d->{announcement_id})){ + $c->log->error("Invalid announcement_id in '$type'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid announcement_id in '$type'"); + return; + }elsif(! $c->model('DB')->resultset('voip_sound_handles')->search_rs({ + 'me.id' => $d->{announcement_id}, + 'group.name' => 'custom_announcements', + },{ + 'join' => 'group' + } + )->first() ){ + $c->log->error("Unknown announcement_id in '$type'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown announcement_id in '$type'"); + return; + } + } } } diff --git a/share/static/css/main.css b/share/static/css/main.css index e27763709a..48cab4790b 100644 --- a/share/static/css/main.css +++ b/share/static/css/main.css @@ -573,4 +573,9 @@ div.login { font-size: 12px; } +/*callforwards announcement_id field for the different destinations*/ +.ngcp-destination { + display: none; +} + /* vim: set tabstop=4 syntax=css expandtab: */ diff --git a/share/templates/customer/details.tt b/share/templates/customer/details.tt index c0b25278c5..621802771e 100644 --- a/share/templates/customer/details.tt +++ b/share/templates/customer/details.tt @@ -14,7 +14,6 @@ { level = 5, text = c.loc("ported (call forwarding only)") }, ]; -%] -