allow undo for checkins
This commit is contained in:
parent
6933b8ee45
commit
f87306dc34
4 changed files with 87 additions and 16 deletions
88
index.pl
88
index.pl
|
@ -30,7 +30,7 @@ my $dbname = $ENV{TRAVELYNX_DB_FILE} // 'travelynx.sqlite';
|
||||||
my %action_type = (
|
my %action_type = (
|
||||||
checkin => 1,
|
checkin => 1,
|
||||||
checkout => 2,
|
checkout => 2,
|
||||||
undo => -1
|
undo => 3,
|
||||||
);
|
);
|
||||||
|
|
||||||
app->defaults( layout => 'default' );
|
app->defaults( layout => 'default' );
|
||||||
|
@ -174,7 +174,7 @@ app->attr(
|
||||||
return $self->app->dbh->prepare(
|
return $self->app->dbh->prepare(
|
||||||
qq{
|
qq{
|
||||||
insert into user_actions (
|
insert into user_actions (
|
||||||
user_id, action_id, action_time,
|
user_id, action_id, action_time
|
||||||
) values (
|
) values (
|
||||||
?, $action_type{undo}, ?
|
?, $action_type{undo}, ?
|
||||||
)
|
)
|
||||||
|
@ -292,6 +292,30 @@ helper 'checkin' => sub {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helper 'undo' => sub {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my $uid = $self->get_user_id;
|
||||||
|
$self->app->get_last_actions_query->execute($uid);
|
||||||
|
my $rows = $self->app->get_last_actions_query->fetchall_arrayref;
|
||||||
|
|
||||||
|
if ( @{$rows} and $rows->[0][0] == $action_type{undo}) {
|
||||||
|
return 'Nested undo (undoing an undo) is not supported';
|
||||||
|
}
|
||||||
|
|
||||||
|
my $success = $self->app->undo_query->execute(
|
||||||
|
$self->get_user_id,
|
||||||
|
DateTime->now( time_zone => 'Europe/Berlin' )->epoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (defined $success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'INSERT failed';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
helper 'checkout' => sub {
|
helper 'checkout' => sub {
|
||||||
my ( $self, $station, $force ) = @_;
|
my ( $self, $station, $force ) = @_;
|
||||||
|
|
||||||
|
@ -513,9 +537,15 @@ helper 'get_user_status' => sub {
|
||||||
|
|
||||||
if ( @{$rows} ) {
|
if ( @{$rows} ) {
|
||||||
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||||
my $ts = epoch_to_dt( $rows->[0][1] );
|
|
||||||
my $checkin_station_name = decode( 'UTF-8', $rows->[0][3] );
|
my @cols = @{$rows->[0]};
|
||||||
my @route = split( qr{[|]}, decode( 'UTF-8', $rows->[0][10] // q{} ) );
|
if (@{$rows} > 2 and $rows->[0][0] == $action_type{undo}) {
|
||||||
|
@cols = @{$rows->[2]};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $ts = epoch_to_dt( $cols[1] );
|
||||||
|
my $checkin_station_name = decode( 'UTF-8', $cols[3] );
|
||||||
|
my @route = split( qr{[|]}, decode( 'UTF-8', $cols[10] // q{} ) );
|
||||||
my @route_after;
|
my @route_after;
|
||||||
my $is_after = 0;
|
my $is_after = 0;
|
||||||
for my $station (@route) {
|
for my $station (@route) {
|
||||||
|
@ -527,15 +557,15 @@ helper 'get_user_status' => sub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
checked_in => ( $rows->[0][0] == $action_type{checkin} ),
|
checked_in => ( $cols[0] == $action_type{checkin} ),
|
||||||
timestamp => $ts,
|
timestamp => $ts,
|
||||||
timestamp_delta => $now->subtract_datetime($ts),
|
timestamp_delta => $now->epoch - $ts->epoch,
|
||||||
station_ds100 => $rows->[0][2],
|
station_ds100 => $cols[2],
|
||||||
station_name => $rows->[0][3],
|
station_name => $cols[3],
|
||||||
train_type => $rows->[0][4],
|
train_type => $cols[4],
|
||||||
train_line => $rows->[0][5],
|
train_line => $cols[5],
|
||||||
train_no => $rows->[0][6],
|
train_no => $cols[6],
|
||||||
train_id => $rows->[0][7],
|
train_id => $cols[7],
|
||||||
route => \@route,
|
route => \@route,
|
||||||
route_after => \@route_after,
|
route_after => \@route_after,
|
||||||
};
|
};
|
||||||
|
@ -600,7 +630,10 @@ post '/action' => sub {
|
||||||
|
|
||||||
if ( not $params->{action} ) {
|
if ( not $params->{action} ) {
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {},
|
json => {
|
||||||
|
success => 0,
|
||||||
|
error => 'Missing action value',
|
||||||
|
},
|
||||||
status => 400,
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -648,6 +681,33 @@ post '/action' => sub {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elsif ( $params->{action} eq 'undo' ) {
|
||||||
|
my $error = $self->undo;
|
||||||
|
if ($error) {
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
success => 0,
|
||||||
|
error => $error,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
success => 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
success => 0,
|
||||||
|
error => 'invalid action value',
|
||||||
|
},
|
||||||
|
status => 400,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
get '/a/history' => sub {
|
get '/a/history' => sub {
|
||||||
|
|
|
@ -39,4 +39,11 @@ $(document).ready(function() {
|
||||||
link.data('force', true);
|
link.data('force', true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
$('.action-undo').click(function() {
|
||||||
|
var link = $(this);
|
||||||
|
var req = {
|
||||||
|
action: 'undo',
|
||||||
|
};
|
||||||
|
tvly_run(link, req, window.location.href);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
2
public/static/js/travelynx-actions.min.js
vendored
2
public/static/js/travelynx-actions.min.js
vendored
|
@ -1 +1 @@
|
||||||
function tvly_run(t,a,n,i){var c='<i class="material-icons">error</i>',o=$('<div class="progress"><div class="indeterminate"></div></div>');t.hide(),t.after(o),$.post("/action",a,function(a){a.success?$(location).attr("href",n):(M.toast({html:c+" "+a.error}),o.remove(),i&&i(),t.append(" "+c),t.show())})}$(document).ready(function(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train")},"/")}),$(".action-checkout").click(function(){var t=$(this),a={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,a,"/"+a.station,function(){t.append(" – Keine Echtzeitdaten vorhanden"),t.data("force",!0)})})});
|
function tvly_run(t,n,i,a){var c='<i class="material-icons">error</i>',o=$('<div class="progress"><div class="indeterminate"></div></div>');t.hide(),t.after(o),$.post("/action",n,function(n){n.success?$(location).attr("href",i):(M.toast({html:c+" "+n.error}),o.remove(),a&&a(),t.append(" "+c),t.show())})}$(document).ready(function(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train")},"/")}),$(".action-checkout").click(function(){var t=$(this),n={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,n,"/"+n.station,function(){t.append(" – Keine Echtzeitdaten vorhanden"),t.data("force",!0)})}),$(".action-undo").click(function(){tvly_run($(this),{action:"undo"},window.location.href)})});
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
<span class="card-title">Hallo, <%= $self->get_user_name %>!</span>
|
<span class="card-title">Hallo, <%= $self->get_user_name %>!</span>
|
||||||
<p>Du bist gerade eingecheckt in
|
<p>Du bist gerade eingecheckt in
|
||||||
<%= $status->{train_type} %> <%= $status->{train_no} %>
|
<%= $status->{train_type} %> <%= $status->{train_no} %>
|
||||||
ab <%= $status->{station_name} %>.</p>
|
ab <%= $status->{station_name} %>.
|
||||||
|
% if ($status->{timestamp_delta} < 3600) {
|
||||||
|
<a class="action-undo"><i class="material-icons">undo</i> Rückgängig</a>
|
||||||
|
% }
|
||||||
|
</p>
|
||||||
<p>Auschecken?</p>
|
<p>Auschecken?</p>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
Loading…
Reference in a new issue