From 98d4309b6710d6c8b9d130d8f21ff55761bc0a88 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 18 Apr 2017 12:38:39 +0100 Subject: [PATCH] Move use statement and refactor register to use mojo validators --- lib/Pear/LocalLoop.pm | 1 - lib/Pear/LocalLoop/Controller/Api/Register.pm | 235 +++++++----------- 2 files changed, 89 insertions(+), 147 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index fe6d738..f0f7f3b 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -4,7 +4,6 @@ use Mojo::Base 'Mojolicious'; use Data::UUID; use Mojo::JSON; use Email::Valid; -use ORM::Date; use Authen::Passphrase::BlowfishCrypt; use Scalar::Util qw(looks_like_number); use Pear::LocalLoop::Schema; diff --git a/lib/Pear/LocalLoop/Controller/Api/Register.pm b/lib/Pear/LocalLoop/Controller/Api/Register.pm index fdab2f3..12cab4e 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Register.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Register.pm @@ -3,8 +3,47 @@ use Mojo::Base 'Mojolicious::Controller'; use ORM::Date; use Data::Dumper; +has error_messages => sub { + return { + token => { + required => { message => 'No token sent.', status => 400 }, + in_resultset => { message => 'Token invalid or has been used.', status => 401 }, + }, + username => { + required => { message => 'No username sent or was blank.', status => 400 }, + like => { message => 'Username can only be A-Z, a-z and 0-9 characters.', status => 400 }, + not_in_resultset => { message => 'Username exists.', status => 403 }, + }, + email => { + required => { message => 'No email sent.', status => 400 }, + email => { message => 'Email is invalid.', status => 400 }, + not_in_resultset => { message => 'Email exists.', status => 403 }, + }, + postcode => { + required => { message => 'No postcode sent.', status => 400 }, + }, + password => { + required => { message => 'No password sent.', status => 400 }, + }, + usertype => { + required => { message => 'No usertype sent.', status => 400 }, + in => { message => '"usertype" is invalid.', status => 400 }, + }, + age => { + required => { message => 'No age sent.', status => 400 }, + in_resultset => { message => 'Age range is invalid.', status => 400 }, + }, + fulladdress => { + required => { message => 'No fulladdress sent.', status => 400 }, + }, + }; +}; + sub post_register{ - my $self = shift; + my $c = shift; + my $self = $c; + + my $validation = $c->validation; my $json = $self->req->json; $self->app->log->debug( "\n\nStart of register"); @@ -18,144 +57,67 @@ sub post_register{ }, status => 400,); #Malformed request } + $validation->input( $json ); - my $token = $json->{token}; - if ( ! defined $token ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No token sent.', - }, - status => 400,); #Malformed request - } - elsif ( ! $self->is_token_unused($token) ) { - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Token invalid or has been used.', - }, - status => 401,); #Unauthorized - } + my $token_rs = $c->schema->resultset('AccountToken')->search_rs({used => 0}); + $validation->required('token')->in_resultset('accounttokenname', $token_rs); - my $username = $json->{username}; - if ( ! defined $username ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No username sent.', - }, - status => 400,); #Malformed request - } - elsif ($username eq ''){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Username cannot be blank.', - }, - status => 400,); #Malformed request - } - elsif ( ! ($self->valid_username($username))){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Username can only be A-Z, a-z and 0-9 characters.', - }, - status => 400,); #Malformed request - } - elsif ( $self->does_username_exist($username) ) { - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Username exists.', - }, - status => 403,); #Forbidden - } + my $customer_rs = $c->schema->resultset('Customer'); + $validation->required('username')->like(qr/^[A-Za-z0-9]+$/)->not_in_resultset('username', $customer_rs); - my $email = $json->{email}; - if ( ! defined $email ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No email sent.', - }, - status => 400,); #Malformed request - } - elsif ( ! $self->valid_email($email)){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Email is invalid.', - }, - status => 400,); #Malformed request - } - elsif($self->does_email_exist($email)) { - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Email exists.', - }, - status => 403,); #Forbidden - } + my $user_rs = $c->schema->resultset('User'); + $validation->required('email')->email->not_in_resultset('email', $user_rs); #TODO test to see if post code is valid. - my $postcode = $json->{postcode}; - if ( ! defined $postcode ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No postcode sent.', - }, - status => 400,); #Malformed request - } + $validation->required('postcode'); #TODO should we enforce password requirements. - my $password = $json->{password}; - if ( ! defined $password ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No password sent.', - }, - status => 400,); #Malformed request + $validation->required('password'); + + $validation->required('usertype')->in('customer', 'organisation'); + + my $usertype = $validation->param('usertype') || ''; + + if ( $usertype eq 'customer' ) { + + my $age_rs = $c->schema->resultset('AgeRange'); + $validation->required('age')->in_resultset('agerangestring', $age_rs); + + } elsif ( $usertype eq 'organisation' ) { + + $validation->required('fulladdress'); + } + + if ( $validation->has_error ) { + my $failed_vals = $validation->failed; + for my $val ( @$failed_vals ) { + my $check = shift @{ $validation->error($val) }; + return $c->render( + json => { + success => Mojo::JSON->false, + message => $c->error_messages->{$val}->{$check}->{message}, + }, + status => $c->error_messages->{$val}->{$check}->{status}, + ); + } + } + + my $token = $validation->param('token'); + my $username = $validation->param('username'); + my $email = $validation->param('email'); + my $postcode = $validation->param('postcode'); + my $password = $validation->param('password'); + my $hashedPassword = $self->generate_hashed_password($password); my $secondsTime = time(); my $date = ORM::Date->new_epoch($secondsTime)->mysql_date; - my $usertype = $json->{usertype}; - - if ( ! defined $usertype ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No usertype sent.', - }, - status => 400,); #Malformed request - } - elsif ($usertype eq 'customer'){ - $self->app->log->debug('Path: file:' . __FILE__ . ', line: ' . __LINE__); - - my $age = $json->{age}; - if ( ! defined $age ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No age sent.', - }, - status => 400,); #Malformed request - } - - my $ageForeignKey = $self->get_age_foreign_key($age); - if ( ! defined $ageForeignKey ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'Age range is invalid.', - }, - status => 400,); #Malformed request - } + if ($usertype eq 'customer'){ + my $ageForeignKey = $self->get_age_foreign_key( $validation->param('age') ); + #TODO this will go away with a transaction, when we move this bit to dbic schema code #TODO UNTESTED as it's hard to simulate. #Token is no longer valid race condition. if ( ! $self->set_token_as_used($token) ){ @@ -182,23 +144,13 @@ sub post_register{ my $insertUser = $self->db->prepare("INSERT INTO Users (CustomerId_FK, Email, JoinDate, HashedPassword) VALUES (?, ?, ?, ?)"); my $rowsInsertedUser = $insertUser->execute($idToUse, $email, $date, $hashedPassword); - $self->app->log->debug('Path Success: file:' . __FILE__ . ', line: ' . __LINE__); return $self->render( json => { success => Mojo::JSON->true } ); } elsif ($usertype eq 'organisation') { - $self->app->log->debug('Path: file:' . __FILE__ . ', line: ' . __LINE__); - #TODO validation on the address. Or perhaps add the organisation to a "to be inspected" list then manually check them. - my $fullAddress = $json->{fulladdress}; - if ( ! defined $fullAddress ){ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => 'No fulladdress sent.', - }, - status => 400,); #Malformed request - } + my $fullAddress = $validation->param('fulladdress'); + # TODO This will go away with transactioning #TODO UNTESTED as it's hard to simulate. #Token is no longer valid race condition. if ( ! $self->set_token_as_used($token) ){ @@ -225,17 +177,8 @@ sub post_register{ my $insertUser = $self->db->prepare("INSERT INTO Users (OrganisationalId_FK, Email, JoinDate, HashedPassword) VALUES (?, ?, ?, ?)"); my $rowsInsertedUser = $insertUser->execute($idToUse, $email, $date, $hashedPassword); - $self->app->log->debug('Path Success: file:' . __FILE__ . ', line: ' . __LINE__); return $self->render( json => { success => Mojo::JSON->true } ); } - else{ - $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); - return $self->render( json => { - success => Mojo::JSON->false, - message => '"usertype" is invalid.', - }, - status => 400,); #Malformed request - } } 1;