Last active
April 3, 2023 21:39
-
-
Save jberger/91a853ee223737c1a1d1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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