You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/lib/NGCP/Panel/Utils/Events.pm

649 lines
22 KiB

package NGCP::Panel::Utils::Events;
use Sipwise::Base;
use NGCP::Panel::Utils::DateTime qw();
use constant ENABLE_EVENTS => 1;
use constant CREATE_EVENT_PER_ALIAS => 1;
sub insert_deferred {
my %params = @_;
my $c = $params{c};
my $schema = $params{schema} // $c->model('DB');
my $events_to_create = $params{events_to_create} // [];
my $inserted = 0;
while (my $event = shift @$events_to_create) {
if ('profile' eq $event->{type}) {
$inserted += insert_profile_events(c => $c, schema => $schema,
%$event
);
} else {
$inserted += insert(c => $c, schema => $schema,
%$event
);
}
}
return $inserted;
}
sub insert_profile_events {
my %params = @_;
return 0 unless ENABLE_EVENTS;
my $c = $params{c};
my $schema = $params{schema} // $c->model('DB');
#my $type = $params{type};
#my $subscriber = $params{subscriber};
my $old_profile_id = $params{old};
my $new_profile_id = $params{new};
my $now_hires = NGCP::Panel::Utils::DateTime::current_local_hires;
#reload it usually:
my $subscriber = $params{subscriber} // $schema->resultset('voip_subscribers')->find({
id => $params{subscriber_id},
});
my $prov_subscriber = $subscriber->provisioning_voip_subscriber;
my $is_pilot = ($prov_subscriber && $prov_subscriber->is_pbx_pilot ? 1 : 0);
my $pilot_subscriber = _get_pilot_subscriber(
c => $c,
schema => $schema,
subscriber => $subscriber,
prov_subscriber => $prov_subscriber,
now_hires => $now_hires,
);
my $pilot_prov_subscriber;
$pilot_prov_subscriber = $pilot_subscriber->provisioning_voip_subscriber if $pilot_subscriber;
my ($old_aliases,$old_aliases_map) = _get_aliases_map($params{old_aliases},$prov_subscriber);
my ($old_pilot_aliases,$old_pilot_aliases_map) = _get_aliases_map($params{old_pilot_aliases},$pilot_prov_subscriber);
my ($new_aliases,$new_aliases_map) = _get_aliases_map($params{new_aliases},$prov_subscriber);
my ($new_pilot_aliases,$new_pilot_aliases_map) = _get_aliases_map($params{new_pilot_aliases},$pilot_prov_subscriber);
my $context = { c => $c, schema => $schema,
subscriber => $subscriber,
old_aliases => $params{old_aliases},
new_aliases => $params{new_aliases},
old_pilot_aliases => $params{old_pilot_aliases},
new_pilot_aliases => $params{new_pilot_aliases},
create_event_per_alias => 0,
now_hires => $now_hires};
my $inserted = 0;
foreach my $new_alias (@$new_aliases) {
$context->{alias} = $new_alias;
if (not exists $old_aliases_map->{$new_alias}) {
if (not $is_pilot and exists $old_pilot_aliases_map->{$new_alias}) {
#aliases moved from pilot to subs
if ($pilot_prov_subscriber) {
$context->{old} = $pilot_prov_subscriber->profile_id;
$context->{new} = $new_profile_id;
$inserted += _insert_profile_event($context);
}
} else {
#aliases added
$context->{old} = undef;
$context->{new} = $new_profile_id;
$inserted += _insert_profile_event($context);
}
} else {
#no number change
$context->{old} = $old_profile_id;
$context->{new} = $new_profile_id;
$inserted += _insert_profile_event($context);
}
}
foreach my $old_alias (@$old_aliases) {
$context->{alias} = $old_alias;
if (not exists $new_aliases_map->{$old_alias}) {
if (not $is_pilot and exists $new_pilot_aliases_map->{$old_alias}) {
#aliases moved from subs to pilot
if ($pilot_prov_subscriber) {
$context->{old} = $old_profile_id;
$context->{new} = $pilot_prov_subscriber->profile_id;
$inserted += _insert_profile_event($context);
}
} else {
#aliases deleted
$context->{old} = $old_profile_id;
$context->{new} = undef;
$inserted += _insert_profile_event($context);
}
} else {
#no number change
}
}
if ((scalar @$old_aliases) + (scalar @$new_aliases) == 0) {
$context->{alias} = undef;
$context->{old} = $old_profile_id;
$context->{new} = $new_profile_id;
$context->{create_event_per_alias} = undef;
$inserted += _insert_profile_event($context);
}
}
sub _insert_profile_event {
my ($context) = @_;
my $inserted = 0;
if(($context->{old} // 0) != ($context->{new} // 0)) {
if(defined $context->{old} && defined $context->{new}) {
$context->{type} = "update_profile";
} elsif(defined $context->{new}) {
$context->{type} = "start_profile";
} else {
$context->{type} = "end_profile";
}
$inserted += insert(%$context);
}
return $inserted;
}
sub insert {
my %params = @_;
return 0 unless ENABLE_EVENTS;
my $c = $params{c};
my $schema = $params{schema} // $c->model('DB');
my $type = $params{type};
#my $subscriber = $params{subscriber};
my $old = $params{old};
my $new = $params{new};
my $old_aliases = $params{old_aliases};
my $old_pilot_aliases = $params{old_pilot_aliases};
my $new_aliases = $params{new_aliases}; #to pass cleared aliases upon termination, as aliases are removed via trigger
my $new_pilot_aliases = $params{new_pilot_aliases};
my $create_event_per_alias = $params{create_event_per_alias} // CREATE_EVENT_PER_ALIAS;
my $event_alias = $params{alias};
my $now_hires = $params{now_hires} // NGCP::Panel::Utils::DateTime::current_local_hires;
#reload it usually:
my $subscriber = $params{subscriber} // $schema->resultset('voip_subscribers')->find({
id => $params{subscriber_id},
});
my $customer = $subscriber->contract;
my $prov_subscriber = $subscriber->provisioning_voip_subscriber;
my $pilot_subscriber = $params{pilot_subscriber} // _get_pilot_subscriber(
c => $c,
schema => $schema,
subscriber => $subscriber,
customer => $customer,
prov_subscriber => $prov_subscriber,
now_hires => $now_hires,
);
my $tags_rs = $schema->resultset('events_tag');
my $relations_rs = $schema->resultset('events_relation');
my @aliases = ();
if ($prov_subscriber) {
if ($create_event_per_alias) { #create events for all aliases
foreach my $alias (_get_aliases_sorted_rs($prov_subscriber)->all) {
push(@aliases,$alias->username);
}
} elsif (defined $event_alias) { #create event for a specific alias
push(@aliases,$event_alias);
}
unless ((scalar @aliases) > 0) { #create event for no alias
push(@aliases,undef);
}
}
my $inserted = 0;
foreach my $alias_username (@aliases) {
my $event = $schema->resultset('events')->create({
type => $type,
subscriber_id => $subscriber->id,
reseller_id => $customer->contact->reseller_id,
old_status => $old // '',
new_status => $new // '',
timestamp => $now_hires,
export_status => 'unexported',
exported_at => undef,
});
_save_voip_number(
schema => $schema,
event => $event,
number => $subscriber->primary_number,
types_prefix => 'primary_number_',
now_hires => $now_hires,
tags_rs => $tags_rs,
relations_rs => $relations_rs,
);
_save_subscriber_profile(
schema => $schema,
event => $event,
subscriber_profile => ($prov_subscriber ? $prov_subscriber->voip_subscriber_profile : undef),
types_prefix => 'subscriber_profile_',
now_hires => $now_hires,
tags_rs => $tags_rs,
relations_rs => $relations_rs,
);
_save_subscriber_profile_set(
schema => $schema,
event => $event,
subscriber_profile_set => ($prov_subscriber ? $prov_subscriber->voip_subscriber_profile_set : undef),
types_prefix => 'subscriber_profile_set_',
now_hires => $now_hires,
tags_rs => $tags_rs,
relations_rs => $relations_rs,
);
_save_first_non_primary_alias(
schema => $schema,
event => $event,
(defined $old_aliases ? (aliases => $old_aliases) : (prov_subscriber => $prov_subscriber)),
types_prefix => '',
types_suffix => '_before',
now_hires => $now_hires,
tags_rs => $tags_rs,
);
_save_first_non_primary_alias(
schema => $schema,
event => $event,
(defined $new_aliases ? (aliases => $new_aliases) : (prov_subscriber => $prov_subscriber)),
types_prefix => '',
types_suffix => '_after',
now_hires => $now_hires,
tags_rs => $tags_rs,
);
_save_alias(
schema => $schema,
event => $event,
alias_username => $alias_username,
now_hires => $now_hires,
tags_rs => $tags_rs,
);
if ($pilot_subscriber) {
$event->create_related("relation_data", {
relation_id => $relations_rs->find({ type => 'pilot_subscriber_id' })->id,
val => $pilot_subscriber->id,
event_timestamp => $now_hires,
});
my $pilot_prov_subscriber = $pilot_subscriber->provisioning_voip_subscriber;
_save_voip_number(
schema => $schema,
event => $event,
number => $pilot_subscriber->primary_number,
types_prefix => 'pilot_primary_number_',
now_hires => $now_hires,
tags_rs => $tags_rs,
relations_rs => $relations_rs,
);
_save_subscriber_profile(
schema => $schema,
event => $event,
subscriber_profile => ($pilot_prov_subscriber ? $pilot_prov_subscriber->voip_subscriber_profile : undef),
types_prefix => 'pilot_subscriber_profile_',
now_hires => $now_hires,
tags_rs => $tags_rs,
relations_rs => $relations_rs,
);
_save_subscriber_profile_set(
schema => $schema,
event => $event,
subscriber_profile_set => ($pilot_prov_subscriber ? $pilot_prov_subscriber->voip_subscriber_profile_set : undef),
types_prefix => 'pilot_subscriber_profile_set_',
now_hires => $now_hires,
tags_rs => $tags_rs,
relations_rs => $relations_rs,
);
_save_first_non_primary_alias(
schema => $schema,
event => $event,
(defined $old_pilot_aliases ? (aliases => $old_pilot_aliases) : (prov_subscriber => $pilot_prov_subscriber)),
types_prefix => 'pilot_',
types_suffix => '_before',
now_hires => $now_hires,
tags_rs => $tags_rs,
);
_save_first_non_primary_alias(
schema => $schema,
event => $event,
(defined $new_pilot_aliases ? (aliases => $new_pilot_aliases) : (prov_subscriber => $pilot_prov_subscriber)),
types_prefix => 'pilot_',
types_suffix => '_after',
now_hires => $now_hires,
tags_rs => $tags_rs,
);
}
$inserted++;
$c->log->debug('edr event "'. $type .'" inserted: subscriber id ' . $subscriber->id . ($alias_username ? ", alias $alias_username" : ''));
}
return $inserted;
}
sub _get_pilot_subscriber {
my %params = @_;
my ($c,
$schema,
$subscriber,
$customer,
$prov_subscriber,
$now_hires,
) = @params{qw/
c
schema
subscriber
customer
prov_subscriber
now_hires
/};
#now_hires
$schema //= $c->model('DB');
#$now_hires //= NGCP::Panel::Utils::DateTime::current_local_hires;
$customer //= $subscriber->contract;
$prov_subscriber //= $subscriber->provisioning_voip_subscriber;
my $pilot_subscriber = undef;
#my $bm_actual = _get_actual_billing_mapping(c => $c,schema => $schema, contract => $customer, now => $now_hires);
#if ($bm_actual->billing_mappings->first->product->class eq 'pbxaccount') {
if ($prov_subscriber and $prov_subscriber->is_pbx_pilot) {
$pilot_subscriber = $subscriber;
} else {
$pilot_subscriber = $customer->voip_subscribers->search({
'provisioning_voip_subscriber.is_pbx_pilot' => 1,
},{
join => 'provisioning_voip_subscriber',
})->first;
}
#}
return $pilot_subscriber;
}
sub _save_voip_number {
my %params = @_;
my ($schema,
$event,
$number,
$types_prefix,
$now_hires,
$tags_rs,
$relations_rs) = @params{qw/
schema
event
number
types_prefix
now_hires
tags_rs
relations_rs
/};
if ($number) {
$tags_rs //= $schema->resultset('events_tag');
$relations_rs //= $schema->resultset('events_relation');
$event->create_related("relation_data", {
relation_id => $relations_rs->find({ type => $types_prefix.'id' })->id,
val => $number->id,
event_timestamp => $now_hires,
});
if (length(my $cc = $number->cc) > 0) {
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => $types_prefix.'cc' })->id,
val => $cc,
event_timestamp => $now_hires,
});
}
if (length(my $ac = $number->ac) > 0) {
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => $types_prefix.'ac' })->id,
val => $ac,
event_timestamp => $now_hires,
});
}
if (length(my $sn = $number->sn) > 0) {
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => $types_prefix.'sn' })->id,
val => $sn,
event_timestamp => $now_hires,
});
}
}
}
sub _save_subscriber_profile {
my %params = @_;
my ($schema,
$event,
$subscriber_profile,
$types_prefix,
$now_hires,
$tags_rs,
$relations_rs) = @params{qw/
schema
event
subscriber_profile
types_prefix
now_hires
tags_rs
relations_rs
/};
if ($subscriber_profile) {
$tags_rs //= $schema->resultset('events_tag');
$relations_rs //= $schema->resultset('events_relation');
$event->create_related("relation_data", {
relation_id => $relations_rs->find({ type => $types_prefix.'id' })->id,
val => $subscriber_profile->id,
event_timestamp => $now_hires,
});
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => $types_prefix.'name' })->id,
val => $subscriber_profile->name,
event_timestamp => $now_hires,
});
}
}
sub _save_subscriber_profile_set {
my %params = @_;
my ($schema,
$event,
$subscriber_profile_set,
$types_prefix,
$now_hires,
$tags_rs,
$relations_rs) = @params{qw/
schema
event
subscriber_profile_set
types_prefix
now_hires
tags_rs
relations_rs
/};
if ($subscriber_profile_set) {
$tags_rs //= $schema->resultset('events_tag');
$relations_rs //= $schema->resultset('events_relation');
$event->create_related("relation_data", {
relation_id => $relations_rs->find({ type => $types_prefix.'id' })->id,
val => $subscriber_profile_set->id,
event_timestamp => $now_hires,
});
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => $types_prefix.'name' })->id,
val => $subscriber_profile_set->name,
event_timestamp => $now_hires,
});
}
}
sub _save_first_non_primary_alias {
my %params = @_;
my ($schema,
$event,
$aliases,
$prov_subscriber,
$types_prefix,
$types_suffix,
$now_hires,
$tags_rs) = @params{qw/
schema
event
aliases
prov_subscriber
types_prefix
types_suffix
now_hires
tags_rs
/};
my $alias_username = undef;
if ($aliases) {
#my $alias = shift(sort { $a->{is_primary} <=> $b->{is_primary} || $a->{id} <=> $b->{id}; } @$aliases);
my $alias = $aliases->[0]; #expect the ary sorted
$alias_username = $alias->{username} if $alias;
} elsif ($prov_subscriber) {
my $alias = _get_aliases_sorted_rs($prov_subscriber)->first;
$alias_username = $alias->username if $alias;
}
if ($alias_username) {
$tags_rs //= $schema->resultset('events_tag');
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => $types_prefix.'first_non_primary_alias_username'.$types_suffix })->id,
val => $alias_username,
event_timestamp => $now_hires,
});
}
}
sub _save_alias {
my %params = @_;
my ($schema,
$event,
$alias_username,
$now_hires,
$tags_rs) = @params{qw/
schema
event
alias_username
now_hires
tags_rs
/};
if ($alias_username) {
$tags_rs //= $schema->resultset('events_tag');
$event->create_related("tag_data", {
tag_id => $tags_rs->find({ type => 'non_primary_alias_username' })->id,
val => $alias_username,
event_timestamp => $now_hires,
});
}
}
sub _get_aliases_sorted_rs {
my ($prov_subscriber) = @_;
return $prov_subscriber->voip_dbaliases->search_rs({
is_primary => 0,
},{
#previously in ngcpcfg: #order_by => { -asc => ['is_primary', 'id'] },
order_by => { -asc => 'is_primary' },
});
}
sub _get_aliases_map {
my ($aliases, $prov_subscriber) = @_;
my @alias_usernames = ();
my %alias_map = ();
if ('ARRAY' eq ref $aliases) {
foreach my $alias (@$aliases) {
$alias_map{$alias->{username}} = $alias;
push(@alias_usernames,$alias->{username});
}
} else {
if ($prov_subscriber) {
foreach my $alias (_get_aliases_sorted_rs($prov_subscriber)->all) {
$alias_map{$alias->username} = { $alias->get_inflated_columns };
push(@alias_usernames,$alias->username);
}
}
}
return (\@alias_usernames,\%alias_map);
}
sub get_aliases_snapshot {
my %params = @_;
my $c = $params{c};
my $schema = $params{schema} // $c->model('DB');
my @aliases = ();
my @pilot_aliases = ();
if (ENABLE_EVENTS) {
my $subscriber = $params{subscriber} // $schema->resultset('voip_subscribers')->find({
id => $params{subscriber_id},
});
my $prov_subscriber = $subscriber->provisioning_voip_subscriber;
foreach my $alias (_get_aliases_sorted_rs($prov_subscriber)->all) {
push(@aliases,{ $alias->get_inflated_columns });
}
my $pilot_subscriber = _get_pilot_subscriber(
c => $c,
schema => $schema,
subscriber => $subscriber,
prov_subscriber => $prov_subscriber,
);
if ($pilot_subscriber) {
my $pilot_prov_subscriber = $pilot_subscriber->provisioning_voip_subscriber;
foreach my $alias (_get_aliases_sorted_rs($pilot_prov_subscriber)->all) {
push(@pilot_aliases,{ $alias->get_inflated_columns });
}
}
}
return { old_aliases => \@aliases, old_pilot_aliases => \@pilot_aliases };
}
#sub _get_actual_billing_mapping {
# my %params = @_;
# my ($c,$schema,$contract,$now) = @params{qw/c schema contract now/};
# $schema //= $c->model('DB');
# $now //= NGCP::Panel::Utils::DateTime::current_local;
# my $contract_create = NGCP::Panel::Utils::DateTime::set_local_tz($contract->create_timestamp // $contract->modify_timestamp);
# my $dtf = $schema->storage->datetime_parser;
# $now = $contract_create if $now < $contract_create; #if there is no mapping starting with or before $now, it would returns the mapping with max(id):
# return $schema->resultset('billing_mappings_actual')->search({ contract_id => $contract->id },{bind => [ ( $dtf->format_datetime($now) ) x 2, ($contract->id) x 2 ],})->first;
#}
sub get_relation_value {
my %params = @_;
my ($c,$schema,$event,$type) = @params{qw/c schema event type/};
$schema //= $c->model('DB');
if ($event) {
my $relations_rs = $schema->resultset('events_relation');
my $relation_data = $event->relation_data->find({
relation_id => $relations_rs->find({ type => $type })->id,
});
if ($relation_data) {
return $relation_data->val;
}
}
return undef;
}
sub get_tag_value {
my %params = @_;
my ($c,$schema,$event,$type) = @params{qw/c schema event type/};
$schema //= $c->model('DB');
if ($event) {
my $tags_rs = $schema->resultset('events_tag');
my $tag_data = $event->tag_data->find({
tag_id => $tags_rs->find({ type => $type })->id,
});
if ($tag_data) {
return $tag_data->val;
}
}
return undef;
}
1;