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/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index b414152..c0cdd51 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/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; }); diff --git a/script/recalc_leaderboards b/script/recalc_leaderboards old mode 100644 new mode 100755 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({ 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({