From 455415562707e408fb31913a865dce3f9bea5f68 Mon Sep 17 00:00:00 2001 From: Kirill Solomko Date: Tue, 22 Mar 2022 18:03:08 +0100 Subject: [PATCH] TT#167400 change call forwardings preference to be distinct * Call forwardings related internal usr preferences are now distinct per call forward type (maximum 1 record per call forward type, if at least one forwarding for this type exists). This change is meant to address the issue when there are >1000 call forwardings per subscriber, which leads to performance issues. Other components (kamailio) only uses this preference as a boolean to check if there are call forwardings at all per type, therefore, more than one preference, per type, per subscriber is not needed. Change-Id: Iffa475700a74f56eff67400ce9b57092018a14a0 --- lib/NGCP/Panel/Controller/Subscriber.pm | 100 +++++++++++++++--------- lib/NGCP/Panel/Utils/CallForwards.pm | 13 ++- 2 files changed, 71 insertions(+), 42 deletions(-) diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index aa6e374645..e7892e5d8a 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -1098,10 +1098,13 @@ sub preferences_callforward :Chained('base') :PathPart('preferences/callforward' else { $map->update({enabled => $cf_form->field('enabled')->value}); } - foreach my $pref($cf_preference->all) { - $pref->delete; + + if ($cf_preference->first) { + $cf_preference->first->update({ value => $map->id }); + } else { + $cf_preference->create({ value => $map->id }); } - $cf_preference->create({ value => $map->id }); + if($cf_type eq 'cft') { if($ringtimeout_preference->first) { if (!$cf_form->field('enabled')->value) { @@ -1280,8 +1283,8 @@ sub preferences_callforward_advanced :Chained('base') :PathPart('preferences/cal $autoattendant_count += NGCP::Panel::Utils::Subscriber::check_dset_autoattendant_status($map->destination_set); $map->delete; } - $cf_preference->delete_all; unless(@active) { + $cf_preference->delete_all; $ringtimeout_preference->first->delete if($cf_type eq "cft" && $ringtimeout_preference->first); NGCP::Panel::Utils::Message::info( @@ -1296,6 +1299,7 @@ sub preferences_callforward_advanced :Chained('base') :PathPart('preferences/cal return; } } + my $cf_pref_created = 0; foreach my $map(@active) { my $m = $cf_mapping->create({ type => $cf_type, @@ -1305,7 +1309,15 @@ sub preferences_callforward_advanced :Chained('base') :PathPart('preferences/cal bnumber_set_id => $map->field('bnumber_set')->value, enabled => $map->field('enabled')->value, }); - $cf_preference->create({ value => $m->id }); + if (!$cf_pref_created) { + if ($cf_preference->count != 1) { + $cf_preference->delete_all; + $cf_preference->create({ value => $m->id }); + } else { + $cf_preference->first->update({ value => $m->id }); + } + $cf_pref_created = 1; + } $autoattendant_count -= NGCP::Panel::Utils::Subscriber::check_dset_autoattendant_status($m->destination_set); } if ($autoattendant_count > 0) { @@ -1491,13 +1503,14 @@ sub preferences_callforward_destinationset_edit :Chained('preferences_callforwar [$c->req->captures->[0]], $cf_type); my $posted = ($c->request->method eq 'POST'); + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; my $cf_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => $cf_type, ); my $ringtimeout_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => 'ringtimeout', ); @@ -1546,8 +1559,6 @@ sub preferences_callforward_destinationset_edit :Chained('preferences_callforwar my @fields = $form->field('destination')->fields; unless(@fields) { foreach my $mapping($set->voip_cf_mappings->all) { - my $cf = $cf_preference->find({ value => $mapping->id }); - $cf->delete if $cf; $ringtimeout_preference->first->delete if($cf_type eq "cft" && $ringtimeout_preference->first); $mapping->delete; @@ -1559,6 +1570,11 @@ sub preferences_callforward_destinationset_edit :Chained('preferences_callforwar ); } $set->delete; + my $maps = $prov_subscriber->voip_cf_mappings->search; + if (!$maps->first) { + $cf_preference->delete_all; + } + NGCP::Panel::Utils::Navigation::back_or($c, $fallback, 1); return; } @@ -1621,24 +1637,22 @@ sub preferences_callforward_destinationset_edit :Chained('preferences_callforwar sub preferences_callforward_destinationset_delete :Chained('preferences_callforward_destinationset_base') :PathPart('delete') :Args(1) { my ($self, $c, $cf_type) = @_; + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; my $cf_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => $cf_type, ); my $ringtimeout_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => 'ringtimeout', ); my $set = $c->stash->{destination_set}; - my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; try { my $schema = $c->model('DB'); $schema->txn_do(sub { my $autoattendant = NGCP::Panel::Utils::Subscriber::check_dset_autoattendant_status($set); foreach my $map($set->voip_cf_mappings->all) { - my $cf = $cf_preference->find({ value => $map->id }); - $cf->delete if $cf; $map->delete; if ($autoattendant) { NGCP::Panel::Utils::Events::insert( @@ -1653,6 +1667,10 @@ sub preferences_callforward_destinationset_delete :Chained('preferences_callforw $ringtimeout_preference->first->delete; } $set->delete; + my $maps = $prov_subscriber->voip_cf_mappings->search; + if (!$maps->first) { + $cf_preference->delete_all; + } }); NGCP::Panel::Utils::Message::info( c => $c, @@ -1800,9 +1818,10 @@ sub preferences_callforward_sourceset_edit :Chained('preferences_callforward_sou [$c->req->captures->[0]], $cf_type); my $posted = ($c->request->method eq 'POST'); + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; my $cf_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => $cf_type, ); my $ringtimeout_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( @@ -1847,13 +1866,15 @@ sub preferences_callforward_sourceset_edit :Chained('preferences_callforward_sou my @fields = $form->field('source')->fields; unless(@fields) { foreach my $mapping($set->voip_cf_mappings->all) { - my $cf = $cf_preference->find({ value => $mapping->id }); - $cf->delete if $cf; $ringtimeout_preference->first->delete if($cf_type eq "cft" && $ringtimeout_preference->first); $mapping->delete; } $set->delete; + my $maps = $prov_subscriber->voip_cf_mappings->search; + if (!$maps->first) { + $cf_preference->delete_all; + } NGCP::Panel::Utils::Navigation::back_or($c, $fallback, 1); return; } @@ -1904,30 +1925,30 @@ sub preferences_callforward_sourceset_edit :Chained('preferences_callforward_sou sub preferences_callforward_sourceset_delete :Chained('preferences_callforward_sourceset_base') :PathPart('delete') :Args(1) { my ($self, $c, $cf_type) = @_; + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; my $cf_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => $cf_type, ); my $ringtimeout_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => 'ringtimeout', ); my $set = $c->stash->{source_set}; - my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; try { my $schema = $c->model('DB'); $schema->txn_do(sub { - foreach my $map($set->voip_cf_mappings->all) { - my $cf = $cf_preference->find({ value => $map->id }); - $cf->delete if $cf; - $map->delete; - } + $set->voip_cf_mappings->delete_all; if($cf_type eq "cft" && $prov_subscriber->voip_cf_mappings->search_rs({ type => $cf_type})->count == 0) { $ringtimeout_preference->first->delete; } $set->delete; + my $maps = $prov_subscriber->voip_cf_mappings->search; + if (!$maps->first) { + $cf_preference->delete_all; + } }); NGCP::Panel::Utils::Message::info( c => $c, @@ -2075,13 +2096,14 @@ sub preferences_callforward_bnumberset_edit :Chained('preferences_callforward_bn [$c->req->captures->[0]], $cf_type); my $posted = ($c->request->method eq 'POST'); + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; my $cf_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => $cf_type, ); my $ringtimeout_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => 'ringtimeout', ); @@ -2122,14 +2144,15 @@ sub preferences_callforward_bnumberset_edit :Chained('preferences_callforward_bn my @fields = $form->field('bnumbers')->fields; unless(@fields) { foreach my $mapping($set->voip_cf_mappings->all) { - # delete it here (this has been a design decicion from the beginning for all parts of cfs) - my $cf = $cf_preference->find({ value => $mapping->id }); - $cf->delete if $cf; $ringtimeout_preference->first->delete if($cf_type eq "cft" && $ringtimeout_preference->first); $mapping->delete; } $set->delete; + my $maps = $prov_subscriber->voip_cf_mappings->search; + if (!$maps->first) { + $cf_preference->delete_all; + } NGCP::Panel::Utils::Navigation::back_or($c, $fallback, 1); return; } @@ -2180,30 +2203,31 @@ sub preferences_callforward_bnumberset_edit :Chained('preferences_callforward_bn sub preferences_callforward_bnumberset_delete :Chained('preferences_callforward_bnumberset_base') :PathPart('delete') :Args(1) { my ($self, $c, $cf_type) = @_; + my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; + my $cf_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => $cf_type, ); my $ringtimeout_preference = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( - c => $c, prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber, + c => $c, prov_subscriber => $prov_subscriber, attribute => 'ringtimeout', ); my $set = $c->stash->{bnumber_set}; - my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber; try { my $schema = $c->model('DB'); $schema->txn_do(sub { - foreach my $map($set->voip_cf_mappings->all) { - my $cf = $cf_preference->find({ value => $map->id }); - $cf->delete if $cf; - $map->delete; - } + $set->voip_cf_mappings->delete_all; if($cf_type eq "cft" && $prov_subscriber->voip_cf_mappings->search_rs({ type => $cf_type})->count == 0) { $ringtimeout_preference->first->delete; } $set->delete; + my $maps = $prov_subscriber->voip_cf_mappings->search; + if (!$maps->first) { + $cf_preference->delete_all; + } }); NGCP::Panel::Utils::Message::info( c => $c, diff --git a/lib/NGCP/Panel/Utils/CallForwards.pm b/lib/NGCP/Panel/Utils/CallForwards.pm index dc0245021d..97731f2311 100644 --- a/lib/NGCP/Panel/Utils/CallForwards.pm +++ b/lib/NGCP/Panel/Utils/CallForwards.pm @@ -346,13 +346,11 @@ sub update_cf_mappings { $autoattendant_count += NGCP::Panel::Utils::Subscriber::check_dset_autoattendant_status($map->destination_set); } $mappings_rs->delete; - for my $type ( qw/cfu cfb cft cfna cfs cfr cfo/) { - $cf_preferences{$type}->delete; - } } $mappings_rs->populate(\@new_mappings); for my $type ( qw/cfu cfb cft cfna cfs cfr cfo/) { + my $cf_preference = $cf_preferences{$type}; my @mapping_ids_by_type = $mappings_rs->search( { type => $type @@ -363,7 +361,14 @@ sub update_cf_mappings { result_class => 'DBIx::Class::ResultClass::HashRefInflator' } )->all(); - $cf_preferences{$type}->populate(\@mapping_ids_by_type); + if (!@mapping_ids_by_type) { + $cf_preference->delete; + } elsif ($cf_preference->count != 1) { + $cf_preference->delete; + $cf_preference->create($mapping_ids_by_type[0]); + } else { + $cf_preference->update($mapping_ids_by_type[0]); + } } unless ($params->{add_only}) {