#!/usr/bin/env perl # Copyright (C) 2023 Birte Kristina Friesel <derf@finalrewind.org> # # SPDX-License-Identifier: MIT use Mojo::Base -strict; # Tests journey entry and statistics use Test::More; use Test::Mojo; use DateTime; use Travel::Status::DE::IRIS::Result; # Include application use FindBin; require "$FindBin::Bin/../index.pl"; my $t = Test::Mojo->new('Travelynx'); if ( not $t->app->config->{db} ) { plan( skip_all => 'No database configured' ); } $t->app->pg->db->query('drop schema if exists travelynx_test_23 cascade'); $t->app->pg->db->query('create schema travelynx_test_23'); $t->app->pg->db->query('set search_path to travelynx_test_23'); $t->app->pg->on( connection => sub { my ( $pg, $dbh ) = @_; $dbh->do('set search_path to travelynx_test_23'); } ); $t->app->config->{mail}->{disabled} = 1; $ENV{__TRAVELYNX_TEST_MINI_IRIS} = 1; $t->app->start( 'database', 'migrate' ); my $u = $t->app->users; sub login { my %opt = @_; my $csrf_token = $t->ua->get('/login')->res->dom->at('input[name=csrf_token]') ->attr('value'); $t->post_ok( '/login' => form => { csrf_token => $csrf_token, user => $opt{user}, password => $opt{password}, } ); $t->status_is(302)->header_is( location => '/' ); } sub logout { my $csrf_token = $t->ua->get('/account')->res->dom->at('input[name=csrf_token]') ->attr('value'); $t->post_ok( '/logout' => form => { csrf_token => $csrf_token, } ); $t->status_is(302)->header_is( location => '/login' ); } sub test_journey_visibility { my %opt = @_; my $jid = $opt{journey_id}; if ( $opt{set_default_visibility} ) { my %p = %{ $u->get_privacy_by( uid => $opt{uid} ) }; $p{default_visibility} = $opt{set_default_visibility}; $u->set_privacy( uid => $opt{uid}, %p ); } if ( $opt{set_visibility} ) { $t->app->journeys->update_visibility( uid => $opt{uid}, id => $jid, visibility => $opt{set_visibility} ); } my $status = $t->app->get_user_status( $opt{uid} ); my $journey = $t->app->journeys->get_single( uid => $opt{uid}, journey_id => $jid ); my $token = q{?token=} . $status->{dep_eva} . q{-} . $journey->{checkin_ts} % 337 . q{-} . $status->{sched_departure}->epoch; my $desc = "journey=$jid vis=$opt{effective_visibility_str} (from $opt{visibility_str})"; is( $status->{visibility}, $opt{visibility}, $desc ); is( $status->{visibility_str}, $opt{visibility_str}, $desc ); is( $status->{effective_visibility}, $opt{effective_visibility}, $desc ); is( $status->{effective_visibility_str}, $opt{effective_visibility_str}, $desc ); if ( $opt{public} ) { $t->get_ok("/p/test1/j/$jid")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } if ( $opt{with_token} ) { $t->get_ok("/p/test1/j/$jid$token")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid$token")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } login( user => 'test1', password => 'password1' ); # users can see their own status if visibility is >= followrs if ( $opt{effective_visibility} >= 60 ) { $t->get_ok("/p/test1/j/$jid")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } # users can see their own status with token if visibility is >= unlisted if ( $opt{effective_visibility} >= 30 ) { $t->get_ok("/p/test1/j/$jid$token")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid$token")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } logout(); login( user => 'test2', password => 'password2' ); # uid2 can see uid1 if visibility is >= followers if ( $opt{effective_visibility} >= 60 ) { $t->get_ok("/p/test1/j/$jid")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } # uid2 can see uid1 with token if visibility is >= unlisted if ( $opt{effective_visibility} >= 30 ) { $t->get_ok("/p/test1/j/$jid$token")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid$token")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } logout(); login( user => 'test3', password => 'password3' ); # uid3 can see uid1 if visibility is >= travelynx if ( $opt{effective_visibility} >= 80 ) { $t->get_ok("/p/test1/j/$jid")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } # uid3 can see uid1 with token if visibility is >= unlisted if ( $opt{effective_visibility} >= 30 ) { $t->get_ok("/p/test1/j/$jid$token")->status_is(200) ->content_like(qr{DPN 667}); } else { $t->get_ok("/p/test1/j/$jid$token")->status_is(404) ->content_like(qr{Zugfahrt nicht gefunden.}); } logout(); } my $uid1 = $u->add( name => 'test1', email => 'test1@example.org', token => 'abcd', password => 'password1', ); my $uid2 = $u->add( name => 'test2', email => 'test2@example.org', token => 'efgh', password => 'password2', ); my $uid3 = $u->add( name => 'test3', email => 'test3@example.org', token => 'ijkl', password => 'password3', ); $u->verify_registration_token( uid => $uid1, token => 'abcd' ); $u->verify_registration_token( uid => $uid2, token => 'efgh' ); $u->verify_registration_token( uid => $uid3, token => 'ijkl' ); $u->set_social( uid => $uid1, accept_follows => 1 ); $u->set_social( uid => $uid2, accept_follows => 1 ); $u->set_social( uid => $uid3, accept_follows => 1 ); $u->follow( uid => $uid2, target => $uid1 ); is( $u->get_relation( subject => $uid2, object => $uid1 ), 'follows' ); is( $u->get_relation( subject => $uid1, object => $uid2 ), undef ); my $dep = DateTime->now; my $arr = $dep->clone->add( hours => 1 ); my $train_dep = Travel::Status::DE::IRIS::Result->new( classes => 'N', type => 'DPN', train_no => '667', raw_id => '1234-2306251312-1', departure_ts => '2306251312', platform => 8, station => 'Aachen Hbf', station_uic => 8000001, route_post => 'Mainz Hbf|Aalen Hbf', ); my $train_arr = Travel::Status::DE::IRIS::Result->new( classes => 'N', type => 'DPN', train_no => '667', raw_id => '1234-2306251312-3', arrival_ts => '2306252000', platform => 1, station => 'Aalen Hbf', station_uic => 8000002, route_pre => 'Aachen Hbf|Mainz Hbf', ); $t->app->in_transit->add( uid => $uid1, departure_eva => 8000001, train => $train_dep, route => [], ); $t->app->in_transit->set_arrival_eva( uid => $uid1, arrival_eva => 8000002, ); my $db = $t->app->pg->db; my $tx = $db->begin; my $journey = $t->app->in_transit->get( uid => $uid1, db => $db, ); my $jid = $t->app->journeys->add_from_in_transit( journey => $journey, db => $db ); $t->app->in_transit->delete( uid => $uid1, db => $db ); $tx->commit; test_journey_visibility( uid => $uid1, journey_id => $jid, visibility => undef, visibility_str => 'default', effective_visibility => 30, effective_visibility_str => 'unlisted', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_default_visibility => 10, visibility => undef, visibility_str => 'default', effective_visibility => 10, effective_visibility_str => 'private', public => 0, with_token => 0, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_default_visibility => 30, visibility => undef, visibility_str => 'default', effective_visibility => 30, effective_visibility_str => 'unlisted', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_default_visibility => 60, visibility => undef, visibility_str => 'default', effective_visibility => 60, effective_visibility_str => 'followers', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_default_visibility => 80, visibility => undef, visibility_str => 'default', effective_visibility => 80, effective_visibility_str => 'travelynx', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_default_visibility => 100, visibility => undef, visibility_str => 'default', effective_visibility => 100, effective_visibility_str => 'public', public => 1, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_visibility => 'private', visibility => 10, visibility_str => 'private', effective_visibility => 10, effective_visibility_str => 'private', public => 0, with_token => 0, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_visibility => 'unlisted', visibility => 30, visibility_str => 'unlisted', effective_visibility => 30, effective_visibility_str => 'unlisted', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_visibility => 'followers', visibility => 60, visibility_str => 'followers', effective_visibility => 60, effective_visibility_str => 'followers', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_visibility => 'travelynx', visibility => 80, visibility_str => 'travelynx', effective_visibility => 80, effective_visibility_str => 'travelynx', public => 0, with_token => 1, ); test_journey_visibility( uid => $uid1, journey_id => $jid, set_visibility => 'public', visibility => 100, visibility_str => 'public', effective_visibility => 100, effective_visibility_str => 'public', public => 1, with_token => 1, ); $t->app->pg->db->query('drop schema travelynx_test_23 cascade'); done_testing();