diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 6e24ebbea..b4cddb16f 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -32,6 +32,7 @@ function number($number, $decimals = 2) { * Calculate hours and minutes from a given duration in seconds. * * @param int $seconds How long in seconds? + * * @return array with `hours`, `minutes` and `showHours`. * @deprecated as soon as vue is implemented */ @@ -47,6 +48,7 @@ function secondsToDuration($seconds): array { /** * @param array $duration from the secondsToDuration + * * @return string * @deprecated as soon as vue is implemented */ @@ -59,33 +61,3 @@ function durationToSpan($duration): string { return $return; } - -/** - * @param $name - * @param string $classes - * @return string - * @deprecated as soon as vue is implemented - */ -function stationLink($name, $classes = "text-trwl clearfix"): string { - $urlname = $name; - - switch ($name) { - // Those are stations that you can ride to but you can't search for them. - case $name == "Köln Messe/Deutz Gl. 9-10": - case $name == "Köln Messe/Deutz Gl.11-12": - $urlname = "Köln Messe/Deutz"; - break; - - // Hamburg's Landungsbrücken has three bridges [1..3], but you cannot search for them. - case preg_match('/Landungsbr.*cken Br.*cke \d/i', $name) > 0: - $urlname = "Landungsbrücken, Hamburg"; - break; - } - - return strtr(':name', [ - ':href' => route('trains.stationboard'), - ':station' => urlencode($urlname), - ':classes' => $classes, - ':name' => $name - ]); -} diff --git a/app/Http/Controllers/API/TransportController.php b/app/Http/Controllers/API/TransportController.php index fb37e24a9..b80e9f2c3 100644 --- a/app/Http/Controllers/API/TransportController.php +++ b/app/Http/Controllers/API/TransportController.php @@ -56,9 +56,9 @@ public function TrainStationboard(Request $request): JsonResponse { try { $trainStationboardResponse = TransportBackend::getDepartures( - $validated['station'], - isset($validated['when']) ? Carbon::parse($validated['when']) : null, - $validated['travelType'] ?? null + stationQuery: $validated['station'], + when: isset($validated['when']) ? Carbon::parse($validated['when']) : null, + travelType: $validated['travelType'] ?? null ); } catch (HafasException $exception) { return $this->sendError($exception->getMessage(), 503); diff --git a/app/Http/Controllers/API/v1/TransportController.php b/app/Http/Controllers/API/v1/TransportController.php index da7aeb9ad..a3f61db0a 100644 --- a/app/Http/Controllers/API/v1/TransportController.php +++ b/app/Http/Controllers/API/v1/TransportController.php @@ -24,7 +24,6 @@ use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Validation\Rule; -use Illuminate\Validation\ValidationException; class TransportController extends ResponseController { @@ -33,7 +32,6 @@ class TransportController extends ResponseController * @param string $name * * @return JsonResponse - * @throws ValidationException * @see All slashes (as well as encoded to %2F) in $name need to be replaced, preferrably by a spache (%20) */ public function departures(Request $request, string $name): JsonResponse { @@ -44,9 +42,9 @@ public function departures(Request $request, string $name): JsonResponse { try { $trainStationboardResponse = TransportBackend::getDepartures( - $name, - isset($validated['when']) ? Carbon::parse($validated['when']) : null, - $validated['travelType'] ?? null + stationQuery: $name, + when: isset($validated['when']) ? Carbon::parse($validated['when']) : null, + travelType: $validated['travelType'] ?? null ); } catch (HafasException) { return $this->sendv1Error("There has been an error with our data provider", 400); @@ -115,8 +113,8 @@ public function create(Request $request): JsonResponse { 'tweet' => ['nullable', 'boolean'], 'toot' => ['nullable', 'boolean'], 'ibnr' => ['nullable', 'boolean'], - 'tripId' => 'required', - 'lineName' => 'required', + 'tripId' => ['required'], + 'lineName' => ['required'], 'start' => ['required', 'numeric'], 'destination' => ['required', 'numeric'], 'departure' => ['required', 'date'], diff --git a/app/Http/Controllers/Backend/Transport/StationController.php b/app/Http/Controllers/Backend/Transport/StationController.php new file mode 100644 index 000000000..5cac6d9bf --- /dev/null +++ b/app/Http/Controllers/Backend/Transport/StationController.php @@ -0,0 +1,43 @@ +first(); + if ($station !== null) { + return $station; + } + } + + //Lookup by ril identifier + if (!is_numeric($query) && strlen($query) <= 5 && ctype_upper($query)) { + $station = HafasController::getTrainStationByRilIdentifier($query); + if ($station !== null) { + return $station; + } + } + + //Lookup HAFAS + $station = HafasController::getStations(query: $query, results: 1)->first(); + if ($station !== null) { + return $station; + } + + throw new ModelNotFoundException; + } +} diff --git a/app/Http/Controllers/Backend/Transport/TrainCheckinController.php b/app/Http/Controllers/Backend/Transport/TrainCheckinController.php index ebba70b49..3364e3961 100644 --- a/app/Http/Controllers/Backend/Transport/TrainCheckinController.php +++ b/app/Http/Controllers/Backend/Transport/TrainCheckinController.php @@ -96,12 +96,7 @@ public static function createTrainCheckin( foreach ($alsoOnThisConnection as $otherStatus) { if ($otherStatus?->user) { - $otherStatus->user->notify(new UserJoinedConnection( - statusId: $status->id, - linename: $trip->linename, - origin: $firstStop->name, - destination: $lastStop->name - )); + $otherStatus->user->notify(new UserJoinedConnection($status)); } } diff --git a/app/Http/Controllers/FrontendStatusController.php b/app/Http/Controllers/FrontendStatusController.php index 05d90b979..8e9ec2919 100644 --- a/app/Http/Controllers/FrontendStatusController.php +++ b/app/Http/Controllers/FrontendStatusController.php @@ -9,6 +9,7 @@ use App\Http\Controllers\Backend\User\DashboardController; use App\Http\Controllers\StatusController as StatusBackend; use App\Models\Status; +use App\Models\TrainStation; use Carbon\Carbon; use Illuminate\Contracts\Support\Renderable; use Illuminate\Database\Eloquent\ModelNotFoundException; @@ -177,16 +178,16 @@ public function getStatus($statusId): Renderable { /** * @param $status * - * @return mixed + * @return TrainStation|null * @deprecated when vue is implemented */ - public static function nextStation(&$status) { + public static function nextStation(&$status): ?TrainStation { if ($status->trainCheckin->HafasTrip->stopoversNEW->count() > 0) { return $status->trainCheckin->HafasTrip->stopoversNEW ->filter(function($stopover) { return $stopover->arrival->isFuture(); })->sortBy('arrival') - ->first()?->trainStation?->name; + ->first()?->trainStation; } $stops = json_decode($status->trainCheckin->HafasTrip->stopovers); @@ -201,6 +202,6 @@ public static function nextStation(&$status) { } break; // Wenn wir diesen Teil der Loop erreichen, kann die Loop beendert werden. } - return $stops[$nextStopIndex]->stop->name; + return $stops[$nextStopIndex]->stop; } } diff --git a/app/Http/Controllers/FrontendTransportController.php b/app/Http/Controllers/FrontendTransportController.php index e3bea0a0b..629634d21 100644 --- a/app/Http/Controllers/FrontendTransportController.php +++ b/app/Http/Controllers/FrontendTransportController.php @@ -37,7 +37,7 @@ public function TrainAutocomplete(string $station): JsonResponse { public function TrainStationboard(Request $request): Renderable|RedirectResponse { $validated = $request->validate([ - 'station' => ['required', 'string'], + 'station' => ['required'], 'when' => ['nullable', 'date'], 'travelType' => ['nullable', Rule::in(TravelType::getList())] ]); @@ -46,9 +46,9 @@ public function TrainStationboard(Request $request): Renderable|RedirectResponse try { $TrainStationboardResponse = TransportBackend::getDepartures( - $validated['station'], - $when, - $validated['travelType'] ?? null + stationQuery: $validated['station'], + when: $when, + travelType: $validated['travelType'] ?? null ); } catch (HafasException $exception) { return back()->with('error', $exception->getMessage()); @@ -84,7 +84,7 @@ public function StationByCoordinates(Request $request): RedirectResponse { } return redirect()->route('trains.stationboard', [ - 'station' => $nearestStation->name, + 'station' => $nearestStation->ibnr, 'provider' => 'train' ]); } diff --git a/app/Http/Controllers/HafasController.php b/app/Http/Controllers/HafasController.php index b5ec324b3..2fd867477 100644 --- a/app/Http/Controllers/HafasController.php +++ b/app/Http/Controllers/HafasController.php @@ -25,7 +25,7 @@ abstract class HafasController extends Controller public static function getTrainStationByRilIdentifier(string $rilIdentifier): ?TrainStation { $trainStation = TrainStation::where('rilIdentifier', $rilIdentifier)->first(); - if ($trainStation != null) { + if ($trainStation !== null) { return $trainStation; } try { diff --git a/app/Http/Controllers/TransportController.php b/app/Http/Controllers/TransportController.php index 690ac8e84..55d858b01 100644 --- a/app/Http/Controllers/TransportController.php +++ b/app/Http/Controllers/TransportController.php @@ -11,6 +11,7 @@ use App\Http\Controllers\Backend\Social\MastodonController; use App\Http\Controllers\Backend\Social\TwitterController; use App\Http\Controllers\Backend\Transport\PointsCalculationController; +use App\Http\Controllers\Backend\Transport\StationController; use App\Http\Resources\HafasTripResource; use App\Models\Event; use App\Models\HafasTrip; @@ -51,7 +52,7 @@ public static function getTrainStationAutocomplete(string $query): Collection { } /** - * @param string $stationName + * @param string|int $stationQuery * @param Carbon|null $when * @param string|null $travelType * @@ -60,22 +61,16 @@ public static function getTrainStationAutocomplete(string $query): Collection { * @api v1 */ #[ArrayShape([ - 'station' => "\App\Models\TrainStation|mixed|null", - 'departures' => "\Illuminate\Support\Collection", + 'station' => TrainStation::class, + 'departures' => Collection::class, 'times' => "array" ])] - public static function getDepartures(string $stationName, Carbon $when = null, string $travelType = null): array { - //first check if the query is a valid DS100 identifier - if (strlen($stationName) <= 5 && ctype_upper($stationName)) { - $station = HafasController::getTrainStationByRilIdentifier($stationName); - } - //if we cannot find any station by DS100 identifier continue to search normal - if (empty($station)) { - $station = HafasController::getStations($stationName)->first(); - if ($station == null) { - throw new ModelNotFoundException; - } - } + public static function getDepartures( + string|int $stationQuery, + Carbon $when = null, + string $travelType = null + ): array { + $station = StationController::lookupStation($stationQuery); $when = $when ?? Carbon::now()->subMinutes(5); $times = [ @@ -390,10 +385,7 @@ public static function TrainCheckin($tripId, // check for other people on this train foreach ($trainCheckin->alsoOnThisConnection as $otherStatus) { - $otherStatus->user->notify(new UserJoinedConnection($status->id, - $status->trainCheckin->HafasTrip->linename, - $status->trainCheckin->Origin->name, - $status->trainCheckin->Destination->name)); + $otherStatus->user->notify(new UserJoinedConnection($status)); } return [ diff --git a/app/Notifications/UserJoinedConnection.php b/app/Notifications/UserJoinedConnection.php index a845de17a..2eb15af8b 100644 --- a/app/Notifications/UserJoinedConnection.php +++ b/app/Notifications/UserJoinedConnection.php @@ -16,26 +16,15 @@ class UserJoinedConnection extends Notification { use Queueable; - private ?int $statusId; - private ?string $linename; - private ?string $origin; - private ?string $destination; + private Status $status; /** * Create a new notification instance * * @return void */ - public function __construct( - int $statusId = null, - string $linename = null, - string $origin = null, - string $destination = null - ) { - $this->statusId = $statusId; - $this->linename = $linename; - $this->origin = $origin; - $this->destination = $destination; + public function __construct(Status $status) { + $this->status = $status; } /** @deprecated will be handled in frontend */ @@ -46,24 +35,25 @@ public static function render(DatabaseNotification $notification): ?string { $notification->delete(); return null; } - $data = $notification->data; return view("includes.notification", [ 'color' => "neutral", 'icon' => "fa fa-train", - 'lead' => __('notifications.userJoinedConnection.lead', - ['username' => $detail->status->user->username - ]), + 'lead' => __('notifications.userJoinedConnection.lead', [ + 'username' => $detail->status->user->username + ]), "link" => route('statuses.get', ['id' => $detail->status->id]), - 'notice' => trans_choice('notifications.userJoinedConnection.notice', - preg_match('/\s/', $data['linename']), [ - 'username' => $detail->status->user->username, - 'linename' => $data['linename'], - 'origin' => $data['origin'], - 'destination' => $data['destination'] - ]), + 'notice' => trans_choice( + 'notifications.userJoinedConnection.notice', + preg_match('/\s/', $detail->status->trainCheckin->HafasTrip->linename), [ + 'username' => $detail->status->user->username, + 'linename' => $detail->status->trainCheckin->HafasTrip->linename, + 'origin' => $detail->status->trainCheckin->Origin->name, + 'destination' => $detail->status->trainCheckin->Destination->name, + ] + ), 'date_for_humans' => $notification->created_at->diffForHumans(), - 'read' => $notification->read_at != null, + 'read' => $notification->read_at !== null, 'notificationId' => $notification->id ])->render(); } @@ -75,34 +65,34 @@ public static function render(DatabaseNotification $notification): ?string { * @throws ShouldDeleteNotificationException */ public static function detail(DatabaseNotification $notification): stdClass { - $data = $notification->data; $notification->detail = new stdClass(); try { - $status = Status::findOrFail($data['status_id']); + $status = Status::findOrFail($notification->data['status_id'] ?? null); } catch (ModelNotFoundException) { throw new ShouldDeleteNotificationException(); } $notification->detail->status = new StatusResource($status); - $notification->detail->message = new UserNotificationMessageResource - ([ - 'icon' => 'fa fa-train', - 'lead' => [ - 'key' => 'notifications.userJoinedConnection.lead', - 'values' => [ - 'username' => $status->user->username - ] - ], - 'notice' => [ - 'key' => 'notifications.userJoinedConnection.notice', - 'values' => [ - 'username' => $status->user->username, - 'linename' => $data['linename'], - 'origin' => $data['origin'], - 'destination' => $data['destination'] - ] - ] - ]); + $notification->detail->message = new UserNotificationMessageResource( + [ + 'icon' => 'fa fa-train', + 'lead' => [ + 'key' => 'notifications.userJoinedConnection.lead', + 'values' => [ + 'username' => $status->user->username + ] + ], + 'notice' => [ + 'key' => 'notifications.userJoinedConnection.notice', + 'values' => [ + 'username' => $status->user->username, + 'linename' => $status->trainCheckin->HafasTrip->linename, + 'origin' => $status->trainCheckin->Origin->name, + 'destination' => $status->trainCheckin->Destination->name, + ] + ] + ] + ); return $notification->detail; } @@ -117,15 +107,16 @@ public function via(): array { /** * Get the array representation of the notification. + * This array is saved as `data` in the database * * @return array */ public function toArray(): array { return [ - 'status_id' => $this->statusId, - 'linename' => $this->linename, - 'origin' => $this->origin, - 'destination' => $this->destination + 'status_id' => $this->status->id, + 'linename' => $this->status->trainCheckin->HafasTrip->linename, + 'origin' => $this->status->trainCheckin->Origin->name, + 'destination' => $this->status->trainCheckin->Destination->name, ]; } } diff --git a/config/trustedproxy.php b/config/trustedproxy.php new file mode 100644 index 000000000..bb8be222a --- /dev/null +++ b/config/trustedproxy.php @@ -0,0 +1,52 @@ + env('TRUSTED_PROXY', null), // [,], '*', ',' + + /* + * To trust one or more specific proxies that connect + * directly to your server, use an array or a string separated by comma of IP addresses: + */ + // 'proxies' => ['192.168.1.1'], + // 'proxies' => '192.168.1.1, 192.168.1.2', + + /* + * Or, to trust all proxies that connect + * directly to your server, use a "*" + */ + // 'proxies' => '*', + + /* + * Which headers to use to detect proxy related data (For, Host, Proto, Port) + * + * Options include: + * + * - Illuminate\Http\Request::HEADER_X_FORWARDED_ALL (use all x-forwarded-* headers to establish trust) + * - Illuminate\Http\Request::HEADER_FORWARDED (use the FORWARDED header to establish trust) + * - Illuminate\Http\Request::HEADER_X_FORWARDED_AWS_ELB (If you are using AWS Elastic Load Balancer) + * + * - 'HEADER_X_FORWARDED_ALL' (use all x-forwarded-* headers to establish trust) + * - 'HEADER_FORWARDED' (use the FORWARDED header to establish trust) + * - 'HEADER_X_FORWARDED_AWS_ELB' (If you are using AWS Elastic Load Balancer) + * + * @link https://symfony.com/doc/current/deployment/proxies.html + */ + 'headers' => Request::HEADER_X_FORWARDED_TRAEFIK, + +]; diff --git a/resources/lang/sv.json b/resources/lang/sv.json index 22b18042f..a9216d5e3 100644 --- a/resources/lang/sv.json +++ b/resources/lang/sv.json @@ -487,5 +487,12 @@ "support.privacy.description2": "Uppgifterna raderas efter ett år oavsett ditt användarkonto hos Träwelling.", "settings.revoke-token.success": "Åtkomsten har återkallats", "support.email-required": "Du behöver en verifierad e-postadress för att skicka en supportförfrågan. Detta är det enda sättet vi kan svara dig på.", - "support.answer": "Vi svarar dig så snart som möjligt. Du får svaret till din e-postadress: adress." + "support.answer": "Vi svarar dig så snart som möjligt. Du får svaret till din e-postadress: adress.", + "support": "Support", + "generic.why": "Varför?", + "checkin.points.earned": "Du får", + "checkin.points.could-have": "Du kunde ha fått fler poäng om du checkade in närmare den verkliga avgångstiden!", + "checkin.points.forced": "Du fick inga poäng för denna incheckning eftersom du tvingade fram den.", + "checkin.conflict.question": "Vill du checka in ändå? Du får inga poäng för detta, men din personliga statistik kommer fortfarande att uppdateras.", + "generic.error": "fel" } diff --git a/resources/views/activejourneys.blade.php b/resources/views/activejourneys.blade.php index 7e893a6c3..77b7fce22 100644 --- a/resources/views/activejourneys.blade.php +++ b/resources/views/activejourneys.blade.php @@ -242,9 +242,9 @@ className: 'text-trwl text-center' "url": "{{$event->url}}", "begin": "{{ $event->begin->format('Y-m-d') }}", "end": "{{ $event->end->format('Y-m-d') }}", - "ts": {!! $event->getTrainStation() !!}, + "ts": {!! $event->station !!}, "mapLink": "{{ route('statuses.byEvent', ['eventSlug' => $event->slug]) }}", - "closestLink": `{!! stationLink($event->getTrainstation()->name) !!}` + "closestLink": "@isset($event->station) 'train', 'station' => $event->station->ibnr])}}\" class=\"text-trwl clearfix\">{{$event->station->name}} @endisset" }, @endforeach ]; @@ -264,7 +264,6 @@ className: 'text-trwl text-center' }); - @include('includes.statuses', ['statuses' => $statuses, 'showDates' => false]) diff --git a/resources/views/events/overview.blade.php b/resources/views/events/overview.blade.php index 3f0e7e712..100146bca 100644 --- a/resources/views/events/overview.blade.php +++ b/resources/views/events/overview.blade.php @@ -32,7 +32,7 @@
{{__('events.closestStation')}}: - + {{$event->station->name}} diff --git a/resources/views/eventsMap.blade.php b/resources/views/eventsMap.blade.php index c820fbebc..7479f6632 100644 --- a/resources/views/eventsMap.blade.php +++ b/resources/views/eventsMap.blade.php @@ -1,6 +1,6 @@ @extends('layouts.app') -@section('title'){{ $event->name }}@endsection +@section('title', $event->name) @section('content')

- {{ __('events.header', ['name' => $event->name]) }} #{{ $event->hashtag }} + + {{ __('events.header', ['name' => $event->name]) }} + #{{ $event->hashtag }} +

 {{ @@ -40,12 +42,14 @@ class="text-white">#{{ $event->hashtag }} @endisset

- @isset($event->station)

- {!! stationLink($event->station->name, "text-white") !!} + + {{$event->station->name}} +

@endisset @@ -56,7 +60,6 @@ class="text-white">#{{ $event->hashtag }}
- @foreach($statuses as $status) @include('includes.status') @endforeach @@ -66,7 +69,7 @@ class="text-white">#{{ $event->hashtag }}
{{ $statuses->links() }}
-
+
@include('includes.edit-modal') @include('includes.delete-modal') diff --git a/resources/views/includes/notification.blade.php b/resources/views/includes/notification.blade.php index 615528a85..5df39caa2 100644 --- a/resources/views/includes/notification.blade.php +++ b/resources/views/includes/notification.blade.php @@ -9,9 +9,10 @@ {!! $notice !!} 
-
{{ $date_for_humans }}
-
\ No newline at end of file +
diff --git a/resources/views/includes/station-autocomplete.blade.php b/resources/views/includes/station-autocomplete.blade.php index 476f8b1f3..b3ab0cdf3 100644 --- a/resources/views/includes/station-autocomplete.blade.php +++ b/resources/views/includes/station-autocomplete.blade.php @@ -16,7 +16,7 @@
station) value="{{request()->station}}" @endisset + @isset($station) value="{{$station->name}}" @endisset /> @if($latest->count() > 0 || Auth::user()->home) @@ -37,7 +37,7 @@
@if(Auth::user()->home) - {{ Auth::user()->home->name }} @@ -48,7 +48,7 @@ class="list-group-item list-group-item-action"> {{__('stationboard.last-stations')}} @endif @foreach($latest as $station) - {{ $station->name }} diff --git a/resources/views/includes/status.blade.php b/resources/views/includes/status.blade.php index a353c6d8e..d6a3b9962 100644 --- a/resources/views/includes/status.blade.php +++ b/resources/views/includes/status.blade.php @@ -25,15 +25,20 @@ @if($status->trainCheckin?->origin_stopover?->isDepartureDelayed) - {{ $status->trainCheckin->origin_stopover->departure_planned->isoFormat(__('time-format')) }} + + {{ $status->trainCheckin->origin_stopover->departure_planned->isoFormat(__('time-format')) }} +   {{ $status->trainCheckin->origin_stopover->departure_real->isoFormat(__('time-format')) }} @else {{ $status->trainCheckin?->origin_stopover?->departure->isoFormat(__('time-format')) ?? $status->trainCheckin->departure->isoFormat(__('time-format')) }} @endif - {!! stationLink($status->trainCheckin->Origin->name) !!} + + + {{$status->trainCheckin->Origin->name}} + +

@if (file_exists(public_path('img/'.$status->trainCheckin->HafasTrip->category.'.svg'))) @@ -53,13 +58,12 @@ class="text-muted">{{ $status->trainCheckin->origin_stopover->departure_planned- {!! durationToSpan(secondsToDuration($status->trainCheckin->duration * 60)) !!} - @if($status->business == 1) + @if($status->business == \App\Enum\Business::BUSINESS) - @endif - @if($status->business == 2) + @elseif($status->business == \App\Enum\Business::COMMUTE) @@ -84,7 +88,9 @@ class="text-muted">{{ $status->trainCheckin->origin_stopover->departure_planned- @if($status->trainCheckin->departure->isPast() && $status->trainCheckin->arrival->isFuture())

{{ __('stationboard.next-stop') }} - {!! stationLink(\App\Http\Controllers\FrontendStatusController::nextStation($status)) !!} + + {{\App\Http\Controllers\FrontendStatusController::nextStation($status)?->name}} +

@endif @@ -101,7 +107,9 @@ class="text-muted">{{ $status->trainCheckin->origin_stopover->departure_planned- {{ $status->trainCheckin?->destination_stopover?->arrival?->isoFormat(__('time-format')) ?? $status->trainCheckin->arrival->isoFormat(__('time-format')) }} @endif - {!! stationLink($status->trainCheckin->Destination->name) !!} + + {{$status->trainCheckin->Destination->name}} +
diff --git a/resources/views/stationboard.blade.php b/resources/views/stationboard.blade.php index bc6fee3b5..275f43533 100644 --- a/resources/views/stationboard.blade.php +++ b/resources/views/stationboard.blade.php @@ -10,7 +10,7 @@
- @@ -19,7 +19,7 @@ class="btn btn-light"> class="btn btn-light btn-rounded c-datepicker-btn"> - diff --git a/tests/Feature/CheckinTest.php b/tests/Feature/CheckinTest.php index dba7ea3bc..7b3314390 100644 --- a/tests/Feature/CheckinTest.php +++ b/tests/Feature/CheckinTest.php @@ -32,12 +32,12 @@ protected function setUp(): void { */ public function stationboardTest(): void { $requestDate = Carbon::parse($this->plus_one_day_then_8pm); - $stationname = "Frankfurt(Main)Hbf"; + $stationName = "Frankfurt(Main)Hbf"; $ibnr = 8000105; // This station has departures throughout the night. try { $trainStationboard = TransportController::getDepartures( - $stationname, - $requestDate + stationQuery: $stationName, + when: $requestDate ); } catch (HafasException $e) { $this->markTestSkipped($e->getMessage()); @@ -46,7 +46,7 @@ public function stationboardTest(): void { $departures = $trainStationboard['departures']; // Ensure its the same station - $this->assertEquals($stationname, $station['name']); + $this->assertEquals($stationName, $station['name']); $this->assertEquals($ibnr, $station['ibnr']); // Analyse the stationboard departures @@ -76,10 +76,10 @@ public function stationboardByLocationPositiveTest(): void { "longitude" => 7.4592 ], */ [ - "name" => "FRA", - "station" => "Frankfurt(M) Flughafen Fernbf", - "latitude" => 50.052926, - "longitude" => 8.569776 + 'name' => 'FRA', + 'station' => 8070003, + 'latitude' => 50.052926, + 'longitude' => 8.569776 ] /*, [ "name" => "Moskau", @@ -92,16 +92,16 @@ public function stationboardByLocationPositiveTest(): void { foreach ($locations as $testcase) { // WHEN: Requesting the stationboard based on Coordinates $response = $this->actingAs($user) - ->get(route("trains.nearby", [ - "latitude" => $testcase["latitude"], - "longitude" => $testcase["longitude"] + ->get(route('trains.nearby', [ + 'latitude' => $testcase['latitude'], + 'longitude' => $testcase['longitude'] ])); // THEN: Expect the redirect to another stationboard $response->assertStatus(302); - $response->assertRedirect(route("trains.stationboard", [ - 'station' => $testcase["station"], - 'provider' => 'train' + $response->assertRedirect(route('trains.stationboard', [ + 'station' => $testcase['station'], + 'provider' => 'train', ])); } } @@ -153,13 +153,13 @@ public function stationboardByLocationNegativeTest(): void { public function testCheckin(): void { // First: Get a train that's fine for our stuff $timestamp = Carbon::parse($this->plus_one_day_then_8pm); - $stationname = "Frankfurt(M) Flughafen Fernbf"; + $stationName = "Frankfurt(M) Flughafen Fernbf"; $ibnr = "8070003"; try { $trainStationboard = TransportController::getDepartures( - $stationname, - $timestamp, - TravelType::EXPRESS + stationQuery: $stationName, + when: $timestamp, + travelType: TravelType::EXPRESS ); } catch (HafasException $e) { $this->markTestSkipped($e->getMessage()); @@ -167,7 +167,7 @@ public function testCheckin(): void { $countDepartures = count($trainStationboard['departures']); if ($countDepartures === 0) { - $this->markTestSkipped("Unable to find matching trains. Is it night in $stationname?"); + $this->markTestSkipped("Unable to find matching trains. Is it night in $stationName?"); } // Second: We don't like broken or cancelled trains. @@ -177,7 +177,7 @@ public function testCheckin(): void { || count($trainStationboard['departures'][$i]->remarks) != 0) { $i++; if ($i == $countDepartures) { - $this->markTestSkipped("Unable to find unbroken train. Is it stormy in $stationname?"); + $this->markTestSkipped("Unable to find unbroken train. Is it stormy in $stationName?"); } } $departure = $trainStationboard['departures'][$i]; @@ -221,7 +221,7 @@ public function testCheckin(): void { // THEN: You can get the status page and see its information $response = $this->get(url('/status/' . $status->id)); $response->assertOk(); - $response->assertSee($stationname, false); // Departure Station + $response->assertSee($stationName, false); // Departure Station $response->assertSee($trip['stopovers'][0]['stop']['name'], false); // Arrival Station $response->assertSee("Example Body"); @@ -431,12 +431,12 @@ public function testCheckinSuccessFlash(): void { public function testCheckinAtBus603Potsdam(): void { // First: Get a train that's fine for our stuff $timestamp = Carbon::parse("+1 days 10:00"); - $stationname = "Schloss Cecilienhof, Potsdam"; + $stationName = "Schloss Cecilienhof, Potsdam"; try { $trainStationboard = TransportController::getDepartures( - $stationname, - $timestamp, - 'bus' + stationQuery: $stationName, + when: $timestamp, + travelType: TravelType::BUS ); } catch (HafasException $e) { $this->markTestSkipped($e->getMessage()); @@ -444,8 +444,7 @@ public function testCheckinAtBus603Potsdam(): void { $countDepartures = count($trainStationboard['departures']); if ($countDepartures === 0) { - $this->markTestSkipped("Unable to find matching bus. Is it night in $stationname?"); - return; + $this->markTestSkipped("Unable to find matching bus. Is it night in $stationName?"); } // The bus runs in a 20min interval @@ -505,12 +504,12 @@ public function testCheckinAtBerlinRingbahnRollingOverSuedkreuz(): void { // First: Get a train that's fine for our stuff // The 10:00 train actually quits at Südkreuz, but the 10:05 does not. $timestamp = Carbon::parse("+1 days 10:03"); - $stationname = "Messe Nord / ICC, Berlin"; + $stationName = "Messe Nord / ICC, Berlin"; try { $trainStationboard = TransportController::getDepartures( - $stationname, - Carbon::parse('+1 days 10:00'), - 'suburban' + stationQuery: $stationName, + when: Carbon::parse('+1 days 10:00'), + travelType: TravelType::SUBURBAN, ); } catch (HafasException $e) { $this->markTestSkipped($e->getMessage()); diff --git a/tests/Feature/NotificationsTest.php b/tests/Feature/NotificationsTest.php index b2a9d8f0d..181d21094 100644 --- a/tests/Feature/NotificationsTest.php +++ b/tests/Feature/NotificationsTest.php @@ -5,6 +5,9 @@ use App\Http\Controllers\UserController as UserBackend; use App\Models\Like; use App\Models\User; +use App\Notifications\StatusLiked; +use App\Notifications\UserFollowed; +use App\Notifications\UserJoinedConnection; use Carbon\Carbon; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Notifications\DatabaseNotification; @@ -23,7 +26,7 @@ protected function setUp(): void { } /** @test */ - public function likes_appear_in_notifications() { + public function likes_appear_in_notifications(): void { // Given: There is a likable status $timestamp = Carbon::parse("+2 day 7:45"); $this->checkin("Hamburg Hbf", $timestamp); @@ -41,14 +44,14 @@ public function likes_appear_in_notifications() { $notifications->assertOk(); $notifications->assertJsonCount(1); // one like $notifications->assertJsonFragment([ - 'type' => "App\\Notifications\\StatusLiked", - 'notifiable_type' => "App\\Models\\User", + 'type' => StatusLiked::class, + 'notifiable_type' => User::class, 'notifiable_id' => (string) $this->user->id ]); } /** @test */ - public function removed_likes_dont_appear_in_notifications() { + public function removed_likes_dont_appear_in_notifications(): void { // Given: There is a likable status $timestamp = Carbon::parse("+2 day 7:45"); $this->checkin("Hamburg Hbf", $timestamp); @@ -69,7 +72,7 @@ public function removed_likes_dont_appear_in_notifications() { } /** @test */ - public function following_a_user_should_spawn_a_notification() { + public function following_a_user_should_spawn_a_notification(): void { // Given: Users Alice and Bob $alice = $this->user; $bob = $this->createGDPRAckedUser(); @@ -84,14 +87,14 @@ public function following_a_user_should_spawn_a_notification() { $notifications->assertOk(); $notifications->assertJsonCount(1); // one follow $notifications->assertJsonFragment([ - 'type' => "App\\Notifications\\UserFollowed", - 'notifiable_type' => "App\\Models\\User", + 'type' => UserFollowed::class, + 'notifiable_type' => User::class, 'notifiable_id' => (string) $bob->id ]); } /** @test */ - public function unfollowing_bob_should_remove_the_notification() { + public function unfollowing_bob_should_remove_the_notification(): void { // Given: Users Alice and Bob and Alice follows Bob $alice = $this->user; $bob = $this->createGDPRAckedUser(); @@ -110,7 +113,7 @@ public function unfollowing_bob_should_remove_the_notification() { } /** @test */ - public function bob_joining_on_alices_connection_should_spawn_a_notification() { + public function bob_joining_on_alices_connection_should_spawn_a_notification(): void { // GIVEN: Alice checked-into a train. $alice = $this->createGDPRAckedUser(); $timestamp = Carbon::parse("+2 day 7:45"); @@ -126,8 +129,8 @@ public function bob_joining_on_alices_connection_should_spawn_a_notification() { $notifications->assertOk(); $notifications->assertJsonCount(1); // One other user on that train $notifications->assertJsonFragment([ - 'type' => "App\\Notifications\\UserJoinedConnection", - 'notifiable_type' => "App\\Models\\User", + 'type' => UserJoinedConnection::class, + 'notifiable_type' => User::class, 'notifiable_id' => (string) $alice->id ]); @@ -144,7 +147,7 @@ public function bob_joining_on_alices_connection_should_spawn_a_notification() { } /** @test */ - public function mark_notification_as_read() { + public function mark_notification_as_read(): void { // GIVEN: Alice has a notification $userToFollow = $this->createGDPRAckedUser(); UserBackend::createFollow($this->user, $userToFollow); @@ -189,16 +192,16 @@ public function deleting_a_user_should_delete_its_notifications(): void { $notifications->assertOk(); $notifications->assertJsonCount(1); // one follow $notifications->assertJsonFragment([ - 'type' => "App\\Notifications\\UserFollowed", - 'notifiable_type' => "App\\Models\\User", + 'type' => UserFollowed::class, + 'notifiable_type' => User::class, 'notifiable_id' => (string) $bob->id ]); // When: Bob deletes its account - $delete = $delete = $this->actingAs($bob) - ->post(route('account.destroy'), [ - 'confirmation' => $bob->username - ]); + $delete = $this->actingAs($bob) + ->post(route('account.destroy'), [ + 'confirmation' => $bob->username + ]); $delete->assertStatus(302); $delete->assertRedirect('/'); diff --git a/tests/Feature/StationSearchTest.php b/tests/Feature/StationSearchTest.php new file mode 100644 index 000000000..ad31d309b --- /dev/null +++ b/tests/Feature/StationSearchTest.php @@ -0,0 +1,28 @@ +assertEquals('Hannover Hbf', $station->name); + } + + public function testDs100Search(): void { + $station = StationController::lookupStation('HH'); + $this->assertEquals('Hannover Hbf', $station->name); + } + + public function testIdSearch(): void { + $station = StationController::lookupStation(1); + $this->assertEquals(TrainStation::find(1)->name, $station->name); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 06eaf1f8c..4956625b9 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -108,18 +108,20 @@ public function acceptGDPR(User $user): void { 'event' => "mixed" ])] protected function checkin($stationName, Carbon $timestamp, User $user = null, bool $forEvent = null): ?array { - if ($user == null) { + if ($user === null) { $user = $this->user; } try { - $trainStationboard = TransportController::getDepartures($stationName, - $timestamp, - TravelType::EXPRESS); + $trainStationboard = TransportController::getDepartures( + stationQuery: $stationName, + when: $timestamp, + travelType: TravelType::EXPRESS + ); } catch (HafasException $e) { $this->markTestSkipped($e->getMessage()); } - $countDepartures = count($trainStationboard['departures']); - if ($countDepartures == 0) { + $countDepartures = $trainStationboard['departures']->count(); + if ($countDepartures === 0) { $this->markTestSkipped("Unable to find matching trains. Is it night in $stationName?"); } diff --git a/tests/Unit/HelperMethodTest.php b/tests/Unit/HelperMethodTest.php index 911b5ed89..fa5610ac4 100644 --- a/tests/Unit/HelperMethodTest.php +++ b/tests/Unit/HelperMethodTest.php @@ -35,49 +35,6 @@ public function testNumberFunction() { $this->assertEquals("-4.294.967.296,00", number(-1 * 2 ** 32)); } - public function testStationLink() { - - $user = $this->createGDPRAckedUser(); - $dom = new DOMDocument; - - foreach ([ - // First, start with something simple - 'Aachen Hbf' => 'Aachen Hbf', - - // Umlaute, Sonderzeichen? - 'Köln Messe/Deutz' => 'Köln Messe/Deutz', - // Da kann man zwar hinfahren, es ist aber keine echte Station und - // wenn man es versucht, gibts einen 404 Fehler von der DB-Rest-API. - 'Köln Messe/Deutz Gl.11-12' => 'Köln Messe/Deutz', - - // Extrem lange Stationen? - 'Frankfurt am Main Flughafen Fernbahnhof' => 'Frankfurt am Main Flughafen Fernbahnhof', - - // Ausland? - 'Wien Meidling' => 'Wien Meidling', - - // Hamburg nummeriert seine Landungsbrücken irgendwie durch, aber nur für Fähren, - // S-/U-/Busse sind normal oder nochmal komisch. - 'Landungsbrücken, Hamburg' => 'Landungsbrücken, Hamburg', - 'Landungsbrücken Brücke 1, Hamburg' => 'Landungsbrücken, Hamburg', - 'Landungsbrücken Brücke 1' => 'Landungsbrücken, Hamburg', - 'Landungsbrücken Brücke 2, Hamburg' => 'Landungsbrücken, Hamburg', - 'Landungsbrücken Brücke 3, Hamburg' => 'Landungsbrücken, Hamburg', - ] as $name => $alternatedTo) { - $link = stationLink($name); - - libxml_use_internal_errors(true); - $dom->loadHTML($link); - $links = $dom->getElementsByTagName('a'); - $this->assertEquals(count($links), 1); - - $response = $this->actingAs($user) - ->get($links[0]->getAttribute('href')); - $response->assertSee('placeholder="Haltestelle / DS100"', false); - $response->assertSee('value="' . $alternatedTo . '"', false); - } - } - public function test_secondsToDuration_and_durationToSpan() { $testcases = [ 0 => "0min", diff --git a/tests/Unit/Transport/PointsCalculation/FactorTest.php b/tests/Unit/Transport/PointsCalculation/FactorTest.php index 57f88cfac..2e932fdf9 100644 --- a/tests/Unit/Transport/PointsCalculation/FactorTest.php +++ b/tests/Unit/Transport/PointsCalculation/FactorTest.php @@ -1,19 +1,12 @@ assertEquals(1, PointsCalculationController::getFactorByReason(PointReasons::IN_TIME)); }