Skip to content

Commit

Permalink
Feat upload json users and groups (#2099)
Browse files Browse the repository at this point in the history
feat: upload users and groups in json file
  • Loading branch information
frankiejol authored Oct 4, 2024
1 parent e98e0b2 commit d3a9ad9
Show file tree
Hide file tree
Showing 9 changed files with 660 additions and 16 deletions.
9 changes: 9 additions & 0 deletions lib/Ravada/Auth/Group.pm
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ sub remove_member($self, $name) {
$sth->execute($id_user);
}

sub remove_other_members($self, $members) {
my %members = map { $_ => 1 } @$members;

for my $name ($self->members ) {
$self->remove_member($name) if !$members{$name};
}

}

sub _remove_all_members($self) {
my $sth = $$CON->dbh->prepare("DELETE FROM users_group "
." WHERE id_group=?"
Expand Down
102 changes: 102 additions & 0 deletions lib/Ravada/Front.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,108 @@ sub upload_users($self, $users, $type, $create=0) {
return ($found, $count, \@error);
}

=head2 upload_users_json
Upload a list of users to the database
=head3 Arguments
=over
=item * string with users and passwords in each line
=item * type: it can be SQL, LDAP or SSO
=back
=cut


sub upload_users_json($self, $data_json, $type='openid') {

my ($found, $count, @error);
my $data;
eval {
$data= decode_json($data_json);
};
if ( $@ ) {
push @error,($@);
$data={}
}

my $result = {
users_found => 0
,users_added => 0
,groups_found => 0
,groups_added => 0
};
if (exists $data->{groups} &&
(!ref($data->{groups}) || ref($data->{groups}) ne 'ARRAY')) {
die "Expecting groups as an array , got ".ref($data->{groups});
}
$data->{groups} = [] if !exists $data->{groups};
for my $g0 (@{$data->{groups}}) {
$result->{groups_found}++;
my $g = $g0;
if (!ref($g)) {
$g = { name => $g0 };
}
$found++;
my $group = Ravada::Auth::Group->new(name => $g->{name});
my $members = delete $g->{members};
if (!$group || !$group->id) {
unless (defined $members && !scalar(@$members) && $data->{options}->{flush} && $data->{options}->{remove_empty}) {
$result->{groups_added}++;
Ravada::Auth::Group::add_group(%$g);
}
} else {
push @error,("Group $g->{name} already added");
}
$self->_add_users($members, $type, $result, \@error, 1);
$group->remove_other_members($members) if $data->{options}->{flush};

for my $m (@$members) {
my $user = Ravada::Auth::SQL->new(name => $m);
$user->add_to_group($g->{name}) unless $user->is_member($g->{name});
}
if ( $data->{options}->{remove_empty} && $group->id && !$group->members ) {
$group->remove();
$result->{groups_removed}++;
push @error,("Group ".$group->name." empty removed");
}
}

$self->_add_users($data->{users}, $type, $result, \@error)
if $data->{users};

return ($result, \@error);
}

sub _add_users($self,$users, $type, $result, $error, $ignore_already=0) {
for my $u0 (@$users) {
$result->{users_found}++;
my $u = $u0;
$u = dclone($u0) if ref($u0);
if (!ref($u)) {
$u = { name => $u0 };
}
if (!exists $u->{is_external}) {
if ($type ne 'sql') {
$u->{is_external} = 1;
$u->{external_auth} = $type ;
}
}
my $user = Ravada::Auth::SQL->new(name => $u->{name});
if ($user && $user->id) {
push @$error,("User $u->{name} already added")
unless $ignore_already;
next;
}
Ravada::Auth::SQL::add_user(%$u);
$result->{users_added}++;
}
}

=head2 create_bundle
Creates a new bundle
Expand Down
52 changes: 43 additions & 9 deletions script/rvd_front
Original file line number Diff line number Diff line change
Expand Up @@ -1845,37 +1845,71 @@ any '/admin/users/upload.#req' => sub($c) {

my $type = $c->req->param('type');

return $c->render(template => "/main/upload_users", done => 0, count => 0, found => 0, type => 'sql') if !$type;
return $c->render(template => "/main/upload_users", done => 0, output => {}
,error => []
,type => 'sql') if !$type;

my $create = ( $c->req->param('create') or 0);

return $c->render(json => { error => "Unknown type $type" })
if $type !~ /^(sql|ldap|sso|openid)/;

my $csv = $c->req->upload('users');
if($csv->headers->content_type !~ m{text/(csv|plain)}) {
my $file = $c->req->upload('users');

if($file->headers->content_type =~ m{text/(csv|plain)}) {
_upload_users_csv($c, $file, $type, $create);
} elsif ( $file->headers->content_type =~ m{application/json}) {
_upload_users_json($c, $file, $type, $create);
} else {
return $c->render(status => 400
,text => "Wrong content type ".$csv->headers->content_type
." , it should be text/csv or plain"
,text => "Wrong content type ".$file->headers->content_type
." , it should be text/csv , application/json or plain"
);

}
};

sub _upload_users_json($c, $file, $type, $create) {

my ($result, $error)=$RAVADA->upload_users_json($file->slurp, $type);

if ($create) {
push @$error,("Warning: create not implemented with json upload");
}
return $c->render(json =>
{
output => $result
,error => $error
}
) if $c->stash('req') eq 'json';

return $c->render(template => "/main/upload_users"
,output => $result
,error => $error
,done => 1
);
}

sub _upload_users_csv($c, $csv, $type, $create) {
my ($found, $count, $error) = $RAVADA->upload_users(
$csv->slurp, $type, $create
);
my $output = {
users_found => $found
,users_added => $count
};

return $c->render(json =>
{ output => "$count users added"
{ output => $output
,error => $error
,done => 1
}) if $c->stash('req') eq 'json';

return $c->render(template => "/main/upload_users"
,count => $count
,found => $found
,error => $error
,done => 1
);
};
}

get '/admin/user/remove/#id' => sub($c) {
return access_denied($c) unless $USER->is_admin;
Expand Down
1 change: 1 addition & 0 deletions t/40_auth_sql.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use Test::Ravada;
use_ok('Ravada');
use_ok('Ravada::Auth::SQL');

init();
my $RAVADA = rvd_back();

Ravada::Auth::SQL::add_user(name => 'test',password => $$);
Expand Down
25 changes: 25 additions & 0 deletions t/lib/Test/Ravada.pm
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,32 @@ sub init($config=undef, $sqlite = 1 , $flush=0) {
$Ravada::VM::KVM::VERIFY_ISO = 0;
$Ravada::VM::MIN_DISK_MB = 1;

_clean_old_users();
_clean_old_groups();
}

sub _clean_old_users() {
my $sth = $CONNECTOR->dbh->prepare("SELECT id,name FROM users WHERE name like ? ");
$sth->execute(base_domain_name().'%');
while ( my ($id,$name) = $sth->fetchrow ) {
next if $USER_ADMIN && $name eq $USER_ADMIN->name;
my $user = Ravada::Auth::SQL->search_by_id($id);
next if !$user;
$user->remove();
}
}

sub _clean_old_groups() {
my $sth = $CONNECTOR->dbh->prepare("SELECT id,name FROM groups_local WHERE name like ? ");
$sth->execute(base_domain_name().'%');
while ( my ($id,$name) = $sth->fetchrow ) {
my $g = Ravada::Auth::Group->open($id);
next if !$g;
$g->remove();
}
}


sub _load_remote_config() {
return {} if ! -e $FILE_CONFIG_REMOTE;
my $conf;
Expand Down Expand Up @@ -1573,6 +1597,7 @@ sub _qemu_storage_pool {
sub remove_void_networks($vm=undef) {
if (!defined $vm) {
eval { $vm = rvd_back->search_vm('Void') };
die $@ if $@;
}
my $dir_net = $vm->dir_img()."/networks";
return if ! -e $dir_net;
Expand Down
Loading

0 comments on commit d3a9ad9

Please sign in to comment.