]> BookStack Code Mirror - bookstack/blob - app/Exceptions/Handler.php
38572064343b84eba1923908694ca7f2f8ee1e57
[bookstack] / app / Exceptions / Handler.php
1 <?php
2
3 namespace BookStack\Exceptions;
4
5 use Exception;
6 use Illuminate\Auth\AuthenticationException;
7 use Illuminate\Database\Eloquent\ModelNotFoundException;
8 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
9 use Illuminate\Http\Exceptions\PostTooLargeException;
10 use Illuminate\Http\JsonResponse;
11 use Illuminate\Http\Request;
12 use Illuminate\Validation\ValidationException;
13 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
14 use Throwable;
15
16 class Handler extends ExceptionHandler
17 {
18     /**
19      * A list of the exception types that are not reported.
20      *
21      * @var array<int, class-string<\Throwable>>
22      */
23     protected $dontReport = [
24         NotFoundException::class,
25         StoppedAuthenticationException::class,
26     ];
27
28     /**
29      * A list of the inputs that are never flashed to the session on validation exceptions.
30      *
31      * @var array<int, string>
32      */
33     protected $dontFlash = [
34         'current_password',
35         'password',
36         'password_confirmation',
37     ];
38
39     /**
40      * Report or log an exception.
41      *
42      * @param \Throwable $exception
43      *
44      * @throws \Throwable
45      *
46      * @return void
47      */
48     public function report(Throwable $exception)
49     {
50         parent::report($exception);
51     }
52
53     /**
54      * Render an exception into an HTTP response.
55      *
56      * @param \Illuminate\Http\Request $request
57      * @param Exception                $e
58      *
59      * @return \Illuminate\Http\Response
60      */
61     public function render($request, Throwable $e)
62     {
63         if ($e instanceof PostTooLargeException) {
64             $e = new NotifyException(trans('errors.server_post_limit'), '/', 413);
65         }
66
67         if ($this->isApiRequest($request)) {
68             return $this->renderApiException($e);
69         }
70
71         return parent::render($request, $e);
72     }
73
74     /**
75      * Check if the given request is an API request.
76      */
77     protected function isApiRequest(Request $request): bool
78     {
79         return str_starts_with($request->path(), 'api/');
80     }
81
82     /**
83      * Render an exception when the API is in use.
84      */
85     protected function renderApiException(Throwable $e): JsonResponse
86     {
87         $code = 500;
88         $headers = [];
89
90         if ($e instanceof HttpExceptionInterface) {
91             $code = $e->getStatusCode();
92             $headers = $e->getHeaders();
93         }
94
95         if ($e instanceof ModelNotFoundException) {
96             $code = 404;
97         }
98
99         $responseData = [
100             'error' => [
101                 'message' => $e->getMessage(),
102             ],
103         ];
104
105         if ($e instanceof ValidationException) {
106             $responseData['error']['message'] = 'The given data was invalid.';
107             $responseData['error']['validation'] = $e->errors();
108             $code = $e->status;
109         }
110
111         $responseData['error']['code'] = $code;
112
113         return new JsonResponse($responseData, $code, $headers);
114     }
115
116     /**
117      * Convert an authentication exception into an unauthenticated response.
118      *
119      * @param \Illuminate\Http\Request                 $request
120      * @param \Illuminate\Auth\AuthenticationException $exception
121      *
122      * @return \Illuminate\Http\Response
123      */
124     protected function unauthenticated($request, AuthenticationException $exception)
125     {
126         if ($request->expectsJson()) {
127             return response()->json(['error' => 'Unauthenticated.'], 401);
128         }
129
130         return redirect()->guest('login');
131     }
132
133     /**
134      * Convert a validation exception into a JSON response.
135      *
136      * @param \Illuminate\Http\Request                   $request
137      * @param \Illuminate\Validation\ValidationException $exception
138      *
139      * @return \Illuminate\Http\JsonResponse
140      */
141     protected function invalidJson($request, ValidationException $exception)
142     {
143         return response()->json($exception->errors(), $exception->status);
144     }
145 }