TT#18883 implement teletek importer #8
+ prepare/merge/clean callforward+voicemail Y/N data + add voip_cf_destinations dao + add voip_cf_destination_sets dao + voip_cf_mappings, destination_sets and destinations insert dao method + write callforwards + write callforward related preference values + not well-formed enough: fixed issues popped up when trying to view/edit created callfowards in panel + fix "database locked" error - properly handle SQLite's serialized transactions (single transaction at a time). + write report file for debugging/review - json graph of merged data of a subscriber - including fields info/warning/error messages for a subscriber - write it snychronized now + get rid of JSON::XS + extend NGCPRestApi connector to support file transfers + heuristic for missing "channels" (by subscriber number count) + prevent mysql deadlocks when writing to ngcp + strictly consider record order from imports + task end result stats polished + cleanup code a bit + add kmailio.location dao + add kmailio.location insert dao method + writing "permanent registrations" to kamailio.location + generate location "ruid" and "partition" according to kamailio Change-Id: Ief9a7634b4930e51d79ac5e963ba48769d3708eachanges/46/15646/15
parent
90d93a9990
commit
bfa6575581
@ -0,0 +1,257 @@
|
|||||||
|
package NGCP::BulkProcessor::Dao::Trunk::kamailio::location;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
## no critic
|
||||||
|
|
||||||
|
#use threads::shared qw();
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::Logging qw(
|
||||||
|
getlogger
|
||||||
|
rowinserted
|
||||||
|
);
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::ConnectorPool qw(
|
||||||
|
get_kamailio_db
|
||||||
|
);
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::SqlProcessor qw(
|
||||||
|
checktableinfo
|
||||||
|
insert_record
|
||||||
|
copy_row
|
||||||
|
);
|
||||||
|
use NGCP::BulkProcessor::SqlRecord qw();
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::Utils qw(threadid);
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
our @ISA = qw(Exporter NGCP::BulkProcessor::SqlRecord);
|
||||||
|
our @EXPORT_OK = qw(
|
||||||
|
gettablename
|
||||||
|
check_table
|
||||||
|
|
||||||
|
insert_row
|
||||||
|
countby_usernamedomain
|
||||||
|
next_ruid
|
||||||
|
);
|
||||||
|
|
||||||
|
my $tablename = 'location';
|
||||||
|
my $get_db = \&get_kamailio_db;
|
||||||
|
|
||||||
|
my $expected_fieldnames = [
|
||||||
|
'id',
|
||||||
|
'username',
|
||||||
|
'domain',
|
||||||
|
'contact',
|
||||||
|
'received',
|
||||||
|
'path',
|
||||||
|
'expires',
|
||||||
|
'q',
|
||||||
|
'callid',
|
||||||
|
'cseq',
|
||||||
|
'last_modified',
|
||||||
|
'flags',
|
||||||
|
'cflags',
|
||||||
|
'user_agent',
|
||||||
|
'socket',
|
||||||
|
'methods',
|
||||||
|
'ruid',
|
||||||
|
'reg_id',
|
||||||
|
'instance',
|
||||||
|
'server_id',
|
||||||
|
'connection_id',
|
||||||
|
'keepalive',
|
||||||
|
'partition',
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
my $indexes = {};
|
||||||
|
|
||||||
|
my $insert_unique_fields = [];
|
||||||
|
|
||||||
|
#/*! call-id used for ul_add and ul_rm_contact */
|
||||||
|
#static str mi_ul_cid = str_init("dfjrewr12386fd6-343@Kamailio.mi");
|
||||||
|
#/*! user agent used for ul_add */
|
||||||
|
#static str mi_ul_ua = str_init("Kamailio MI Server");
|
||||||
|
|
||||||
|
my $default_expires = 0; #4294967295
|
||||||
|
my $default_path = '<sip:127.0.0.1:5060;lr>';
|
||||||
|
my $default_q = 1.0;
|
||||||
|
my $default_cseq = 1;
|
||||||
|
my $default_callid = 'dfjrewr12386fd6-343@Kamailio.mi';
|
||||||
|
my $default_useragent = 'SIP Router MI Server'; #'Kamailio MI Server';
|
||||||
|
#\kamailio-master\src\lib\srutils\sruid.c
|
||||||
|
my $ruid_time = time();
|
||||||
|
my $ruid_counter = 0;
|
||||||
|
my $ruid_format = 'ulcx-%x-%x-%x';
|
||||||
|
my $partition_counter = 0;
|
||||||
|
my $max_partitions = undef; #>30...;
|
||||||
|
|
||||||
|
sub next_ruid {
|
||||||
|
return sprintf($ruid_format,$ruid_time,threadid(),$ruid_counter++);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _get_partition {
|
||||||
|
my $partition = $partition_counter + threadid();
|
||||||
|
$partition_counter++;
|
||||||
|
if (defined $max_partitions and $max_partitions > 0) {
|
||||||
|
return $partition % $max_partitions;
|
||||||
|
}
|
||||||
|
return $partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
|
||||||
|
my $class = shift;
|
||||||
|
my $self = NGCP::BulkProcessor::SqlRecord->new($class,$get_db,
|
||||||
|
$tablename,$expected_fieldnames,$indexes);
|
||||||
|
|
||||||
|
copy_row($self,shift,$expected_fieldnames);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub countby_usernamedomain {
|
||||||
|
|
||||||
|
my ($username,$domain) = @_;
|
||||||
|
|
||||||
|
check_table();
|
||||||
|
my $db = &$get_db();
|
||||||
|
my $table = $db->tableidentifier($tablename);
|
||||||
|
|
||||||
|
my $stmt = 'SELECT COUNT(*) FROM ' . $table;
|
||||||
|
my @params = ();
|
||||||
|
my @terms = ();
|
||||||
|
if (defined $username) {
|
||||||
|
push(@terms,'username = ?');
|
||||||
|
push(@params,$username);
|
||||||
|
}
|
||||||
|
if (defined $domain) {
|
||||||
|
push(@terms,'domain = ?');
|
||||||
|
push(@params,$domain);
|
||||||
|
}
|
||||||
|
if ((scalar @terms) > 0) {
|
||||||
|
$stmt .= ' WHERE ' . join(' AND ',@terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $db->db_get_value($stmt,@params);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub insert_row {
|
||||||
|
|
||||||
|
my $db = &$get_db();
|
||||||
|
my $xa_db = shift // $db;
|
||||||
|
if ('HASH' eq ref $_[0]) {
|
||||||
|
my ($data,$insert_ignore) = @_;
|
||||||
|
check_table();
|
||||||
|
if (insert_record($db,$xa_db,__PACKAGE__,$data,$insert_ignore,$insert_unique_fields)) {
|
||||||
|
return $xa_db->db_last_insert_id();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
my %params = @_;
|
||||||
|
my ($username,
|
||||||
|
$domain,
|
||||||
|
$contact,
|
||||||
|
$q,
|
||||||
|
$expires,
|
||||||
|
$ruid) = @params{qw/
|
||||||
|
username
|
||||||
|
domain
|
||||||
|
contact
|
||||||
|
q
|
||||||
|
expires
|
||||||
|
ruid
|
||||||
|
/};
|
||||||
|
|
||||||
|
$expires //= $default_expires;
|
||||||
|
$q //= $default_q;
|
||||||
|
$ruid //= next_ruid();
|
||||||
|
my $partition = _get_partition();
|
||||||
|
my $path = $default_path;
|
||||||
|
my $cseq = $default_cseq;
|
||||||
|
my $callid = $default_callid;
|
||||||
|
my $useragent = $default_useragent;
|
||||||
|
|
||||||
|
if ($xa_db->db_do('INSERT INTO ' . $db->tableidentifier($tablename) . ' (' .
|
||||||
|
$db->columnidentifier('username') . ', ' .
|
||||||
|
$db->columnidentifier('domain') . ', ' .
|
||||||
|
$db->columnidentifier('contact') . ', ' .
|
||||||
|
$db->columnidentifier('path') . ', ' .
|
||||||
|
$db->columnidentifier('q') . ', ' .
|
||||||
|
$db->columnidentifier('last_modified') . ', ' .
|
||||||
|
$db->columnidentifier('expires') . ', ' .
|
||||||
|
$db->columnidentifier('cseq') . ', ' .
|
||||||
|
$db->columnidentifier('callid') . ', ' .
|
||||||
|
$db->columnidentifier('user_agent') . ', ' .
|
||||||
|
$db->columnidentifier('partition') . ', ' .
|
||||||
|
$db->columnidentifier('ruid') . ') VALUES (' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'FROM_UNIXTIME(0), ' .
|
||||||
|
'FROM_UNIXTIME(?), ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?)',
|
||||||
|
$username,
|
||||||
|
$domain,
|
||||||
|
$contact,
|
||||||
|
$path,
|
||||||
|
$q,
|
||||||
|
$expires,
|
||||||
|
$cseq,
|
||||||
|
$callid,
|
||||||
|
$useragent,
|
||||||
|
$partition,
|
||||||
|
$ruid,
|
||||||
|
)) {
|
||||||
|
rowinserted($db,$tablename,getlogger(__PACKAGE__));
|
||||||
|
return $xa_db->db_last_insert_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub buildrecords_fromrows {
|
||||||
|
|
||||||
|
my ($rows,$load_recursive) = @_;
|
||||||
|
|
||||||
|
my @records = ();
|
||||||
|
my $record;
|
||||||
|
|
||||||
|
if (defined $rows and ref $rows eq 'ARRAY') {
|
||||||
|
foreach my $row (@$rows) {
|
||||||
|
$record = __PACKAGE__->new($row);
|
||||||
|
|
||||||
|
# transformations go here ...
|
||||||
|
|
||||||
|
push @records,$record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return \@records;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub gettablename {
|
||||||
|
|
||||||
|
return $tablename;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub check_table {
|
||||||
|
|
||||||
|
return checktableinfo($get_db,
|
||||||
|
__PACKAGE__,$tablename,
|
||||||
|
$expected_fieldnames,
|
||||||
|
$indexes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -0,0 +1,148 @@
|
|||||||
|
package NGCP::BulkProcessor::Dao::Trunk::provisioning::voip_cf_destination_sets;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
## no critic
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::ConnectorPool qw(
|
||||||
|
get_provisioning_db
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::SqlProcessor qw(
|
||||||
|
checktableinfo
|
||||||
|
copy_row
|
||||||
|
insert_record
|
||||||
|
);
|
||||||
|
use NGCP::BulkProcessor::SqlRecord qw();
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
our @ISA = qw(Exporter NGCP::BulkProcessor::SqlRecord);
|
||||||
|
our @EXPORT_OK = qw(
|
||||||
|
gettablename
|
||||||
|
check_table
|
||||||
|
|
||||||
|
countby_subscriberid_type
|
||||||
|
insert_row
|
||||||
|
);
|
||||||
|
|
||||||
|
my $tablename = 'voip_cf_destination_sets';
|
||||||
|
my $get_db = \&get_provisioning_db;
|
||||||
|
|
||||||
|
my $expected_fieldnames = [
|
||||||
|
'id',
|
||||||
|
'subscriber_id',
|
||||||
|
'name',
|
||||||
|
];
|
||||||
|
|
||||||
|
my $indexes = {};
|
||||||
|
|
||||||
|
my $insert_unique_fields = [];
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
|
||||||
|
my $class = shift;
|
||||||
|
my $self = NGCP::BulkProcessor::SqlRecord->new($class,$get_db,
|
||||||
|
$tablename,$expected_fieldnames,$indexes);
|
||||||
|
|
||||||
|
copy_row($self,shift,$expected_fieldnames);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub countby_subscriberid_type {
|
||||||
|
|
||||||
|
my ($subscriber_id,$type,$load_recursive) = @_;
|
||||||
|
|
||||||
|
check_table();
|
||||||
|
my $db = &$get_db();
|
||||||
|
my $table = $db->tableidentifier($tablename);
|
||||||
|
|
||||||
|
my $stmt = 'SELECT COUNT(*) FROM ' . $table;
|
||||||
|
my @params = ();
|
||||||
|
my @terms = ();
|
||||||
|
if ($subscriber_id) {
|
||||||
|
push(@terms,$db->columnidentifier('subscriber_id') . ' = ?');
|
||||||
|
push(@params,$subscriber_id);
|
||||||
|
}
|
||||||
|
if ($type) {
|
||||||
|
push(@terms,$db->columnidentifier('type') . ' = ?');
|
||||||
|
push(@params,$type);
|
||||||
|
}
|
||||||
|
if ((scalar @terms) > 0) {
|
||||||
|
$stmt .= ' WHERE ' . join(' AND ',@terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $db->db_get_value($stmt,@params);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub insert_row {
|
||||||
|
|
||||||
|
my $db = &$get_db();
|
||||||
|
my $xa_db = shift // $db;
|
||||||
|
if ('HASH' eq ref $_[0]) {
|
||||||
|
my ($data,$insert_ignore) = @_;
|
||||||
|
check_table();
|
||||||
|
if (insert_record($db,$xa_db,__PACKAGE__,$data,$insert_ignore,$insert_unique_fields)) {
|
||||||
|
return $xa_db->db_last_insert_id();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
my %params = @_;
|
||||||
|
my ($subscriber_id,
|
||||||
|
$name) = @params{qw/
|
||||||
|
subscriber_id
|
||||||
|
name
|
||||||
|
/};
|
||||||
|
|
||||||
|
if ($xa_db->db_do('INSERT INTO ' . $db->tableidentifier($tablename) . ' (' .
|
||||||
|
$db->columnidentifier('subscriber_id') . ', ' .
|
||||||
|
$db->columnidentifier('name') .') VALUES (' .
|
||||||
|
'?, ' .
|
||||||
|
'?)'
|
||||||
|
)) {
|
||||||
|
rowinserted($db,$tablename,getlogger(__PACKAGE__));
|
||||||
|
return $xa_db->db_last_insert_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub buildrecords_fromrows {
|
||||||
|
|
||||||
|
my ($rows,$load_recursive) = @_;
|
||||||
|
|
||||||
|
my @records = ();
|
||||||
|
my $record;
|
||||||
|
|
||||||
|
if (defined $rows and ref $rows eq 'ARRAY') {
|
||||||
|
foreach my $row (@$rows) {
|
||||||
|
$record = __PACKAGE__->new($row);
|
||||||
|
|
||||||
|
# transformations go here ...
|
||||||
|
|
||||||
|
push @records,$record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return \@records;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub gettablename {
|
||||||
|
|
||||||
|
return $tablename;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub check_table {
|
||||||
|
|
||||||
|
return checktableinfo($get_db,
|
||||||
|
__PACKAGE__,$tablename,
|
||||||
|
$expected_fieldnames,
|
||||||
|
$indexes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -0,0 +1,163 @@
|
|||||||
|
package NGCP::BulkProcessor::Dao::Trunk::provisioning::voip_cf_destinations;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
## no critic
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::ConnectorPool qw(
|
||||||
|
get_provisioning_db
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
use NGCP::BulkProcessor::SqlProcessor qw(
|
||||||
|
checktableinfo
|
||||||
|
copy_row
|
||||||
|
insert_record
|
||||||
|
);
|
||||||
|
use NGCP::BulkProcessor::SqlRecord qw();
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
our @ISA = qw(Exporter NGCP::BulkProcessor::SqlRecord);
|
||||||
|
our @EXPORT_OK = qw(
|
||||||
|
gettablename
|
||||||
|
check_table
|
||||||
|
|
||||||
|
countby_subscriberid_type
|
||||||
|
insert_row
|
||||||
|
);
|
||||||
|
|
||||||
|
my $tablename = 'voip_cf_destinations';
|
||||||
|
my $get_db = \&get_provisioning_db;
|
||||||
|
|
||||||
|
my $expected_fieldnames = [
|
||||||
|
'id',
|
||||||
|
'destination_set_id',
|
||||||
|
'destination',
|
||||||
|
'priority',
|
||||||
|
'timeout',
|
||||||
|
'announcement_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
my $indexes = {};
|
||||||
|
|
||||||
|
my $insert_unique_fields = [];
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
|
||||||
|
my $class = shift;
|
||||||
|
my $self = NGCP::BulkProcessor::SqlRecord->new($class,$get_db,
|
||||||
|
$tablename,$expected_fieldnames,$indexes);
|
||||||
|
|
||||||
|
copy_row($self,shift,$expected_fieldnames);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub countby_subscriberid_type {
|
||||||
|
|
||||||
|
my ($subscriber_id,$type,$load_recursive) = @_;
|
||||||
|
|
||||||
|
check_table();
|
||||||
|
my $db = &$get_db();
|
||||||
|
my $table = $db->tableidentifier($tablename);
|
||||||
|
|
||||||
|
my $stmt = 'SELECT COUNT(*) FROM ' . $table;
|
||||||
|
my @params = ();
|
||||||
|
my @terms = ();
|
||||||
|
if ($subscriber_id) {
|
||||||
|
push(@terms,$db->columnidentifier('subscriber_id') . ' = ?');
|
||||||
|
push(@params,$subscriber_id);
|
||||||
|
}
|
||||||
|
if ($type) {
|
||||||
|
push(@terms,$db->columnidentifier('type') . ' = ?');
|
||||||
|
push(@params,$type);
|
||||||
|
}
|
||||||
|
if ((scalar @terms) > 0) {
|
||||||
|
$stmt .= ' WHERE ' . join(' AND ',@terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $db->db_get_value($stmt,@params);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub insert_row {
|
||||||
|
|
||||||
|
my $db = &$get_db();
|
||||||
|
my $xa_db = shift // $db;
|
||||||
|
if ('HASH' eq ref $_[0]) {
|
||||||
|
my ($data,$insert_ignore) = @_;
|
||||||
|
check_table();
|
||||||
|
if (insert_record($db,$xa_db,__PACKAGE__,$data,$insert_ignore,$insert_unique_fields)) {
|
||||||
|
return $xa_db->db_last_insert_id();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
my %params = @_;
|
||||||
|
my ($destination_set_id,
|
||||||
|
$destination,
|
||||||
|
$priority,
|
||||||
|
$timeout,
|
||||||
|
$announcement_id) = @params{qw/
|
||||||
|
destination_set_id
|
||||||
|
destination
|
||||||
|
priority
|
||||||
|
timeout
|
||||||
|
announcement_id
|
||||||
|
/};
|
||||||
|
|
||||||
|
if ($xa_db->db_do('INSERT INTO ' . $db->tableidentifier($tablename) . ' (' .
|
||||||
|
$db->columnidentifier('destination_set_id') . ', ' .
|
||||||
|
$db->columnidentifier('destination') . ', ' .
|
||||||
|
$db->columnidentifier('priority') . ', ' .
|
||||||
|
$db->columnidentifier('timeout') . ', ' .
|
||||||
|
$db->columnidentifier('announcement_id') .') VALUES (' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'?, ' .
|
||||||
|
'NULL)'
|
||||||
|
)) {
|
||||||
|
rowinserted($db,$tablename,getlogger(__PACKAGE__));
|
||||||
|
return $xa_db->db_last_insert_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub buildrecords_fromrows {
|
||||||
|
|
||||||
|
my ($rows,$load_recursive) = @_;
|
||||||
|
|
||||||
|
my @records = ();
|
||||||
|
my $record;
|
||||||
|
|
||||||
|
if (defined $rows and ref $rows eq 'ARRAY') {
|
||||||
|
foreach my $row (@$rows) {
|
||||||
|
$record = __PACKAGE__->new($row);
|
||||||
|
|
||||||
|
# transformations go here ...
|
||||||
|
|
||||||
|
push @records,$record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return \@records;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub gettablename {
|
||||||
|
|
||||||
|
return $tablename;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub check_table {
|
||||||
|
|
||||||
|
return checktableinfo($get_db,
|
||||||
|
__PACKAGE__,$tablename,
|
||||||
|
$expected_fieldnames,
|
||||||
|
$indexes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -1,433 +0,0 @@
|
|||||||
package NGCP::BulkProcessor::Projects::Migration::Teletek::Api;
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
## no critic
|
|
||||||
|
|
||||||
use threads::shared qw();
|
|
||||||
#use List::Util qw();
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Projects::Migration::Teletek::Settings qw(
|
|
||||||
$dry
|
|
||||||
$skip_errors
|
|
||||||
$batch
|
|
||||||
|
|
||||||
$domain_name
|
|
||||||
$reseller_id
|
|
||||||
$subsciber_username_prefix
|
|
||||||
|
|
||||||
$set_call_forwards_multithreading
|
|
||||||
$set_call_forwards_numofthreads
|
|
||||||
$cfb_priorities
|
|
||||||
$cfb_timeouts
|
|
||||||
$cfu_priorities
|
|
||||||
$cfu_timeouts
|
|
||||||
$cft_priorities
|
|
||||||
$cft_timeouts
|
|
||||||
$cfna_priorities
|
|
||||||
$cfna_timeouts
|
|
||||||
$cfnumber_exclude_pattern
|
|
||||||
$cfnumber_trim_pattern
|
|
||||||
$ringtimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Logging qw (
|
|
||||||
getlogger
|
|
||||||
processing_info
|
|
||||||
processing_debug
|
|
||||||
);
|
|
||||||
use NGCP::BulkProcessor::LogError qw(
|
|
||||||
rowprocessingerror
|
|
||||||
rowprocessingwarn
|
|
||||||
);
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Dao::Trunk::billing::voip_subscribers qw();
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber qw();
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Dao::Trunk::provisioning::voip_subscribers qw();
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::RestRequests::Trunk::CallForwards qw();
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::ConnectorPool qw(
|
|
||||||
get_xa_db
|
|
||||||
);
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Projects::Migration::Teletek::ProjectConnectorPool qw(
|
|
||||||
destroy_all_dbs
|
|
||||||
);
|
|
||||||
|
|
||||||
use NGCP::BulkProcessor::Utils qw(threadid);
|
|
||||||
|
|
||||||
require Exporter;
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT_OK = qw(
|
|
||||||
set_call_forwards
|
|
||||||
);
|
|
||||||
|
|
||||||
sub set_call_forwards {
|
|
||||||
|
|
||||||
my $static_context = {};
|
|
||||||
my $result = _set_call_forwards_checks($static_context);
|
|
||||||
|
|
||||||
destroy_all_dbs();
|
|
||||||
my $warning_count :shared = 0;
|
|
||||||
return ($result && NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber::process_records(
|
|
||||||
static_context => $static_context,
|
|
||||||
process_code => sub {
|
|
||||||
my ($context,$records,$row_offset) = @_;
|
|
||||||
my $rownum = $row_offset;
|
|
||||||
foreach my $imported_subscriber (@$records) {
|
|
||||||
$rownum++;
|
|
||||||
next unless _reset_set_call_forward_context($context,$imported_subscriber,$rownum);
|
|
||||||
_set_call_forward($context);
|
|
||||||
}
|
|
||||||
|
|
||||||
#return 0;
|
|
||||||
return 1;
|
|
||||||
},
|
|
||||||
init_process_context_code => sub {
|
|
||||||
my ($context)= @_;
|
|
||||||
$context->{db} = &get_xa_db();
|
|
||||||
$context->{error_count} = 0;
|
|
||||||
$context->{warning_count} = 0;
|
|
||||||
# below is not mandatory..
|
|
||||||
_check_insert_tables();
|
|
||||||
},
|
|
||||||
uninit_process_context_code => sub {
|
|
||||||
my ($context)= @_;
|
|
||||||
undef $context->{db};
|
|
||||||
destroy_all_dbs();
|
|
||||||
{
|
|
||||||
lock $warning_count;
|
|
||||||
$warning_count += $context->{warning_count};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
load_recursive => 0,
|
|
||||||
multithreading => $set_call_forwards_multithreading,
|
|
||||||
numofthreads => $set_call_forwards_numofthreads,
|
|
||||||
),$warning_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _check_insert_tables {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _invoke_api {
|
|
||||||
my ($context,$api_code) = @_;
|
|
||||||
|
|
||||||
eval {
|
|
||||||
$context->{db}->db_begin();
|
|
||||||
#rowprocessingwarn($context->{tid},'AutoCommit is on' ,getlogger(__PACKAGE__)) if $context->{db}->{drh}->{AutoCommit};
|
|
||||||
|
|
||||||
my $existing_billing_voip_subscribers = NGCP::BulkProcessor::Dao::Trunk::billing::voip_subscribers::findby_domainid_username_states($context->{db},
|
|
||||||
$context->{billing_domain}->{id},$context->{username},{ 'NOT IN' => $NGCP::BulkProcessor::Dao::Trunk::billing::voip_subscribers::TERMINATED_STATE});
|
|
||||||
if ((scalar @$existing_billing_voip_subscribers) == 0) {
|
|
||||||
|
|
||||||
#if ($context->{subscriberdelta} eq
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber::deleted_delta) {
|
|
||||||
# _info($context,"($context->{rownum}) " . 'subscriber ' . $context->{cli} . ' is deleted, and no active subscriber found',1);
|
|
||||||
#} else {
|
|
||||||
# _warn($context,"($context->{rownum}) no active subscriber found for susbcriber " . $context->{cli});
|
|
||||||
#}
|
|
||||||
} elsif ((scalar @$existing_billing_voip_subscribers) == 1) {
|
|
||||||
$context->{billing_voip_subscriber} = $existing_billing_voip_subscribers->[0];
|
|
||||||
$context->{provisioning_voip_subscriber} = NGCP::BulkProcessor::Dao::Trunk::provisioning::voip_subscribers::findby_uuid(
|
|
||||||
$context->{db},$context->{billing_voip_subscriber}->{uuid});
|
|
||||||
if (defined $context->{provisioning_voip_subscriber}) {
|
|
||||||
#if ($context->{subscriberdelta} eq
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber::deleted_delta) {
|
|
||||||
#
|
|
||||||
# _warn($context,"($context->{rownum}) " . 'subscriber ' . $context->{cli} . ' is deleted, but active subscriber found');
|
|
||||||
|
|
||||||
#} else {
|
|
||||||
if (defined $api_code and 'CODE' eq ref $api_code) {
|
|
||||||
&$api_code($context);
|
|
||||||
}
|
|
||||||
#}
|
|
||||||
} else {
|
|
||||||
if ($skip_errors) {
|
|
||||||
_warn($context,"($context->{rownum}) " . 'no provisioning subscriber found: ' . $context->{cli});
|
|
||||||
} else {
|
|
||||||
_error($context,"($context->{rownum}) " . 'no provisioning subscriber found: ' . $context->{cli});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rowprocessingwarn($context->{tid},"($context->{rownum}) " . 'multiple (' . (scalar @$existing_billing_voip_subscribers) . ') existing billing subscribers with username ' . $context->{username} . ' found, skipping' ,getlogger(__PACKAGE__));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($dry) {
|
|
||||||
$context->{db}->db_rollback(0);
|
|
||||||
} else {
|
|
||||||
$context->{db}->db_commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
my $err = $@;
|
|
||||||
if ($err) {
|
|
||||||
eval {
|
|
||||||
$context->{db}->db_rollback(1);
|
|
||||||
};
|
|
||||||
if ($skip_errors) {
|
|
||||||
_warn($context,"($context->{rownum}) " . 'database error with subscriber ' . $context->{cli} . ': ' . $err);
|
|
||||||
} else {
|
|
||||||
_error($context,"($context->{rownum}) " . 'database error with subscriber ' . $context->{cli} . ': ' . $err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _set_call_forward {
|
|
||||||
my ($context) = @_;
|
|
||||||
_invoke_api($context,\&_set_cf_simple);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _checks {
|
|
||||||
|
|
||||||
my ($context) = @_;
|
|
||||||
|
|
||||||
my $result = 1;
|
|
||||||
|
|
||||||
#my $userpasswordcount = 0;
|
|
||||||
#eval {
|
|
||||||
# $userpasswordcount = NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::UsernamePassword::countby_fqdn();
|
|
||||||
#};
|
|
||||||
#if ($@ or $userpasswordcount == 0) {
|
|
||||||
# rowprocessingerror(threadid(),'please import user passwords first',getlogger(__PACKAGE__));
|
|
||||||
# $result = 0; #even in skip-error mode..
|
|
||||||
#}
|
|
||||||
#my $subscribercount = 0;
|
|
||||||
#my $subscriber_barring_profiles = [];
|
|
||||||
#eval {
|
|
||||||
# $subscribercount = NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber::countby_subscribernumber();
|
|
||||||
# $subscriber_barring_profiles = NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber::list_barringprofiles();
|
|
||||||
#};
|
|
||||||
#if ($@ or $subscribercount == 0) {
|
|
||||||
# rowprocessingerror(threadid(),'please import subscribers first',getlogger(__PACKAGE__));
|
|
||||||
# $result = 0; #even in skip-error mode..
|
|
||||||
#}
|
|
||||||
|
|
||||||
#eval {
|
|
||||||
# $context->{billing_domain} = NGCP::BulkProcessor::Dao::Trunk::billing::domains::findby_domain($domain_name);
|
|
||||||
# if (defined $context->{billing_domain}
|
|
||||||
# and NGCP::BulkProcessor::Dao::Trunk::billing::domain_resellers::countby_domainid_resellerid($context->{billing_domain}->{id},$reseller_id) == 0) {
|
|
||||||
# undef $context->{billing_domain};
|
|
||||||
# }
|
|
||||||
#};
|
|
||||||
#if ($@ or not defined $context->{billing_domain}) {
|
|
||||||
# rowprocessingerror(threadid(),'cannot find billing domain',getlogger(__PACKAGE__));
|
|
||||||
# $result = 0; #even in skip-error mode..
|
|
||||||
#}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _set_call_forwards_checks {
|
|
||||||
my ($context) = @_;
|
|
||||||
|
|
||||||
my $result = _checks($context);
|
|
||||||
|
|
||||||
#my $optioncount = 0;
|
|
||||||
#eval {
|
|
||||||
# $optioncount = NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOption::countby_subscribernumber_option();
|
|
||||||
#};
|
|
||||||
#if ($@ or $optioncount == 0) {
|
|
||||||
# rowprocessingerror(threadid(),'please import subscriber features first',getlogger(__PACKAGE__));
|
|
||||||
# $result = 0; #even in skip-error mode..
|
|
||||||
#}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _set_cf_simple {
|
|
||||||
|
|
||||||
my ($context) = @_;
|
|
||||||
|
|
||||||
my $result = 0;
|
|
||||||
#my $cf_path = NGCP::BulkProcessor::RestRequests::Trunk::CallForwards::get_item_path($context->{billing_voip_subscriber}->{id});
|
|
||||||
#eval {
|
|
||||||
# my $callforwards;
|
|
||||||
# if ($dry) {
|
|
||||||
# $callforwards = NGCP::BulkProcessor::RestRequests::Trunk::CallForwards::get_item($context->{billing_voip_subscriber}->{id});
|
|
||||||
# } else {
|
|
||||||
# $callforwards = NGCP::BulkProcessor::RestRequests::Trunk::CallForwards::set_item(
|
|
||||||
# $context->{billing_voip_subscriber}->{id},$context->{call_forwards});
|
|
||||||
# }
|
|
||||||
# $result = (defined $callforwards ? 1 : 0);
|
|
||||||
#};
|
|
||||||
#if ($@ or not $result) {
|
|
||||||
# if ($skip_errors) {
|
|
||||||
# _warn($context,"($context->{rownum}) " . 'subscriber ' . $context->{cli} . ': could not ' . ($dry ? 'fetch' : 'set') . ' call forwards ' . $cf_path);
|
|
||||||
# } else {
|
|
||||||
# _error($context,"($context->{rownum}) " . 'subscriber ' . $context->{cli} . ': could not ' . ($dry ? 'fetch' : 'set') . ' call forwards ' . $cf_path);
|
|
||||||
# }
|
|
||||||
#} else {
|
|
||||||
# _info($context,"($context->{rownum}) " . 'subscriber ' . $context->{cli} . ': call forwards ' . $cf_path . ($dry ? ' fetched' : ' set'));
|
|
||||||
#}
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _reset_context {
|
|
||||||
|
|
||||||
my ($context,$imported_subscriber,$rownum) = @_;
|
|
||||||
|
|
||||||
my $result = 1;
|
|
||||||
|
|
||||||
$context->{rownum} = $rownum;
|
|
||||||
|
|
||||||
#$context->{cli} = $imported_subscriber->subscribernumber();
|
|
||||||
#$context->{e164} = {};
|
|
||||||
#$context->{e164}->{cc} = substr($context->{cli},0,3);
|
|
||||||
#$context->{e164}->{ac} = '';
|
|
||||||
#$context->{e164}->{sn} = substr($context->{cli},3);
|
|
||||||
|
|
||||||
#$context->{subscriberdelta} = $imported_subscriber->{delta};
|
|
||||||
|
|
||||||
#my $userpassword = NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::UsernamePassword::findby_fqdn($context->{cli});
|
|
||||||
#if (defined $userpassword) {
|
|
||||||
# $context->{username} = (defined $subsciber_username_prefix ? $subsciber_username_prefix : '') . $userpassword->{username};
|
|
||||||
# $context->{password} = $userpassword->{password};
|
|
||||||
# $context->{userpassworddelta} = $userpassword->{delta};
|
|
||||||
#} else {
|
|
||||||
# # once full username+passwords is available:
|
|
||||||
# delete $context->{username};
|
|
||||||
# delete $context->{password};
|
|
||||||
# delete $context->{userpassworddelta};
|
|
||||||
# if ($context->{subscriberdelta} eq
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::Subscriber::deleted_delta) {
|
|
||||||
#
|
|
||||||
# } else {
|
|
||||||
# $result &= 0;
|
|
||||||
#
|
|
||||||
# if ($skip_errors) {
|
|
||||||
# # for now, as username+passwords are incomplete:
|
|
||||||
# _warn($context,"($context->{rownum}) " . 'no username/password for subscriber found: ' . $context->{cli});
|
|
||||||
# } else {
|
|
||||||
# _error($context,"($context->{rownum}) " . 'no username/password for subscriber found: ' . $context->{cli});
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
|
|
||||||
#delete $context->{billing_voip_subscriber};
|
|
||||||
#delete $context->{provisioning_voip_subscriber};
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _reset_set_call_forward_context {
|
|
||||||
|
|
||||||
my ($context,$imported_subscriber,$rownum) = @_;
|
|
||||||
|
|
||||||
my $result = _reset_context($context,$imported_subscriber,$rownum);
|
|
||||||
|
|
||||||
#my $call_forwards = {};
|
|
||||||
#if (NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::countby_subscribernumber_option_optionsetitem(
|
|
||||||
# $context->{cli}, { 'IN' => [
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_ON_BUSY_OPTION_SET,
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_ALL_CALLS_OPTION_SET,
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_ON_NO_ANSWER_OPTION_SET,
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_UNAVAILABLE_OPTION_SET,
|
|
||||||
# ]}) > 0) {
|
|
||||||
|
|
||||||
# $call_forwards->{cfb} = _prepare_callforward($context,$cfb_priorities,$cfb_timeouts,
|
|
||||||
# NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::findby_subscribernumber_option_optionsetitem(
|
|
||||||
# $context->{cli},
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_ON_BUSY_OPTION_SET,
|
|
||||||
# ));
|
|
||||||
|
|
||||||
# $call_forwards->{cfu} = _prepare_callforward($context,$cfu_priorities,$cfu_timeouts,
|
|
||||||
# NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::findby_subscribernumber_option_optionsetitem(
|
|
||||||
# $context->{cli},
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_ALL_CALLS_OPTION_SET,
|
|
||||||
# ));
|
|
||||||
|
|
||||||
# $call_forwards->{cft} = _prepare_callforward($context,$cft_priorities,$cft_timeouts,
|
|
||||||
# NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::findby_subscribernumber_option_optionsetitem(
|
|
||||||
# $context->{cli},
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_ON_NO_ANSWER_OPTION_SET,
|
|
||||||
# ));
|
|
||||||
# $call_forwards->{cft}->{ringtimeout} = $ringtimeout if defined $call_forwards->{cft};
|
|
||||||
|
|
||||||
# $call_forwards->{cfna} = _prepare_callforward($context,$cfna_priorities,$cfna_timeouts,
|
|
||||||
# NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::findby_subscribernumber_option_optionsetitem(
|
|
||||||
# $context->{cli},
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::FORWARD_UNAVAILABLE_OPTION_SET,
|
|
||||||
# ));
|
|
||||||
#} else {
|
|
||||||
# _info($context,"($context->{rownum}) " . 'subscriber ' . $context->{cli} . ' never had call forwards, skipping',1);
|
|
||||||
# $call_forwards->{cfb} = undef;
|
|
||||||
# $call_forwards->{cfu} = undef;
|
|
||||||
# $call_forwards->{cft} = undef;
|
|
||||||
# $call_forwards->{cfna} = undef;
|
|
||||||
# $result = 0;
|
|
||||||
#}
|
|
||||||
#$context->{call_forwards} = $call_forwards;
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _prepare_callforward {
|
|
||||||
|
|
||||||
my ($context,$priorities,$timeouts,$cf_option_set_items) = @_;
|
|
||||||
my @destinations = ();
|
|
||||||
#my $i = 0;
|
|
||||||
#foreach my $cf_option_set_item (@$cf_option_set_items) {
|
|
||||||
# if (defined $cf_option_set_item and $cf_option_set_item->{delta} ne
|
|
||||||
# $NGCP::BulkProcessor::Projects::Migration::Teletek::Dao::import::FeatureOptionSetItem::deleted_delta) {
|
|
||||||
# if (defined $cfnumber_exclude_pattern and $cf_option_set_item->{optionsetitem} =~ $cfnumber_exclude_pattern) {
|
|
||||||
# _warn($context,"($context->{rownum}) " . $cf_option_set_item->{option} . " '" . $cf_option_set_item->{optionsetitem} . "' of subscriber " . $context->{cli} . ': exclude pattern match');
|
|
||||||
# } else {
|
|
||||||
# my $destination = $cf_option_set_item->{optionsetitem};
|
|
||||||
# if (defined $cfnumber_trim_pattern) {
|
|
||||||
# $destination =~ s/$cfnumber_trim_pattern//;
|
|
||||||
# if ($cf_option_set_item->{optionsetitem} ne $destination) {
|
|
||||||
# _info($context,"($context->{rownum}) " . $cf_option_set_item->{option} . " '" . $cf_option_set_item->{optionsetitem} . "' of subscriber " . $context->{cli} . ": trim pattern match, changed to to '$destination'");
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# push(@destinations, {
|
|
||||||
# destination => $destination,
|
|
||||||
# priority => (defined $priorities->[$i] ? $priorities->[$i] : $priorities->[-1]),
|
|
||||||
# timeout => (defined $timeouts->[$i] ? $timeouts->[$i] : $timeouts->[-1]),
|
|
||||||
# });
|
|
||||||
# $i++;
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
if ((scalar @destinations) > 0) {
|
|
||||||
return { destinations => \@destinations , times => [], };
|
|
||||||
} else {
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _error {
|
|
||||||
|
|
||||||
my ($context,$message) = @_;
|
|
||||||
$context->{error_count} = $context->{error_count} + 1;
|
|
||||||
rowprocessingerror($context->{tid},$message,getlogger(__PACKAGE__));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _warn {
|
|
||||||
|
|
||||||
my ($context,$message) = @_;
|
|
||||||
$context->{warning_count} = $context->{warning_count} + 1;
|
|
||||||
rowprocessingwarn($context->{tid},$message,getlogger(__PACKAGE__));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _info {
|
|
||||||
|
|
||||||
my ($context,$message,$debug) = @_;
|
|
||||||
if ($debug) {
|
|
||||||
processing_debug($context->{tid},$message,getlogger(__PACKAGE__));
|
|
||||||
} else {
|
|
||||||
processing_info($context->{tid},$message,getlogger(__PACKAGE__));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
Loading…
Reference in new issue