Adding verification email.

This commit is contained in:
sergiotarxz 2022-04-24 03:01:21 +02:00
parent f2cf883f34
commit deeb0da8cd
18 changed files with 353 additions and 54 deletions

View File

@ -24,6 +24,7 @@ my $build = Module::Build->new(
'Email::Valid' => 0,
'Crypt::Bcrypt' => 0,
'Email::Sender' => 0,
'HTML::Entities' => 0,
},
install_path => {
'templates' => "$HOME/.local/share/peace/template",

View File

@ -7,6 +7,7 @@ use warnings;
use Test::Most tests => 2;
use Crypt::URandom q/urandom/;
use DateTime;
use Peace;
@ -32,6 +33,7 @@ use Peace::DAO::Developer;
verified => 0,
secret_bcrypt => $secret_bcrypt
);
$developer->email($developer->email =~ s/\@/unpack('H*', urandom(100)).'@'/er);
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
## WHEN

View File

@ -10,6 +10,7 @@ use Data::Dumper;
use Test::Most tests => 4;
use DateTime;
use Crypt::URandom q/urandom/;
use Peace;
use Peace::DB;
@ -30,6 +31,7 @@ use Peace::Test::Mock::Model::Application;
my $dbh = Peace::DB->dbh( config => $config );
my $developer = Peace::Test::Mock::Model::Developer->new;
$developer->email($developer->email =~ s/\@/unpack('H*', urandom(100)).'@'/er);
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
$developer_dao->create( developer => $developer );
@ -60,6 +62,7 @@ use Peace::Test::Mock::Model::Application;
my $secret_bcrypt = 'hola';
my $developer = Peace::Test::Mock::Model::Developer->new;
$developer->email($developer->email =~ s/\@/unpack('H*', urandom(100)).'@'/er);
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
$developer_dao->create( developer => $developer );

View File

@ -10,6 +10,7 @@ use Data::Dumper;
use Test::Most tests => 2;
use DateTime;
use Crypt::URandom q/urandom/;
use Peace;
use Peace::DB;
@ -32,6 +33,7 @@ use Peace::Test::Mock::Model::Release;
my $dbh = Peace::DB->dbh( config => $config );
my $developer = Peace::Test::Mock::Model::Developer->new;
$developer->email($developer->email =~ s/\@/unpack('H*', urandom(100)).'@'/er);
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
$developer_dao->create( developer => $developer );

View File

@ -8,6 +8,7 @@ use warnings;
use Test::Most tests => 2;
use DateTime;
use Crypt::URandom q/urandom/;
use Peace;
use Peace::DB;
@ -31,6 +32,8 @@ use Peace::Test::Mock::Model::Build;
my $release_dao = Peace::DAO::Release->new( dbh => $dbh );
my $application_dao = Peace::DAO::Application->new( dbh => $dbh );
my $build_dao = Peace::DAO::Build->new( dbh => $dbh );
my $developer = $build->release->application->developer;
$developer->email($developer->email =~ s/\@/unpack('H*', urandom(100)).'@'/er);
$developer_dao->create(
developer => $build->release->application->developer );
$build->release->application->app_id(

View File

@ -8,6 +8,9 @@
<li>
<a href="lib/Peace.pm.html">Peace</a>
</li>
<li>
<a href="lib/Peace/Controller/Application.pm.html">Peace::Controller::Application</a>
</li>
<li>
<a href="lib/Peace/Controller/Developer.pm.html">Peace::Controller::Developer</a>
</li>
@ -32,6 +35,9 @@
<li>
<a href="lib/Peace/DB.pm.html">Peace::DB</a>
</li>
<li>
<a href="lib/Peace/Email.pm.html">Peace::Email</a>
</li>
<li>
<a href="lib/Peace/Model/Application.pm.html">Peace::Model::Application</a>
</li>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Peace::Controller::Application - Application&#39;s http endpoint.</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
<link href="mailto:Alpine@build-edge-aarch64.nonet" rev="made" />
</head>
<body>
<ul id="index">
<li><a href="#NAME">NAME</a></li>
<li><a href="#SYNOPSIS">SYNOPSIS</a></li>
<li><a href="#DESCRIPTION">DESCRIPTION</a></li>
<li><a href="#METHODS">METHODS</a>
<ul>
<li><a href="#developer_application_post">developer_application_post</a></li>
</ul>
</li>
<li><a href="#SEE-ALSO">SEE ALSO</a></li>
</ul>
<h1 id="NAME">NAME</h1>
<p>Peace::Controller::Application - Application&#39;s http endpoint.</p>
<h1 id="SYNOPSIS">SYNOPSIS</h1>
<pre><code># This object is used by mojolicious.</code></pre>
<h1 id="DESCRIPTION">DESCRIPTION</h1>
<p>Peace::Controller::Application allows to interact using a json http api with the <a href="../Model/Application.pm.html">Peace::Model::Application</a> objects in Peace.</p>
<h1 id="METHODS">METHODS</h1>
<p>Peace::Controller::Developer implements the following methods:</p>
<h2 id="developer_application_post">developer_application_post</h2>
<pre><code># To be used by mojolicious.</code></pre>
<p>Creates a application in db with the data given by the user.</p>
<h1 id="SEE-ALSO">SEE ALSO</h1>
<p><a href="../Model/Application.pm.html">Peace::Model::Application</a>, <a href="../DAO/Application.pm.html">Peace::DAO::Application</a></p>
</body>
</html>

View File

@ -24,6 +24,7 @@
<ul>
<li><a href="#create">create</a></li>
<li><a href="#recover_by_uuid">recover_by_uuid</a></li>
<li><a href="#recover_by_identifier">recover_by_identifier</a></li>
</ul>
</li>
<li><a href="#SEE-ALSO">SEE ALSO</a></li>
@ -73,6 +74,12 @@ my $developer = $developer_dao-&gt;recover_by_uuid( uuid =&gt; $uuid );</code></
<p>Recovers the <a href="../Model/Developer.pm.html">Peace::Model::Developer</a> associated from an uuid from database.</p>
<h2 id="recover_by_identifier">recover_by_identifier</h2>
<pre><code>my $developer = $developer_dao-&gt;recover_by_identifier( identifier =&gt; $identifier );</code></pre>
<p>Recovers the <a href="../Model/Developer.pm.html">Peace::Model::Developer</a> associated from an identifier from database.</p>
<h1 id="SEE-ALSO">SEE ALSO</h1>
<p><a href="../DB.pm.html">Peace::DB</a>, <a href="../Model/Developer.pm.html">Peace::Model::Developer</a></p>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Peace::Email - The mail sender module for Peace.</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
<link href="mailto:Alpine@build-edge-aarch64.nonet" rev="made" />
</head>
<body>
<ul id="index">
<li><a href="#NAME">NAME</a></li>
<li><a href="#SYNOPSIS">SYNOPSIS</a></li>
<li><a href="#DESCRIPTION">DESCRIPTION</a></li>
<li><a href="#INSTANCE-METHODS">INSTANCE METHODS</a>
<ul>
<li><a href="#new">new</a></li>
</ul>
</li>
<li><a href="#METHODS">METHODS</a>
<ul>
<li><a href="#sendmail">sendmail</a></li>
</ul>
</li>
<li><a href="#SEE-ALSO">SEE ALSO</a></li>
</ul>
<h1 id="NAME">NAME</h1>
<p>Peace::Email - The mail sender module for Peace.</p>
<h1 id="SYNOPSIS">SYNOPSIS</h1>
<pre><code>my $mailer = Peace::Email-&gt;new;
$mailer-&gt;sendmail(
to =&gt; &#39;larry@perl,org&#39;,
text =&gt; &#39;hola&#39;,
html =&gt; &#39;&lt;b&gt;hola&lt;/b&gt;&#39;,
subject =&gt; &#39;Patch&#39;,
);</code></pre>
<h1 id="DESCRIPTION">DESCRIPTION</h1>
<p>Peace::Email reads the Peace config to determine the credentials to send mail and does an abstraction around those.</p>
<h1 id="INSTANCE-METHODS">INSTANCE METHODS</h1>
<p>Peace::Email implements the following instance methods:</p>
<h2 id="new">new</h2>
<pre><code>my $mailer = Peace::Email-&gt;new;</code></pre>
<p>Instances a new mailer.</p>
<h1 id="METHODS">METHODS</h1>
<p>Peace::Email implements the following methods:</p>
<h2 id="sendmail">sendmail</h2>
<pre><code>$mailer-&gt;sendmail(
to =&gt; &#39;larry@perl,org&#39;,
text =&gt; &#39;hola&#39;,
html =&gt; &#39;&lt;b&gt;hola&lt;/b&gt;&#39;,
subject =&gt; &#39;Patch&#39;,
);</code></pre>
<p>Sends a mail to the given mail address.</p>
<h1 id="SEE-ALSO">SEE ALSO</h1>
<p><a href="../Peace.pm.html">Peace</a></p>
</body>
</html>

View File

@ -22,6 +22,7 @@
</li>
<li><a href="#METHODS">METHODS</a>
<ul>
<li><a href="#to_json">to_json</a></li>
<li><a href="#uuid">uuid</a></li>
<li><a href="#date_creation">date_creation</a></li>
<li><a href="#name">name</a></li>
@ -85,6 +86,12 @@
<p>Peace::Model::Application implements the following methods:</p>
<h2 id="to_json">to_json</h2>
<pre><code>my $json = $application-&gt;to_json;</code></pre>
<p>Retrieves the json representation of the application.</p>
<h2 id="uuid">uuid</h2>
<pre><code>my $uuid = $application-&gt;uuid;

View File

@ -23,6 +23,7 @@
<li><a href="#METHODS">METHODS</a>
<ul>
<li><a href="#to_json">to_json</a></li>
<li><a href="#login">login</a></li>
<li><a href="#applications">applications</a></li>
<li><a href="#uuid">uuid</a></li>
<li><a href="#date_creation">date_creation</a></li>
@ -33,6 +34,7 @@
<li><a href="#stripe_id">stripe_id</a></li>
<li><a href="#country">country</a></li>
<li><a href="#verified">verified</a></li>
<li><a href="#verification_secret">verification_secret</a></li>
</ul>
</li>
<li><a href="#SEE-ALSO">SEE ALSO</a></li>
@ -86,6 +88,12 @@
<p>Renders the developer in a json like structure.</p>
<h2 id="login">login</h2>
<pre><code>my $logged = $developer-&gt;login( secret =&gt; $secret );</code></pre>
<p>Returns true if the login is successful, false otherwise.</p>
<h2 id="applications">applications</h2>
<pre><code>my $applications = $developer-&gt;applications;</code></pre>
@ -156,12 +164,20 @@ $developer-&gt;country($country);</code></pre>
<h2 id="verified">verified</h2>
<pre><code>my $verified = $developer-&gt;verified
<pre><code>my $verified = $developer-&gt;verified;
$developer-&gt;verified($verified);</code></pre>
<p>Allows to retrieve and set the developer verified.</p>
<h2 id="verification_secret">verification_secret</h2>
<pre><code>my $verification_secret = $developer-&gt;verification_secret;
$developer-&gt;verification_secret($verification_secret);</code></pre>
<p>Allows to retrieve and set the developer verification_secret.</p>
<h1 id="SEE-ALSO">SEE ALSO</h1>
<p><a href="../DAO/Developer.pm.html">Peace::DAO::Developer</a>, <a href="Application.pm.html">Peace::Model::Application</a></p>

View File

@ -26,6 +26,7 @@
<li><a href="#validate_request">validate_request</a></li>
<li><a href="#developer">developer</a></li>
<li><a href="#developer_post">developer_post</a></li>
<li><a href="#developer_application_post">developer_application_post</a></li>
</ul>
</li>
</ul>
@ -78,10 +79,16 @@
<h2 id="developer_post">developer_post</h2>
<pre><code>my $developer_post = $swagger-&gt;developer_post</code></pre>
<pre><code>my $developer_post = $swagger-&gt;developer_post;</code></pre>
<p>Returns the schema of the post request to the /developer enpoint.</p>
<h2 id="developer_application_post">developer_application_post</h2>
<pre><code>my $developer_application_post = $swagger-&gt;developer_application_post;</code></pre>
<p>Returns the schema of the post request to the /developer/:identifier/application endpoint.</p>
</body>

View File

@ -11,12 +11,14 @@ use Data::Dumper;
use Const::Fast;
use Peace::Swagger;
use Crypt::Bcrypt qw/bcrypt/;
use Crypt::URandom qw/urandom/;
use HTML::Entities;
use Peace;
use Peace::DB;
use Peace::Email;
use Peace::Swagger;
use Peace::Model::Developer;
use Peace::DAO::Developer;
@ -28,6 +30,8 @@ sub post {
my $json = $self->req->json;
my $peace = Peace->new;
my $config = $peace->peace_config;
my $mailer = Peace::Email->new;
my $url = $config->{url};
my $dbh = Peace::DB->dbh( config => $config );
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
@ -53,6 +57,13 @@ sub post {
$self->render( status => 400, text => $@ );
return;
}
my $verification_url = "$url/web/account-verification/@{[$developer->verification_secret]}";
my $verification_url_html = HTML::Entities::encode_entities($verification_url);
$mailer->sendmail( to => $developer->email,
text => "Verify your account at $verification_url",
html => "Verify your account at <a href=\"$verification_url_html\">$verification_url_html</a>.",
subject => 'Verify your Peace account.',
);
$self->render( json => $developer->to_json() );
}
1;

View File

@ -47,13 +47,14 @@ EOF
my $result;
eval {
$result = $dbh->selectrow_hashref(
$insert, undef, $developer->secret_bcrypt,
$developer->name, $developer->surname, $developer->email,
$developer->country, $developer->verified
$insert, undef,
$developer->secret_bcrypt, $developer->name,
$developer->surname, $developer->email,
$developer->country, $developer->verified
);
};
if ($@) {
if ($@ =~ /duplicate key value/) {
if ( $@ =~ /duplicate key value/ ) {
die "Email already registered.";
}
die $@;
@ -63,6 +64,7 @@ EOF
my $new_developer = $self->recover_by_uuid( uuid => $uuid );
$developer->date_creation( $new_developer->date_creation )
if defined $new_developer->date_creation;
$developer->verification_secret( $new_developer->verification_secret );
return $developer;
}
}
@ -78,16 +80,16 @@ EOF
my $self = shift;
my %params = $validator->(@_);
my $uuid = $params{uuid};
my $dbh = $self->_dbh;
my $dbh = $self->_dbh;
my $result = $dbh->selectrow_hashref( <<'EOF', undef, $uuid );
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified, verification_secret
FROM developers
WHERE uuid = ?;
EOF
if (!defined $result) {
if ( !defined $result ) {
die "No such developer $uuid.";
}
for my $key (keys %$result) {
for my $key ( keys %$result ) {
delete $result->{$key} unless defined $result->{$key};
}
@ -110,19 +112,19 @@ EOF
);
sub recover_by_identifier {
my $self = shift;
my %params = $validator->(@_);
my $identifier =$params{identifier};
my $dbh = $self->_dbh;
my $result = $dbh->selectrow_hashref( <<'EOF', undef, $identifier );
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified
my $self = shift;
my %params = $validator->(@_);
my $identifier = $params{identifier};
my $dbh = $self->_dbh;
my $result = $dbh->selectrow_hashref( <<'EOF', undef, $identifier );
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified, verification_secret
FROM developers
WHERE email = $1 or uuid::text = $1;
EOF
if (!defined $result) {
if ( !defined $result ) {
die "No such developer $identifier.";
}
for my $key (keys %$result) {
for my $key ( keys %$result ) {
delete $result->{$key} unless defined $result->{$key};
}
@ -136,11 +138,13 @@ EOF
return $developer;
}
}
sub _dbh {
my $self = shift;
return $self->{dbh};
}
1;
=encoding utf8
=head1 NAME

View File

@ -34,6 +34,12 @@ my @migrations = (
stripe_id TEXT,
country TEXT NOT NULL,
verified BOOL DEFAULT false,
verification_secret TEXT NOT NULL
DEFAULT encode(
sha512(
gen_random_uuid()::text::bytea
)::bytea, \'hex\'
) UNIQUE,
PRIMARY KEY (uuid)
);',
'CREATE TABLE applications (

View File

@ -5,6 +5,8 @@ use v5.30.0;
use strict;
use warnings;
use Encode qw/decode/;
use Peace;
use Params::ValidationCompiler qw/validation_for/;
@ -22,60 +24,63 @@ sub new {
{
my $validator = validation_for(
params => {
text => { type => Str },
html => { type => Str },
to => { type => Str },
text => { type => Str },
html => { type => Str },
to => { type => Str },
subject => { type => Str },
}
);
sub sendmail {
my $self = shift;
my %params = $validator->(@_);
my ( $text, $html, $to ) = @params{qw/text html to/};
my ( $text, $html, $to, $subject ) = @params{qw/text html to subject/};
my @parts = (
Email::MIME->create(
attributes => {
content_type => 'multipart/alternative',
encoding => 'base64',
},
parts => [
Email::MIME->create(
attributes => {
charset => 'UTF-8',
content_type => 'text/plain',
encoding => "quoted-printable",
disposition => 'inline',
encoding => 'base64',
disposition => 'inline',
},
body_str => $text,
body_str => decode('utf-8', $text),
),
Email::MIME->create(
attributes => {
charset => 'UTF-8',
content_type => 'text/html',
encoding => "quoted-printable",
disposition => 'inline',
encoding => 'base64',
disposition => 'inline',
},
body_str => $html,
body_str => decode('utf-8', $html),
)
]
)
);
my $email = Email::MIME->create(
header_str => [
From => Peace->new->peace_config->{smtp}{sasl_username},
To => $to,
From => Peace->new->peace_config->{smtp}{sasl_username},
To => $to,
Subject => $subject,
],
attributes => {
encoding => 'base64',
encoding => 'base64',
content_type => 'multipart/mixed'
},
parts => [@parts],
);
Email::Sender::Simple::send( 'Email::Sender::Simple', $email,
{ transport => $self->generate_transport } );
{ transport => $self->_generate_transport } );
}
}
sub generate_transport {
sub _generate_transport {
my $peace_config = Peace->new->peace_config;
my $transport = Email::Sender::Transport::SMTP->new(
hosts => [ $peace_config->{smtp}{smtp_host} ],
@ -87,3 +92,55 @@ sub generate_transport {
return $transport;
}
1;
=encoding utf8
=head1 NAME
Peace::Email - The mail sender module for Peace.
=head1 SYNOPSIS
my $mailer = Peace::Email->new;
$mailer->sendmail(
to => 'larry@perl,org',
text => 'hola',
html => '<b>hola</b>',
subject => 'Patch',
);
=head1 DESCRIPTION
Peace::Email reads the Peace config to determine the credentials
to send mail and does an abstraction around those.
=head1 INSTANCE METHODS
Peace::Email implements the following instance methods:
=head2 new
my $mailer = Peace::Email->new;
Instances a new mailer.
=head1 METHODS
Peace::Email implements the following methods:
=head2 sendmail
$mailer->sendmail(
to => 'larry@perl,org',
text => 'hola',
html => '<b>hola</b>',
subject => 'Patch',
);
Sends a mail to the given mail address.
=head1 SEE ALSO
L<Peace>
=cut

View File

@ -17,13 +17,14 @@ use Peace::DAO::Application;
params => {
uuid => { type => Str, optional => 1 },
date_creation => { type => InstanceOf ['DateTime'], optional => 1 },
secret_bcrypt => { type => Str },
name => { type => Str },
surname => { type => Str },
email => { type => Str },
stripe_id => { type => Str, optional => 1 },
country => { type => Str },
verified => { type => Bool },
secret_bcrypt => { type => Str },
name => { type => Str },
surname => { type => Str },
email => { type => Str },
stripe_id => { type => Str, optional => 1 },
country => { type => Str },
verified => { type => Bool },
verification_secret => { type => Str, optional => 1 },
dbh => { type => HasMethods ['selectall_arrayref'], optional => 1 },
}
);
@ -55,12 +56,13 @@ sub to_json {
secret => { type => Str },
}
);
sub login {
my $self = shift;
my %params = $validator->(@_);
my $secret = $params{secret};
my $self = shift;
my %params = $validator->(@_);
my $secret = $params{secret};
my $secret_bcrypt = $self->secret_bcrypt;
return bcrypt_check($secret, $secret_bcrypt);
return bcrypt_check( $secret, $secret_bcrypt );
}
}
@ -207,6 +209,20 @@ sub applications {
}
}
{
my $validator =
validation_for( params => [ { type => Str, optional => 1 } ] );
sub verification_secret {
my $self = shift;
if (@_) {
my ($new_verification_secret) = $validator->(@_);
$self->{verification_secret} = $new_verification_secret;
}
return $self->{verification_secret};
}
}
sub _dbh {
my $self = shift;
return $self->{dbh};
@ -342,12 +358,20 @@ Allows to retrieve and set the developer country.
=head2 verified
my $verified = $developer->verified
my $verified = $developer->verified;
$developer->verified($verified);
Allows to retrieve and set the developer verified.
=head2 verification_secret
my $verification_secret = $developer->verification_secret;
$developer->verification_secret($verification_secret);
Allows to retrieve and set the developer verification_secret.
=head1 SEE ALSO
L<Peace::DAO::Developer>, L<Peace::Model::Application>

View File

@ -46,7 +46,7 @@ EOF
results => [ ['uuid'], [$uuid], ]
};
$sql = <<'EOF';
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified, verification_secret
FROM developers
WHERE uuid = ?;
EOF
@ -60,11 +60,12 @@ EOF
'surname', 'email',
'country', 'verified',
'secret_bcrypt', 'date_creation',
'stripe_id'
'stripe_id', 'verification_secret'
],
[
$uuid, $name, $surname, $email, $country, $verified,
$secret_bcrypt, $formatter->format_datetime($datetime), undef
$uuid, $name, $surname, $email, $country, $verified,
$secret_bcrypt, $formatter->format_datetime($datetime),
undef, 'aaa'
]
],
};
@ -81,7 +82,7 @@ EOF
my $dbh = DBI->connect( 'DBI:Mock:', '', '' );
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
my $sql = <<'EOF';
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified, verification_secret
FROM developers
WHERE uuid = ?;
EOF
@ -105,11 +106,12 @@ EOF
'surname', 'email',
'country', 'verified',
'secret_bcrypt', 'date_creation',
'stripe_id'
'stripe_id', 'verification_secret'
],
[
$uuid, $name, $surname, $email, $country, $verified,
$secret_bcrypt, $formatter->format_datetime($datetime), undef
$uuid, $name, $surname, $email, $country, $verified,
$secret_bcrypt, $formatter->format_datetime($datetime),
undef, 'aaa'
]
],
};