hydra: added some user admin

[?]
Dec 3, 2010, 9:40 AM
SZYDW2DG5Z7BR3ICKWDXVUNSMCDSXMYZUB6FQ4W2B2FVZJD6PULQC

Dependencies

  • [2] MVB7RRLT * Move NARs from the NixChannel controller to the Root controller and
  • [3] 6XJH4OFL add datetime to deps
  • [4] SMCOU72F hydra: add some admin for adding/enabling/etc build machines
  • [5] J5UVLXOK * Start of a basic Catalyst web interface.
  • [6] LBNVQXUB * Build the /build stuff in a separate controller.
  • [7] 2GK5DOU7 * Downloading closures.
  • [8] 2JQ7WEFM
  • [9] FPK5LF53 * Put the project-related actions in a separate controller. Put the
  • [10] SHBLLAVH * More global substitution.
  • [11] SMM4HQTP * Put actions related to builds under /build (e.g. /log/<buildid>
  • [12] 5NO7NCKT * Refactoring.
  • [*] SAFVRDTK * Put Hydra's dependencies so that they can easily be installed in a
  • [*] DO432JDJ * Build Hydra with the Nix Perl bindings.
  • [*] ZWCTAZGL added newsitems, added some admin options to clear various caches.
  • [*] D5QIOJGP * Move everything up one directory.
  • [*] ODNCGFQ5 * Improved the navigation bar: don't include all projects (since that

Change contents

  • edit in deps.nix at line 40
    [3.24]
    [15.327]
    perlPackages.DigestSHA1
    perlPackages.CryptRandPasswd
  • edit in src/lib/Hydra/Controller/Admin.pm at line 10
    [4.25]
    [4.25]
    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;
  • edit in src/lib/Hydra/Controller/Admin.pm at line 65
    [4.1491]
    [4.1491]
    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';
    }
  • edit in src/lib/Hydra/Controller/Admin.pm at line 111
    [4.1492]
    [4.1492]
    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");
    }
  • replacement in src/lib/Hydra/Controller/Root.pm at line 8
    [5.32][5.908:909](),[5.110][5.908:909](),[5.3368][5.908:909](),[5.908][5.908:909]()
    [5.3368]
    [5.0]
    use Digest::SHA1 qw(sha1_hex);
  • edit in src/lib/Hydra/Controller/Root.pm at line 199
    [2.684]
    [2.684]
    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("/");
    }
  • file addition: change-password.tt (----------)
    [17.1486]
    [% 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 %]
  • edit in src/root/navbar.tt at line 85
    [4.12341]
    [4.12341]
    [% INCLUDE makeLink
    uri = c.uri_for(c.controller('Admin').action_for('users'))
    title = "Users" %]
  • file addition: user.tt (----------)
    [17.1486]
    [% 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 %]
  • file addition: users.tt (----------)
    [17.1486]
    [% 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 %]