diff --git a/app/Exceptions/AircraftNotAtAirport.php b/app/Exceptions/AircraftNotAtAirport.php index 77086f6b..b5c75a54 100644 --- a/app/Exceptions/AircraftNotAtAirport.php +++ b/app/Exceptions/AircraftNotAtAirport.php @@ -2,11 +2,49 @@ namespace App\Exceptions; +use App\Models\Aircraft; + /** * Class AircraftNotAtAirport */ -class AircraftNotAtAirport extends InternalError +class AircraftNotAtAirport extends HttpException { - public const FIELD = 'aircraft_id'; public const MESSAGE = 'The aircraft is not at the departure airport'; + + private $aircraft; + + public function __construct(Aircraft $aircraft) + { + $this->aircraft = $aircraft; + parent::__construct( + 400, + static::MESSAGE + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'aircraft-not-at-airport'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return [ + 'aircraft_id' => $this->aircraft->id, + ]; + } } diff --git a/app/Exceptions/AircraftPermissionDenied.php b/app/Exceptions/AircraftPermissionDenied.php index b702a3c4..a9efb24a 100644 --- a/app/Exceptions/AircraftPermissionDenied.php +++ b/app/Exceptions/AircraftPermissionDenied.php @@ -2,11 +2,51 @@ namespace App\Exceptions; -/** - * Class AircraftPermissionDenied - */ -class AircraftPermissionDenied extends InternalError +use App\Models\Aircraft; +use App\Models\User; + +class AircraftPermissionDenied extends HttpException { - public const FIELD = 'aircraft_id'; public const MESSAGE = 'User is not allowed to fly this aircraft'; + + private $aircraft; + private $user; + + public function __construct(User $user, Aircraft $aircraft) + { + $this->aircraft = $aircraft; + $this->user = $user; + + parent::__construct( + 400, + static::MESSAGE + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'aircraft-permission-denied'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return [ + 'aircraft_id' => $this->aircraft->id, + 'user_id' => $this->user->id, + ]; + } } diff --git a/app/Exceptions/BidExists.php b/app/Exceptions/BidExists.php deleted file mode 100644 index 02da3675..00000000 --- a/app/Exceptions/BidExists.php +++ /dev/null @@ -1,26 +0,0 @@ -flight = $flight; + parent::__construct( + 409, + 'A bid already exists for this flight' + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'bid-exists'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return [ + 'flight_id' => $this->flight->id, + ]; + } +} diff --git a/app/Exceptions/Converters/GenericException.php b/app/Exceptions/Converters/GenericException.php new file mode 100644 index 00000000..ff8b949f --- /dev/null +++ b/app/Exceptions/Converters/GenericException.php @@ -0,0 +1,51 @@ +exception = $exception; + parent::__construct( + 503, + $exception->getMessage() + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'internal-error'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + // Only add trace if in dev + if (config('app.env') === 'dev') { + return [ + 'trace' => $this->exception->getTrace()[0], + ]; + } + + return []; + } +} diff --git a/app/Exceptions/Converters/NotFound.php b/app/Exceptions/Converters/NotFound.php new file mode 100644 index 00000000..a8839d4f --- /dev/null +++ b/app/Exceptions/Converters/NotFound.php @@ -0,0 +1,44 @@ +exception = $exception; + parent::__construct( + 404, + $exception->getMessage() + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'not-found'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return []; + } +} diff --git a/app/Exceptions/Converters/SymfonyException.php b/app/Exceptions/Converters/SymfonyException.php new file mode 100644 index 00000000..8887d6df --- /dev/null +++ b/app/Exceptions/Converters/SymfonyException.php @@ -0,0 +1,51 @@ +exception = $exception; + parent::__construct( + $exception->getStatusCode(), + $exception->getMessage() + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'internal-error'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + // Only add trace if in dev + if (config('app.env') === 'dev') { + return [ + 'trace' => $this->exception->getTrace()[0], + ]; + } + + return []; + } +} diff --git a/app/Exceptions/Converters/ValidationException.php b/app/Exceptions/Converters/ValidationException.php new file mode 100644 index 00000000..dfecedf9 --- /dev/null +++ b/app/Exceptions/Converters/ValidationException.php @@ -0,0 +1,63 @@ +validationException = $validationException; + $this->processValidationErrors(); + + parent::__construct( + 400, + 'Validation exception' + ); + } + + private function processValidationErrors() + { + $error_messages = []; + $this->errors = $this->validationException->errors(); + foreach ($this->errors as $field => $error) { + $error_messages[] = implode(', ', $error); + } + + $this->errorDetail = implode(', ', $error_messages); + // Log::error('Validation errors', $this->errors); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'validation-exception'; + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorDetails(): string + { + return $this->errorDetail; + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return [ + 'errors' => $this->errors, + ]; + } +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 2fb46324..9466622e 100755 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -2,13 +2,21 @@ namespace App\Exceptions; +use App\Exceptions\Converters\GenericException; +use App\Exceptions\Converters\NotFound; +use App\Exceptions\Converters\SymfonyException; +use App\Exceptions\Converters\ValidationException; use Exception; +use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\AuthenticationException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; -use Illuminate\Validation\ValidationException; -use Log; -use Symfony\Component\HttpKernel\Exception\HttpException; +use Illuminate\Http\Request; +use Illuminate\Session\TokenMismatchException; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException as IlluminateValidationException; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\HttpException as SymfonyHttpException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -21,85 +29,56 @@ class Handler extends ExceptionHandler * A list of the exception types that should not be reported. */ protected $dontReport = [ - \Illuminate\Auth\AuthenticationException::class, - \Illuminate\Auth\Access\AuthorizationException::class, - \Symfony\Component\HttpKernel\Exception\HttpException::class, - \Illuminate\Database\Eloquent\ModelNotFoundException::class, - \Illuminate\Session\TokenMismatchException::class, - \Illuminate\Validation\ValidationException::class, + AuthenticationException::class, + AuthorizationException::class, + HttpException::class, + IlluminateValidationException::class, + ModelNotFoundException::class, + SymfonyHttpException::class, + TokenMismatchException::class, ]; - /** - * Create an error message - * - * @param $status_code - * @param $message - * - * @return array - */ - protected function createError($status_code, $message) - { - return [ - 'error' => [ - 'status' => $status_code, - 'message' => $message, - ], - ]; - } - /** * Render an exception into an HTTP response. * - * @param \Illuminate\Http\Request $request - * @param \Exception $exception + * @param Request $request + * @param Exception $exception * * @return mixed */ public function render($request, Exception $exception) { if ($request->is('api/*')) { - $headers = []; - Log::error('API Error', $exception->getTrace()); + if ($exception instanceof HttpException) { + return $exception->getResponse(); + } + + /* + * Not of the HttpException abstract class. Map these into + */ + if ($exception instanceof ModelNotFoundException || $exception instanceof NotFoundHttpException) { - $error = $this->createError(404, $exception->getMessage()); + $error = new NotFound($exception); + return $error->getResponse(); } // Custom exceptions should be extending HttpException - elseif ($exception instanceof HttpException) { - $error = $this->createError( - $exception->getStatusCode(), - $exception->getMessage() - ); - - $headers = $exception->getHeaders(); + if ($exception instanceof SymfonyHttpException) { + $error = new SymfonyException($exception); + return $error->getResponse(); } // Create the detailed errors from the validation errors - elseif ($exception instanceof ValidationException) { - $error_messages = []; - $errors = $exception->errors(); - foreach ($errors as $field => $error) { - $error_messages[] = implode(', ', $error); - } - - $message = implode(', ', $error_messages); - $error = $this->createError(400, $message); - $error['error']['errors'] = $errors; - - Log::error('Validation errors', $errors); - } else { - $error = $this->createError(400, $exception->getMessage()); + if ($exception instanceof IlluminateValidationException) { + $error = new ValidationException($exception); + return $error->getResponse(); } - // Only add trace if in dev - if (config('app.env') === 'dev') { - $error['error']['trace'] = $exception->getTrace()[0]; - } - - return response()->json($error, $error['error']['status'], $headers); + $error = new GenericException($exception); + return $error->getResponse(); } if ($exception instanceof HttpException @@ -113,16 +92,16 @@ class Handler extends ExceptionHandler /** * Convert an authentication exception into an unauthenticated response. * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Auth\AuthenticationException $exception + * @param Request $request + * @param AuthenticationException $exception * * @return \Illuminate\Http\Response */ protected function unauthenticated($request, AuthenticationException $exception) { if ($request->expectsJson() || $request->is('api/*')) { - $error = $this->createError(401, 'Unauthenticated'); - return response()->json($error, 401); + $error = new Unauthenticated(); + return $error->getResponse(); } return redirect()->guest('login'); @@ -133,7 +112,7 @@ class Handler extends ExceptionHandler * * @param HttpException $e * - * @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response + * @return \Illuminate\Http\Response|Response */ protected function renderHttpException(HttpExceptionInterface $e) { diff --git a/app/Exceptions/HttpException.php b/app/Exceptions/HttpException.php new file mode 100644 index 00000000..16c18544 --- /dev/null +++ b/app/Exceptions/HttpException.php @@ -0,0 +1,60 @@ +getErrorType(); + $response['title'] = $this->getMessage(); + $response['details'] = $this->getErrorDetails(); + + // For backwards compatibility + $response['error'] = [ + 'status' => $this->getStatusCode(), + 'message' => $this->getErrorDetails(), + ]; + + return array_merge($response, $this->getErrorMetadata()); + } + + /** + * Return a response object that can be used by Laravel + * + * @return \Illuminate\Http\JsonResponse + */ + public function getResponse() + { + return response() + ->json( + $this->getJson(), + $this->getStatusCode(), + [ + 'content-type' => 'application/problem+json', + ] + ); + } +} diff --git a/app/Exceptions/InternalError.php b/app/Exceptions/InternalError.php index 4885e0f7..5cf78d99 100644 --- a/app/Exceptions/InternalError.php +++ b/app/Exceptions/InternalError.php @@ -2,9 +2,9 @@ namespace App\Exceptions; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Validator; use Illuminate\Validation\ValidationException; -use Log; -use Validator; /** * Show an internal error, bug piggyback off of the validation diff --git a/app/Exceptions/PirepCancelled.php b/app/Exceptions/PirepCancelled.php index 328c9f72..a904cf5c 100644 --- a/app/Exceptions/PirepCancelled.php +++ b/app/Exceptions/PirepCancelled.php @@ -2,25 +2,38 @@ namespace App\Exceptions; -use Symfony\Component\HttpKernel\Exception\HttpException; +use App\Models\Pirep; -/** - * Class PirepCancelled - */ class PirepCancelled extends HttpException { - public function __construct( - string $message = null, - \Exception $previous = null, - int $code = 0, - array $headers = [] - ) { + private $pirep; + + public function __construct(Pirep $pirep) + { + $this->pirep = $pirep; parent::__construct( 400, - 'PIREP has been cancelled, updates are not allowed', - $previous, - $headers, - $code + 'PIREP has been cancelled, updates are not allowed' ); } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'pirep-cancelled'; + } + + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + public function getErrorMetadata(): array + { + return [ + 'pirep_id' => $this->pirep->id, + ]; + } } diff --git a/app/Exceptions/Unauthenticated.php b/app/Exceptions/Unauthenticated.php new file mode 100644 index 00000000..21e30ffe --- /dev/null +++ b/app/Exceptions/Unauthenticated.php @@ -0,0 +1,38 @@ +getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return []; + } +} diff --git a/app/Exceptions/UserNotAtAirport.php b/app/Exceptions/UserNotAtAirport.php index ef65c3ea..8165400b 100644 --- a/app/Exceptions/UserNotAtAirport.php +++ b/app/Exceptions/UserNotAtAirport.php @@ -2,11 +2,51 @@ namespace App\Exceptions; -/** - * Class UserNotAtAirport - */ -class UserNotAtAirport extends InternalError +use App\Models\Airport; +use App\Models\User; + +class UserNotAtAirport extends HttpException { - public const FIELD = 'dpt_airport_id'; public const MESSAGE = 'Pilot is not at the departure airport'; + + private $airport; + private $user; + + public function __construct(User $user, Airport $airport) + { + $this->airport = $airport; + $this->user = $user; + + parent::__construct( + 400, + static::MESSAGE + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'user-not-at-airport'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return [ + 'airport_id' => $this->airport->id, + 'user_id' => $this->user->id, + ]; + } } diff --git a/app/Exceptions/UserPilotIdExists.php b/app/Exceptions/UserPilotIdExists.php index 3fd62082..9851d03a 100644 --- a/app/Exceptions/UserPilotIdExists.php +++ b/app/Exceptions/UserPilotIdExists.php @@ -2,8 +2,47 @@ namespace App\Exceptions; -class UserPilotIdExists extends InternalError +use App\Models\User; + +class UserPilotIdExists extends HttpException { - public const FIELD = 'pilot_id'; public const MESSAGE = 'A user with this pilot ID already exists'; + + private $user; + + public function __construct(User $user) + { + $this->user = $user; + + parent::__construct( + 400, + static::MESSAGE + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'pilot-id-already-exists'; + } + + /** + * Get the detailed error string + */ + public function getErrorDetails(): string + { + return $this->getMessage(); + } + + /** + * Return an array with the error details, merged with the RFC7807 response + */ + public function getErrorMetadata(): array + { + return [ + 'user_id' => $this->user->id, + ]; + } } diff --git a/app/Http/Controllers/Api/AcarsController.php b/app/Http/Controllers/Api/AcarsController.php index 3d081bdc..9ff26e0b 100644 --- a/app/Http/Controllers/Api/AcarsController.php +++ b/app/Http/Controllers/Api/AcarsController.php @@ -57,7 +57,7 @@ class AcarsController extends Controller protected function checkCancelled(Pirep $pirep) { if ($pirep->cancelled) { - throw new PirepCancelled(); + throw new PirepCancelled($pirep); } } diff --git a/app/Http/Controllers/Api/PirepController.php b/app/Http/Controllers/Api/PirepController.php index 9a655b80..2cd6205b 100644 --- a/app/Http/Controllers/Api/PirepController.php +++ b/app/Http/Controllers/Api/PirepController.php @@ -221,20 +221,20 @@ class PirepController extends Controller /* @noinspection NotOptimalIfConditionsInspection */ if (setting('pilots.only_flights_from_current') && $user->curr_airport_id !== $pirep->dpt_airport_id) { - throw new UserNotAtAirport(); + throw new UserNotAtAirport($user, $pirep->dpt_airport); } // See if this user is allowed to fly this aircraft if (setting('pireps.restrict_aircraft_to_rank', false) && !$this->userSvc->aircraftAllowed($user, $pirep->aircraft_id)) { - throw new AircraftPermissionDenied(); + throw new AircraftPermissionDenied($user, $pirep->aircraft); } // See if this aircraft is at the departure airport /* @noinspection NotOptimalIfConditionsInspection */ if (setting('pireps.only_aircraft_at_dpt_airport') && $pirep->aircraft_id !== $pirep->dpt_airport_id) { - throw new AircraftNotAtAirport(); + throw new AircraftNotAtAirport($pirep->aircraft); } // Find if there's a duplicate, if so, let's work on that @@ -293,7 +293,7 @@ class PirepController extends Controller ) { $can_use_ac = $this->userSvc->aircraftAllowed($user, $pirep->aircraft_id); if (!$can_use_ac) { - throw new AircraftPermissionDenied(); + throw new AircraftPermissionDenied($user, $pirep->aircraft); } } @@ -335,7 +335,7 @@ class PirepController extends Controller ) { $can_use_ac = $this->userSvc->aircraftAllowed($user, $pirep->aircraft_id); if (!$can_use_ac) { - throw new AircraftPermissionDenied(); + throw new AircraftPermissionDenied($user, $pirep->aircraft); } } diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php index 03d6d0e7..491e7d37 100644 --- a/app/Http/Controllers/Api/UserController.php +++ b/app/Http/Controllers/Api/UserController.php @@ -98,7 +98,7 @@ class UserController extends Controller * @param Request $request * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - * @throws \App\Exceptions\BidExists + * @throws \App\Exceptions\BidExistsForFlight * * @return mixed */ diff --git a/app/Services/FlightService.php b/app/Services/FlightService.php index 66ff2d20..2352fdae 100644 --- a/app/Services/FlightService.php +++ b/app/Services/FlightService.php @@ -3,7 +3,7 @@ namespace App\Services; use App\Contracts\Service; -use App\Exceptions\BidExists; +use App\Exceptions\BidExistsForFlight; use App\Models\Bid; use App\Models\Flight; use App\Models\FlightFieldValue; @@ -198,7 +198,7 @@ class FlightService extends Service * @param Flight $flight * @param User $user * - * @throws \App\Exceptions\BidExists + *@throws \App\Exceptions\BidExistsForFlight * * @return mixed */ @@ -208,7 +208,7 @@ class FlightService extends Service // bids $bids = Bid::where('user_id', $user->id)->get(); if ($bids->count() > 0 && setting('bids.allow_multiple_bids') === false) { - throw new BidExists('User "'.$user->ident.'" already has bids, skipping'); + throw new BidExistsForFlight('User "'.$user->ident.'" already has bids, skipping'); } // Get all of the bids for this flight @@ -230,11 +230,11 @@ class FlightService extends Service // Check if the flight should be blocked off if (setting('bids.disable_flight_on_bid') === true) { - throw new BidExists('Flight "'.$flight->ident.'" already has a bid, skipping'); + throw new BidExistsForFlight($flight); } if (setting('bids.allow_multiple_bids') === false) { - throw new BidExists('A bid already exists for this flight'); + throw new BidExistsForFlight($flight); } } else { /* @noinspection NestedPositiveIfStatementsInspection */ diff --git a/app/Services/UserService.php b/app/Services/UserService.php index 79a82049..1e2dcc53 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -137,7 +137,7 @@ class UserService extends Service if ($this->isPilotIdAlreadyUsed($pilot_id)) { Log::error('User with id '.$pilot_id.' already exists'); - throw new UserPilotIdExists(); + throw new UserPilotIdExists($user); } $old_id = $user->pilot_id; diff --git a/composer.lock b/composer.lock index 065ff490..ce681afc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "da494f087ae565d209fc971170f5a259", + "content-hash": "4ff465ff2b45de41c61ce5a6f55db121", "packages": [ { "name": "akaunting/money", @@ -857,6 +857,66 @@ ], "time": "2019-05-27T17:52:04+00:00" }, + { + "name": "crell/api-problem", + "version": "3.2", + "source": { + "type": "git", + "url": "https://github.com/Crell/ApiProblem.git", + "reference": "de9ab4d17f80b19af772f9906061863b296ab427" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Crell/ApiProblem/zipball/de9ab4d17f80b19af772f9906061863b296ab427", + "reference": "de9ab4d17f80b19af772f9906061863b296ab427", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "7.*", + "psr/http-factory": "^1.0", + "psr/http-message": "1.*", + "zendframework/zend-diactoros": "~1.0" + }, + "suggest": { + "psr/http-factory": "Common interfaces for PSR-7 HTTP message factories", + "psr/http-message": "Common interface for HTTP messages" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Crell\\ApiProblem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Larry Garfield", + "email": "larry@garfieldtech.com", + "homepage": "http://www.garfieldtech.com/" + } + ], + "description": "PHP wrapper for the api-problem IETF specification", + "homepage": "https://github.com/Crell/ApiProblem", + "keywords": [ + "api-problem", + "http", + "json", + "rest", + "xml" + ], + "time": "2019-08-18T10:47:17+00:00" + }, { "name": "doctrine/cache", "version": "v1.8.0", @@ -9305,9 +9365,9 @@ "prefer-lowest": false, "platform": { "php": ">=7.2", - "ext-calendar": "*", "ext-json": "*", "ext-mbstring": "*", + "ext-simplexml": "*", "ext-pdo": "*" }, "platform-dev": [] diff --git a/config/phpvms.php b/config/phpvms.php index 3908e27e..61b66a3c 100644 --- a/config/phpvms.php +++ b/config/phpvms.php @@ -15,6 +15,16 @@ return [ */ 'installed' => env('PHPVMS_INSTALLED', false), + /* + * Avatar resize settings + * feel free to edit the following lines. + * Both parameters are in px. + */ + 'avatar' => [ + 'width' => '200', + 'height' => '200', + ], + /* * Where to redirect after logging in */ @@ -79,12 +89,8 @@ return [ ], /* - * Avatar resize settings - * feel free to edit the following lines. - * Both parameters are in px. + * DO NOT CHANGE THIS. This is used to map error codes to the approriate + * RFC 7807 type, which can be used as a machine-readable error code/map */ - 'avatar' => [ - 'width' => '200', - 'height' => '200', - ], + 'error_root' => 'https://phpvms.net/errors', ]; diff --git a/phpunit.xml b/phpunit.xml index 7e1c06c0..09c8eced 100755 --- a/phpunit.xml +++ b/phpunit.xml @@ -26,7 +26,7 @@ - + diff --git a/tests/FlightTest.php b/tests/FlightTest.php index b6f125f8..2df5294b 100644 --- a/tests/FlightTest.php +++ b/tests/FlightTest.php @@ -500,7 +500,7 @@ class FlightTest extends TestCase $this->flightSvc->addBid($flight, $user1); // Try adding again, should throw an exception - $this->expectException(\App\Exceptions\BidExists::class); + $this->expectException(\App\Exceptions\BidExistsForFlight::class); $this->flightSvc->addBid($flight, $user2); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 81efbff6..b23e6605 100755 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,6 +6,7 @@ use GuzzleHttp\Client; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; use GuzzleHttp\Psr7\Response; +use Illuminate\Routing\Middleware\ThrottleRequests; use Tests\TestData; /** @@ -38,6 +39,12 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase public function setUp() : void { parent::setUp(); + + // Don't throttle requests when running the tests + $this->withoutMiddleware( + ThrottleRequests::class + ); + Artisan::call('database:create', ['--reset' => true]); Artisan::call('migrate:refresh', ['--env' => 'unittest']); }