forked from lix-project/hydra
hydra: added some user admin
This commit is contained in:
parent
6d6f43fa0c
commit
cd7742f610
2
deps.nix
2
deps.nix
|
@ -37,5 +37,7 @@ in
|
||||||
perlPackages.DataDump
|
perlPackages.DataDump
|
||||||
perlPackages.JSONXS
|
perlPackages.JSONXS
|
||||||
perlPackages.DateTime
|
perlPackages.DateTime
|
||||||
|
perlPackages.DigestSHA1
|
||||||
|
perlPackages.CryptRandPasswd
|
||||||
nixPerl
|
nixPerl
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,6 +7,12 @@ use Hydra::Helper::Nix;
|
||||||
use Hydra::Helper::CatalystUtils;
|
use Hydra::Helper::CatalystUtils;
|
||||||
use Hydra::Helper::AddBuilds;
|
use Hydra::Helper::AddBuilds;
|
||||||
use Data::Dump qw(dump);
|
use Data::Dump qw(dump);
|
||||||
|
use Digest::SHA1 qw(sha1_hex);
|
||||||
|
use Crypt::RandPasswd;
|
||||||
|
use Sys::Hostname::Long;
|
||||||
|
use Email::Simple;
|
||||||
|
use Email::Sender::Simple qw(sendmail);
|
||||||
|
use Email::Sender::Transport::SMTP;
|
||||||
|
|
||||||
sub nixMachines {
|
sub nixMachines {
|
||||||
my ($c) = @_;
|
my ($c) = @_;
|
||||||
|
@ -57,6 +63,111 @@ sub index : Chained('admin') PathPart('') Args(0) {
|
||||||
$c->stash->{template} = 'admin.tt';
|
$c->stash->{template} = 'admin.tt';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub updateUser {
|
||||||
|
my ($c, $user) = @_;
|
||||||
|
|
||||||
|
my $username = trim $c->request->params->{"username"};
|
||||||
|
my $fullname = trim $c->request->params->{"fullname"};
|
||||||
|
my $emailaddress = trim $c->request->params->{"emailaddress"};
|
||||||
|
my $emailonerror = trim $c->request->params->{"emailonerror"};
|
||||||
|
my $roles = $c->request->params->{"roles"} ;
|
||||||
|
|
||||||
|
error($c, "Invalid or empty username.") if $username eq "";
|
||||||
|
|
||||||
|
$user->update(
|
||||||
|
{ username => $username
|
||||||
|
, maxconcurrent => $fullname
|
||||||
|
, emailaddress => $emailaddress
|
||||||
|
, emailonerror => $emailonerror
|
||||||
|
});
|
||||||
|
$user->userroles->delete_all;
|
||||||
|
if(ref($roles) eq 'ARRAY') {
|
||||||
|
for my $s (@$roles) {
|
||||||
|
$user->userroles->create({ role => $s}) ;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$user->userroles->create({ role => $roles}) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub user : Chained('admin') PathPart('user') CaptureArgs(1) {
|
||||||
|
my ($self, $c, $username) = @_;
|
||||||
|
|
||||||
|
requireAdmin($c);
|
||||||
|
|
||||||
|
my $user = $c->model('DB::Users')->find($username)
|
||||||
|
or notFound($c, "User $username doesn't exist.");
|
||||||
|
|
||||||
|
$c->stash->{user} = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub users : Chained('admin') PathPart('users') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
$c->stash->{users} = [$c->model('DB::Users')->search({}, {order_by => "username"})];
|
||||||
|
|
||||||
|
$c->stash->{template} = 'users.tt';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub user_edit : Chained('user') PathPart('edit') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
$c->stash->{template} = 'user.tt';
|
||||||
|
$c->stash->{edit} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub user_edit_submit : Chained('user') PathPart('submit') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
requirePost($c);
|
||||||
|
|
||||||
|
txn_do($c->model('DB')->schema, sub {
|
||||||
|
updateUser($c, $c->stash->{user}) ;
|
||||||
|
});
|
||||||
|
$c->res->redirect("/admin/users");
|
||||||
|
}
|
||||||
|
|
||||||
|
sub sendemail {
|
||||||
|
my ($to, $subject, $body) = @_;
|
||||||
|
|
||||||
|
my $url = hostname_long;
|
||||||
|
my $sender = ($ENV{'USER'} || "hydra") . "@" . $url;
|
||||||
|
|
||||||
|
my $email = Email::Simple->create(
|
||||||
|
header => [
|
||||||
|
To => $to,
|
||||||
|
From => "Hydra <$sender>",
|
||||||
|
Subject => $subject
|
||||||
|
],
|
||||||
|
body => $body
|
||||||
|
);
|
||||||
|
|
||||||
|
sendmail($email);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub reset_password : Chained('user') PathPart('reset-password') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
# generate password
|
||||||
|
my $password = Crypt::RandPasswd->word(8,10);
|
||||||
|
|
||||||
|
# calculate hash
|
||||||
|
my $hashed = sha1_hex($password);
|
||||||
|
|
||||||
|
$c->stash->{user}-> update({ password => $hashed}) ;
|
||||||
|
|
||||||
|
# send email
|
||||||
|
|
||||||
|
sendemail(
|
||||||
|
$c->user->emailaddress,
|
||||||
|
"New password for Hydra",
|
||||||
|
"Hi,\n\n".
|
||||||
|
"Your password has been reset. Your new password is '$password'.\n".
|
||||||
|
"You can change your password at http://".hostname_long." .\n".
|
||||||
|
"With regards, Hydra\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
$c->res->redirect("/admin/users");
|
||||||
|
}
|
||||||
|
|
||||||
sub machines : Chained('admin') PathPart('machines') Args(0) {
|
sub machines : Chained('admin') PathPart('machines') Args(0) {
|
||||||
my ($self, $c) = @_;
|
my ($self, $c) = @_;
|
||||||
$c->stash->{machines} = [$c->model('DB::BuildMachines')->search({}, {order_by => "hostname"})];
|
$c->stash->{machines} = [$c->model('DB::BuildMachines')->search({}, {order_by => "hostname"})];
|
||||||
|
|
|
@ -5,7 +5,7 @@ use warnings;
|
||||||
use base 'Hydra::Base::Controller::ListBuilds';
|
use base 'Hydra::Base::Controller::ListBuilds';
|
||||||
use Hydra::Helper::Nix;
|
use Hydra::Helper::Nix;
|
||||||
use Hydra::Helper::CatalystUtils;
|
use Hydra::Helper::CatalystUtils;
|
||||||
|
use Digest::SHA1 qw(sha1_hex);
|
||||||
|
|
||||||
# Put this controller at top-level.
|
# Put this controller at top-level.
|
||||||
__PACKAGE__->config->{namespace} = '';
|
__PACKAGE__->config->{namespace} = '';
|
||||||
|
@ -196,5 +196,29 @@ sub nar :Local :Args(1) {
|
||||||
$c->stash->{storePath} = $path;
|
$c->stash->{storePath} = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub change_password : Path('change-password') : Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
requireLogin($c) if !$c->user_exists;
|
||||||
|
|
||||||
|
$c->stash->{template} = 'change-password.tt';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub change_password_submit : Path('change-password/submit') : Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
requireLogin($c) if !$c->user_exists;
|
||||||
|
|
||||||
|
my $password = $c->request->params->{"password"};
|
||||||
|
my $password_check = $c->request->params->{"password_check"};
|
||||||
|
print STDERR "$password \n";
|
||||||
|
print STDERR "$password_check \n";
|
||||||
|
error($c, "Passwords did not match, go back and try again!") if $password ne $password_check;
|
||||||
|
|
||||||
|
my $hashed = sha1_hex($password);
|
||||||
|
$c->user->update({ password => $hashed}) ;
|
||||||
|
|
||||||
|
$c->res->redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
23
src/root/change-password.tt
Normal file
23
src/root/change-password.tt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
[% WRAPPER layout.tt title="Change password" %]
|
||||||
|
[% PROCESS common.tt %]
|
||||||
|
|
||||||
|
<form action="[% c.uri_for('/change-password/submit') %]" method="post">
|
||||||
|
|
||||||
|
<h2>Change password</h2>
|
||||||
|
|
||||||
|
<table class="layoutTable">
|
||||||
|
<tr>
|
||||||
|
<th>Enter password:</th>
|
||||||
|
<td><input type="password" class="string" id="password" name="password" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Enter password again:</th>
|
||||||
|
<td><input type="password" class="string" id="password_check" name="password_check" /></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p><button type="submit"><img src="/static/images/success.gif" />Change</button></p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
[% END %]
|
|
@ -82,6 +82,9 @@
|
||||||
[% INCLUDE makeLink
|
[% INCLUDE makeLink
|
||||||
uri = c.uri_for(c.controller('Admin').action_for('managenews'))
|
uri = c.uri_for(c.controller('Admin').action_for('managenews'))
|
||||||
title = "News" %]
|
title = "News" %]
|
||||||
|
[% INCLUDE makeLink
|
||||||
|
uri = c.uri_for(c.controller('Admin').action_for('users'))
|
||||||
|
title = "Users" %]
|
||||||
[% END %]
|
[% END %]
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
||||||
|
|
70
src/root/user.tt
Normal file
70
src/root/user.tt
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
[% WRAPPER layout.tt title=(create ? "New user" : "Editing user '$user.username'") %]
|
||||||
|
[% PROCESS common.tt %]
|
||||||
|
|
||||||
|
[% BLOCK roleoption %]
|
||||||
|
<option value="[% role %]"
|
||||||
|
[% checked = false %]
|
||||||
|
[% FOREACH r IN user.userroles %]
|
||||||
|
[% checked = r.role == role %]
|
||||||
|
[% BREAK IF checked %]
|
||||||
|
[% END %]
|
||||||
|
[% IF checked %]
|
||||||
|
SELECTED
|
||||||
|
[% END %]
|
||||||
|
>[% role %]</option>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
<form action="[% IF create %][% c.uri_for('/admin/create-user/submit') %][% ELSE %][% c.uri_for('/admin/user' user.username 'submit') %][% END %]" method="post">
|
||||||
|
|
||||||
|
<h2>User[% IF ! create %] '[% user.username %]'[% END %]</h2>
|
||||||
|
|
||||||
|
<table class="layoutTable">
|
||||||
|
[% IF create %]
|
||||||
|
<tr>
|
||||||
|
<th>Username:</th>
|
||||||
|
<td>[% INCLUDE maybeEditString param="username" value=user.username %]</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
<tr>
|
||||||
|
<th>Full name:</th>
|
||||||
|
<td>[% INCLUDE maybeEditString param="fullname" value=user.fullname %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Email:</th>
|
||||||
|
<td>[% INCLUDE maybeEditString param="emailaddress" value=user.emailaddress %]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Evaluation error notifications:</th>
|
||||||
|
<td>
|
||||||
|
[% INCLUDE renderSelection param="emailonerror" curValue=user.emailonerror options={"1" = "Yes", "0" = "No"} %]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Roles:</th>
|
||||||
|
<td>
|
||||||
|
<select multiple name="roles" style="width: 27em;">
|
||||||
|
[% INCLUDE roleoption role="admin" %]
|
||||||
|
[% INCLUDE roleoption role="create-project" %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p><button type="submit"><img src="/static/images/success.gif" />[%IF create %]Create[% ELSE %]Apply changes[% END %]</button></p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
[% IF !create %]
|
||||||
|
|
||||||
|
<form action="[% c.uri_for('/admin/user' user.hostname 'delete') %]" method="post">
|
||||||
|
<p><button id="delete-user" type="submit"><img src="/static/images/failure.gif" />Remove this user</button></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$("#delete-user").click(function() {
|
||||||
|
return confirm("Are you sure you want to delete this user?");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[% END %]
|
34
src/root/users.tt
Normal file
34
src/root/users.tt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[% WRAPPER layout.tt title="Users" %]
|
||||||
|
[% PROCESS common.tt %]
|
||||||
|
|
||||||
|
<h1>Users</h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Roles</th>
|
||||||
|
<th>Eval. notifications</th>
|
||||||
|
<th>Options</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
[% FOREACH u IN users %]
|
||||||
|
<tr>
|
||||||
|
<td>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('user_edit'), [u.username]) content = u.username %]</td>
|
||||||
|
<td>[% u.fullname %]</td>
|
||||||
|
<td>[% u.emailaddress %]</td>
|
||||||
|
<td>[% FOREACH r IN u.userroles %]<i>[% r.role %]</i> [% END %]</td>
|
||||||
|
<td>[% IF u.emailonerror %]Yes[% ELSE %]No[% END %]</td>
|
||||||
|
<td>[ [% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('reset_password'), [u.username]) content = "Reset password" confirmmsg = "Are you sure you want to reset the password for this user?" %] ]</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>[ <a href="[% c.uri_for(c.controller('Admin').action_for('create_user')) %]">Add a new user</a> ]</p>
|
||||||
|
|
||||||
|
[% END %]
|
Loading…
Reference in a new issue