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/Phonebook.pm

278 lines
7.3 KiB

package NGCP::Panel::Utils::Phonebook;
use strict;
use warnings;
use Sipwise::Base;
use English;
use NGCP::Panel::Utils::Generic qw(:all);
use NGCP::Panel::Utils::Message;
sub get_reseller_phonebook {
my ($c, $reseller_id) = @_;
my @pb;
my $r_pb_rs = $c->model('DB')->resultset('reseller_phonebook')->search({
reseller_id => $reseller_id,
});
for my $r ($r_pb_rs->all) {
push @pb, { name => $r->name, number => $r->number };
}
return [ sort { $a->{name} cmp $b->{name} } @pb ];
}
sub get_contract_phonebook {
my ($c, $contract_id) = @_;
my @pb;
my %c_numbers;
my $contract = $c->model('DB')->resultset('contracts')->search({
id => $contract_id,
})->first;
my $r_pb_rs = $c->model('DB')->resultset('reseller_phonebook')->search({
reseller_id => $contract->contact->reseller->id,
});
my $c_pb_rs = $c->model('DB')->resultset('contract_phonebook')->search({
contract_id => $contract_id,
});
for my $r ($c_pb_rs->all) {
push @pb, { name => $r->name, number => $r->number };
$c_numbers{$r->number} = $r->name;
}
for my $r ($r_pb_rs->all) {
unless (exists $c_numbers{$r->number}) {
push @pb, { name => $r->name, number => $r->number };
}
}
return [ sort { $a->{name} cmp $b->{name} } @pb ];
}
sub get_subscriber_phonebook {
my ($c, $subscriber_id) = @_;
my @pb;
my %c_numbers;
my $sub = $c->model('DB')->resultset('voip_subscribers')->search({
id => $subscriber_id,
})->first;
my $r_pb_rs = $c->model('DB')->resultset('reseller_phonebook')->search({
reseller_id => $sub->contract->contact->reseller->id,
});
my $c_pb_rs = $c->model('DB')->resultset('contract_phonebook')->search({
contract_id => $sub->contract_id,
});
my $a_pb_rs = $c->model('DB')->resultset('subscriber_phonebook')->search({
shared => 1,
'contract.id' => $sub->contract_id,
},{
join => { 'subscriber' => 'contract' },
});
my $s_pb_rs = $c->model('DB')->resultset('subscriber_phonebook')->search({
subscriber_id => $subscriber_id,
});
for my $r ($s_pb_rs->all) {
push @pb, { name => $r->name, number => $r->number };
$c_numbers{$r->number} = $r->name;
}
for my $r ($c_pb_rs->all) {
unless (exists $c_numbers{$r->number}) {
push @pb, { name => $r->name, number => $r->number };
$c_numbers{$r->number} = $r->name;
}
}
for my $r ($a_pb_rs->all) {
unless (exists $c_numbers{$r->number}) {
push @pb, { name => $r->name, number => $r->number };
$c_numbers{$r->number} = $r->name;
}
}
for my $r ($r_pb_rs->all) {
unless (exists $c_numbers{$r->number}) {
push @pb, { name => $r->name, number => $r->number };
}
}
return [ sort { $a->{name} cmp $b->{name} } @pb ];
}
sub ui_upload_csv {
my ($c, $rs, $form, $owner, $owner_id, $action, $back) = @_;
my $upload = $c->req->upload('upload_phonebook');
my $posted = $c->req->method eq 'POST';
my @params = ( upload_phonebook => $posted ? $upload : undef, );
$form->process(
posted => $posted,
params => { @params },
action => $action,
);
if($form->validated) {
unless($upload) {
NGCP::Panel::Utils::Message::error(
c => $c,
desc => $c->loc('No phonebook entries file specified!'),
);
$c->response->redirect($back);
return;
}
my $data = $upload->slurp;
my($entries, $fails, $text_success);
try {
my ($entries, $fails, $text) =
upload_csv($c, $rs, $owner, $owner_id,
$c->req->params->{purge_existing}, \$data);
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $$text,
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
desc => $c->loc('Failed to upload Phonebook entries'),
);
}
$c->response->redirect($back);
}
return;
}
sub upload_csv {
my ($c, $rs, $owner, $owner_id, $purge, $data) = @_;
my $csv = Text::CSV_XS->new({ allow_whitespace => 1, binary => 1, keep_meta_info => 1 });
my @cols = qw/name number/;
my @fields ;
my @fails = ();
my $linenum = 0;
my @entries;
$c->model('DB')->txn_do(sub {
open(my $fh, '<:encoding(utf8)', $data);
while ( my $line = <$fh> ){
++$linenum;
next unless length $line;
unless($csv->parse($line)) {
push @fails, $linenum;
next;
}
@fields = $csv->fields();
my $row = {};
# name,number
if (scalar @fields == 2) {
@{$row}{@cols} = @fields;
# name,number,reseller_id (in case of admin uploads)
} elsif ($c->user->roles eq "admin" &&
$owner eq 'reseller' && scalar @fields == 3) {
@{$row}{@cols,'reseller_id'} = @fields;
# name,number,shared
} elsif ($owner eq 'subscriber' && scalar @fields == 3) {
@{$row}{@cols,'shared'} = @fields;
# hmmm
} else {
push @fails, $linenum;
next;
}
$row->{$owner.'_id'} //= $owner_id;
push @entries, $row;
unless ($purge) {
$rs->update_or_create($row,{key=>'rel_u_idx'});
}
}
if ($purge) {
my ($start, $end);
$start = time;
$rs->delete;
$end = time;
$c->log->debug("Purging phonebook entries took " . ($end - $start) . "s");
$start = time;
$rs->populate(\@entries);
$end = time;
$c->log->debug("Populating phonebook entries took " . ($end - $start) . "s");
}
});
my $text = $c->loc('Phonebook entries successfully uploaded');
if (@fails) {
$text .= $c->loc(", but skipped the following line numbers: ") . (join ", ", @fails);
}
return ( \@entries, \@fails, \$text );
}
sub download_csv {
my ($c, $rs, $owner, $owner_id) = @_;
my @cols = qw/name number/;
if ($owner eq 'admin') {
push @cols, 'reseller_id';
} elsif ($owner eq 'subscriber') {
push @cols, 'shared';
}
my ($start, $end);
$start = time;
foreach my $row ($rs->all) {
my %entry = $row->get_inflated_columns;
delete $entry{id};
$c->res->write_fh->write(join (",", @entry{@cols}) );
$c->res->write_fh->write("\n");
}
$c->res->write_fh->close;
$end = time;
$c->log->debug("Creating phonebook entries CSV for download took " . ($end - $start) . "s");
return 1;
}
1;
=head1 NAME
NGCP::Panel::Utils::Phonebook
=head1 DESCRIPTION
A helper to manipulate the phonebook data
=head1 METHODS
=head2 get_reseller_phonebook
=head2 get_contract_phonebook
=head2 get_subscriber_phonebook
=head1 AUTHOR
Sipwise Development Team
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# vim: set tabstop=4 expandtab: