diff --git a/debian/control b/debian/control index c4e9a3eeab..f2ab2073e2 100644 --- a/debian/control +++ b/debian/control @@ -110,6 +110,7 @@ Depends: libuuid-perl, libxml-mini-perl, libxml-xpath-perl, + libtie-ixhash-perl, lsb-base (>= 3.0-6), ngcp-schema, nginx-common, diff --git a/lib/NGCP/Panel/Controller/API/Conversations.pm b/lib/NGCP/Panel/Controller/API/Conversations.pm new file mode 100644 index 0000000000..b38243f92f --- /dev/null +++ b/lib/NGCP/Panel/Controller/API/Conversations.pm @@ -0,0 +1,64 @@ +package NGCP::Panel::Controller::API::Conversations; + +use Sipwise::Base; +#use NGCP::Panel::Utils::Generic qw(:all); +use HTTP::Status qw(:constants); + +use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::Conversations/; + +__PACKAGE__->set_config(); + +sub allowed_methods{ + return [qw/GET OPTIONS HEAD/]; +} + +sub api_description { + return 'Combined collection of conversation events (calls, voice mails, sms, faxes, xmpp messages).'; +}; + +sub query_params { + return [ + { + param => 'subscriber_id', + description => 'Filter for conversation events of a specific subscriber. Either this or customer_id filter is mandatory if called by admin, reseller or subscriberadmin.', + }, + { + param => 'customer_id', + description => 'Filter for conversation events for a specific customer. Either this or subscriber_id filter is mandatory if called by admin, reseller or subscriberadmin.', + }, + + { + param => 'direction', + description => 'Filter for conversation events with a specific direction. One of "in", "out". Voicemails are considered as incoming only.', + }, + + { + param => 'status', + description => 'todo', + }, + + { + param => 'type', + description => 'Filter for conversation events of given types ("call", "voicemail", "sms", "fax", "xmpp"). Multiple types can be included by concatenating type strings, eg. "?type=call-voicemial".', + }, + + { + param => 'from', + description => 'Filter for conversation events starting greater or equal the specified time stamp.', + }, + { + param => 'to', + description => 'Filter for conversation events starting lower or equal the specified time stamp.', + }, + + ]; +} + +sub order_by_cols { + return { + 'timestamp' => 'me.timestamp', + 'type' => 'me.type', + }; +} + +1; diff --git a/lib/NGCP/Panel/Controller/API/Root.pm b/lib/NGCP/Panel/Controller/API/Root.pm index 4e5c44cbfc..fc56745409 100644 --- a/lib/NGCP/Panel/Controller/API/Root.pm +++ b/lib/NGCP/Panel/Controller/API/Root.pm @@ -158,12 +158,16 @@ sub GET : Allow { my ($form) = $full_mod->get_form($c); my $sorting_cols = []; - my $item_rs; - try { - $item_rs = $full_mod->item_rs($c, ""); - } - if ($item_rs) { - $sorting_cols = [$item_rs->result_source->columns]; + if (my $order_by_cols = eval { $full_mod->order_by_cols(); }) { + $sorting_cols = [ keys %$order_by_cols ]; + } else { + my $item_rs; + try { + $item_rs = $full_mod->item_rs($c, ""); + } + if ($item_rs) { + $sorting_cols = [$item_rs->result_source->columns]; + } } my ($form_fields,$form_fields_upload) = $form ? $self->get_collection_properties($form) : ([],[]); diff --git a/lib/NGCP/Panel/Form/Conversation/API.pm b/lib/NGCP/Panel/Form/Conversation/API.pm new file mode 100644 index 0000000000..3fcabf3590 --- /dev/null +++ b/lib/NGCP/Panel/Form/Conversation/API.pm @@ -0,0 +1,24 @@ +package NGCP::Panel::Form::Conversation::API; + +use HTML::FormHandler::Moose; +extends 'HTML::FormHandler'; + +has_field 'type' => ( + type => 'Text', + label => 'The conversation event type: call/voicemail/sms/fax/xmpp.', + required => 1, +); + +has_field 'id' => ( + type => 'PosInteger', + label => 'The original conversation record id - cdr id/voicemail id/sms id/fax journal record id/prosody message archive mgmt (mam) record id.', + required => 1, +); + +has_field 'timestamp' => ( + type => 'Text', + label => 'The timestamp of the conversation event.', + required => 1, +); + +1; diff --git a/lib/NGCP/Panel/Role/API.pm b/lib/NGCP/Panel/Role/API.pm index 45e18aee8f..2105d6b5ac 100644 --- a/lib/NGCP/Panel/Role/API.pm +++ b/lib/NGCP/Panel/Role/API.pm @@ -553,18 +553,18 @@ sub paginate_order_collection_rs { page => $page, rows => $rows, }); - if ($order_by && $item_rs->result_source->has_column($order_by)) { - my $me = $item_rs->current_source_alias; + if ($order_by && ((my $explicit = ($self->can('order_by_cols') && exists $self->order_by_cols()->{$order_by})) or $item_rs->result_source->has_column($order_by))) { + my $col = ($explicit ? $self->order_by_cols()->{$order_by} : $item_rs->current_source_alias . '.' . $order_by); if (lc($direction) eq 'desc') { $item_rs = $item_rs->search(undef, { - order_by => {-desc => "$me.$order_by"}, + order_by => {-desc => $col}, }); - $c->log->debug("ordering by $me.$order_by DESC"); + $c->log->debug("ordering by $col DESC"); } else { $item_rs = $item_rs->search(undef, { - order_by => "$me.$order_by", + order_by => "$col", }); - $c->log->debug("ordering by $me.$order_by"); + $c->log->debug("ordering by $col"); } } return ($total_count, $item_rs); @@ -984,7 +984,7 @@ sub get_form { sub get_item_id{ my($self, $c, $item, $resource, $form) = @_; - return int($item->id); + return int(blessed $item ? $item->id : $item->{id}); } sub item_by_id { diff --git a/lib/NGCP/Panel/Role/API/Conversations.pm b/lib/NGCP/Panel/Role/API/Conversations.pm new file mode 100644 index 0000000000..31e74f10c8 --- /dev/null +++ b/lib/NGCP/Panel/Role/API/Conversations.pm @@ -0,0 +1,669 @@ +package NGCP::Panel::Role::API::Conversations; + +use parent qw/NGCP::Panel::Role::API/; + +use Sipwise::Base; +#use NGCP::Panel::Utils::Generic qw(:all); +use NGCP::Panel::Utils::CallList qw(); + +use NGCP::Panel::Utils::DateTime qw(); +use DateTime::Format::Strptime qw(); +use HTTP::Status qw(:constants); +use NGCP::Panel::Form::Conversation::API qw(); + +use Tie::IxHash; + +my %call_fields = (); +tie(%call_fields, 'Tie::IxHash'); +$call_fields{source_user_id} = 'me.source_user_id'; +$call_fields{source_account_id} = 'me.source_account_id'; +$call_fields{source_clir} = 'me.source_clir'; +$call_fields{source_cli} = 'me.source_cli'; +$call_fields{source_user} = 'me.source_user'; +$call_fields{source_domain} = 'me.source_domain'; + +$call_fields{destination_user_id} = 'me.destination_user_id'; +$call_fields{destination_account_id} = 'me.destination_account_id'; +$call_fields{destination_user_in} = 'me.destination_user_in'; +$call_fields{destination_domain} = 'me.destination_domain'; + +$call_fields{call_type} = 'me.call_type'; +$call_fields{call_status} = 'me.call_status'; +$call_fields{start_time} = 'me.start_time'; +$call_fields{duration} = 'me.duration'; + +my %voicemail_fields = (); +tie(%voicemail_fields, 'Tie::IxHash'); +$voicemail_fields{duration} = 'me.duration'; +$voicemail_fields{origtime} = 'me.origtime'; +$voicemail_fields{callerid} = 'me.callerid'; +$voicemail_fields{mailboxuser} = 'me.mailboxuser'; +$voicemail_fields{dir} = 'me.dir'; + +my %sms_fields = (); +tie(%sms_fields, 'Tie::IxHash'); +$sms_fields{subscriber_id} = 'me.subscriber_id'; +$sms_fields{time} = 'me.time'; +$sms_fields{direction} = 'me.direction'; +$sms_fields{caller} = 'me.callee'; +$sms_fields{text} = 'me.text'; +$sms_fields{reason} = 'me.reason'; +$sms_fields{status} = 'me.status'; + +my %fax_fields = (); +tie(%fax_fields, 'Tie::IxHash'); +$fax_fields{subscriber_id} = 'me.subscriber_id'; +$fax_fields{time} = 'me.time'; +$fax_fields{direction} = 'me.direction'; +$fax_fields{duration} = 'duration'; +$fax_fields{caller} = 'me.caller'; +$fax_fields{callee} = 'me.callee'; +$fax_fields{pages} = 'me.pages'; +$fax_fields{reason} = 'me.reason'; +$fax_fields{status} = 'me.status'; +$fax_fields{signal_rate} = 'me.signal_rate'; +$fax_fields{quality} = 'me.quality'; +$fax_fields{filename} = 'me.filename'; +$fax_fields{sid} = 'me.sid'; +$fax_fields{caller_uuid} = 'me.caller_uuid'; +$fax_fields{callee_uuid} = 'me.callee_uuid'; + +my %xmpp_fields = (); +tie(%xmpp_fields, 'Tie::IxHash'); +$xmpp_fields{subscriber_id} = 'me.id'; +$xmpp_fields{user} = 'me.user'; +$xmpp_fields{with} = 'me.with'; +$xmpp_fields{epoch} = 'me.epoch'; + +my $max_fields = scalar keys %call_fields; +$max_fields += scalar NGCP::Panel::Utils::CallList::get_suppression_id_colnames(); +$max_fields = scalar keys %voicemail_fields if ((scalar keys %voicemail_fields) > $max_fields); +$max_fields = scalar keys %sms_fields if ((scalar keys %sms_fields) > $max_fields); +$max_fields = scalar keys %fax_fields if ((scalar keys %fax_fields) > $max_fields); +$max_fields = scalar keys %xmpp_fields if ((scalar keys %xmpp_fields) > $max_fields); + +sub item_name{ + return 'conversation'; +} + +sub resource_name{ + return 'conversations'; +} + +sub dispatch_path{ + return '/api/conversations/'; +} + +sub relation{ + return 'http://purl.org/sipwise/ngcp-api/#rel-conversations'; +} + +sub config_allowed_roles { + return [qw/admin reseller subscriberadmin subscriber/]; +} + +sub _item_rs { + my ($self, $c, $params) = @_; + + $params //= $c->req->params; + $params = { %$params }; + + my ($uuid,$contract_id,$reseller_id,$provider_id,$show); + + if ($params->{subscriber_id}) { + my $subscriber; + eval { + $subscriber = $c->model('DB')->resultset('voip_subscriber')->find($params->{subscriber_id}); + }; + if ($subscriber) { + $uuid = $subscriber->uuid; + } else { + #die invalid subscriber_id '$params->{subscriber_id}' + } + } + if ($params->{customer_id}) { + # ensure integer, allow terminated + my $contract; + eval { + $contract = $c->model('DB')->resultset('contract')->find($params->{subscriber_id}); + }; + if ($contract) { + $contract_id = $contract->id; + } else { + #die invalid customer_id '$params->{customer_id}' + } + } + + if ($c->user->roles eq "subscriber") { + $uuid = $c->user->voip_subscriber->uuid; + } elsif ($c->user->roles eq "subscriberadmin") { + $contract_id = $c->user->account_id; + } elsif ($c->user->roles eq "reseller") { + $reseller_id = $c->user->reseller_id; + $provider_id = $c->user->reseller->contract_id; + } + + unless (defined $uuid or defined $contract_id) { + #die subscriber_id or customer_id required + } + + my $item_rs; + my $type_param = ((exists $params->{type}) ? ($params->{type} // '') : undef); + foreach my $type (qw(call voicemail sms fax xmpp)) { + if ((not defined $type_param) or index(lc($type_param),$type) > -1) { + my $sub_name = '_get_' . $type . '_rs'; + my $rs = $self->$sub_name( + c => $c, + uuid => $uuid, + contract_id => $contract_id, + reseller_id => $reseller_id, + provider_id => $provider_id, + params => $params); + if ($rs) { + $rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + $item_rs = (defined $item_rs ? $item_rs->union_all($rs) : $rs); + } + } + } + + return $item_rs; + +} + +sub _apply_timestamp_from_to { + my $self = shift; + my %params = @_; + my ($rs,$params,$col,$cond_code) = @params{qw/rs params col cond/}; + + $cond_code //= sub { return shift->epoch; }; + + if (exists $params->{from}) { + my $from = NGCP::Panel::Utils::DateTime::from_string($params->{from}); + if ($from) { + $rs = $rs->search_rs({ + $col => { '>=' => &$cond_code($from) } + }); + } else { + #die invalid from timestamp $params->{from} + } + } + if (exists $params->{to}) { + my $to = NGCP::Panel::Utils::DateTime::from_string($params->{to}); + if ($to) { + $rs = $rs->search_rs({ + $col => { '<=' => &$cond_code($to) } + }); + } else { + #die invalid to timestamp $params->{to} + } + } + return $rs; +} + +sub _apply_direction { + my $self = shift; + my %params = @_; + my ($params,$apply_in_code,$apply_out_code,$apply_inout_code) = @params{qw/params in out inout/}; + + $apply_in_code //= sub {}; + $apply_out_code //= sub {}; + $apply_inout_code //= sub {}; + + if (exists $params->{direction}) { + if ('in' eq lc($params->{direction})) { + &$apply_in_code(); + } elsif ('out' eq lc($params->{direction})) { + &$apply_out_code(); + } else { + #die invalid to direction $params->{direction} + } + } else { + &$apply_inout_code(); + } +} + +sub _get_call_rs { + + my $self = shift; + my %params = @_; + my ($c,$uuid,$contract_id,$provider_id,$params) = @params{qw/c uuid contract_id provider_id params/}; + + my $rs = $c->model('DB')->resultset('cdr'); + + $rs = $self->_apply_timestamp_from_to(rs => $rs,params => $params,col => 'me.start_time'); + + if ($provider_id) { + $self->_apply_direction(params => $params, + in => sub { + $rs = $rs->search({ + { destination_provider_id => $provider_id }, + }); + }, + out => sub { + $rs = $rs->search({ + { source_provider_id => $provider_id }, + }); + }, + inout => sub { + $rs = $rs->search({ + -or => [ + { source_provider_id => $provider_id }, + { destination_provider_id => $provider_id }, + ], + }); + }, + ); + } + if ($contract_id) { + $self->_apply_direction(params => $params, + in => sub { + $rs = $rs->search({ + { destination_account_id => $contract_id }, + }); + }, + out => sub { + $rs = $rs->search({ + { source_account_id => $contract_id }, + }); + }, + inout => sub { + $rs = $rs->search_rs({ + -or => [ + { source_account_id => $contract_id }, + { destination_account_id => $contract_id }, + ], + }); + }, + ); + } + my $max = scalar keys %call_fields; + $rs = $rs->search(undef,{ + 'select' => [ + { '' => \'"call"', -as => 'type' }, + { '' => 'me.id', -as => 'id' }, + { '' => 'me.start_time', -as => 'timestamp' }, + _get_select_list(\%call_fields,undef,$max), #_get_max_fields(1)), + ], + 'as' => [ + 'type', + 'id', + 'timestamp', + _get_as_list(\%call_fields,undef,$max), #_get_max_fields(1)), + ], + }); + + my @suppression_aliases = (); + foreach (NGCP::Panel::Utils::CallList::get_suppression_id_colnames()) { + $max += 1; + push(@suppression_aliases,_get_alias($max)); + } + if ($uuid) { + my $out_rs = NGCP::Panel::Utils::CallList::call_list_suppressions_rs($c,$rs->search_rs({ + source_user_id => $uuid, + }),NGCP::Panel::Utils::CallList::SUPPRESS_OUT,@suppression_aliases); + my $in_rs = NGCP::Panel::Utils::CallList::call_list_suppressions_rs($c,$rs->search_rs({ + destination_user_id => $uuid, + }),NGCP::Panel::Utils::CallList::SUPPRESS_IN,@suppression_aliases); + + $self->_apply_direction(params => $params, + in => sub { + $rs = $in_rs; + }, + out => sub { + $rs = $out_rs; + }, + inout => sub { + $rs = $out_rs->union_all($in_rs); + }, + ); + } else { + $rs = NGCP::Panel::Utils::CallList::call_list_suppressions_rs($c,$rs, + NGCP::Panel::Utils::CallList::SUPPRESS_INOUT,@suppression_aliases); + } + return $rs->search(undef,{ + '+select' => [ + _get_select_list(\%call_fields,$max,undef), #_get_max_fields(1)), + ], + '+as' => [ + _get_as_list(\%call_fields,$max,undef), #_get_max_fields(1)), + ], + }) if $max_fields > $max; + return $rs; + +} + +sub _get_voicemail_rs { + + my $self = shift; + my %params = @_; + my ($c,$uuid,$contract_id,$reseller_id,$params) = @params{qw/c uuid contract_id reseller_id params/}; + + my $rs = $c->model('DB')->resultset('voicemail_spool')->search({ + duration => { '!=' => '' }, + }); + + $rs = $self->_apply_timestamp_from_to(rs => $rs,params => $params,col => 'me.origtime'); + + if ($reseller_id) { + $rs = $rs->search({ + 'contact.reseller_id' => $reseller_id, + },{ + join => { mailboxuser => { provisioning_voip_subscriber => { voip_subscriber => { contract => 'contact' } } } }, + }); + } + if ($contract_id) { + $rs = $rs->search({ + 'contract.id' => $contract_id, + },{ + join => { mailboxuser => { provisioning_voip_subscriber => { voip_subscriber => 'contract' } } }, + }); + } + if ($uuid) { + $rs = $rs->search({ + 'voip_subscriber.uuid' => $c->user->uuid, + },{ + join => { mailboxuser => { provisioning_voip_subscriber => 'voip_subscriber' } }, + }); + } else { + $rs = $rs->search({ + 'voip_subscriber.id' => { '!=' => undef }, + },{ + join => { mailboxuser => { provisioning_voip_subscriber => 'voip_subscriber' } }, + }); + } + $rs = $rs->search(undef,{ + select => [ + { '' => \'"voicemail"', -as => 'type' }, + { '' => 'me.id', -as => 'id' }, + { '' => 'me.origtime', -as => 'timestamp' }, + _get_select_list(\%voicemail_fields), + ], + as => ['type','id','timestamp',_get_as_list(\%voicemail_fields),], + }); + $self->_apply_direction(params => $params, + out => sub { + undef $rs; + }, + ); + return $rs; + +} + +sub _get_sms_rs { + + my $self = shift; + my %params = @_; + my ($c,$uuid,$contract_id,$reseller_id,$params) = @params{qw/c uuid contract_id reseller_id params/}; + + my $rs = $c->model('DB')->resultset('sms_journal'); + + $rs = $self->_apply_timestamp_from_to(rs => $rs,params => $params,col => 'me.time'); + + $self->_apply_direction(params => $params, + in => sub { + $rs = $rs->search_rs({ + 'me.direction' => 'in', + }); + }, + out => sub { + $rs = $rs->search_rs({ + 'me.direction' => 'out', + }); + }, + ); + + if ($reseller_id) { + $rs = $rs->search_rs({ + 'contact.reseller_id' => $reseller_id, + },{ + join => { provisioning_voip_subscriber => { subscriber => { contract => 'contact'} } }, + }); + } + if ($contract_id) { + $rs = $rs->search({ + 'contract.id' => $contract_id, + },{ + join => { provisioning_voip_subscriber => { subscriber => 'contract' } }, + }); + } + if ($uuid) { + $rs = $rs->search_rs({ + 'provisioning_voip_subscriber.uuid' => $uuid, + },{ + join => 'provisioning_voip_subscriber', + }); + } + return $rs->search(undef,{ + select => [ + { '' => \'"sms"', -as => 'type' }, + { '' => 'me.id', -as => 'id' }, + { '' => 'me.time', -as => 'timestamp' }, + _get_select_list(\%sms_fields), + ], + as => ['type','id','timestamp',_get_as_list(\%sms_fields),], + }); + +} + +sub _get_fax_rs { + + my $self = shift; + my %params = @_; + my ($c,$uuid,$contract_id,$reseller_id,$params) = @params{qw/c uuid contract_id reseller_id params/}; + + my $rs = $c->model('DB')->resultset('voip_fax_journal'); + + $rs = $self->_apply_timestamp_from_to(rs => $rs,params => $params,col => 'me.time'); + + $self->_apply_direction(params => $params, + in => sub { + $rs = $rs->search_rs({ + 'me.direction' => 'in', + }); + }, + out => sub { + $rs = $rs->search_rs({ + 'me.direction' => 'out', + }); + }, + ); + + if ($reseller_id) { + $rs = $rs->search_rs({ + 'contact.reseller_id' => $reseller_id, + },{ + join => { provisioning_voip_subscriber => { subscriber => { contract => 'contact'} } }, + }); + } + if ($contract_id) { + $rs = $rs->search({ + 'contract.id' => $contract_id, + },{ + join => { provisioning_voip_subscriber => { subscriber => 'contract' } }, + }); + } + if ($uuid) { + $rs = $rs->search({ + 'voip_subscriber.uuid' => $c->user->uuid, + },{ + join => { provisioning_voip_subscriber => 'voip_subscriber' }, + }); + } else { + $rs = $rs->search({ + 'voip_subscriber.id' => { '!=' => undef }, + },{ + join => { provisioning_voip_subscriber => 'voip_subscriber' }, + }); + } + return $rs->search(undef,{ + select => [ + { '' => \'"fax"', -as => 'type' }, + { '' => 'me.id', -as => 'id' }, + { '' => 'me.time', -as => 'timestamp' }, + _get_select_list(\%fax_fields), + ], + as => ['type','id','timestamp',_get_as_list(\%fax_fields),], + }); + +} + +sub _get_xmpp_rs { + + my $self = shift; + my %params = @_; + my ($c,$uuid,$contract_id,$reseller_id,$params) = @params{qw/c uuid contract_id reseller_id params/}; + + my $rs = $c->model('DB')->resultset('provisioning_voip_subscribers')->search_rs(undef,{ + #join => [ 'domain', 'sipwise_mam_user', 'sipwise_mam_with' ], + join => 'domain', + }); + + $rs = $self->_apply_timestamp_from_to(rs => $rs,params => $params,col => 'epoch'); + + if ($reseller_id) { + $rs = $rs->search_rs({ + 'contact.reseller_id' => $reseller_id, + },{ + join => { voip_subscriber => { contract => 'contact'} }, + }); + } + if ($contract_id) { + $rs = $rs->search({ + 'contract.id' => $contract_id, + },{ + join => { voip_subscriber => 'contract' }, + }); + } + if ($uuid) { + $rs = $rs->search({ + 'me.uuid' => $c->user->uuid, + }); + } + + my $out_rs = $rs->search_rs(undef,{ + join => 'sipwise_mam_user', + '+select' => [ + { '' => \'"out"', -as => 'direction' }, + { '' => 'sipwise_mam_user.id', -as => 'mam_id' }, + { '' => 'sipwise_mam_user.username', -as => 'user' }, + { '' => 'sipwise_mam_user.with', -as => 'with' }, + { '' => 'sipwise_mam_user.epoch', -as => 'epoch' }, + ], + '+as' => ['direction','mam_id','user','with','epoch'], + }); + my $in_rs = $rs->search_rs(undef,{ + join => 'sipwise_mam_with', + '+select' => [ + { '' => \'"in"', -as => 'direction' }, + { '' => 'sipwise_mam_with.id', -as => 'mam_id' }, + { '' => 'sipwise_mam_with.username', -as => 'user' }, + { '' => 'sipwise_mam_with.with', -as => 'with' }, + { '' => 'sipwise_mam_with.epoch', -as => 'epoch' }, + ], + '+as' => ['direction','mam_id','user','with','epoch'], + }); + + $self->_apply_direction(params => $params, + in => sub { + $rs = $in_rs; + }, + out => sub { + $rs = $out_rs; + }, + inout => sub { + $rs = $out_rs->union_all($in_rs); + }, + ); + + return $rs->search(undef,{ + select => [ + { '' => \'"xmpp"', -as => 'type' }, + { '' => 'mam_id', -as => 'id' }, + { '' => 'epoch', -as => 'timestamp' }, + _get_select_list(\%xmpp_fields), + ], + as => ['type','id','timestamp',_get_as_list(\%xmpp_fields),], + }); + +} + +sub _get_select_list { + + my ($fields,$min,$max) = @_; + $min //= 1; + $max //= $max_fields; + my @projections = values %$fields; + my @select = (); + foreach my $i ($min..$max) { + push(@select,{ + '' => ($projections[$i - 1] ? $projections[$i - 1] : \'""'), + -as => _get_alias($i) + }); + } + return @select; + +} + +sub _get_as_list { + + my ($fields,$min,$max) = @_; + $min //= 1; + $max //= $max_fields; + my @accessors = keys %$fields; + my @as = (); + foreach my $i ($min..$max) { + push(@as,_get_alias($i)); + #push(@as,($accessors[$i - 1] ? $accessors[$i - 1] : 'field'.$i)); + } + return @as; + +} + +sub _get_alias { + return 'field' . shift; +} + +sub get_form { + my ($self, $c) = @_; + return (NGCP::Panel::Form::Conversation::API->new(ctx => $c),['id']); +} + +sub process_hal_resource { + my($self, $c, $item, $resource, $form) = @_; + + use Data::Dumper; + $c->log->debug(Dumper($item)); + + my $datetime_fmt = DateTime::Format::Strptime->new( + pattern => '%F %T', + ); + my $timestamp = NGCP::Panel::Utils::DateTime::epoch_local($resource->{timestamp}); + #if($c->req->param('tz') && DateTime::TimeZone->is_valid_name($c->req->param('tz'))) { + # $timestamp->set_time_zone($c->req->param('tz')); + #} + $resource->{timestamp} = $datetime_fmt->format_datetime($timestamp); + $resource->{timestamp} .= '.' . $timestamp->millisecond if $timestamp->millisecond > 0.0; + + # todo: mashal specific fields, per conversation event type ... + + return $resource; +} + +sub hal_links { + my($self, $c, $item, $resource, $form) = @_; + return [ + ('call' eq $item->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:calls', href => sprintf("/api/calls/%d", $item->{id})) : ()), + ('voicemail' eq $item->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:voicemails', href => sprintf("/api/voicemails/%d", $item->{id})) : ()), + ('sms' eq $item->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:sms', href => sprintf("/api/sms/%d", $item->{id})) : ()), + ('fax' eq $item->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:faxes', href => sprintf("/api/faxes/%d", $item->{id})) : ()), + # todo - add xmpp mam rail: + # ('xmpp' eq $item->{type} ? + # NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:xmpp', href => sprintf("/api/xmpp/%d", $item->{id})) : ()), + ]; +} + +1; diff --git a/lib/NGCP/Panel/Utils/CallList.pm b/lib/NGCP/Panel/Utils/CallList.pm index ef72ebb048..f82c25c6f0 100644 --- a/lib/NGCP/Panel/Utils/CallList.pm +++ b/lib/NGCP/Panel/Utils/CallList.pm @@ -335,55 +335,59 @@ sub _is_show_suppressions { sub call_list_suppressions_rs { - my ($c,$rs,$mode) = @_; + my ($c,$rs,$mode, + $source_cli_suppression_id_colname, + $destination_user_in_suppression_id_colname) = @_; return $rs unless ENABLE_SUPPRESSIONS; + $source_cli_suppression_id_colname //= SOURCE_CLI_SUPPRESSION_ID_COLNAME; + $destination_user_in_suppression_id_colname //= DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME; my %search_cond = (); my %search_xtra = (); if (_is_show_suppressions($c)) { if (defined $mode and SUPPRESS_OUT == $mode) { $search_xtra{'+select'} = [ - #{ '' => \[ 'me.source_cli' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ _get_call_list_suppression_sq('outgoing',qw(filter obfuscate)) ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + #{ '' => \[ 'me.source_cli' ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ _get_call_list_suppression_sq('outgoing',qw(filter obfuscate)) ] , -as => $destination_user_in_suppression_id_colname }, ]; } elsif (defined $mode and SUPPRESS_IN == $mode) { $search_xtra{'+select'} = [ - { '' => \[ _get_call_list_suppression_sq('incoming',qw(filter obfuscate)) ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - #{ '' => \[ 'me.destination_user_in' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + { '' => \[ _get_call_list_suppression_sq('incoming',qw(filter obfuscate)) ] , -as => $source_cli_suppression_id_colname }, + #{ '' => \[ 'me.destination_user_in' ] , -as => $destination_user_in_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $destination_user_in_suppression_id_colname }, ]; } elsif (defined $mode and SUPPRESS_INOUT == $mode) { $search_xtra{'+select'} = [ - { '' => \[ _get_call_list_suppression_sq('incoming',qw(filter obfuscate)) ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ _get_call_list_suppression_sq('outgoing',qw(filter obfuscate)) ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + { '' => \[ _get_call_list_suppression_sq('incoming',qw(filter obfuscate)) ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ _get_call_list_suppression_sq('outgoing',qw(filter obfuscate)) ] , -as => $destination_user_in_suppression_id_colname }, ]; } else { $search_xtra{'+select'} = [ - #{ '' => \[ 'me.source_cli' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - #{ '' => \[ 'me.destination_user_in' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + #{ '' => \[ 'me.source_cli' ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $source_cli_suppression_id_colname }, + #{ '' => \[ 'me.destination_user_in' ] , -as => $destination_user_in_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $destination_user_in_suppression_id_colname }, ]; } } else { if (defined $mode and SUPPRESS_OUT == $mode) { $search_xtra{'+select'} = [ - #{ '' => \[ 'me.source_cli' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ _get_call_list_suppression_sq('outgoing',qw(obfuscate)) ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + #{ '' => \[ 'me.source_cli' ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ _get_call_list_suppression_sq('outgoing',qw(obfuscate)) ] , -as => $destination_user_in_suppression_id_colname }, ]; $search_cond{'-not exists'} = \[ '('._get_call_list_suppression_sq('outgoing',qw(filter)).')' ]; } elsif (defined $mode and SUPPRESS_IN == $mode) { $search_xtra{'+select'} = [ - { '' => \[ _get_call_list_suppression_sq('incoming',qw(obfuscate)) ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - #{ '' => \[ 'me.destination_user_in' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + { '' => \[ _get_call_list_suppression_sq('incoming',qw(obfuscate)) ] , -as => $source_cli_suppression_id_colname }, + #{ '' => \[ 'me.destination_user_in' ] , -as => $destination_user_in_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $destination_user_in_suppression_id_colname }, ]; $search_cond{'-not exists'} = \[ '('._get_call_list_suppression_sq('incoming',qw(filter)).')' ]; } elsif (defined $mode and SUPPRESS_INOUT == $mode) { $search_xtra{'+select'} = [ - { '' => \[ _get_call_list_suppression_sq('incoming',qw(obfuscate)) ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ _get_call_list_suppression_sq('outgoing',qw(obfuscate)) ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + { '' => \[ _get_call_list_suppression_sq('incoming',qw(obfuscate)) ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ _get_call_list_suppression_sq('outgoing',qw(obfuscate)) ] , -as => $destination_user_in_suppression_id_colname }, ]; $search_cond{'-and'} = [ { '-not exists' => \[ '('._get_call_list_suppression_sq('incoming',qw(filter)).')' ] }, @@ -391,10 +395,10 @@ sub call_list_suppressions_rs { ]; } else { $search_xtra{'+select'} = [ - #{ '' => \[ 'me.source_cli' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => SOURCE_CLI_SUPPRESSION_ID_COLNAME }, - #{ '' => \[ 'me.destination_user_in' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, - { '' => \[ 'NULL' ] , -as => DESTINATION_USER_IN_SUPPRESSION_ID_COLNAME }, + #{ '' => \[ 'me.source_cli' ] , -as => $source_cli_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $source_cli_suppression_id_colname }, + #{ '' => \[ 'me.destination_user_in' ] , -as => $destination_user_in_suppression_id_colname }, + { '' => \[ 'NULL' ] , -as => $destination_user_in_suppression_id_colname }, ]; } }