From ab869fa2a42b3e8cb6ae00e63d69b6285f6a8125 Mon Sep 17 00:00:00 2001 From: Rene Krenn Date: Tue, 10 Oct 2017 03:10:57 +0200 Subject: [PATCH] TT#23275 TT#21348 hash2obj util method + working example for api/conversation -> process_cdr_item Change-Id: I12357d6105618743f6a1270a0c5995f8db8b60a2 --- lib/NGCP/Panel/Role/API/Conversations.pm | 161 ++++++++++++++++++----- sandbox/hash2obj.pl | 98 ++++++++++++++ 2 files changed, 226 insertions(+), 33 deletions(-) create mode 100644 sandbox/hash2obj.pl diff --git a/lib/NGCP/Panel/Role/API/Conversations.pm b/lib/NGCP/Panel/Role/API/Conversations.pm index 9d06c8cda5..3761f38c13 100644 --- a/lib/NGCP/Panel/Role/API/Conversations.pm +++ b/lib/NGCP/Panel/Role/API/Conversations.pm @@ -14,7 +14,7 @@ use NGCP::Panel::Form; use Tie::IxHash; my %call_fields = (); -tie(%call_fields, 'Tie::IxHash'); +my $call_fields_tied = 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'; @@ -32,6 +32,39 @@ $call_fields{call_status} = 'me.call_status'; $call_fields{start_time} = 'me.start_time'; $call_fields{duration} = 'me.duration'; +$call_fields{call_id} = 'me.call_id'; +$call_fields{rating_status} = 'me.rating_status'; +$call_fields{source_customer_cost} = 'me.source_customer_cost'; +$call_fields{destination_customer_cost} = 'me.destination_customer_cost'; +$call_fields{source_customer_free_time} = 'me.source_customer_free_time'; + +my $cdr_proto = _hash2obj( + classname => 'cdr_item', + accessors => { + (map { $_ => _get_alias($call_fields_tied->Indices($_) + 1); } keys %call_fields), + #call_id => sub { #override + # my $self = shift; + # use Data::Dumper; + # my $test = { %$self }; + # delete $test->{c}; + # $self->{c}->log->debug(Dumper([map { $_ => _get_alias($call_fields_tied->Indices($_) + 1); } keys %call_fields])); + # return $self->{'field15'}; + #}, + get_column => sub { + my ($self,$colname) = @_; + return $self->{$colname}; + }, + source_subscriber => sub { + my $self = shift; + return $self->{c}->model('DB')->resultset('voip_subscribers')->find({ uuid => $self->source_user_id() }); + }, + destination_subscriber => sub { + my $self = shift; + return $self->{c}->model('DB')->resultset('voip_subscribers')->find({ uuid => $self->destination_user_id() }); + }, + }, +); + my %voicemail_fields = (); tie(%voicemail_fields, 'Tie::IxHash'); $voicemail_fields{duration} = 'me.duration'; @@ -118,29 +151,8 @@ sub _item_rs { 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}' - } - } + (my $subscriber,$uuid) = $self->_get_subscriber($c,$params); + (my $contract,$contract_id) = $self->_get_contract($c,$params); if ($c->user->roles eq "subscriber") { $uuid = $c->user->voip_subscriber->uuid; @@ -178,6 +190,41 @@ sub _item_rs { } +sub _get_subscriber { + my ($self, $c, $params) = @_; + $params //= $c->req->params; + my ($subscriber,$uuid); + if ($params->{subscriber_id}) { + eval { + $subscriber = $c->model('DB')->resultset('voip_subscribers')->find($params->{subscriber_id}); + }; + if ($subscriber) { + $uuid = $subscriber->uuid; + } else { + #die invalid subscriber_id '$params->{subscriber_id}' + } + } + return ($subscriber,$uuid); +} + +sub _get_contract { + my ($self, $c, $params) = @_; + $params //= $c->req->params; + my ($contract,$contract_id); + if ($params->{customer_id}) { + # ensure integer, allow terminated + eval { + $contract = $c->model('DB')->resultset('contracts')->find($params->{customer_id}); + }; + if ($contract) { + $contract_id = $contract->id; + } else { + #die invalid customer_id '$params->{customer_id}' + } + } + return ($contract,$contract_id); +} + sub _apply_timestamp_from_to { my $self = shift; my %params = @_; @@ -640,7 +687,8 @@ sub process_hal_resource { my($self, $c, $item, $resource, $form) = @_; use Data::Dumper; - $c->log->debug(Dumper($item)); + #$c->log->debug(Dumper($item)); + #$c->log->debug(Dumper($resource)); my $datetime_fmt = DateTime::Format::Strptime->new( pattern => '%F %T', @@ -654,24 +702,71 @@ sub process_hal_resource { # todo: mashal specific fields, per conversation event type ... + if ('call' eq $resource->{type}) { + my $cdr_item = NGCP::Panel::Utils::CallList::process_cdr_item($c,_hash2obj( + classname => ref $cdr_proto, + hash => $resource, + private => { c => $c, }, + ),{ + subscriber => ($self->_get_subscriber($c))[0], + customer => ($self->_get_contract($c))[0], + }, + ); + # todo: populate $resource ... + $c->log->debug(Dumper($cdr_item)); + } + 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})) : ()), + ('call' eq $resource->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:calls', href => sprintf("/api/calls/%d", $resource->{id})) : ()), + ('voicemail' eq $resource->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:voicemails', href => sprintf("/api/voicemails/%d", $resource->{id})) : ()), + ('sms' eq $resource->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:sms', href => sprintf("/api/sms/%d", $resource->{id})) : ()), + ('fax' eq $resource->{type} ? + NGCP::Panel::Utils::DataHalLink->new(relation => 'ngcp:faxes', href => sprintf("/api/faxes/%d", $resource->{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})) : ()), ]; } +sub _hash2obj { + my %params = @_; + my ($hash,$private,$classname,$accessors) = @params{qw/hash private classname accessors/}; + + my $obj; + $obj = $hash if 'HASH' eq ref $hash; + $obj //= {}; + $obj = { %$obj, %$private } if 'HASH' eq ref $private; + unless (defined $classname and length($classname) > 0) { + my @chars = ('A'..'Z'); + $classname //= ''; + $classname .= $chars[rand scalar @chars] for 1..8; + } + $classname = __PACKAGE__ . '::' . $classname unless $classname =~ /::/; + bless($obj,$classname); + no strict "refs"; + return $obj if scalar %{$classname . '::'}; + print "registering class $classname\n"; + $accessors //= {}; + foreach my $accessor (keys %$accessors) { + print "registering accessor $classname::$accessor\n"; + *{$classname . '::' . $accessor} = sub { + my $self = shift; + return &{$accessors->{$accessor}}($self,@_); + } if 'CODE' eq ref $accessors->{$accessor}; + *{$classname . '::' . $accessor} = sub { + my $self = shift; + return $self->{$accessors->{$accessor}}; + } if '' eq ref $accessors->{$accessor}; + } + return $obj; +} + 1; diff --git a/sandbox/hash2obj.pl b/sandbox/hash2obj.pl new file mode 100644 index 0000000000..b41bd2222f --- /dev/null +++ b/sandbox/hash2obj.pl @@ -0,0 +1,98 @@ +use strict; +use warnings; + +use Data::Dumper; + +my $cdr_hash1 = { + field1 => "value1", + field2 => "value2", + field3 => "value3", +}; +my $cdr_hash2 = { + field1 => "value4", + field2 => "value5", + field3 => "value6", +}; + +my $item1 = hash2obj( + hash => $cdr_hash1, + classname => "myCDRItem", + private => {}, + accessors => { + source_user => sub { + my $self = shift; + return $self->{field1}; + }, + destination_user_in => sub { + my $self = shift; + return $self->{field2}; + }, + start_time => sub { + my $self = shift; + return $self->{field2}; + }, + } +); +my $item2 = hash2obj( + hash => $cdr_hash2, + #classname => "myCDRItem", + private => {}, + accessors => { + source_user => sub { + my $self = shift; + return $self->{field1}; + }, + destination_user_in => sub { + my $self = shift; + return $self->{field2} . 'xx'; + }, + start_time => sub { + my $self = shift; + return $self->{field2}; + }, + } +); + +print $item1->destination_user_in; +print $item2->destination_user_in; +print $item2->field1; +exit; + +sub hash2obj { + #my $self = shift; + my %params = @_; + my ($hash,$classname,$accessors) = @params{qw/hash classname accessors/}; + + my $obj; + $obj = $hash if 'HASH' eq ref $hash; + $obj //= {}; + unless (defined $classname and length($classname) > 0) { + my @chars = ('A'..'Z'); + $classname //= ''; + $classname .= $chars[rand scalar @chars] for 1..8; + } + $classname = __PACKAGE__ . '::' . $classname unless $classname =~ /::/; + bless($obj,$classname); + no strict "refs"; # for below and to register new methods in package + return $obj if scalar %{$classname . '::'}; + print "registering class $classname\n"; + $accessors //= {}; + my %accessors = ( (map { $_ => undef; } keys %$obj), %$accessors); # create accessors for fields too + for my $accessor (keys %accessors) { + print "registering accessor $classname::$accessor\n"; + # see http://search.cpan.org/~gsar/perl-5.6.1/pod/perltootc.pod + # accessor can be a coderef ... + *{$classname . '::' . $accessor} = sub { + my $self = shift; + &{$accessors{$accessor}}($self,shift) if scalar @_; #setter + return &{$accessors{$accessor}}($self); #getter + } if 'CODE' eq ref $accessors{$accessor}; + # ... or hash field name: + *{$classname . '::' . $accessor} = sub { + my $self = shift; + $self->{$accessors{$accessor}} = shift if scalar @_; #setter + return $self->{$accessors{$accessor}}; #getter + } if '' eq ref $accessors{$accessor}; + } + return $obj; +} \ No newline at end of file