Skip to content

Instantly share code, notes, and snippets.

@jberger
Last active April 3, 2023 21:39
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jberger/91a853ee223737c1a1d1 to your computer and use it in GitHub Desktop.
Save jberger/91a853ee223737c1a1d1 to your computer and use it in GitHub Desktop.
use Mojolicious::Lite;
use DBM::Deep;
use Mojo::JWT;
plugin 'Bcrypt';
plugin 'Minion' => {SQLite => 'minion.db'};
helper users => sub { state $db = DBM::Deep->new('users.db') };
helper send_email => sub {
my ($c, $address, $subject, $body) = @_;
require Email::Simple;
require Email::Sender::Simple;
my $email = Email::Simple->create(
header => [
To => $address,
From => 'me@nobody.com',
Subject => $subject,
],
body => $body,
);
Email::Sender::Simple->send($email);
};
helper jwt => sub { Mojo::JWT->new(secret => shift->app->secrets->[0] || die) };
app->minion->add_task(email_task => sub { shift->app->send_email(@_) });
helper email => sub { shift->minion->enqueue(email_task => [@_]) };
helper to_index => sub { shift->flash(message => shift)->redirect_to('index') };
any '/' => sub {
my $c = shift;
$c->render('logged_in') if $c->session('username');
} => 'index';
any '/logout' => sub { shift->session(expires => 1)->to_index };
post '/sign_in' => sub {
my $c = shift;
my $username = $c->param('username');
return $c->to_index("Username $username not found")
unless my $user = $c->users->{$username};
return $c->to_index("Username $username has not been confirmed")
unless $user->{confirmed};
return $c->to_index('Password not correct')
unless $c->bcrypt_validate($c->param('password') || '', $user->{password});
$c->session(username => $username)->to_index;
};
post '/sign_up' => sub {
my $c = shift;
my $username = $c->param('username');
return $c->to_index("Username $username is taken")
if $c->users->{$username};
return $c->to_index('Password cannot be blank')
unless my $password = $c->param('password');
return $c->to_index('Email cannot be blank')
unless my $email = $c->param('email');
$c->users->{$username} = {
email => $email,
password => $c->bcrypt($password),
confirmed => 0,
};
my $jwt = $c->jwt->claims({username => $username})->encode;
my $url = $c->url_for('confirm')->to_abs->query(jwt => $jwt);
$c->email($email, 'Confirm registration', "Please visit $url to confirm");
$c->to_index('registration complete, please confirm via email');
};
get '/confirm' => sub {
my $c = shift;
my $username = $c->jwt->decode($c->param('jwt'))->{username};
$c->users->{$username}{confirmed} = 1;
$c->to_index('registration confirmed, please log in');
};
app->start;
__DATA__
@@ index.html.ep
<p>Hello Guest!</p>
<p><%= flash('message') || 'Sign in or sign up!' %></p>
%= form_for sign_in => begin
%= label_for username => 'Username'
%= text_field 'username'
%= label_for password => 'Password'
%= password_field 'password'
%= label_for email => 'Email'
%= email_field 'email', placeholder => 'sign up only'
<br>
%= submit_button 'Sign In'
%= submit_button 'Sign Up', formaction => url_for('sign_up')
% end
@@ logged_in.html.ep
<p>Welcome back <%= session 'username' %>!</p>
<p><%= link_to 'Log out' => 'logout' %></p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment