diff --git a/app/Exceptions/TrainCheckinAlreadyExistException.php b/app/Exceptions/TrainCheckinAlreadyExistException.php new file mode 100644 index 000000000..bdda95fa9 --- /dev/null +++ b/app/Exceptions/TrainCheckinAlreadyExistException.php @@ -0,0 +1,10 @@ +sendError('Given stations are not on the trip.', 400); } catch (Throwable $exception) { report($exception); - return $this->sendError('Unknown Error occured', 500); + return $this->sendError('Unknown Error occurred', 500); } } diff --git a/app/Http/Controllers/API/v1/TransportController.php b/app/Http/Controllers/API/v1/TransportController.php index 75b7cd810..f586d431d 100644 --- a/app/Http/Controllers/API/v1/TransportController.php +++ b/app/Http/Controllers/API/v1/TransportController.php @@ -8,6 +8,7 @@ use App\Exceptions\CheckInCollisionException; use App\Exceptions\HafasException; use App\Exceptions\StationNotOnTripException; +use App\Exceptions\TrainCheckinAlreadyExistException; use App\Http\Controllers\API\ResponseController; use App\Http\Controllers\HafasController; use App\Http\Controllers\StatusController as StatusBackend; @@ -179,6 +180,8 @@ public function create(Request $request): JsonResponse { } catch (HafasException $exception) { $status?->delete(); return $this->sendv1Error($exception->getMessage(), 400); + } catch (TrainCheckinAlreadyExistException) { + return $this->sendv1Error('CheckIn already exists', 409); } } diff --git a/app/Http/Controllers/FrontendTransportController.php b/app/Http/Controllers/FrontendTransportController.php index b244f50c5..79ec17842 100644 --- a/app/Http/Controllers/FrontendTransportController.php +++ b/app/Http/Controllers/FrontendTransportController.php @@ -6,6 +6,7 @@ use App\Enum\TravelType; use App\Exceptions\CheckInCollisionException; use App\Exceptions\HafasException; +use App\Exceptions\TrainCheckinAlreadyExistException; use App\Http\Controllers\Backend\EventController as EventBackend; use App\Http\Controllers\TransportController as TransportBackend; use Carbon\Carbon; @@ -177,6 +178,8 @@ public function TrainCheckin(Request $request): RedirectResponse { ] )); + } catch (TrainCheckinAlreadyExistException) { + return redirect()->route('dashboard')->with('error', __('messages.exception.general')); } catch (Throwable $exception) { report($exception); return redirect() diff --git a/app/Http/Controllers/TransportController.php b/app/Http/Controllers/TransportController.php index 69bc8d3dd..a23d92473 100644 --- a/app/Http/Controllers/TransportController.php +++ b/app/Http/Controllers/TransportController.php @@ -6,6 +6,7 @@ use App\Exceptions\CheckInCollisionException; use App\Exceptions\HafasException; use App\Exceptions\StationNotOnTripException; +use App\Exceptions\TrainCheckinAlreadyExistException; use App\Http\Controllers\Backend\GeoController; use App\Http\Controllers\Backend\Social\TwitterController; use App\Http\Controllers\Backend\Transport\PointsCalculationController; @@ -28,6 +29,7 @@ use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\RequestException; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Database\QueryException; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; @@ -251,6 +253,7 @@ public static function getTrainTrip(string $tripId, string $lineName, string $st * @throws CheckInCollisionException * @throws HafasException * @throws StationNotOnTripException + * @throws TrainCheckinAlreadyExistException * @deprecated replaced by createTrainCheckin() */ #[ArrayShape([ @@ -350,18 +353,26 @@ public static function TrainCheckin($tripId, $stopovers[$offset2]['plannedArrival'] ?? $stopovers[$offset2]['plannedDeparture'] ); - $trainCheckin = TrainCheckin::create([ - 'status_id' => $status->id, - 'user_id' => $user->id, - 'trip_id' => $tripId, - 'origin' => $originStation->ibnr, - 'destination' => $destinationStation->ibnr, - 'distance' => $distanceInMeters, - 'points' => $points, - 'departure' => $plannedDeparture, - 'arrival' => $plannedArrival - ]); - + try { + $trainCheckin = TrainCheckin::create([ + 'status_id' => $status->id, + 'user_id' => $user->id, + 'trip_id' => $tripId, + 'origin' => $originStation->ibnr, + 'destination' => $destinationStation->ibnr, + 'distance' => $distanceInMeters, + 'points' => $points, + 'departure' => $plannedDeparture, + 'arrival' => $plannedArrival + ]); + } catch (QueryException $exception) { + $errorCode = $exception->errorInfo[1]; + if ($errorCode == 1062) { + //duplicate entry + $status->delete(); + throw new TrainCheckinAlreadyExistException(); + } + } $user->load(['statuses']); // Let's connect our statuses and the events @@ -513,6 +524,7 @@ public static function postTwitter(Status $status): void { * @throws StationNotOnTripException * @throws CheckInCollisionException * @throws ModelNotFoundException + * @throws TrainCheckinAlreadyExistException * @api v1 */ public static function createTrainCheckin( @@ -561,18 +573,27 @@ public static function createTrainCheckin( departure: $firstStop->departure, arrival: $lastStop->arrival ); + try { + $trainCheckin = TrainCheckin::create([ + 'status_id' => $status->id, + 'user_id' => auth()->user()->id, + 'trip_id' => $trip->trip_id, + 'origin' => $firstStop->trainStation->ibnr, + 'destination' => $lastStop->trainStation->ibnr, + 'distance' => $distance, + 'points' => $points, + 'departure' => $firstStop->departure_planned, + 'arrival' => $lastStop->arrival_planned + ]); + } catch (QueryException $exception) { + $errorCode = $exception->errorInfo[1]; + if ($errorCode == 1062) { + //duplicate entry + $status->delete(); + throw new TrainCheckinAlreadyExistException(); + } + } - $trainCheckin = TrainCheckin::create([ - 'status_id' => $status->id, - 'user_id' => auth()->user()->id, - 'trip_id' => $trip->trip_id, - 'origin' => $firstStop->trainStation->ibnr, - 'destination' => $lastStop->trainStation->ibnr, - 'distance' => $distance, - 'points' => $points, - 'departure' => $firstStop->departure_planned, - 'arrival' => $lastStop->arrival_planned - ]); foreach ($trainCheckin->alsoOnThisConnection as $otherStatus) { if ($otherStatus?->user) { $otherStatus->user->notify(new UserJoinedConnection( diff --git a/database/migrations/2021_11_03_211948_add_unique_key_to_train_checkins.php b/database/migrations/2021_11_03_211948_add_unique_key_to_train_checkins.php new file mode 100644 index 000000000..3ac2ce2f9 --- /dev/null +++ b/database/migrations/2021_11_03_211948_add_unique_key_to_train_checkins.php @@ -0,0 +1,21 @@ +unique(['user_id', 'trip_id', 'origin', 'departure'], 'user_trip_origin_departure'); + }); + } + + public function down(): void { + Schema::table('train_checkins', function(Blueprint $table) { + $table->dropUnique('user_trip_origin_departure'); + }); + } +}