MT#59001 improve phonebook csv upload

* the expected csv fields are as following:
  - /api/resellerphonebookentries/?reseller_id=1
    name,number
  - /api/customerphonebookentries/?customer_id=1
    name,number
  - /api/subscriberphonebookentries/?subscriber_id=1
    name,number,shared
  - /api/resellerphonebookentries/
    name,number,reseller_id
  - /api/customerphonebookentries/
    name,number,contract_id
  - /api/customerphonebookentries/
    name,number,shared,subcriber_id

  (note: the fields are taken from the leftmost side
   as the minimum required fields, so if one provides as:
    - /api/resellerphonebookentries/?reseller_id=1
    name,number,reseller_id
    this line will be uploaded and columns after 'number' are
    ignored in this case.
   this is for convenience if you have a prepared upload
   for different customers/resellers for instance, you can
   upload it under one customer/reseller when needed

* user access scope is now validated, e.g.:
  resellers cannot upload phonebook entries to another resellers,
  etc.
* fix csv upload for /api/customerphonebookentries/?customer_id=1

Change-Id: I970ac36fdb8b366adff15515a48d296e8abeff13
mr12.2
Kirill Solomko 2 years ago
parent 1e9f223276
commit b6b453d69d

@ -74,7 +74,7 @@ sub process_data :Private {
my $customer_id = $params->{'customer_id'} // '';
my ($entries, $fails, $text) =
NGCP::Panel::Utils::Phonebook::upload_csv($c, $rs, 'customer',
NGCP::Panel::Utils::Phonebook::upload_csv($c, $rs, 'contract',
$customer_id, $params->{purge_existing}, $data_ref);
$c->log->info( $$text );
}

@ -158,13 +158,115 @@ sub upload_csv {
my $csv = Text::CSV_XS->new({ allow_whitespace => 1, binary => 1, keep_meta_info => 1 });
my $schema = $c->model('DB');
my @cols = qw/name number/;
my @fields ;
my @fails = ();
my $linenum = 0;
my @entries;
$c->model('DB')->txn_do(sub {
my $no_access = 0;
my %contract_ids;
my %subscriber_ids;
# check user access to owner_id
if ($c->user->roles eq 'reseller') {
if ($owner_id && $owner eq 'reseller' && $owner_id != $c->user->reseller_id) {
$no_access = 1;
} elsif ($owner eq 'contract') {
my $found = 0;
foreach my $row ($schema->resultset('contracts')->search({
'contact.reseller_id' => $c->user->reseller_id,
},{
select => ['me.id'],
as => ['id'],
join => 'contact',
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
})->all) {
my $id = $row->{id};
if ($owner_id) {
if ($id == $owner_id) {
$found = 1;
last;
}
} else {
$contract_ids{$id} = 1;
}
}
if ($owner_id) {
$no_access = 1 unless $found;
}
} elsif ($owner eq 'subscriber') {
my $found = 0;
foreach my $row ($schema->resultset('voip_subscribers')->search({
'contact.reseller_id' => $c->user->reseller_id,
},{
select => ['me.id'],
as => ['id'],
join => { 'contract' => 'contact' },
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
})->all) {
my $id = $row->{id};
if ($owner_id) {
if ($id == $owner_id) {
$found = 1;
last;
}
} else {
$subscriber_ids{$id} = 1;
}
}
if ($owner_id) {
$no_access = 1 unless $found;
}
}
} elsif ($c->user->roles eq 'subscriberadmin') {
if ($owner_id && $owner eq 'reseller') {
$no_access = 1;
} elsif ($owner_id && $owner eq 'contract' && $owner_id != $c->user->account_id) {
$no_access = 1;
} elsif ($owner eq 'subscriber') {
my $found = 0;
foreach my $row ($schema->resultset('voip_subscribers')->search({
'contract_id' => $c->user->account_id,
},{
select => ['me.id'],
as => ['id'],
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
})->all) {
my $id = $row->{id};
if ($owner_id) {
if ($id == $owner_id) {
$found = 1;
last;
}
} else {
$subscriber_ids{$id} = 1;
}
}
if ($owner_id) {
$no_access = 1 unless $found;
}
}
} elsif ($owner_id && $c->user->roles eq 'subscriber') {
if ($owner eq 'reseller') {
$no_access = 1;
} elsif ($owner eq 'contract') {
$no_access = 1;
} elsif ($owner eq 'subscriber' && $owner_id != $c->user->voip_subscriber->id) {
$no_access = 1;
}
}
if ($no_access) {
my $accepted = 0;
my (@entries, @fails);
my $text = 'Phonebook entries upload failed: ';
$text .= "user does not have access to $owner with id $owner_id\n";
return (\@entries, \@fails, \$text);
}
$schema->txn_do(sub {
open(my $fh, '<:encoding(utf8)', $data);
@ -178,26 +280,102 @@ sub upload_csv {
@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
if ($owner_id) {
# name,number
if ($owner ne 'subscriber' && scalar @fields >= 2) {
@{$row}{@cols} = splice @fields, 0, 2;
# name,number,shared
} elsif ($owner eq 'subscriber' && scalar @fields >= 3) {
my $shared = int($fields[2]);
if ($shared != 1 && $shared != 0) {
push @fails, $linenum;
next;
}
@{$row}{@cols,'shared'} = splice @fields, 0, 3;
} else {
push @fails, $linenum;
next;
}
$row->{$owner.'_id'} = $owner_id;
} else {
push @fails, $linenum;
next;
if ($owner eq 'reseller') {
# name,number,reseller_id
if (scalar @fields != 3) {
push @fails, $linenum;
next;
}
my $reseller_id_f = int($fields[2]);
if ($c->user->roles eq 'admin') {
@{$row}{@cols,'reseller_id'} = @fields;
} elsif ($c->user->roles eq 'reseller' &&
$reseller_id_f == $c->user->reseller_id) {
@{$row}{@cols,'reseller_id'} = @fields;
} else {
push @fails, $linenum;
next;
}
} elsif ($owner eq 'contract') {
# name,number,contract_id
if (scalar @fields != 3) {
push @fails, $linenum;
next;
}
my $contract_id_f = int($fields[2]);
if ($c->user->roles eq 'admin') {
@{$row}{@cols,'contract_id'} = @fields;
} elsif ($c->user->roles eq 'reseller' &&
exists $contract_ids{$contract_id_f}) {
@{$row}{@cols,'contract_id'} = @fields;
} elsif ($c->user->roles eq 'subscriberadmin' &&
$contract_id_f == $c->user->account_id) {
@{$row}{@cols,'contract_id'} = @fields;
} else {
push @fails, $linenum;
next;
}
} elsif ($owner eq 'subscriber') {
# name,number,shared,subscriber_id
if (scalar @fields != 4) {
push @fails, $linenum;
next;
}
my $subscriber_id_f = int($fields[3]);
my $shared = int($fields[2]);
if ($shared != 1 && $shared != 0) {
push @fails, $linenum;
next;
}
if ($c->user->roles eq 'admin') {
@{$row}{@cols,'shared','subscriber_id'} = @fields;
} elsif ($c->user->roles eq 'reseller' &&
exists $subscriber_ids{$subscriber_id_f}) {
@{$row}{@cols,'shared','subscriber_id'} = @fields;
} elsif ($c->user->roles eq 'subscriberadmin' &&
exists $subscriber_ids{$subscriber_id_f}) {
@{$row}{@cols,'shared','subscriber_id'} = @fields;
} elsif ($c->user->roles eq 'subscriber' &&
$subscriber_id_f == $c->user->voip_subscriber->id) {
@{$row}{@cols,'shared','subscriber_id'} = @fields;
} else {
push @fails, $linenum;
next;
}
} else {
push @fails, $linenum;
next;
}
}
$row->{$owner.'_id'} //= $owner_id;
push @entries, $row;
unless ($purge) {
$rs->update_or_create($row,{key=>'rel_u_idx'});
try {
$rs->update_or_create($row,{key=>'rel_u_idx'});
} catch($e) {
push @fails, $linenum;
next;
}
}
push @entries, $row;
}
if ($purge) {

Loading…
Cancel
Save