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.
		
		
		
		
		
			
		
			
				
					
					
						
							278 lines
						
					
					
						
							7.3 KiB
						
					
					
				
			
		
		
	
	
							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:
 |