From b2758ddf96a1a4009e542749e05b5bfd442be85f Mon Sep 17 00:00:00 2001 From: sergiotarxz Date: Tue, 15 Mar 2022 02:45:16 +0100 Subject: [PATCH] Fixing errors in customer, adding developer. Improving migrations, adding/fixing tests. --- Build.PL | 2 + db_tests/00001-customer-dao.t | 36 ++++++++ lib/Peace/DAO/Customer.pm | 17 ++-- lib/Peace/DAO/Developer.pm | 83 ++++++++++++++++++ lib/Peace/DB.pm | 17 ++-- lib/Peace/Model/Customer.pm | 10 +-- lib/Peace/Model/Developer.pm | 161 ++++++++++++++++++++++++++++++++++ t/00001-customer-model.t | 10 +-- t/00002-customer-dao.t | 26 +++--- t/00005-developer-model.t | 60 +++++++++++++ 10 files changed, 386 insertions(+), 36 deletions(-) create mode 100644 db_tests/00001-customer-dao.t create mode 100644 lib/Peace/DAO/Developer.pm create mode 100644 lib/Peace/Model/Developer.pm create mode 100644 t/00005-developer-model.t diff --git a/Build.PL b/Build.PL index e24f8de..0ae1a95 100644 --- a/Build.PL +++ b/Build.PL @@ -12,6 +12,8 @@ my $build = Module::Build->new( 'DBI' => 0, 'DBD::Pg' => 0, 'DBD::Mock' => 0, + 'DateTime' => 0, + 'DateTime::Format::Pg' => 0, }, install_path => { 'templates' => "$HOME/.local/share/peace/template", diff --git a/db_tests/00001-customer-dao.t b/db_tests/00001-customer-dao.t new file mode 100644 index 0000000..59e0602 --- /dev/null +++ b/db_tests/00001-customer-dao.t @@ -0,0 +1,36 @@ +#!/usr/bin/env perl + +use v5.30.0; + +use strict; +use warnings; + +use Test::Most tests => 2; + +use DateTime; + +use Peace; +use Peace::DB; +use Peace::Model::Customer; +use Peace::DAO::Customer; + +{ + ## GIVEN + my $current_date = DateTime->now; + my $peace = Peace->new; + my $home = $ENV{HOME}; + my $config = + $peace->plugin( + JSONConfig => { file => "$home/.config/peace/peace.conf" } ); + my $dbh = Peace::DB->dbh( config => $config ); + my $secret_bcrypt = 'hola'; + my $customer = Peace::Model::Customer->new( secret_bcrypt => $secret_bcrypt ); + my $customer_dao = Peace::DAO::Customer->new( dbh => $dbh ); + + ## WHEN + $customer_dao->create( customer => $customer ); + + ## THEN + ok $customer->uuid, 'Generated uuid.'; + ok $customer->date_creation > $current_date, 'The date is recent.'; +} diff --git a/lib/Peace/DAO/Customer.pm b/lib/Peace/DAO/Customer.pm index b4a59a9..d867b8b 100644 --- a/lib/Peace/DAO/Customer.pm +++ b/lib/Peace/DAO/Customer.pm @@ -8,6 +8,8 @@ use warnings; use Params::ValidationCompiler qw/validation_for/; use Types::Standard qw/HasMethods InstanceOf Str/; +use DateTime::Format::Pg; + { my $validator = validation_for( params => { @@ -38,19 +40,15 @@ use Types::Standard qw/HasMethods InstanceOf Str/; my $customer = $params{customer}; my $dbh = $self->_dbh; my $insert = <<'EOF'; -INSERT INTO customers (secret) VALUES (?) RETURNING uuid; +INSERT INTO customers (secret_bcrypt) VALUES (?) RETURNING uuid; EOF my $result = - $dbh->selectrow_hashref( $insert, undef, $customer->secret ); + $dbh->selectrow_hashref( $insert, undef, $customer->secret_bcrypt ); my $uuid = $result->{uuid}; $customer->uuid($uuid); my $new_customer = $self->recover_by_uuid( uuid => $uuid ); - $customer->secret( $new_customer->secret ) - if defined $new_customer->secret; $customer->date_creation( $new_customer->date_creation ) if defined $new_customer->date_creation; - $customer->stripe_id( $new_customer->stripe_id ) - if defined $new_customer->stripe_id; return $customer; } } @@ -70,8 +68,13 @@ EOF my $uuid = $params{uuid}; my $result = $dbh->selectrow_hashref( <<'EOF', undef, $uuid ); -SELECT uuid, date_creation, secret, stripe_id FROM customer WHERE uuid = ?; +SELECT uuid, date_creation, secret_bcrypt, stripe_id FROM customers WHERE uuid = ?; EOF + if ( exists $result->{date_creation} ) { + my $iso8601 = DateTime::Format::Pg->new; + $result->{date_creation} = + $iso8601->parse_datetime( $result->{date_creation} ); + } for my $key ( keys %$result ) { delete $result->{$key} unless defined $result->{$key}; } diff --git a/lib/Peace/DAO/Developer.pm b/lib/Peace/DAO/Developer.pm new file mode 100644 index 0000000..225ae58 --- /dev/null +++ b/lib/Peace/DAO/Developer.pm @@ -0,0 +1,83 @@ +package Peace::DAO::Developer; + +use v5.30.0; + +use strict; +use warnings; + +use Params::ValidationCompiler qw/validation_for/; +use Types::Standard qw/HasMethods InstanceOf Str/; + +{ + my $validator = validation_for( + params => { + dbh => { type => HasMethods ['selectall_arrayref'] }, + } + ); + + sub new { + my $class = shift; + my %params = $validator->(@_); + + my $self = bless {}, $class; + $self->{dbh} = $params{dbh}; + return $self; + } +} + +{ + my $validator = validation_for( + params => { + developer => { type => InstanceOf ['Peace::Model::Developer'] }, + } + ); + + sub create { + my $self = shift; + my %params = $validator->(@_); + my $developer = $params{developer}; + my $dbh = $self->_dbh; + my $insert = <<'EOF'; +INSERT INTO developers (secret_bcrypt, name, surname, email, country, verified) + VALUES (?, ?, ?, ?, ?, ?) + RETURNING uuid; +EOF + my $result = $dbh->selectrow_hashref( + $insert, undef, $developer->secret, + $developer->name, $developer->surname, $developer->email, + $developer->country, $developer->verified + ); + my $uuid = $result->{uuid}; + $developer->uuid($uuid); + my $new_developer = $self->recover_by_uuid( uuid => $uuid ); + $developer->date_creation( $new_developer->date_creation ) + if defined $new_developer->date_creation; + return $developer; + } +} + +{ + my $validator = validation_for( + params => { + uuid => { type => Str }, + } + ); + + sub recover_by_uuid { + my $self = shift; + my %params = $validator->(@_); + my $uuid = $params{uuid}; + 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 + FROM customer + WHERE uuid = ?; +EOF + for my $key (keys %$result) { + delete $result->{$key} unless defined $result->{$key}; + } + my $developer = Peace::Model::Developer->new(%$result); + return $developer; + } +} +1; diff --git a/lib/Peace/DB.pm b/lib/Peace/DB.pm index 2132e0f..205a69e 100644 --- a/lib/Peace/DB.pm +++ b/lib/Peace/DB.pm @@ -20,13 +20,14 @@ my @migrations = ( 'CREATE TABLE customers ( uuid UUID NOT NULL DEFAULT gen_random_uuid(), date_creation timestamp DEFAULT NOW(), - secret TEXT NOT NULL, + secret_bcrypt TEXT NOT NULL, stripe_id TEXT, PRIMARY KEY (uuid) );', 'CREATE TABLE developers ( uuid UUID NOT NULL DEFAULT gen_random_uuid(), date_creation timestamp DEFAULT NOW(), + secret_bcrypt TEXT NOT NULL, name TEXT NOT NULL, surname TEXT NOT NULL, email TEXT NOT NULL, @@ -127,14 +128,14 @@ sub run_migrations { for my $migration (@needed_migrations) { $dbh->do($migration); my $update_result = - $dbh->do( 'UPDATE options SET value = ? WHERE key = \'migration\';', - undef, ++$current_migration ); + $dbh->do( <<'EOF', undef, ++$current_migration ); +UPDATE options SET value = ? WHERE key = 'migration'; +EOF - unless ( defined $update_result ) { - $dbh->do( - 'INSERT INTO options (key, value) VALUES (\"migration\", ?)', - undef, $current_migration - ); + unless ( defined $update_result && 0+$update_result ) { + say $dbh->do( <<'EOF', undef, $current_migration); +INSERT INTO options (key, value) VALUES ('migration', ?); +EOF } } } diff --git a/lib/Peace/Model/Customer.pm b/lib/Peace/Model/Customer.pm index de1dd43..6f966c9 100644 --- a/lib/Peace/Model/Customer.pm +++ b/lib/Peace/Model/Customer.pm @@ -14,7 +14,7 @@ use DateTime; params => { uuid => { type => Str, optional => 1 }, date_creation => { type => InstanceOf ['DateTime'], optional => 1 }, - secret => { type => Str }, + secret_bcrypt => { type => Str }, stripe_id => { type => Str, optional => 1 }, } ); @@ -60,13 +60,13 @@ use DateTime; my $validator = validation_for( params => [ { type => Str, optional => 1 } ] ); - sub secret { + sub secret_bcrypt { my $self = shift; if (@_) { - my ($new_secret) = $validator->(@_); - $self->{secret} = $new_secret; + my ($new_secret_bcrypt) = $validator->(@_); + $self->{secret_bcrypt} = $new_secret_bcrypt; } - return $self->{secret}; + return $self->{secret_bcrypt}; } } diff --git a/lib/Peace/Model/Developer.pm b/lib/Peace/Model/Developer.pm new file mode 100644 index 0000000..10435e0 --- /dev/null +++ b/lib/Peace/Model/Developer.pm @@ -0,0 +1,161 @@ +package Peace::Model::Developer; +use v5.30.0; + +use strict; +use warnings; + +use Params::ValidationCompiler qw/validation_for/; +use Types::Standard qw/Str InstanceOf Bool/; + +use DateTime; + +{ + my $validator = validation_for( + 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 }, + } + ); + + sub new { + my $class = shift; + my %params = $validator->(@_); + my $self = bless {%params}, $class; + return $self; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub uuid { + my $self = shift; + if (@_) { + my ($new_uuid) = $validator->(@_); + $self->{uuid} = $new_uuid; + } + return $self->{uuid}; + } +} + +{ + my $validator = + validation_for( + params => [ { type => InstanceOf ['DateTime'], optional => 1 } ] ); + + sub date_creation { + my $self = shift; + if (@_) { + my ($new_date_creation) = $validator->(@_); + $self->{date_creation} = $new_date_creation; + } + return $self->{date_creation}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub secret_bcrypt { + my $self = shift; + if (@_) { + my ($new_secret_bcrypt) = $validator->(@_); + $self->{secret_bcrypt} = $new_secret_bcrypt; + } + return $self->{secret_bcrypt}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub name { + my $self = shift; + if (@_) { + my ($new_name) = $validator->(@_); + $self->{name} = $new_name; + } + return $self->{name}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub surname { + my $self = shift; + if (@_) { + my ($new_surname) = $validator->(@_); + $self->{surname} = $new_surname; + } + return $self->{surname}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub email { + my $self = shift; + if (@_) { + my ($new_email) = $validator->(@_); + $self->{email} = $new_email; + } + return $self->{email}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub stripe_id { + my $self = shift; + if (@_) { + my ($new_stripe_id) = $validator->(@_); + $self->{stripe_id} = $new_stripe_id; + } + return $self->{stripe_id}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Str, optional => 1 } ] ); + + sub country { + my $self = shift; + if (@_) { + my ($new_country) = $validator->(@_); + $self->{country} = $new_country; + } + return $self->{country}; + } +} + +{ + my $validator = + validation_for( params => [ { type => Bool, optional => 1 } ] ); + + sub verified { + my $self = shift; + if (@_) { + my ($new_verified) = $validator->(@_); + $self->{verified} = $new_verified; + } + return $self->{verified}; + } +} +1; diff --git a/t/00001-customer-model.t b/t/00001-customer-model.t index 7ac77ff..0c80b4c 100644 --- a/t/00001-customer-model.t +++ b/t/00001-customer-model.t @@ -11,21 +11,21 @@ BEGIN { { ## GIVEN - my $secret = 'hola'; + my $secret_bcrypt = 'hola'; ## WHEN - my $customer = Peace::Model::Customer->new( secret => $secret ); + my $customer = Peace::Model::Customer->new( secret_bcrypt => $secret_bcrypt ); ## THEN ok $customer->isa('Peace::Model::Customer'), 'Instanced customer is made of Peace::Model::Customer.'; - is $customer->secret, $secret, 'Secret is correctly setup'; + is $customer->secret_bcrypt, $secret_bcrypt, 'Secret is correctly setup'; is $customer->uuid, undef, 'Uuid is undef.'; } { ## GIVEN - my $secret = 'hola'; + my $secret_bcrypt = 'hola'; my $uuid = 'example'; - my $customer = Peace::Model::Customer->new( secret => $secret ); + my $customer = Peace::Model::Customer->new( secret_bcrypt => $secret_bcrypt ); ## WHEN $customer->uuid($uuid); diff --git a/t/00002-customer-dao.t b/t/00002-customer-dao.t index 10fe549..8fb759a 100644 --- a/t/00002-customer-dao.t +++ b/t/00002-customer-dao.t @@ -17,11 +17,11 @@ BEGIN { { ## GIVEN my $sql = <<'EOF'; -INSERT INTO customers (secret) VALUES (?) RETURNING uuid; +INSERT INTO customers (secret_bcrypt) VALUES (?) RETURNING uuid; EOF my $uuid = 'hola'; my $dbh = DBI->connect( 'DBI:Mock:', '', '' ); - my $customer = Peace::Model::Customer->new( secret => 'hola' ); + my $customer = Peace::Model::Customer->new( secret_bcrypt => 'hola' ); my $customer_dao = Peace::DAO::Customer->new( dbh => $dbh ); $dbh->{mock_add_resultset} = { @@ -29,11 +29,14 @@ EOF results => [ ['uuid'], [$uuid], ] }; $sql = <<'EOF'; -SELECT uuid, date_creation, secret, stripe_id FROM customer WHERE uuid = ?; +SELECT uuid, date_creation, secret_bcrypt, stripe_id FROM customer WHERE uuid = ?; EOF $dbh->{mock_add_resultset} = { sql => $sql, - results => [ ['uuid', 'secret', 'date_creation', 'stripe_id'], [$uuid, 'hola', undef, undef] ], + results => [ + [ 'uuid', 'secret_bcrypt', 'date_creation', 'stripe_id' ], + [ $uuid, 'hola', undef, undef ] + ], }; ## WHEN $customer_dao->create( customer => $customer ); @@ -44,21 +47,21 @@ EOF { ## GIVEN - my $dbh = DBI->connect( 'DBI:Mock:', '', '' ); + my $dbh = DBI->connect( 'DBI:Mock:', '', '' ); my $customer_dao = Peace::DAO::Customer->new( dbh => $dbh ); - my $sql = <<'EOF'; -SELECT uuid, date_creation, secret, stripe_id FROM customer WHERE uuid = ?; + my $sql = <<'EOF'; +SELECT uuid, date_creation, secret_bcrypt, stripe_id FROM customer WHERE uuid = ?; EOF my $uuid = 'hola'; my $date_creation = DateTime->now; - my $secret = 'hola'; + my $secret_bcrypt = 'hola'; my $stripe_id = undef; $dbh->{mock_add_resultset} = { sql => $sql, results => [ - [ 'uuid', 'date_creation', 'secret', 'stripe_id' ], - [ $uuid, $date_creation, $secret, $stripe_id ], + [ 'uuid', 'date_creation', 'secret_bcrypt', 'stripe_id' ], + [ $uuid, $date_creation, $secret_bcrypt, $stripe_id ], ] }; @@ -69,7 +72,8 @@ EOF is $customer->uuid, $uuid, 'Uuid is recovered correctly'; is $customer->date_creation, $date_creation, 'Date creation is recovered correctly'; - is $customer->secret, $secret, 'Secret is recovered correctly'; + is $customer->secret_bcrypt, $secret_bcrypt, + 'Secret is recovered correctly'; is $customer->stripe_id, $stripe_id, 'Secret is recovered correctly'; } diff --git a/t/00005-developer-model.t b/t/00005-developer-model.t new file mode 100644 index 0000000..c472966 --- /dev/null +++ b/t/00005-developer-model.t @@ -0,0 +1,60 @@ +use v5.30.0; + +use strict; +use warnings; + +use Test::Most tests => 5; + +BEGIN { + use_ok 'Peace::Model::Developer'; +} + +{ + ## GIVEN + my $secret_bcrypt = 'hola'; + my $name = 'Larry'; + my $surname = 'Wall'; + my $email = 'larry@perl.org'; + my $country = 'US'; + my $verified = 0; + ## WHEN + my $developer = Peace::Model::Developer->new( + secret_bcrypt => $secret_bcrypt, + name => $name, + surname => $surname, + email => $email, + country => $country, + verified => $verified, + ); + ## THEN + ok $developer->isa('Peace::Model::Developer'), + 'Instanced developer is made of Peace::Model::Developer.'; + is $developer->secret_bcrypt, $secret_bcrypt, 'Secret is correctly setup'; + is $developer->uuid, undef, 'Uuid is undef.'; +} + +{ + ## GIVEN + my $uuid = 'example'; + my $secret_bcrypt = 'hola'; + my $name = 'Larry'; + my $surname = 'Wall'; + my $email = 'larry@perl.org'; + my $country = 'US'; + my $verified = 0; + + my $developer = Peace::Model::Developer->new( + secret_bcrypt => $secret_bcrypt, + name => $name, + surname => $surname, + email => $email, + country => $country, + verified => $verified + ); + + ## WHEN + $developer->uuid($uuid); + + ## THEN + is $developer->uuid, $uuid, 'Uuid can be set.'; +}