2013-02-27 18:33:47 +01:00
|
|
|
package Hydra::Controller::User;
|
|
|
|
|
2013-03-04 15:25:23 +01:00
|
|
|
use utf8;
|
2013-02-27 18:33:47 +01:00
|
|
|
use strict;
|
|
|
|
use warnings;
|
2013-06-17 12:34:21 -04:00
|
|
|
use base 'Hydra::Base::Controller::REST';
|
2013-03-04 15:25:23 +01:00
|
|
|
use Crypt::RandPasswd;
|
2013-02-27 18:33:47 +01:00
|
|
|
use Digest::SHA1 qw(sha1_hex);
|
|
|
|
use Hydra::Helper::Nix;
|
|
|
|
use Hydra::Helper::CatalystUtils;
|
|
|
|
|
|
|
|
|
|
|
|
__PACKAGE__->config->{namespace} = '';
|
|
|
|
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
sub login :Local :Args(0) :ActionClass('REST::ForBrowsers') { }
|
|
|
|
|
|
|
|
sub login_GET {
|
2013-02-27 18:33:47 +01:00
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
my $baseurl = $c->uri_for('/');
|
|
|
|
my $referer = $c->request->referer;
|
|
|
|
$c->session->{referer} = $referer if defined $referer && $referer =~ m/^($baseurl)/;
|
2013-02-27 18:33:47 +01:00
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
$c->stash->{template} = 'login.tt';
|
|
|
|
}
|
|
|
|
|
|
|
|
sub login_POST {
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
|
|
|
my $username;
|
|
|
|
my $password;
|
|
|
|
|
|
|
|
$username = $c->stash->{params}->{username};
|
|
|
|
$password = $c->stash->{params}->{password};
|
2013-02-27 18:33:47 +01:00
|
|
|
|
|
|
|
if ($username && $password) {
|
2013-06-17 12:34:21 -04:00
|
|
|
if ($c->authenticate({username => $username, password => $password})) {
|
|
|
|
if ($c->request->looks_like_browser) {
|
|
|
|
backToReferer($c);
|
|
|
|
} else {
|
|
|
|
currentUser_GET($self, $c);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$self->status_forbidden($c, message => "Bad username or password.");
|
|
|
|
if ($c->request->looks_like_browser) {
|
|
|
|
login_GET($self, $c);
|
|
|
|
}
|
|
|
|
}
|
2013-02-27 18:33:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
sub logout :Local :Args(0) :ActionClass('REST::ForBrowsers') { }
|
|
|
|
|
|
|
|
sub logout_POST {
|
2013-02-27 18:33:47 +01:00
|
|
|
my ($self, $c) = @_;
|
|
|
|
$c->logout;
|
2013-06-17 12:34:21 -04:00
|
|
|
if ($c->request->looks_like_browser) {
|
|
|
|
$c->response->redirect($c->request->referer || $c->uri_for('/'));
|
|
|
|
} else {
|
|
|
|
$self->status_no_content($c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub logout_GET {
|
|
|
|
# Probably a better way to do this
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
logout_POST($self, $c);
|
2013-02-27 18:33:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub captcha :Local Args(0) {
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
$c->create_captcha();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 15:25:23 +01:00
|
|
|
sub isValidPassword {
|
|
|
|
my ($password) = @_;
|
|
|
|
return length($password) >= 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub setPassword {
|
|
|
|
my ($user, $password) = @_;
|
|
|
|
$user->update({ password => sha1_hex($password) });
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-27 18:33:47 +01:00
|
|
|
sub register :Local Args(0) {
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
2013-03-28 11:56:12 +01:00
|
|
|
die "Not implemented!\n";
|
|
|
|
|
2013-02-27 18:33:47 +01:00
|
|
|
$c->stash->{template} = 'user.tt';
|
|
|
|
$c->stash->{create} = 1;
|
|
|
|
return if $c->request->method ne "POST";
|
|
|
|
|
|
|
|
my $userName = trim $c->req->params->{username};
|
|
|
|
my $fullName = trim $c->req->params->{fullname};
|
|
|
|
my $password = trim $c->req->params->{password};
|
|
|
|
$c->stash->{username} = $userName;
|
|
|
|
$c->stash->{fullname} = $fullName;
|
|
|
|
|
|
|
|
sub fail {
|
|
|
|
my ($c, $msg) = @_;
|
|
|
|
$c->stash->{errorMsg} = $msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fail($c, "You did not enter the correct digits from the security image.")
|
|
|
|
unless $c->validate_captcha($c->req->param('captcha'));
|
|
|
|
|
|
|
|
return fail($c, "Your user name is invalid. It must start with a lower-case letter followed by lower-case letters, digits, dots or underscores.")
|
|
|
|
if $userName !~ /^$userNameRE$/;
|
|
|
|
|
|
|
|
return fail($c, "Your user name is already taken.")
|
|
|
|
if $c->find_user({ username => $userName });
|
|
|
|
|
|
|
|
return fail($c, "Your must specify your full name.") if $fullName eq "";
|
|
|
|
|
|
|
|
return fail($c, "You must specify a password of at least 6 characters.")
|
2013-03-04 15:25:23 +01:00
|
|
|
unless isValidPassword($password);
|
2013-02-27 18:33:47 +01:00
|
|
|
|
|
|
|
return fail($c, "The passwords you specified did not match.")
|
|
|
|
if $password ne trim $c->req->params->{password2};
|
|
|
|
|
|
|
|
txn_do($c->model('DB')->schema, sub {
|
|
|
|
my $user = $c->model('DB::Users')->create(
|
|
|
|
{ username => $userName
|
|
|
|
, fullname => $fullName
|
2013-03-04 15:25:23 +01:00
|
|
|
, password => "!"
|
2013-02-27 18:33:47 +01:00
|
|
|
, emailaddress => "",
|
|
|
|
});
|
2013-03-04 15:25:23 +01:00
|
|
|
setPassword($user, $password);
|
2013-02-27 18:33:47 +01:00
|
|
|
});
|
|
|
|
|
2013-03-04 15:25:23 +01:00
|
|
|
unless ($c->user_exists) {
|
|
|
|
$c->authenticate({username => $userName, password => $password})
|
|
|
|
or error($c, "Unable to authenticate the new user!");
|
|
|
|
}
|
2013-02-27 18:33:47 +01:00
|
|
|
|
|
|
|
$c->flash->{successMsg} = "User <tt>$userName</tt> has been created.";
|
2013-03-04 15:25:23 +01:00
|
|
|
backToReferer($c);
|
2013-02-27 18:33:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
sub currentUser :Path('/current-user') :ActionClass('REST') { }
|
|
|
|
|
|
|
|
sub currentUser_GET {
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
|
|
|
requireLogin($c) if !$c->user_exists;
|
|
|
|
|
|
|
|
$self->status_ok(
|
|
|
|
$c,
|
|
|
|
entity => $c->model('DB::Users')->find({ 'me.username' => $c->user->username}, {
|
|
|
|
columns => [ "me.fullname", "me.emailaddress", "me.username", "userroles.role" ]
|
|
|
|
, join => [ "userroles" ]
|
|
|
|
, collapse => 1
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 15:25:23 +01:00
|
|
|
sub user :Chained('/') PathPart('user') CaptureArgs(1) {
|
|
|
|
my ($self, $c, $userName) = @_;
|
|
|
|
|
|
|
|
requireLogin($c) if !$c->user_exists;
|
|
|
|
|
|
|
|
error($c, "You do not have permission to edit other users.")
|
|
|
|
if $userName ne $c->user->username && !isAdmin($c);
|
|
|
|
|
|
|
|
$c->stash->{user} = $c->model('DB::Users')->find($userName)
|
|
|
|
or notFound($c, "User $userName doesn't exist.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub deleteUser {
|
|
|
|
my ($self, $c, $user) = @_;
|
|
|
|
my ($project) = $c->model('DB::Projects')->search({ owner => $user->username });
|
|
|
|
error($c, "User " . $user->username . " is still owner of project " . $project->name . ".")
|
|
|
|
if defined $project;
|
|
|
|
$c->logout() if $user->username eq $c->user->username;
|
|
|
|
$user->delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
sub edit :Chained('user') :Args(0) :ActionClass('REST::ForBrowsers') { }
|
|
|
|
|
|
|
|
sub edit_GET {
|
2013-02-27 18:33:47 +01:00
|
|
|
my ($self, $c) = @_;
|
2013-03-04 15:25:23 +01:00
|
|
|
|
|
|
|
my $user = $c->stash->{user};
|
|
|
|
|
|
|
|
$c->stash->{template} = 'user.tt';
|
|
|
|
|
|
|
|
$c->session->{referer} = $c->request->referer if !defined $c->session->{referer};
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
$c->stash->{fullname} = $user->fullname;
|
|
|
|
|
|
|
|
$c->stash->{emailonerror} = $user->emailonerror;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub edit_POST {
|
|
|
|
my ($self, $c) = @_;
|
2013-03-04 15:25:23 +01:00
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
my $user = $c->stash->{user};
|
|
|
|
|
|
|
|
$c->stash->{template} = 'user.tt';
|
|
|
|
|
|
|
|
$c->session->{referer} = $c->request->referer if !defined $c->session->{referer};
|
|
|
|
|
|
|
|
if (($c->stash->{params}->{submit} // "") eq "delete") {
|
2013-03-04 15:25:23 +01:00
|
|
|
deleteUser($self, $c, $user);
|
|
|
|
backToReferer($c);
|
|
|
|
}
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
if (($c->stash->{params}->{submit} // "") eq "reset-password") {
|
2013-03-04 15:25:23 +01:00
|
|
|
$c->stash->{json} = {};
|
|
|
|
error($c, "No email address is set for this user.")
|
|
|
|
unless $user->emailaddress;
|
|
|
|
my $password = Crypt::RandPasswd->word(8,10);
|
|
|
|
setPassword($user, $password);
|
|
|
|
sendEmail($c,
|
|
|
|
$user->emailaddress,
|
|
|
|
"Hydra password reset",
|
|
|
|
"Hi,\n\n".
|
|
|
|
"Your password has been reset. Your new password is '$password'.\n\n".
|
|
|
|
"You can change your password at " . $c->uri_for($self->action_for('edit'), [$user->username]) . ".\n\n".
|
|
|
|
"With regards,\n\nHydra.\n"
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
my $fullName = trim $c->stash->{params}->{fullname};
|
2013-03-04 15:25:23 +01:00
|
|
|
|
|
|
|
txn_do($c->model('DB')->schema, sub {
|
|
|
|
|
|
|
|
error($c, "Your must specify your full name.") if $fullName eq "";
|
|
|
|
|
|
|
|
$user->update(
|
|
|
|
{ fullname => $fullName
|
2013-06-17 12:34:21 -04:00
|
|
|
, emailonerror => $c->stash->{params}->{"emailonerror"} ? 1 : 0
|
2013-03-04 15:25:23 +01:00
|
|
|
});
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
my $password = $c->stash->{params}->{password} // "";
|
2013-03-04 15:25:23 +01:00
|
|
|
if ($password ne "") {
|
|
|
|
error($c, "You must specify a password of at least 6 characters.")
|
|
|
|
unless isValidPassword($password);
|
|
|
|
error($c, "The passwords you specified did not match.")
|
2013-06-17 12:34:21 -04:00
|
|
|
if $password ne trim $c->stash->{params}->{password2};
|
2013-03-04 15:25:23 +01:00
|
|
|
setPassword($user, $password);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isAdmin($c)) {
|
|
|
|
$user->userroles->delete_all;
|
|
|
|
$user->userroles->create({ role => $_})
|
|
|
|
foreach paramToList($c, "roles");
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2013-06-17 12:34:21 -04:00
|
|
|
if ($c->request->looks_like_browser) {
|
|
|
|
backToReferer($c);
|
|
|
|
} else {
|
|
|
|
$self->status_no_content($c);
|
|
|
|
}
|
2013-02-27 18:33:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
1;
|