diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index 3d9552da21..4e21209633 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -14,6 +14,7 @@ use NGCP::Panel::Utils::Preferences; use NGCP::Panel::Utils::Message; use NGCP::Panel::Utils::DateTime; use NGCP::Panel::Utils::Sems; +use NGCP::Panel::Utils::Hylafax; use NGCP::Panel::Form::Subscriber; use NGCP::Panel::Form::SubscriberEdit; use NGCP::Panel::Form::Customer::PbxExtensionSubscriberEdit; @@ -41,6 +42,7 @@ use NGCP::Panel::Form::Faxserver::Active; use NGCP::Panel::Form::Faxserver::SendStatus; use NGCP::Panel::Form::Faxserver::SendCopy; use NGCP::Panel::Form::Faxserver::Destination; +use NGCP::Panel::Form::Subscriber::Webfax; use NGCP::Panel::Utils::XMLDispatcher; use UUID; @@ -294,8 +296,103 @@ sub base :Chained('sub_list') :PathPart('') :CaptureArgs(1) { { name => "choice", search => 1, title => $c->loc('Slot') }, { name => "destination", search => 1, title => $c->loc('Destination') }, ]); + $c->stash->{fax_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ + { name => "id", search => 1, title => $c->loc('#') }, + { name => "the_timestamp", search_from_epoch => 1, search_to_epoch => 1, title => $c->loc('Timestamp') }, + { name => "status", search => 1, title => $c->loc('Status') }, + { name => "duration", search => 1, title => $c->loc('Duration') }, + { name => "direction", search => 1, title => $c->loc('Direction') }, + { name => "peer_number", search => 1, title => $c->loc('Peer Number') }, + { name => "pages", search => 1, title => $c->loc('Pages') }, + ]); +} + +sub webfax :Chained('base') :PathPart('webfax') :Args(0) { + my ($self, $c) = @_; + + $c->stash( + template => 'subscriber/webfax.tt', + ); +} + +sub webfax_send :Chained('base') :PathPart('webfax/send') :Args(0) { + my ($self, $c) = @_; + + my $subscriber = $c->stash->{subscriber}; + my $form = NGCP::Panel::Form::Subscriber::Webfax->new; + my $posted = ($c->request->method eq 'POST'); + + my $params = {}; + if($posted) { + $c->req->params->{faxfile} = $c->req->upload('faxfile'); + } + $form->process( + posted => $posted, + params => $c->req->params, + ); + + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, + back_uri => $c->uri_for_action('/subscriber/webfax', $c->req->captures), + ); + + if($posted && $form->validated) { + try { + if(defined $form->params->{faxfile}) { + NGCP::Panel::Utils::Hylafax::send_fax( + c => $c, + subscriber => $subscriber, + destination => $form->params->{destination}, + #resolution => 'low', # opt (low, medium, extended) + #notify => 'someone@example.org', # TODO: handle in send_fax, read from prefs! + #coverpage => 1, + upload => $form->params->{faxfile}, + ); + } else { + NGCP::Panel::Utils::Hylafax::send_fax( + c => $c, + subscriber => $subscriber, + destination => $form->params->{destination}, + #resolution => 'low', # opt (low, medium, extended) + #notify => 'someone@example.org', # TODO: handle in send_fax, read from prefs! + #coverpage => 1, + data => $form->params->{data}, + ); + } + } catch($e) { + NGCP::Panel::Utils::Message->error( + c => $c, + error => "failed to send fax: $e", + desc => $c->loc('Internal error while sending fax'), + ); + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/subscriber/webfax', $c->req->captures)); + return; + } + } + + $c->stash( + template => 'subscriber/webfax.tt', + form => $form, + create_flag => 1, + ); } +sub webfax_ajax :Chained('base') :PathPart('webfax/ajax') :Args(0) { + my ($self, $c) = @_; + + my $s = $c->stash->{subscriber}->provisioning_voip_subscriber; + my $fax_rs = $c->model('DB')->resultset('fax_journal')->search({ + subscriber_id => $s->id, + }); + + NGCP::Panel::Utils::Datatables::process($c, $fax_rs, $c->stash->{fax_dt_columns}); + + $c->detach( $c->view("JSON") ); +} + + sub webphone :Chained('base') :PathPart('webphone') :Args(0) { my ($self, $c) = @_; diff --git a/lib/NGCP/Panel/Form/Subscriber/Webfax.pm b/lib/NGCP/Panel/Form/Subscriber/Webfax.pm new file mode 100644 index 0000000000..398f673c3d --- /dev/null +++ b/lib/NGCP/Panel/Form/Subscriber/Webfax.pm @@ -0,0 +1,76 @@ +package NGCP::Panel::Form::Subscriber::Webfax; + +use HTML::FormHandler::Moose; +extends 'HTML::FormHandler'; +use Moose::Util::TypeConstraints; + +use HTML::FormHandler::Widget::Block::Bootstrap; + +has '+widget_wrapper' => ( default => 'Bootstrap' ); +has '+enctype' => ( default => 'multipart/form-data'); +has_field 'submitid' => ( type => 'Hidden' ); +sub build_render_list {[qw/submitid fields actions/]} +sub build_form_element_class {[qw(form-horizontal)]} + +has_field 'destination' => ( + type => 'Text', + label => 'Destination Number', + required => 1, + element_attr => { + rel => ['tooltip'], + title => ['The number to send the fax to'] + }, +); + +has_field 'data' => ( + type => 'TextArea', + label => 'Content', + cols => 200, + rows => 10, + maxlength => '1048576', # 1MB + element_class => [qw/ngcp-autoconf-area/], +); + +has_field 'faxfile' => ( + type => 'Upload', + max_size => 67108864, + label => 'or File', + element_attr => { + rel => ['tooltip'], + title => ['Supported File Types are TXT, PDF, PS, TIFF'] + }, +); + +has_field 'save' => ( + type => 'Submit', + value => 'Send', + element_class => [qw/btn btn-primary/], + label => '', +); + +has_block 'fields' => ( + tag => 'div', + class => [qw/modal-body/], + render_list => [qw/destination data faxfile/], +); + +has_block 'actions' => ( + tag => 'div', + class => [qw/modal-footer/], + render_list => [qw/save/], +); + +sub validate { + my $self = shift; + my $data = $self->field('data')->value; + my $upload = $self->field('faxfile')->value; + + use Data::Printer; print ">>>>>>>>>>>>>>>>>>>>>> upload\n"; p $data; p $upload; p $self->fields; + + unless($data || $upload) { + $self->field('faxfile')->add_error("You need to specify a file to fax, if no text is entered in the content field"); + } +} + +1; +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Utils/Hylafax.pm b/lib/NGCP/Panel/Utils/Hylafax.pm new file mode 100644 index 0000000000..03cc7fd634 --- /dev/null +++ b/lib/NGCP/Panel/Utils/Hylafax.pm @@ -0,0 +1,89 @@ +package NGCP::Panel::Utils::Hylafax; + +use Sipwise::Base; +use File::Temp qw/tempfile/; +use TryCatch; + +use Data::Dumper; + +sub send_fax { + my (%args) = @_; + + my $c = $args{c}; + my $subscriber = $args{subscriber}; + my $prov_subscriber = $subscriber->provisioning_voip_subscriber; + + my $sendfax = $c->config->{faxserver}->{sendfax} // '/usr/bin/sendfax'; + my @sendfax_args = (); + + my $sender = 'webfax'; + my $number; + if($subscriber->primary_number) { + $number = $subscriber->primary_number->cc . + ($subscriber->primary_number->ac // ''). + $subscriber->primary_number->sn; + } else { + $number = $sender; + } + if($prov_subscriber->voip_fax_preference) { + $sender = $prov_subscriber->voip_fax_preference->name; + if($prov_subscriber->voip_fax_preference->password) { + push @sendfax_args, '-o '.$number.':'.$prov_subscriber->voip_fax_preference->password; + } else { + push @sendfax_args, '-o '.$number; + } + } else { + push @sendfax_args, '-o '.$number; + } + + push @sendfax_args, '-h '.($c->config->{faxserver}->{ip} // '127.0.0.1'); + if($args{notify}) { + push @sendfax_args, '-D'; + push @sendfax_args, "-f '$sender <$args{notify}>'"; + } else { + push @sendfax_args, "-f '$sender'"; + } + unless($args{coverpage}) { + push @sendfax_args, '-n'; + } + if($args{resolution}) { + if($args{resolution} eq 'low') { + push @sendfax_args, '-l'; + } elsif($args{resolution} eq 'medium') { + push @sendfax_args, '-m'; + } elsif($args{resolution} eq 'extended') { + push @sendfax_args, '-G'; + } + } + + push @sendfax_args, '-d '.$args{destination}; + + my ($fh, $filename); + if($args{data}) { + ($fh, $filename) = tempfile; + unless(print $fh $args{data}) { + my $err = $!; + close $fh; + unlink $filename; + die $c->loc("Failed to write fax data to temporary file: [_1]", $err); + } + close $fh; + } else { + $filename = eval { $args{upload}->tempname }; + } + push @sendfax_args, $filename; + + my $sa = join(' ', @sendfax_args); + my $output = `$sendfax $sa 2>&1`; + my $exit = $?; + unlink $filename; + + if($exit ne '0') { + chomp $output; + die $output."\n"; + } +} + +1; + +# vim: set tabstop=4 expandtab: diff --git a/ngcp_panel.conf b/ngcp_panel.conf index d044f19384..8371fc452a 100644 --- a/ngcp_panel.conf +++ b/ngcp_panel.conf @@ -28,6 +28,11 @@ log4perl.appender.Default.layout.ConversionPattern=%d{ISO8601} [%p] [%F +%L] %m{ cloudpbx 1 + + sendfax /usr/bin/sendfax + ip 127.0.0.1 + + element_order source element_order destination diff --git a/share/templates/helpers/datatables.tt b/share/templates/helpers/datatables.tt index ebf6f9a695..b1da51715c 100644 --- a/share/templates/helpers/datatables.tt +++ b/share/templates/helpers/datatables.tt @@ -26,6 +26,7 @@ $.extend( $.fn.dataTableExt.oStdClasses, { } ); $(document).ready(function() { + var date_search_rendered = 0; var [% helper.id_from_name %]_table = $('#[% helper.id_from_name %]_table') .dataTable( { "sDom": "<'row-fluid ngcp_dt_top_elements'lf>t<'row-fluid'<'pull-left'i><'pull-right'p>>", @@ -114,6 +115,43 @@ $(document).ready(function() { function() { $(this).find('.sw_actions').css('visibility','visible'); }, function() { $(this).find('.sw_actions').css('visibility','hidden'); } ); + + if(date_search_rendered) return; + date_search_rendered = 1; + [% has_from = 0; has_to = 0; -%] + [% FOR col IN helper.dt_columns -%] + [% IF col.search_from_epoch && !has_from -%] + var f = ''; + $('#[% helper.id_from_name %]_table_filter').prepend(f); + $('#[% helper.id_from_name %]_datepicker_start').datepicker({ + "dateFormat": "yy-mm-dd", + "onSelect": function(date) { + [% helper.id_from_name %]_table.fnFilter(date, 0); + } + }).keyup( function () { + [% helper.id_from_name %]_table.fnFilter(this.value, 0); + }); + [% has_from = 1 -%] + [% END -%] + [% IF col.search_to_epoch && !has_to -%] + + var t = ''; + if($('#[% helper.id_from_name %]_datepicker_start').length > 0) { + $('#[% helper.id_from_name %]_datepicker_start').parent().after(t); + } else { + $('#[% helper.id_from_name %]_table_filter').prepend(t); + } + $('#[% helper.id_from_name %]_datepicker_end').datepicker({ + "dateFormat": "yy-mm-dd", + "onSelect": function(date) { + [% helper.id_from_name %]_table.fnFilter(date, 1); + } + }).keyup( function () { + [% helper.id_from_name %]_table.fnFilter(this.value, 1); + }); + [% has_to = 1-%] + [% END -%] + [% END %] }, "fnRowCallback": function(nRow, aData, iDisplayIndex) { nRow.className = "sw_action_row"; @@ -121,40 +159,6 @@ $(document).ready(function() { }, } ); - [% has_from = 0; has_to = 0; -%] - [% FOR col IN helper.dt_columns -%] - [% IF col.search_from_epoch && !has_from -%] - var f = ''; - $('#[% helper.id_from_name %]_table_filter').prepend(f); - $('#[% helper.id_from_name %]_datepicker_start').datepicker({ - "dateFormat": "yy-mm-dd", - "onSelect": function(date) { - [% helper.id_from_name %]_table.fnFilter(date, 0); - } - }).keyup( function () { - [% helper.id_from_name %]_table.fnFilter(this.value, 0); - }); - [% has_from = 1 -%] - [% END -%] - [% IF col.search_to_epoch && !has_to -%] - - var t = ''; - if($('#[% helper.id_from_name %]_datepicker_start').length > 0) { - $('#[% helper.id_from_name %]_datepicker_start').parent().after(t); - } else { - $('#[% helper.id_from_name %]_table_filter').prepend(t); - } - $('#[% helper.id_from_name %]_datepicker_end').datepicker({ - "dateFormat": "yy-mm-dd", - "onSelect": function(date) { - [% helper.id_from_name %]_table.fnFilter(date, 1); - } - }).keyup( function () { - [% helper.id_from_name %]_table.fnFilter(this.value, 1); - }); - [% has_to = 1-%] - [% END -%] - [% END %] } ); diff --git a/share/templates/subscriber/webfax.tt b/share/templates/subscriber/webfax.tt new file mode 100644 index 0000000000..51beae383a --- /dev/null +++ b/share/templates/subscriber/webfax.tt @@ -0,0 +1,19 @@ +[% site_config.title = c.loc('Fax Journal for [_1]@[_2]', subscriber.username, subscriber.domain.domain) -%] + +[% + helper.name = c.loc('Fax'); + helper.dt_columns = fax_dt_columns; + helper.column_sort = 'the_timestamp'; + helper.form_object = form; + helper.create_flag = create_flag; + helper.ajax_uri = c.uri_for_action('/subscriber/webfax_ajax', [c.req.captures.0]); + helper.messages = messages; + + helper.top_buttons = [ + { name = c.loc('Send Fax'), uri = c.uri_for_action('/subscriber/webfax_send', [ subscriber.id ]), icon = 'icon-print' }, + ]; + + PROCESS 'helpers/datatables.tt'; +%] + +[% # vim: set tabstop=4 syntax=html expandtab: -%]