From e13a12817963b617ea4566635a298d79471cf648 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 8 Sep 2017 12:00:23 +0100 Subject: [PATCH 01/21] Add zero to sums to force number on output --- lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index 5b4eab5..24e4263 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -102,7 +102,7 @@ sub _sales_last_duration { my $transactions = $entity->sales ->search_between( $start, $next_end ) ->get_column('value') - ->sum || 0; + ->sum + 0; push @{ $data->{ labels } }, $start->day_name; push @{ $data->{ data } }, $transactions; $start->add( days => 1 ); @@ -134,7 +134,7 @@ sub _purchases_last_duration { my $transactions = $entity->purchases ->search_between( $start, $next_end ) ->get_column('value') - ->sum || 0; + ->sum + 0; push @{ $data->{ labels } }, $start->day_name; push @{ $data->{ data } }, $transactions; $start->add( days => 1 ); From 83094f380db9a3ab4589796ea577e46b3080270d Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 8 Sep 2017 12:03:48 +0100 Subject: [PATCH 02/21] Continue defaulting to 0 as well --- lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index 24e4263..b414152 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -102,7 +102,7 @@ sub _sales_last_duration { my $transactions = $entity->sales ->search_between( $start, $next_end ) ->get_column('value') - ->sum + 0; + ->sum || 0 + 0; push @{ $data->{ labels } }, $start->day_name; push @{ $data->{ data } }, $transactions; $start->add( days => 1 ); @@ -134,7 +134,7 @@ sub _purchases_last_duration { my $transactions = $entity->purchases ->search_between( $start, $next_end ) ->get_column('value') - ->sum + 0; + ->sum || 0 + 0; push @{ $data->{ labels } }, $start->day_name; push @{ $data->{ data } }, $transactions; $start->add( days => 1 ); From 4176c61c0066f453e381723bd8e6e20bb85efd24 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 8 Sep 2017 12:46:54 +0100 Subject: [PATCH 03/21] Remove post user/day, and reformat validators --- lib/Pear/LocalLoop.pm | 11 ---- lib/Pear/LocalLoop/Controller/Api/User.pm | 16 ------ lib/Pear/LocalLoop/Plugin/Datetime.pm | 66 ++++++++++++++--------- lib/Pear/LocalLoop/Plugin/Validators.pm | 4 +- 4 files changed, 44 insertions(+), 53 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 18e997b..a1763b4 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -74,16 +74,6 @@ sub startup { } }); - $self->helper( datetime_formatter => sub { - my $c = shift; - - return DateTime::Format::Strptime->new( - pattern => '%FT%T%z', - strict => 1, - on_error => 'undef', - ); - }); - $self->helper( get_path_from_uuid => sub { my $c = shift; my $uuid = shift; @@ -150,7 +140,6 @@ sub startup { $api->post('/search')->to('api-upload#post_search'); $api->post('/user')->to('api-user#post_account'); $api->post('/user/account')->to('api-user#post_account_update'); - $api->post('/user/day')->to('api-user#post_day'); $api->post('/user-history')->to('api-user#post_user_history'); $api->post('/stats')->to('api-stats#post_index'); $api->post('/stats/leaderboard')->to('api-stats#post_leaderboards'); diff --git a/lib/Pear/LocalLoop/Controller/Api/User.pm b/lib/Pear/LocalLoop/Controller/Api/User.pm index dfe9bb3..0c0a2f3 100644 --- a/lib/Pear/LocalLoop/Controller/Api/User.pm +++ b/lib/Pear/LocalLoop/Controller/Api/User.pm @@ -39,22 +39,6 @@ has error_messages => sub { }; }; -sub post_day { - my $c = shift; - - my $validation = $c->validation; - - $validation->input( $c->stash->{api_json} ); - - $validation->optional('day')->is_iso_datetime; - - return $c->api_validation_error if $validation->has_error; - - $c->render( json => { - success => Mojo::JSON->true, - }); -} - sub post_account { my $c = shift; diff --git a/lib/Pear/LocalLoop/Plugin/Datetime.pm b/lib/Pear/LocalLoop/Plugin/Datetime.pm index a94c292..8b7495a 100644 --- a/lib/Pear/LocalLoop/Plugin/Datetime.pm +++ b/lib/Pear/LocalLoop/Plugin/Datetime.pm @@ -7,34 +7,52 @@ sub register { my ( $plugin, $app, $conf ) = @_; $app->helper( iso_datetime_parser => sub { - return DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S.%3N%z' ); -}); + return DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S.%3N%z' ); + }); -$app->helper( parse_iso_datetime => sub { - my ( $c, $date_string ) = @_; - return $c->iso_datetime_parser->parse_datetime( - $date_string, - ); -}); + $app->helper( iso_date_parser => sub { + return DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); + }); -$app->helper( format_iso_datetime => sub { - my ( $c, $datetime_obj ) = @_; - return $c->iso_datetime_parser->parse_datetime( - $datetime_obj, - ); -}); + $app->helper( parse_iso_date => sub { + my ( $c, $date_string ) = @_; + return $c->iso_date_parser->parse_datetime( + $date_string, + ); + }); -$app->helper( db_datetime_parser => sub { - return shift->schema->storage->datetime_parser; -}); + $app->helper( format_iso_date => sub { + my ( $c, $datetime_obj ) = @_; + return $c->iso_date_parser->format_datetime( + $datetime_obj, + ); + }); -$app->helper( format_db_datetime => sub { - my ( $c, $datetime_obj ) = @_; - $datetime_obj->set_time_zone('UTC'); - return $c->db_datetime_parser->format_datetime( - $datetime_obj, - ); -}); + $app->helper( parse_iso_datetime => sub { + my ( $c, $date_string ) = @_; + return $c->iso_datetime_parser->parse_datetime( + $date_string, + ); + }); + + $app->helper( format_iso_datetime => sub { + my ( $c, $datetime_obj ) = @_; + return $c->iso_datetime_parser->format_datetime( + $datetime_obj, + ); + }); + + $app->helper( db_datetime_parser => sub { + return shift->schema->storage->datetime_parser; + }); + + $app->helper( format_db_datetime => sub { + my ( $c, $datetime_obj ) = @_; + $datetime_obj->set_time_zone('UTC'); + return $c->db_datetime_parser->format_datetime( + $datetime_obj, + ); + }); } diff --git a/lib/Pear/LocalLoop/Plugin/Validators.pm b/lib/Pear/LocalLoop/Plugin/Validators.pm index 33aeca2..bab1863 100644 --- a/lib/Pear/LocalLoop/Plugin/Validators.pm +++ b/lib/Pear/LocalLoop/Plugin/Validators.pm @@ -53,9 +53,9 @@ sub register { return $app->types->type($extension) eq $filetype ? undef : 1; }); - $app->validator->add_check( is_iso_datetime => sub { + $app->validator->add_check( is_iso_date => sub { my ( $validation, $name, $value ) = @_; - $value = $app->datetime_formatter->parse_datetime( $value ); + $value = $app->iso_date_parser->parse_datetime( $value ); return defined $value ? undef : 1; }); From 6de616584a2b41b33a52745c5f76daa07d8609f1 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 8 Sep 2017 12:47:20 +0100 Subject: [PATCH 04/21] Add customer_range graph --- .../Controller/Api/V1/Organisation/Graphs.pm | 35 +++++++++++++++++++ t/api/v1/organisation/graphs.t | 12 +++++++ 2 files changed, 47 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index 5b4eab5..2fb474a 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -22,6 +22,7 @@ sub index { sales_last_30_days purchases_last_7_days purchases_last_30_days + customers_range / ); return $c->api_validation_error if $validation->has_error; @@ -43,6 +44,40 @@ sub index { return $c->$graph_sub; } +sub graph_customers_range { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('start')->is_iso_date; + $validation->required('end')->is_iso_date; + + return $c->api_validation_error if $validation->has_error; + + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + my $start = $c->parse_iso_date( $validation->param('start') ); + my $end = $c->parse_iso_date( $validation->param('end') ); + + while ( $start <= $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = $entity->sales + ->search_between( $start, $next_end ) + ->count; + push @{ $data->{ labels } }, $c->format_iso_date( $start ); + push @{ $data->{ data } }, $transactions; + $start->add( days => 1 ); + } + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); +} + sub graph_customers_last_7_days { my $c = shift; diff --git a/t/api/v1/organisation/graphs.t b/t/api/v1/organisation/graphs.t index 45531a6..d373aa1 100644 --- a/t/api/v1/organisation/graphs.t +++ b/t/api/v1/organisation/graphs.t @@ -78,6 +78,18 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { data => [ 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10 ], }); +$t->post_ok('/api/v1/organisation/graphs' => json => { + session_key => $session_key, + graph => 'customers_range', + start => $start->clone->subtract( days => 8 )->ymd, + end => $start->clone->ymd, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/graph', { + labels => [ map { $start->clone->subtract( days => $_ )->ymd } reverse ( 0 .. 8 ) ], + data => [ 2, 4, 2, 4, 2, 3, 3, 4, 1 ], + }); + $framework->logout( $session_key ); $session_key = $framework->login({ From ebfd162b0791d869175e41a118f49cc017d337d8 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 8 Sep 2017 13:12:56 +0100 Subject: [PATCH 05/21] Make leaderboard calc script executable --- script/recalc_leaderboards | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 script/recalc_leaderboards diff --git a/script/recalc_leaderboards b/script/recalc_leaderboards old mode 100644 new mode 100755 From ffd9b43231b0cfaf3f9f4eadf26700ae392ee34f Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 8 Sep 2017 13:22:49 +0100 Subject: [PATCH 06/21] Remove tests against removed endpoint --- t/api/user.t | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/t/api/user.t b/t/api/user.t index a848e95..643165a 100644 --- a/t/api/user.t +++ b/t/api/user.t @@ -32,28 +32,6 @@ my $session_key = $framework->login({ password => $password, }); -my $json_no_date = { session_key => $session_key }; -$t->post_ok('/api/user/day', json => $json_no_date) - ->status_is(200)->or($framework->dump_error) - ->json_is('/success', Mojo::JSON->true); - -my $json_invalid_date = { - session_key => $session_key, - day => 'invalid', -}; -$t->post_ok('/api/user/day', json => $json_invalid_date) - ->status_is(400)->or($framework->dump_error) - ->json_is('/success', Mojo::JSON->false) - ->json_like('/message', qr/Invalid ISO8601 Datetime/); - -my $json_valid_date = { - session_key => $session_key, - day => $t->app->datetime_formatter->format_datetime(DateTime->now), -}; -$t->post_ok('/api/user/day', json => $json_valid_date) - ->status_is(200)->or($framework->dump_error) - ->json_is('/success', Mojo::JSON->true); - $t->post_ok('/api/user', json => { session_key => $session_key }) ->status_is(200)->or($framework->dump_error) ->json_is({ From 1c7c59687a24240d0efe1a8b4fc086d9d4c6d3e4 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Wed, 13 Sep 2017 15:23:01 +0100 Subject: [PATCH 07/21] Fix organisation boolean in test --- t/admin/organisation.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/admin/organisation.t b/t/admin/organisation.t index cfc906b..32f066d 100644 --- a/t/admin/organisation.t +++ b/t/admin/organisation.t @@ -30,7 +30,7 @@ my $pending_entity = $schema->resultset('Entity')->create({ town => 'Midgar', sector => 'A', postcode => 'WC1E 6AD', - pending => \"1", + pending => 1, }, type => "organisation", }); From 51e1c4d7d4dde82471651ffa088d0be56c43e8aa Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Wed, 13 Sep 2017 15:23:23 +0100 Subject: [PATCH 08/21] Change to using Moo for Test framework, and allow for PG testing --- lib/Test/Pear/LocalLoop.pm | 99 +++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/lib/Test/Pear/LocalLoop.pm b/lib/Test/Pear/LocalLoop.pm index 5fb6fae..961fd55 100644 --- a/lib/Test/Pear/LocalLoop.pm +++ b/lib/Test/Pear/LocalLoop.pm @@ -1,5 +1,5 @@ package Test::Pear::LocalLoop; -use Mojo::Base -base; +use Moo; use Test::More; use File::Temp; @@ -7,12 +7,48 @@ use Test::Mojo; use DateTime::Format::Strptime; use DBIx::Class::Fixtures; -has config => sub { +# Conditionally require Test::PostgreSQL +sub BUILD { + if ( $ENV{PEAR_TEST_PG} ) { + require Test::PostgreSQL + or die "you need Test::PostgreSQL to run PG testing"; + Test::PostgreSQL->import; + } +} + +sub DEMOLISH { + my ( $self, $in_global_destruction ) = @_; + + if ( $ENV{PEAR_TEST_PG} && !$in_global_destruction ) { + $self->mojo->app->schema->storage->dbh->disconnect; + $self->pg->stop; + } +} + +has pg => ( + is => 'lazy', + builder => sub { + return Test::PostgreSQL->new(); + }, +); + +has config => ( + is => 'lazy', + builder => sub { + my $self = shift; my $file = File::Temp->new; - print $file <<'END'; + my $dsn; + + if ( $ENV{PEAR_TEST_PG} ) { + $dsn = $self->pg->dsn; + } else { + $dsn = "dbi:SQLite::memory:"; + } + + print $file <<"END"; { - dsn => "dbi:SQLite::memory:", + dsn => "$dsn", user => undef, pass => undef, } @@ -20,9 +56,12 @@ END $file->seek( 0, SEEK_END ); return $file; -}; + }, +); -has mojo => sub { +has mojo => ( + is => 'lazy', + builder => sub { my $self = shift; $ENV{MOJO_CONFIG} = $self->config->filename; @@ -31,9 +70,18 @@ has mojo => sub { $t->app->schema->deploy; return $t; -}; + }, +); -has _deployed => sub { 0 }; +has etc_dir => ( + is => 'lazy', + builder => sub { die "etc dir not set" }, +); + +has _deployed => ( + is => 'rwp', + default => 0, +); sub framework { my $self = shift; @@ -56,13 +104,11 @@ sub framework { ]); } - $self->_deployed(1); + $self->_set__deployed(1); return $t; }; -has etc_dir => sub { die "etc dir not set" }; - sub dump_error { return sub { my $self = shift; @@ -142,11 +188,40 @@ sub install_fixtures { }); my $t = $self->framework(1); + my $schema = $t->app->schema; + $fixtures->populate({ directory => File::Spec->catdir( $self->etc_dir, 'fixtures', 'data', $fixture_name ), no_deploy => 1, - schema => $t->app->schema, + schema => $schema, }); + + # Reset table id sequences + if ( $ENV{PEAR_TEST_PG} ) { + $schema->storage->dbh_do( + sub { + my ( $storage, $dbh, $sets ) = @_; + for my $table ( keys %$sets ) { + my $seq = $sets->{$table}; + $dbh->do( + qq/ + SELECT setval( + '$seq', + COALESCE( + (SELECT MAX(id)+1 FROM $table), + 1 + ), + false + ); + /); + } + }, + { + entities => 'entities_id_seq', + organisations => 'organisations_id_seq', + } + ); + } } 1; From b34e47215ab376ca3e74865312a2c6eefec3a4c6 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Wed, 13 Sep 2017 15:23:48 +0100 Subject: [PATCH 09/21] Change to using straight numeric columns with no decimal points --- lib/Pear/LocalLoop/Schema.pm | 2 +- lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm | 4 ++-- lib/Pear/LocalLoop/Schema/Result/Transaction.pm | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index b4bf402..a7fc365 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 6; +our $VERSION = 7; __PACKAGE__->load_namespaces; diff --git a/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm b/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm index 1125c35..8c08f1c 100644 --- a/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm +++ b/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm @@ -28,8 +28,8 @@ __PACKAGE__->add_columns( is_nullable => 0, }, "value" => { - data_type => "decimal", - size => [ 16, 2 ], + data_type => "numeric", + size => [ 100, 0 ], is_nullable => 0, }, "trend" => { diff --git a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm index 13654be..efdac85 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm @@ -29,8 +29,8 @@ __PACKAGE__->add_columns( is_nullable => 0, }, "value" => { - data_type => "decimal", - size => [ 16, 2 ], + data_type => "numeric", + size => [ 100, 0 ], is_nullable => 0, }, "proof_image" => { From c2cc0006bc32a0c319adb200b8ffb83fed5d1f24 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Wed, 13 Sep 2017 15:32:56 +0100 Subject: [PATCH 10/21] Finished upgrade script for value * 1000 --- .../deploy/7/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/7/001-auto.sql | 210 ++++ share/ddl/PostgreSQL/upgrade/6-7/001-auto.sql | 15 + .../SQLite/deploy/7/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/7/001-auto.sql | 145 +++ share/ddl/SQLite/upgrade/6-7/001-auto.sql | 98 ++ .../_source/deploy/7/001-auto-__VERSION.yml | 91 ++ share/ddl/_source/deploy/7/001-auto.yml | 1064 +++++++++++++++++ 8 files changed, 1659 insertions(+) create mode 100644 share/ddl/PostgreSQL/deploy/7/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/7/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/6-7/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/7/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/7/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/6-7/001-auto.sql create mode 100644 share/ddl/_source/deploy/7/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/7/001-auto.yml diff --git a/share/ddl/PostgreSQL/deploy/7/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/7/001-auto-__VERSION.sql new file mode 100644 index 0000000..3a15182 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/7/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Wed Sep 13 15:24:20 2017 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/7/001-auto.sql b/share/ddl/PostgreSQL/deploy/7/001-auto.sql new file mode 100644 index 0000000..46d7045 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/7/001-auto.sql @@ -0,0 +1,210 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Wed Sep 13 15:24:20 2017 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "submitted_by_id" integer, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/6-7/001-auto.sql b/share/ddl/PostgreSQL/upgrade/6-7/001-auto.sql new file mode 100644 index 0000000..4b30c31 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/6-7/001-auto.sql @@ -0,0 +1,15 @@ +-- Convert schema 'share/ddl/_source/deploy/6/001-auto.yml' to 'share/ddl/_source/deploy/7/001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE leaderboard_values ALTER COLUMN value TYPE numeric(100,0) USING value * 100000; + +; +ALTER TABLE transactions ALTER COLUMN value TYPE numeric(100,0) USING value * 100000; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/7/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/7/001-auto-__VERSION.sql new file mode 100644 index 0000000..4602862 --- /dev/null +++ b/share/ddl/SQLite/deploy/7/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Wed Sep 13 15:24:20 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/7/001-auto.sql b/share/ddl/SQLite/deploy/7/001-auto.sql new file mode 100644 index 0000000..4c8b658 --- /dev/null +++ b/share/ddl/SQLite/deploy/7/001-auto.sql @@ -0,0 +1,145 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Wed Sep 13 15:24:20 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + submitted_by_id integer, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/6-7/001-auto.sql b/share/ddl/SQLite/upgrade/6-7/001-auto.sql new file mode 100644 index 0000000..4b6298a --- /dev/null +++ b/share/ddl/SQLite/upgrade/6-7/001-auto.sql @@ -0,0 +1,98 @@ +-- Convert schema 'share/ddl/_source/deploy/6/001-auto.yml' to 'share/ddl/_source/deploy/7/001-auto.yml':; + +; +BEGIN; + +; +CREATE TEMPORARY TABLE leaderboard_values_temp_alter ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value decimal(16,2) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +INSERT INTO leaderboard_values_temp_alter( id, entity_id, set_id, position, value, trend) SELECT id, entity_id, set_id, position, value, trend FROM leaderboard_values; + +; +DROP TABLE leaderboard_values; + +; +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +CREATE INDEX leaderboard_values_idx_enti00 ON leaderboard_values (entity_id); + +; +CREATE INDEX leaderboard_values_idx_set_00 ON leaderboard_values (set_id); + +; +CREATE UNIQUE INDEX leaderboard_values_entity_i00 ON leaderboard_values (entity_id, set_id); + +; +INSERT INTO leaderboard_values SELECT id, entity_id, set_id, position, value, trend FROM leaderboard_values_temp_alter; + +; +DROP TABLE leaderboard_values_temp_alter; + +; +CREATE TEMPORARY TABLE transactions_temp_alter ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value decimal(16,2) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +INSERT INTO transactions_temp_alter( id, buyer_id, seller_id, value, proof_image, submitted_at, purchase_time) SELECT id, buyer_id, seller_id, value, proof_image, submitted_at, purchase_time FROM transactions; + +; +DROP TABLE transactions; + +; +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +CREATE INDEX transactions_idx_buyer_id02 ON transactions (buyer_id); + +; +CREATE INDEX transactions_idx_seller_id02 ON transactions (seller_id); + +; +INSERT INTO transactions SELECT id, buyer_id, seller_id, value * 100000, proof_image, submitted_at, purchase_time FROM transactions_temp_alter; + +; +DROP TABLE transactions_temp_alter; + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/7/001-auto-__VERSION.yml b/share/ddl/_source/deploy/7/001-auto-__VERSION.yml new file mode 100644 index 0000000..907f443 --- /dev/null +++ b/share/ddl/_source/deploy/7/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/share/ddl/_source/deploy/7/001-auto.yml b/share/ddl/_source/deploy/7/001-auto.yml new file mode 100644 index 0000000..e5c5ed6 --- /dev/null +++ b/share/ddl/_source/deploy/7/001-auto.yml @@ -0,0 +1,1064 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 4 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 2 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 9 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 5 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 11 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 3 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 10 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 6 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 10 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 7 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 8 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Customer + - Entity + - Feedback + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - Organisation + - SessionToken + - Transaction + - User + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 From 1ffabb3e944d12ffe489c3bc6ad5b76a4558a8f1 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Wed, 13 Sep 2017 16:07:23 +0100 Subject: [PATCH 11/21] Updated all endpoints to use new transaction value multiple --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 24 +++++++++++-------- .../LocalLoop/Controller/Api/Transactions.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 2 +- .../Controller/Api/V1/Organisation/Graphs.pm | 4 ++-- .../Api/V1/Organisation/Snippets.pm | 6 +++++ t/api/stats.t | 14 +++++------ t/api/v1/organisation/graphs.t | 2 +- t/api/v1/organisation/snippets.t | 2 +- 8 files changed, 33 insertions(+), 23 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 3ee2617..ddb5152 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -18,23 +18,23 @@ sub post_index { my $user = $c->stash->{api_user}->entity; my $today_rs = $user->purchases->today_rs; - my $today_sum = $today_rs->get_column('value')->sum; + my $today_sum = $today_rs->get_column('value')->sum || 0; my $today_count = $today_rs->count; my $week_rs = $user->purchases->week_rs; - my $week_sum = $week_rs->get_column('value')->sum; + my $week_sum = $week_rs->get_column('value')->sum || 0; my $week_count = $week_rs->count; my $month_rs = $user->purchases->month_rs; - my $month_sum = $month_rs->get_column('value')->sum; + my $month_sum = $month_rs->get_column('value')->sum || 0; my $month_count = $month_rs->count; my $user_rs = $user->purchases; - my $user_sum = $user_rs->get_column('value')->sum; + my $user_sum = $user_rs->get_column('value')->sum || 0; my $user_count = $user_rs->count; my $global_rs = $c->schema->resultset('Transaction'); - my $global_sum = $global_rs->get_column('value')->sum; + my $global_sum = $global_rs->get_column('value')->sum || 0; my $global_count = $global_rs->count; my $leaderboard_rs = $c->schema->resultset('Leaderboard'); @@ -44,15 +44,15 @@ sub post_index { return $c->render( json => { success => Mojo::JSON->true, - today_sum => $today_sum || 0, + today_sum => $today_sum / 100000, today_count => $today_count, - week_sum => $week_sum || 0, + week_sum => $week_sum / 100000, week_count => $week_count, - month_sum => $month_sum || 0, + month_sum => $month_sum / 100000, month_count => $month_count, - user_sum => $user_sum || 0, + user_sum => $user_sum / 100000, user_count => $user_count, - global_sum => $global_sum || 0, + global_sum => $global_sum / 100000, global_count => $global_count, user_position => defined $current_user_position ? $current_user_position->position : 0, }); @@ -91,6 +91,10 @@ sub post_leaderboards { my @leaderboard_array = $today_values->all; + if ( $validation->param('type') =~ /total$/ ) { + map { $_->{value} / 100000 } @leaderboard_array; + } + my $current_user_position = $today_values->find({ entity_id => $c->stash->{api_user}->entity->id }); return $c->render( json => { diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index d205b69..79e61ad 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -34,7 +34,7 @@ sub post_transaction_list_purchases { my @transaction_list = ( map {{ seller => $_->seller->name, - value => $_->value, + value => $_->value / 100000, purchase_time => $_->purchase_time, }} $transactions->all ); diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 7b037d5..e7ae0d5 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -176,7 +176,7 @@ sub post_upload { 'sales', { buyer => $user->entity, - value => $transaction_value, + value => $transaction_value * 100000, ( defined $file ? ( proof_image => $file ) : () ), purchase_time => $c->format_db_datetime($purchase_time), } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index c0cdd51..d1eddaf 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -139,7 +139,7 @@ sub _sales_last_duration { ->get_column('value') ->sum || 0 + 0; push @{ $data->{ labels } }, $start->day_name; - push @{ $data->{ data } }, $transactions; + push @{ $data->{ data } }, $transactions / 100000; $start->add( days => 1 ); } @@ -171,7 +171,7 @@ sub _purchases_last_duration { ->get_column('value') ->sum || 0 + 0; push @{ $data->{ labels } }, $start->day_name; - push @{ $data->{ data } }, $transactions; + push @{ $data->{ data } }, $transactions / 100000; $start->add( days => 1 ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm index 6bcd55c..07cd90a 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm @@ -28,26 +28,32 @@ sub index { my $today_sales = $entity->sales->search_between( $today, $now ); $data->{ today_sales_count } = $today_sales->count; $data->{ today_sales_total } = $today_sales->get_column('value')->sum || 0; + $data->{ today_sales_total } /= 100000; my $week_sales = $entity->sales->search_between( $week_ago, $today ); $data->{ this_week_sales_count } = $week_sales->count; $data->{ this_week_sales_total } = $week_sales->get_column('value')->sum || 0; + $data->{ this_week_sales_total } /= 100000; my $month_sales = $entity->sales->search_between( $month_ago, $today ); $data->{ this_month_sales_count } = $month_sales->count; $data->{ this_month_sales_total } = $month_sales->get_column('value')->sum || 0; + $data->{ this_month_sales_total } /= 100000; my $today_purchases = $entity->purchases->search_between( $today, $now ); $data->{ today_purchases_count } = $today_purchases->count; $data->{ today_purchases_total } = $today_purchases->get_column('value')->sum || 0; + $data->{ today_purchases_total } /= 100000; my $week_purchases = $entity->purchases->search_between( $week_ago, $today ); $data->{ this_week_purchases_count } = $week_purchases->count; $data->{ this_week_purchases_total } = $week_purchases->get_column('value')->sum || 0; + $data->{ this_week_purchases_total } /= 100000; my $month_purchases = $entity->purchases->search_between( $month_ago, $today ); $data->{ this_month_purchases_count } = $month_purchases->count; $data->{ this_month_purchases_total } = $month_purchases->get_column('value')->sum || 0; + $data->{ this_month_purchases_total } /= 100000; return $c->render( json => { diff --git a/t/api/stats.t b/t/api/stats.t index 8e8fbc1..0484664 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -43,7 +43,7 @@ $t->post_ok('/api/stats' => json => { session_key => $session_key } ) for ( 1 .. 10 ) { $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => $_, + value => $_ * 100000, proof_image => 'a', }); } @@ -51,7 +51,7 @@ for ( 1 .. 10 ) { for ( 11 .. 20 ) { $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => $_, + value => $_ * 100000, proof_image => 'a', purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 5 )), }); @@ -60,7 +60,7 @@ for ( 11 .. 20 ) { for ( 21 .. 30 ) { $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => $_, + value => $_ * 100000, proof_image => 'a', purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 25 )), }); @@ -69,7 +69,7 @@ for ( 21 .. 30 ) { for ( 31 .. 40 ) { $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => $_, + value => $_ * 100000, proof_image => 'a', purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 50 )), }); @@ -78,7 +78,7 @@ for ( 31 .. 40 ) { for ( 41 .. 50 ) { $org_result->create_related( 'purchases', { seller_id => $org_result->id, - value => $_, + value => $_ * 100000, proof_image => 'a', purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 50 )), }); @@ -91,8 +91,8 @@ is $user_result->purchases->search({ $dtf->format_datetime(DateTime->today()->add( days => 1 )), ], }, -})->get_column('value')->sum, 55, 'Got correct sum'; -is $user_result->purchases->today_rs->get_column('value')->sum, 55, 'Got correct sum through rs'; +})->get_column('value')->sum, 5500000, 'Got correct sum'; +is $user_result->purchases->today_rs->get_column('value')->sum, 5500000, 'Got correct sum through rs'; $t->post_ok('/api/stats' => json => { session_key => $session_key } ) ->status_is(200) diff --git a/t/api/v1/organisation/graphs.t b/t/api/v1/organisation/graphs.t index d373aa1..57b6cbb 100644 --- a/t/api/v1/organisation/graphs.t +++ b/t/api/v1/organisation/graphs.t @@ -115,7 +115,7 @@ sub create_random_transaction { $schema->resultset('Transaction')->create({ buyer => $buyer_result, seller => $seller_result, - value => 10, + value => 10 * 100000, proof_image => 'a', purchase_time => $time, }); diff --git a/t/api/v1/organisation/snippets.t b/t/api/v1/organisation/snippets.t index b7e127a..f4ee79c 100644 --- a/t/api/v1/organisation/snippets.t +++ b/t/api/v1/organisation/snippets.t @@ -73,7 +73,7 @@ sub create_random_transaction { $schema->resultset('Transaction')->create({ buyer => $buyer_result, seller => $seller_result, - value => 10, + value => 10 * 100000, proof_image => 'a', purchase_time => $time, }); From d9127b135df8564055fc30e41b72f5a44b179707 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Thu, 14 Sep 2017 15:20:41 +0100 Subject: [PATCH 12/21] Added changelog file --- CHANGELOG.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5c00e79 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,55 @@ +# Changelog + +# v0.9.1 + +* Change to semantic versioning +* Change database schema to use entity style model +* Added schema graphs for showing the schema layout +* **Fix:** null values on Org Graphs +* **Feature:** Org Graphs for sales and purchase data +* **Fix:** Deny organisations buying from themselves +* **Feature:** API endpoint for viewing purchases +* **Feature:** Transaction viewing in Admin interface +* **Fix:** Booleans under postgres and sqlite +* **Feature:** Organisation snippets API + +# v0.009 + +*No changes recorded* + +# v0.008.1 + +*No changes recorded* + +# v0.008 + +*No changes recorded* + +# v0.007 + +*No changes recorded* + +# v0.006 + +*No changes recorded* + +# v0.005 + +*No changes recorded* + +# v0.004 + +*No changes recorded* + +# v0.003 + +Made leaderboard cronjob scripts work correctly by using production config +instead of defaulting to development + +# v0.002 + +Release with leaderboard scripts for automatic generation of leaderboards + +# v0.001 + +First release with basic functionality. From 88bcb9b6b0678d3dd455243332b8287cfbc3460f Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Thu, 14 Sep 2017 15:21:05 +0100 Subject: [PATCH 13/21] Added section for next release to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c00e79..a90e471 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +# Next Release + # v0.9.1 * Change to semantic versioning From d1757bdac9df743df9ef587d9ec091513644ea9a Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Sep 2017 11:18:27 +0100 Subject: [PATCH 14/21] Changed routing on submission --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 6921c6a..4fefec3 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -115,7 +115,7 @@ sub valid_edit { $c->flash( success => 'Updated Organisation' ); } }; - $c->redirect_to( '/admin/organisations/' . $valid_org->id ); + $c->redirect_to( '/admin/organisations/'); } 1; From 25511ced69e664a5a759f8bc58d5a12efd770772 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 15 Sep 2017 12:54:36 +0100 Subject: [PATCH 15/21] Fix calculation mistake on leadearboard display --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 7 ++++++- t/api/stats_leaderboards.t | 16 ++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index ddb5152..d909fad 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -92,7 +92,12 @@ sub post_leaderboards { my @leaderboard_array = $today_values->all; if ( $validation->param('type') =~ /total$/ ) { - map { $_->{value} / 100000 } @leaderboard_array; + @leaderboard_array = (map { + { + %$_, + value => $_->{value} / 100000, + } + } @leaderboard_array); } my $current_user_position = $today_values->find({ entity_id => $c->stash->{api_user}->entity->id }); diff --git a/t/api/stats_leaderboards.t b/t/api/stats_leaderboards.t index 84eb331..95b71b1 100644 --- a/t/api/stats_leaderboards.t +++ b/t/api/stats_leaderboards.t @@ -80,13 +80,13 @@ my $now = DateTime->today(); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 1, + value => 100000, proof_image => 'a', }); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 9, + value => 900000, proof_image => 'a', purchase_time => $dtf->format_datetime($now->clone->subtract( days => 1 )), }); @@ -97,13 +97,13 @@ my $now = DateTime->today(); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 3, + value => 300000, proof_image => 'a', }); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 1, + value => 100000, proof_image => 'a', purchase_time => $dtf->format_datetime($now->clone->subtract( days => 1 )), }); @@ -114,13 +114,13 @@ my $now = DateTime->today(); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 5, + value => 500000, proof_image => 'a', }); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 5, + value => 500000, proof_image => 'a', purchase_time => $dtf->format_datetime($now->clone->subtract( days => 1 )), }); @@ -131,13 +131,13 @@ my $now = DateTime->today(); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 9, + value => 900000, proof_image => 'a', }); $user_result->create_related( 'purchases', { seller_id => $org_result->id, - value => 3, + value => 300000, proof_image => 'a', purchase_time => $dtf->format_datetime($now->clone->subtract( days => 1 )), }); From 9800a6c082caf6f72bf268ff51fde9dbd0c2b995 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 15 Sep 2017 12:55:41 +0100 Subject: [PATCH 16/21] Update changelog for 0.9.2 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a90e471..a33145a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # Next Release +# v0.9.2 + +* **Fix:** Leaderboard total calculations not mapped correctly +* **Fix:** Reroute to org list on submission + # v0.9.1 * Change to semantic versioning From 414acd76fb09ebd033b54a19cc5397dc2c3e1047 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 11:11:53 +0100 Subject: [PATCH 17/21] Transaction API errors improved --- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index e7ae0d5..0a75f3f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -54,13 +54,13 @@ has error_messages => sub { in => { message => 'transaction_type is not a valid value.', status => 400 }, }, transaction_value => { - required => { message => 'transaction_value is missing', status => 400 }, - number => { message => 'transaction_value does not look like a number', status => 400 }, - gt_num => { message => 'transaction_value cannot be equal to or less than zero', status => 400 }, + required => { message => 'transaction amount is missing', status => 400 }, + number => { message => 'transaction amount does not look like a number', status => 400 }, + gt_num => { message => 'transaction amount cannot be equal to or less than zero', status => 400 }, }, purchase_time => { - required => { message => 'purchase_time is missing', status => 400 }, - is_full_iso_datetime => { message => 'purchase_time is in incorrect format', status => 400 }, + required => { message => 'purchase time is missing', status => 400 }, + is_full_iso_datetime => { message => 'purchase time is in incorrect format', status => 400 }, }, file => { required => { message => 'No file uploaded', status => 400 }, @@ -68,15 +68,18 @@ has error_messages => sub { filetype => { message => 'File must be of type image/jpeg', status => 400 }, }, organisation_id => { - required => { message => 'organisation_id is missing', status => 400 }, - number => { message => 'organisation_id is not a number', status => 400 }, - in_resultset => { message => 'organisation_id does not exist in the database', status => 400 }, + required => { message => 'existing organisation ID is missing', status => 400 }, + number => { message => 'organisation ID is not a number', status => 400 }, + in_resultset => { message => 'organisation ID does not exist in the database', status => 400 }, }, organisation_name => { - required => { message => 'organisation_name is missing', status => 400 }, + required => { message => 'organisation name is missing', status => 400 }, + }, + town => { + required => { message => 'town/city is missing', status => 400 }, }, search_name => { - required => { message => 'search_name is missing', status => 400 }, + required => { message => 'search name is missing', status => 400 }, }, postcode => { required => { message => 'postcode is missing', status => 400 }, @@ -139,7 +142,7 @@ sub post_upload { # Unknown Organisation $validation->required('organisation_name'); $validation->optional('street_name'); - $validation->optional('town'); + $validation->required('town'); $validation->optional('postcode')->postcode; return $c->api_validation_error if $validation->has_error; From dd36cd0c0c68ffd4f13bb2cd954f73567a633164 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 11:31:57 +0100 Subject: [PATCH 18/21] Feedback API error improved --- lib/Pear/LocalLoop/Controller/Api/Feedback.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm index eafce88..f33eaec 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm @@ -5,7 +5,7 @@ has error_messages => sub { return { email => { required => { message => 'Email is required', status => 400 }, - in_resultset => { message => 'Change meeee', status => 400 }, + in_resultset => { message => 'Email does not exist in database', status => 400 }, }, feedbacktext => { required => { message => 'Feedback is required', status => 400 }, diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 0a75f3f..f921d11 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -50,8 +50,8 @@ The postcode of an organisation, optional key. Used when transaction_Type is 3. has error_messages => sub { return { transaction_type => { - required => { message => 'transaction_type is missing.', status => 400 }, - in => { message => 'transaction_type is not a valid value.', status => 400 }, + required => { message => 'transaction type is missing.', status => 400 }, + in => { message => 'transaction type is not a valid value.', status => 400 }, }, transaction_value => { required => { message => 'transaction amount is missing', status => 400 }, From 9e56383b4600b07c7b0edbfc47a51549889bc659 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 11:34:22 +0100 Subject: [PATCH 19/21] User and Register API errors improved --- lib/Pear/LocalLoop/Controller/Api/Register.pm | 20 +++++++++---------- lib/Pear/LocalLoop/Controller/Api/User.pm | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Register.pm b/lib/Pear/LocalLoop/Controller/Api/Register.pm index 8ba4f11..822087d 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Register.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Register.pm @@ -9,18 +9,18 @@ has error_messages => sub { in_resultset => { message => 'Token invalid or has been used.', status => 401 }, }, name => { - required => { message => 'No name sent or was blank.', status => 400 }, + required => { message => 'No organisation name sent or was blank.', status => 400 }, }, display_name => { - required => { message => 'No name sent or was blank.', status => 400 }, + required => { message => 'No display name sent or was blank.', status => 400 }, }, full_name => { - required => { message => 'No name sent or was blank.', status => 400 }, + required => { message => 'No full name sent or was blank.', status => 400 }, }, email => { required => { message => 'No email sent.', status => 400 }, email => { message => 'Email is invalid.', status => 400 }, - not_in_resultset => { message => 'Email exists.', status => 403 }, + not_in_resultset => { message => 'Email already in use.', status => 403 }, }, postcode => { required => { message => 'No postcode sent.', status => 400 }, @@ -34,16 +34,16 @@ has error_messages => sub { in => { message => '"usertype" is invalid.', status => 400 }, }, year_of_birth => { - required => { message => 'No year_of_birth sent.', status => 400 }, - number => { message => 'year_of_birth is invalid', status => 400 }, - gt_num => { message => 'year_of_birth must be within last 150 years', status => 400 }, - lt_num => { message => 'year_of_birth must be atleast 10 years ago', status => 400 }, + required => { message => 'No year of birth sent.', status => 400 }, + number => { message => 'year of birth is invalid', status => 400 }, + gt_num => { message => 'year of birth must be within last 150 years', status => 400 }, + lt_num => { message => 'year of birth must be atleast 10 years ago', status => 400 }, }, street_name => { - required => { message => 'No street_name sent.', status => 400 }, + required => { message => 'No street name sent.', status => 400 }, }, town => { - required => { message => 'No town sent.', status => 400 }, + required => { message => 'No town/city sent.', status => 400 }, }, }; }; diff --git a/lib/Pear/LocalLoop/Controller/Api/User.pm b/lib/Pear/LocalLoop/Controller/Api/User.pm index 0c0a2f3..d85e2d8 100644 --- a/lib/Pear/LocalLoop/Controller/Api/User.pm +++ b/lib/Pear/LocalLoop/Controller/Api/User.pm @@ -28,10 +28,10 @@ has error_messages => sub { required => { message => 'No password sent.', status => 400 }, }, street_name => { - required => { message => 'No street_name sent.', status => 400 }, + required => { message => 'No street name sent.', status => 400 }, }, town => { - required => { message => 'No town sent.', status => 400 }, + required => { message => 'No town/city sent.', status => 400 }, }, sector => { required => { message => 'No sector sent.', status => 400 }, From 5b3ef1bf2781f2c84b36f247e50f25436afe1e0c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 12:05:30 +0100 Subject: [PATCH 20/21] Tests fixed --- t/api/register.t | 12 ++++++------ t/api/upload.t | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/t/api/register.t b/t/api/register.t index 203cde4..fd16642 100644 --- a/t/api/register.t +++ b/t/api/register.t @@ -73,7 +73,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no name sent/i); + ->content_like(qr/no display name sent/i); #name missing JSON $testJson = { 'usertype' => 'customer', @@ -87,7 +87,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no name sent/i); + ->content_like(qr/no full name sent/i); #Blank name $testJson = { @@ -235,7 +235,7 @@ $t->post_ok('/api/register' => json => $testJson) ->status_is(403) ->json_is('/success', Mojo::JSON->false) ->content_like(qr/email/i) - ->content_like(qr/exists/i); + ->content_like(qr/already in use/i); #postcode missing JSON $testJson = { @@ -315,7 +315,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no year_of_birth sent/i); + ->content_like(qr/no year of birth sent/i); #Age is invalid $testJson = { @@ -331,7 +331,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/year_of_birth/i) + ->content_like(qr/year of birth/i) ->content_like(qr/invalid/i); #full address missing JSON @@ -347,7 +347,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no street_name sent/i); + ->content_like(qr/no street name sent/i); #TODO Validation of full address diff --git a/t/api/upload.t b/t/api/upload.t index 74b3409..0522345 100644 --- a/t/api/upload.t +++ b/t/api/upload.t @@ -123,7 +123,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value is missing/i); + ->content_like(qr/transaction amount is missing/i); print "test 7 - transaction_value non-numbers\n"; $json = { @@ -137,7 +137,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value does not look like a number/i); + ->content_like(qr/transaction amount does not look like a number/i); print "test 8 - transaction_value equal to zero\n"; $json = { @@ -151,7 +151,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value cannot be equal to or less than zero/i); + ->content_like(qr/transaction amount cannot be equal to or less than zero/i); print "test 9 - transaction_value less than zero\n"; $json = { @@ -165,7 +165,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value cannot be equal to or less than zero/i); + ->content_like(qr/transaction amount cannot be equal to or less than zero/i); print "test 10 - transaction_type missing\n"; $json = { @@ -177,7 +177,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_type is missing/i); + ->content_like(qr/transaction type is missing/i); print "test 11 - transaction_type invalid.\n"; $json = { @@ -191,7 +191,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_type is not a valid value/i); + ->content_like(qr/transaction type is not a valid value/i); print "test 12 - file not uploaded.\n"; $json = { @@ -220,7 +220,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id is missing/i); + ->content_like(qr/organisation ID is missing/i); print "test 14 - organisation_id for non-existent id. (type 1: already validated)\n"; $json = { @@ -234,7 +234,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id does not exist in the database/i); + ->content_like(qr/organisation ID does not exist in the database/i); print "test 15 - valid addition. (type 1: already validated)\n"; is $schema->resultset('Transaction')->count, 1, "1 transaction"; @@ -268,7 +268,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_name is missing/i); + ->content_like(qr/organisation name is missing/i); print "test 17 - add valid transaction (type 3: new organisation)\n"; is $schema->resultset('Organisation')->search({ pending => 1 })->count, 0, "No pending organisations"; @@ -306,7 +306,7 @@ $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->or($framework->dump_error) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id is missing/i); + ->content_like(qr/organisation ID is missing/i); print "test 19 - organisation_id not a number (type 2: existing organisation)\n"; $json = { @@ -320,7 +320,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id is not a number/i); + ->content_like(qr/organisation ID is not a number/i); print "test 20 - id does not exist (type 2: existing organisation)\n"; $json = { @@ -334,7 +334,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id does not exist in the database/i); + ->content_like(qr/organisation ID does not exist in the database/i); print "test 21 - purchase_time is missing\n"; is $schema->resultset('Organisation')->search({ pending => 1 })->entity->sales->count, 1, "1 pending transactions"; @@ -385,7 +385,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id does not exist in the database/i); + ->content_like(qr/organisation ID does not exist in the database/i); is $schema->resultset('Organisation')->search({ pending => 1 })->entity->sales->count, 1, "1 pending transactions"; print "test 25 - Logout Hojo\n"; @@ -475,7 +475,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->json_like('/message', qr/organisation_id does not exist in the database/); + ->json_like('/message', qr/organisation ID does not exist in the database/); is $schema->resultset('Transaction')->count, 6, "6 transaction"; done_testing(); From 9cb4f7c782e4897495b9ad71c7343a0201b06c4c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 13:31:30 +0100 Subject: [PATCH 21/21] Added error rewrites and added feedback test --- lib/Pear/LocalLoop.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Feedback.pm | 4 +- t/api/feedback.t | 146 ++++++++++++++++++ 3 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 t/api/feedback.t diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index a1763b4..36e0c84 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -67,7 +67,7 @@ sub startup { json => { success => Mojo::JSON->false, message => $c->error_messages->{$val}->{$check}->{message}, - error => $check, + error => $c->error_messages->{$val}->{$check}->{error} || $check, }, status => $c->error_messages->{$val}->{$check}->{status}, ); diff --git a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm index f33eaec..cda98f1 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm @@ -4,8 +4,8 @@ use Mojo::Base 'Mojolicious::Controller'; has error_messages => sub { return { email => { - required => { message => 'Email is required', status => 400 }, - in_resultset => { message => 'Email does not exist in database', status => 400 }, + required => { message => 'Email is required or not registered', status => 400 }, + in_resultset => { message => 'Email is required or not registered', status => 400, error => "required" }, }, feedbacktext => { required => { message => 'Feedback is required', status => 400 }, diff --git a/t/api/feedback.t b/t/api/feedback.t new file mode 100644 index 0000000..6f8da2f --- /dev/null +++ b/t/api/feedback.t @@ -0,0 +1,146 @@ +use Mojo::Base -strict; + +use FindBin qw/ $Bin /; + +use Test::More; +use Mojo::JSON; +use Test::Pear::LocalLoop; + +my $framework = Test::Pear::LocalLoop->new( + etc_dir => "$Bin/../etc", +); +$framework->install_fixtures('users'); + +my $t = $framework->framework; +my $schema = $t->app->schema; + +#test email errors +$t->post_ok('/api/feedback' => json => { + email => '', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +$t->post_ok('/api/feedback' => json => { + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +$t->post_ok('/api/feedback' => json => { + email => 'banana', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +$t->post_ok('/api/feedback' => json => { + email => 'test21318432148@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +# Test for missing feedback +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Feedback is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => '', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Feedback is required/); + +# Test for missing extra details +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/App Name is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Package Name is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Version Code is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Version Number is required/); + +# Valid Feedback +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +done_testing;