Skip to content

Commit

Permalink
Merge branch 'develop' into dev-ks/2411/hafastrips
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKrisKrisu committed Mar 17, 2024
2 parents 86b854c + 914f8a3 commit bf44ec8
Show file tree
Hide file tree
Showing 34 changed files with 595 additions and 191 deletions.
20 changes: 18 additions & 2 deletions API_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,25 @@ In this we try to keep track of changes to the API.
Primarily this should document changes that are not backwards compatible or belongs to already documented endpoints.
This is to help you keep track of the changes and to help you update your code accordingly.

## 2024-03-16

Replaced `GET /trains/station/{name}/departures` with `GET /station/{id}/departures`.
The old endpoint is marked as deprecated and will be removed after 2024-06.

Please note, that the ID is the Träwelling internal ID and not the IBNR!

## 2024-03-10

Replaced `PUT /trains/station/{name}/home` with `PUT /station/{id}/home`.
The old endpoint is marked as deprecated and will be removed after 2024-06.

Please note, that the ID is the Träwelling internal ID and not the IBNR!

## 2024-03-01
> **warning**
> Possibly breaking change: The implementation of next/prev links on user/{username}/statuses endpoint has been changed to adhere to the documentation.

> [!WARNING]
> Possibly breaking change: The implementation of next/prev links on user/{username}/statuses endpoint has been changed
> to adhere to the documentation.
## 2024-01-21

Expand Down
2 changes: 1 addition & 1 deletion app/Helpers/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function hasStationBoardTimezoneOffsetToUser(Collection $departures, User $user)
return false;
}

function errorMessage(Exception $exception, ?string $text = null): array|null|string {
function errorMessage(Exception|Error $exception, ?string $text = null): array|null|string {
$text = $text ?? __('messages.exception.general');

if (!$exception instanceof Referencable) {
Expand Down
168 changes: 113 additions & 55 deletions app/Http/Controllers/API/v1/TransportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use App\Models\Event;
use App\Models\Station;
use Carbon\Carbon;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
Expand All @@ -30,17 +31,49 @@

class TransportController extends Controller
{
/**
* @see All slashes (as well as encoded to %2F) in $name need to be replaced, preferrably by a space (%20)
*/
public function getLegacyDepartures(Request $request, string $name): JsonResponse { //TODO: remove endpoint after 2024-06
$validated = $request->validate([
'when' => ['nullable', 'date'],
'travelType' => ['nullable', new Enum(TravelType::class)],
]);

try {
$trainStationboardResponse = TransportBackend::getDepartures(
stationQuery: $name,
when: isset($validated['when']) ? Carbon::parse($validated['when']) : null,
travelType: TravelType::tryFrom($validated['travelType'] ?? null),
localtime: isset($validated['when']) && !preg_match('(\+|Z)', $validated['when'])
);
} catch (HafasException) {
return $this->sendError(__('messages.exception.generalHafas', [], 'en'), 502);
} catch (ModelNotFoundException) {
return $this->sendError(__('controller.transport.no-station-found', [], 'en'));
} catch (Exception $exception) {
report($exception);
return $this->sendError('An unknown error occurred.', 500);
}
return $this->sendResponse(
data: $trainStationboardResponse['departures'],
additional: ["meta" => ['station' => StationDto::fromModel($trainStationboardResponse['station']),
'times' => $trainStationboardResponse['times'],
]]
);
}

/**
* @OA\Get(
* path="/trains/station/{name}/departures",
* path="/station/{id}/departures",
* operationId="getDepartures",
* tags={"Checkin"},
* summary="Get departures from a station",
* description="Get departures from a station",
* @OA\Parameter(
* name="name",
* name="id",
* in="path",
* description="Name of the station (replace slashes with spaces)",
* description="Träwelling-ID of the station (station needs to be looked up first)",
* required=true,
* ),
* @OA\Parameter(
Expand Down Expand Up @@ -130,56 +163,58 @@ class TransportController extends Controller
* )
* )
* ),
* @OA\Response(
* response=404,
* description="Station not found",
* ),
* @OA\Response(
* response=502,
* description="Error with our data provider",
* ),
* @OA\Response(
* response=422,
* description="Invalid input",
* ),
* @OA\Response(response=401, description="Unauthorized"),
* security={
* {"passport": {"create-statuses"}}, {"token": {}}
*
* }
* @OA\Response(response=401, description="Unauthorized"),
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=422, description="Invalid input"),
* @OA\Response(response=502, description="Error with our data provider"),
* security={{"passport": {"create-statuses"}}, {"token": {}}}
* )
*
* @param Request $request
* @param string $name
* @param int $stationId
*
* @return JsonResponse
* @see All slashes (as well as encoded to %2F) in $name need to be replaced, preferrably by a space (%20)
*/
public function departures(Request $request, string $name): JsonResponse {
public function getDepartures(Request $request, int $stationId): JsonResponse {
$validated = $request->validate([
'when' => ['nullable', 'date'],
'travelType' => ['nullable', new Enum(TravelType::class)],
]);

$timestamp = isset($validated['when']) ? Carbon::parse($validated['when']) : now();
$station = Station::findOrFail($stationId);

try {
$trainStationboardResponse = TransportBackend::getDepartures(
stationQuery: $name,
when: isset($validated['when']) ? Carbon::parse($validated['when']) : null,
travelType: TravelType::tryFrom($validated['travelType'] ?? null),
localtime: isset($validated['when']) && !preg_match('(\+|Z)', $validated['when'])
$departures = HafasController::getDepartures(
station: $station,
when: $timestamp,
type: TravelType::tryFrom($validated['travelType'] ?? null),
localtime: isset($validated['when']) && !preg_match('(\+|Z)', $validated['when'])
)->sortBy(function($departure) {
return $departure->when ?? $departure->plannedWhen;
});

return $this->sendResponse(
data: $departures->values(),
additional: [
'meta' => [
'station' => StationDto::fromModel($station),
'times' => [
'now' => $timestamp,
'prev' => $timestamp->clone()->subMinutes(15),
'next' => $timestamp->clone()->addMinutes(15)
],
]
]
);
} catch (HafasException) {
return $this->sendError(__('messages.exception.generalHafas', [], 'en'), 502);
} catch (ModelNotFoundException) {
return $this->sendError(__('controller.transport.no-station-found', [], 'en'));
} catch (Exception $exception) {
report($exception);
return $this->sendError('An unknown error occurred.', 500);
}

return $this->sendResponse(
data: $trainStationboardResponse['departures'],
additional: ["meta" => ['station' => StationDto::fromModel($trainStationboardResponse['station']),
'times' => $trainStationboardResponse['times'],
]]
);
}

/**
Expand Down Expand Up @@ -420,18 +455,45 @@ public function create(Request $request): JsonResponse {
}
}

/**
* @param string $stationName
*
* @return JsonResponse
* @see All slashes (as well as encoded to %2F) in $name need to be replaced, preferrably by a space (%20)
* @deprecated Replaced by setHome (with "ID" instead of StationName and without "trains" in the path)
*/
public function setHomeLegacy(string $stationName): JsonResponse { //ToDo: Remove this endpoint after 2024-06 (replaced by id)
try {
$station = HafasController::getStations(query: $stationName, results: 1)->first();
if ($station === null) {
return $this->sendError("Your query matches no station");
}

$station = HomeController::setHome(user: auth()->user(), station: $station);

return $this->sendResponse(
data: new StationResource($station),
);
} catch (HafasException) {
return $this->sendError("There has been an error with our data provider", 502);
} catch (ModelNotFoundException) {
return $this->sendError("Your query matches no station");
}
}


/**
* @OA\Put(
* path="/trains/station/{name}/home",
* path="/station/{id}/home",
* operationId="setHomeStation",
* tags={"Checkin"},
* summary="Set a station as home station",
* @OA\Parameter(
* name="name",
* name="id",
* in="path",
* description="Name of the station",
* description="Träwelling-ID of the station",
* required=true,
* example="Karlsruhe Hbf",
* example=1234,
* ),
* @OA\Response(
* response=200,
Expand All @@ -444,33 +506,29 @@ public function create(Request $request): JsonResponse {
* @OA\Response(response=400, description="Bad request"),
* @OA\Response(response=401, description="Unauthorized"),
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=502, description="Error with our data provider"),
* security={
* {"passport": {"create-statuses"}}, {"token": {}}
*
* }
* @OA\Response(response=500, description="Unknown error"),
* security={{"passport": {"create-statuses"}}, {"token": {}}}
* )
* @param string $stationName
* @param int $stationId
*
* @return JsonResponse
* @see All slashes (as well as encoded to %2F) in $name need to be replaced, preferrably by a space (%20)
*/
public function setHome(string $stationName): JsonResponse {
public function setHome(int $stationId): JsonResponse {
try {
$station = HafasController::getStations(query: $stationName, results: 1)->first();
if ($station === null) {
return $this->sendError("Your query matches no station");
}
$station = Station::findOrFail($stationId);

$station = HomeController::setHome(user: auth()->user(), station: $station);
auth()->user()?->update([
'home_id' => $station->id
]);

return $this->sendResponse(
data: new StationResource($station),
);
} catch (HafasException) {
return $this->sendError("There has been an error with our data provider", 502);
} catch (ModelNotFoundException) {
return $this->sendError("Your query matches no station");
return $this->sendError('The station could not be found');
} catch (Exception $exception) {
report($exception);
return $this->sendError('Unknown error', 500);
}
}

Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Backend/Transport/HomeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ abstract class HomeController extends Controller
* @param Station $station
*
* @return Station
* @api v1
* @api v1
* @deprecated just use $user->update(...) directly...?
*/
public static function setHome(User $user, Station $station): Station {
$user->update([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
use App\Models\Status;
use App\Models\StatusTag;
use App\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate;

abstract class StatusTagController extends Controller
{
public static function getVisibleTagsForUser(Status $status, User $user = null) {
public static function getVisibleTagsForUser(Status $status, User $user = null): Collection {
return $status->tags->filter(function(StatusTag $tag) use ($user) {
return Gate::forUser($user)->allows('view', $tag);
});
Expand Down
5 changes: 3 additions & 2 deletions app/Http/Controllers/FrontendTransportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public function TrainTrip(Request $request): Renderable|RedirectResponse {
// in long term to support multiple data providers we only support IDs here - no IBNRs.
$startStation = Station::findOrFail($validated['start']);
}

$departure = Carbon::parse($validated['departure']);

$trip = TrainCheckinController::getHafasTrip(
Expand All @@ -137,9 +138,9 @@ public function TrainTrip(Request $request): Renderable|RedirectResponse {

$encounteredStart = false;
$stopovers = $trip->stopovers
->filter(function(Stopover $stopover) use ($departure, $startStation, &$encounteredStart): bool {
->filter(function(Stopover $stopover) use ($startStation, &$encounteredStart): bool {
if (!$encounteredStart) { // this assumes stopovers being ordered correctly
$encounteredStart = $stopover->departure_planned == $departure && $stopover->station->is($startStation);
$encounteredStart = $stopover->station->is($startStation);
return false;
}
return true;
Expand Down
7 changes: 5 additions & 2 deletions app/Http/Controllers/TransportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
use App\Enum\TravelType;
use App\Exceptions\HafasException;
use App\Http\Controllers\Backend\Transport\StationController;
use App\Models\PolyLine;
use App\Models\Checkin;
use App\Models\PolyLine;
use App\Models\Station;
use App\Models\User;
use Carbon\Carbon;
Expand Down Expand Up @@ -49,10 +49,13 @@ public static function getTrainStationAutocomplete(string $query): Collection {
* @param string|int $stationQuery
* @param Carbon|null $when
* @param TravelType|null $travelType
* @param bool $localtime
*
* @return array
* @throws HafasException
* @api v1
* @deprecated use HafasController::getDepartures(...) directly instead (-> less overhead)
*
* @api v1
*/
#[ArrayShape([
'station' => Station::class,
Expand Down
Loading

0 comments on commit bf44ec8

Please sign in to comment.