diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index abe9130b53..22c9e0df38 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -22,6 +22,7 @@ use NGCP::Panel::Form::Voicemail::Delete; use NGCP::Panel::Form::Reminder; use NGCP::Panel::Form::Subscriber::TrustedSource; use NGCP::Panel::Form::Subscriber::Location; +use NGCP::Panel::Form::Subscriber::SpeedDial; use NGCP::Panel::Form::Faxserver::Name; use NGCP::Panel::Form::Faxserver::Password; use NGCP::Panel::Form::Faxserver::Active; @@ -226,6 +227,12 @@ sub base :Chained('/subscriber/sub_list') :PathPart('') :CaptureArgs(1) { } $c->stash(subscriber => $res); + + $c->stash->{sd_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ + { name => "id", search => 1, title => "#" }, + { name => "slot", search => 1, title => "Slot" }, + { name => "destination", search => 1, title => "Destination" }, + ]); } sub ajax :Chained('sub_list') :PathPart('ajax') :Args(0) { @@ -1898,7 +1905,7 @@ sub voicemail :Chained('master') :PathPart('voicemail') :CaptureArgs(1) { }); unless($rs->first) { $c->log->error("no such voicemail file with id '$vm_id' for uuid ".$c->stash->{subscriber}->uuid); - $c->flash(messages => [{type => 'error', text => 'No such voicemail file to play'}]); + $c->flash(messages => [{type => 'error', text => 'No such voicemail file'}]); $c->response->redirect($c->uri_for_action('/subscriber/details', [$c->req->captures->[0]])); return; } @@ -2166,6 +2173,140 @@ sub delete_trusted :Chained('trusted_base') :PathPart('delete') :Args(0) { $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); } + +sub ajax_speeddial :Chained('base') :PathPart('preferences/speeddial/ajax') :Args(0) { + my ($self, $c) = @_; + + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; + my $sd_rs = $prov_subscriber->voip_speed_dials; + NGCP::Panel::Utils::Datatables::process($c, $sd_rs, $c->stash->{sd_dt_columns}); + + $c->detach( $c->view("JSON") ); +} + +sub create_speeddial :Chained('base') :PathPart('preferences/speeddial/create') :Args(0) { + my ($self, $c) = @_; + + my $posted = ($c->request->method eq 'POST'); + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; + my $slots = $prov_subscriber->voip_speed_dials; + $c->stash->{used_sd_slots} = $slots; + my $form = NGCP::Panel::Form::Subscriber::SpeedDial->new(ctx => $c); + + $form->process(params => $c->req->params); + if($posted && $form->validated) { + try { + my $d = $form->field('destination')->value; + if($d !~ /\@/) { + $d .= '@'.$prov_subscriber->domain->domain; + } + if($d !~ /^sip:/) { + $d = 'sip:' . $d; + } + $slots->create({ + slot => $form->field('slot')->value, + destination => $d, + }); + $c->flash(messages => [{type => 'success', text => 'Successfully created speed dial slot'}]); + $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); + return; + } catch($e) { + $c->log->error("failed to create speed dial slot: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to created speed dial slot'}]); + $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); + return; + } + } + + delete $c->stash->{used_sd_slots}; + $c->stash( + template => 'subscriber/preferences.tt', + edit_cf_flag => 1, + cf_description => "Speed Dial Slot", + cf_form => $form, + close_target => $c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]), + ); +} + +sub speeddial :Chained('base') :PathPart('preferences/speeddial') :CaptureArgs(1) { + my ($self, $c, $sd_id) = @_; + + my $sd = $c->stash->{subscriber}->provisioning_voip_subscriber->voip_speed_dials + ->find($sd_id); + unless($sd) { + $c->log->error("no such speed dial slot with id '$sd_id' for uuid ".$c->stash->{subscriber}->uuid); + $c->flash(messages => [{type => 'error', text => 'No such speed dial id'}]); + $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); + return; + } + $c->stash->{speeddial} = $sd; +} + +sub delete_speeddial :Chained('speeddial') :PathPart('delete') :Args(0) { + my ($self, $c) = @_; + + try { + $c->stash->{speeddial}->delete; + $c->flash(messages => [{type => 'success', text => 'Successfully deleted speed dial slot'}]); + } catch($e) { + $c->log->error("failed to delete speed dial slot: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to delete speed dial slot'}]); + } + + $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); +} + +sub edit_speeddial :Chained('speeddial') :PathPart('edit') :Args(0) { + my ($self, $c) = @_; + + my $posted = ($c->request->method eq 'POST'); + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; + my $slots = $prov_subscriber->voip_speed_dials; + $c->stash->{used_sd_slots} = $slots; + my $form = NGCP::Panel::Form::Subscriber::SpeedDial->new(ctx => $c); + + my $params; + unless($posted) { + $params->{slot} = $c->stash->{speeddial}->slot; + $params->{destination} = $c->stash->{speeddial}->destination; + } + + $form->process(params => $posted ? $c->req->params : $params); + if($posted && $form->validated) { + try { + my $d = $form->field('destination')->value; + if($d !~ /\@/) { + $d .= '@'.$prov_subscriber->domain->domain; + } + if($d !~ /^sip:/) { + $d = 'sip:' . $d; + } + $c->stash->{speeddial}->update({ + slot => $form->field('slot')->value, + destination => $d, + }); + $c->flash(messages => [{type => 'success', text => 'Successfully updated speed dial slot'}]); + $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); + return; + } catch($e) { + $c->log->error("failed to update speed dial slot: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to update speed dial slot'}]); + $c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]])); + return; + } + } + + delete $c->stash->{used_sd_slots}; + $c->stash( + template => 'subscriber/preferences.tt', + edit_cf_flag => 1, + cf_description => "Speed Dial Slot", + cf_form => $form, + close_target => $c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]), + ); +} + + =head1 AUTHOR Andreas Granig,,, diff --git a/lib/NGCP/Panel/Form/Subscriber/SpeedDial.pm b/lib/NGCP/Panel/Form/Subscriber/SpeedDial.pm new file mode 100644 index 0000000000..54ebe2d08f --- /dev/null +++ b/lib/NGCP/Panel/Form/Subscriber/SpeedDial.pm @@ -0,0 +1,77 @@ +package NGCP::Panel::Form::Subscriber::SpeedDial; + +use HTML::FormHandler::Moose; +extends 'HTML::FormHandler'; +use Moose::Util::TypeConstraints; + +use HTML::FormHandler::Widget::Block::Bootstrap; + +with 'NGCP::Panel::Render::RepeatableJs'; + +has '+widget_wrapper' => ( default => 'Bootstrap' ); +sub build_render_list {[qw/fields actions/]} +sub build_form_element_class { [qw/form-horizontal/] } + +has_field 'slot' => ( + type => 'Select', + label => 'Slot', + options_method => \&set_slots, + required => 1, + wrapper_class => [qw/hfh-rep-field/], +); + +sub set_slots { + my($self) = @_; + my @options = (); + my @used = (); + my $current; + if(defined $self->form->ctx && + defined $self->form->ctx->stash->{used_sd_slots}) { + foreach my $s($self->form->ctx->stash->{used_sd_slots}->all) { + push @used, $s->slot; + } + } + if(defined $self->form->ctx && + defined $self->form->ctx->stash->{speeddial}) { + $current = $self->form->ctx->stash->{speeddial}->slot; + } + foreach my $s(@{ $self->form->ctx->config->{speed_dial_vsc_presets}->{vsc} }) + { + if($s ~~ @used) { + next unless(defined $current && $s eq $current); + } + push @options, { label => $s, value => $s }; + } + return \@options; +} + +has_field 'destination' => ( + type => 'Text', + label => 'Destination', + required => 1, + wrapper_class => [qw/hfh-rep-field/], +); + +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/slot destination/ ], +); + +has_block 'actions' => ( + tag => 'div', + class => [qw/modal-footer/], + render_list => [qw/save/], +); + +1; + +# vim: set tabstop=4 expandtab: diff --git a/ngcp_panel.conf b/ngcp_panel.conf index 9bec8a8d1d..d784f2273b 100644 --- a/ngcp_panel.conf +++ b/ngcp_panel.conf @@ -35,3 +35,15 @@ log4perl.appender.Default.layout.ConversionPattern=%d{ISO8601} [%p] [%F +%L] %m{ path + + vsc *0 + vsc *1 + vsc *2 + vsc *3 + vsc *4 + vsc *5 + vsc *6 + vsc *7 + vsc *8 + vsc *9 + diff --git a/share/layout/html.tt b/share/layout/html.tt index c83f3173eb..43fbd89b62 100644 --- a/share/layout/html.tt +++ b/share/layout/html.tt @@ -13,7 +13,7 @@ - + diff --git a/share/templates/subscriber/master.tt b/share/templates/subscriber/master.tt index 2cb9615357..4e2d70bf9b 100644 --- a/share/templates/subscriber/master.tt +++ b/share/templates/subscriber/master.tt @@ -85,13 +85,8 @@ [% helper.name = 'Calls'; - helper.column_sort = 'status'; helper.dt_columns = calls_dt_columns; helper.column_sort = 'start_time'; - - helper.close_target = close_target; - helper.create_flag = create_flag; - helper.edit_flag = edit_flag; helper.form_object = form; helper.ajax_uri = c.uri_for_action('/subscriber/ajax_calls', [c.req.captures.0]); @@ -113,9 +108,6 @@ helper.column_sort = 'origtime'; helper.dt_columns = vm_dt_columns; - helper.close_target = close_target; - helper.create_flag = create_flag; - helper.edit_flag = edit_flag; helper.form_object = form; helper.ajax_uri = c.uri_for_action('/subscriber/ajax_voicemails', [c.req.captures.0]); diff --git a/share/templates/subscriber/preferences.tt b/share/templates/subscriber/preferences.tt index 6d5a2ce9e8..a02cc6df53 100644 --- a/share/templates/subscriber/preferences.tt +++ b/share/templates/subscriber/preferences.tt @@ -296,6 +296,32 @@ +
+ +
+
+ + Create Slot +[% + helper.messages = ''; + helper.name = 'Speeddial'; + helper.column_sort = 'slot'; + helper.dt_columns = sd_dt_columns; + helper.ajax_uri = c.uri_for_action('/subscriber/ajax_speeddial', [c.req.captures.0]); + + helper.dt_buttons = [ + { name = 'Edit', uri = "preferences/speeddial/'+full.id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, + { name = 'Delete', uri = "preferences/speeddial/'+full.id+'/delete", class = 'btn-small btn-secondary', icon = 'icon-trash' }, + ]; + + PROCESS 'helpers/datatables.tt'; +%] +
+
+
+