mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-11-22 17:06:39 -06:00
New code for API 2
This commit is contained in:
parent
e0c9d3627e
commit
b12d72bef6
@ -83,9 +83,13 @@ abstract class Controller extends BaseController
|
||||
{
|
||||
$bag = new ParameterBag;
|
||||
$page = (int)request()->get('page');
|
||||
if (0 === $page) {
|
||||
|
||||
if ($page < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
if ($page > (2^16)) {
|
||||
$page = (2^16);
|
||||
}
|
||||
$bag->set('page', $page);
|
||||
|
||||
// some date fields:
|
||||
|
@ -62,7 +62,7 @@ class AboutController extends Controller
|
||||
'driver' => $currentDriver,
|
||||
];
|
||||
|
||||
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
|
||||
return response()->api(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,6 +83,6 @@ class AboutController extends Controller
|
||||
|
||||
$resource = new Item(auth()->user(), $transformer, 'users');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
return response()->api($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ class StoreRequest extends FormRequest
|
||||
$type = $this->convertString('type');
|
||||
$rules = [
|
||||
'name' => 'required|min:1|uniqueAccountForUser',
|
||||
'type' => 'required|' . sprintf('in:%s', $types),
|
||||
'type' => 'required|min:1|' . sprintf('in:%s', $types),
|
||||
'iban' => ['iban', 'nullable', new UniqueIban(null, $type)],
|
||||
'bic' => 'bic|nullable',
|
||||
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber(null, $type)],
|
||||
|
@ -59,7 +59,7 @@ class SumController extends Controller
|
||||
$converted = $this->cerSum($result);
|
||||
|
||||
// convert to JSON response:
|
||||
return response()->json($converted);
|
||||
return response()->api($converted);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,6 +73,6 @@ class SumController extends Controller
|
||||
$converted = $this->cerSum($result);
|
||||
|
||||
// convert to JSON response:
|
||||
return response()->json($converted);
|
||||
return response()->api($converted);
|
||||
}
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ class DateRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'required|date',
|
||||
'end' => 'required|date|after:start',
|
||||
'start' => 'required|date|after:1900-01-01|before:2099-12-31',
|
||||
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
13
app/Exceptions/BadHttpHeaderException.php
Normal file
13
app/Exceptions/BadHttpHeaderException.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class BadHttpHeaderException extends Exception
|
||||
{
|
||||
public int $statusCode = 406;
|
||||
}
|
@ -40,7 +40,9 @@ use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\ValidationException as LaravelValidationException;
|
||||
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Throwable;
|
||||
|
||||
@ -94,8 +96,19 @@ class Handler extends ExceptionHandler
|
||||
// somehow Laravel handler does not catch this:
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
|
||||
}
|
||||
if($e instanceof BadRequestHttpException) {
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadRequestHttpException'], 400);
|
||||
}
|
||||
|
||||
if ($e instanceof BadHttpHeaderException) {
|
||||
// is always API exception.
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadHttpHeaderException'], $e->statusCode);
|
||||
}
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
$errorCode = 500;
|
||||
$errorCode = $e instanceof MethodNotAllowedHttpException ? 405: $errorCode;
|
||||
|
||||
$isDebug = config('app.debug', false);
|
||||
if ($isDebug) {
|
||||
return response()->json(
|
||||
@ -106,12 +119,13 @@ class Handler extends ExceptionHandler
|
||||
'file' => $e->getFile(),
|
||||
'trace' => $e->getTrace(),
|
||||
],
|
||||
500
|
||||
$errorCode
|
||||
);
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
['message' => sprintf('Internal Firefly III Exception: %s', $e->getMessage()), 'exception' => get_class($e)], 500
|
||||
['message' => sprintf('Internal Firefly III Exception: %s', $e->getMessage()), 'exception' => get_class($e)],
|
||||
$errorCode
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http;
|
||||
|
||||
use FireflyIII\Http\Middleware\AcceptHeaders;
|
||||
use FireflyIII\Http\Middleware\Authenticate;
|
||||
use FireflyIII\Http\Middleware\Binder;
|
||||
use FireflyIII\Http\Middleware\EncryptCookies;
|
||||
@ -177,6 +178,7 @@ class Kernel extends HttpKernel
|
||||
],
|
||||
|
||||
'api' => [
|
||||
AcceptHeaders::class,
|
||||
EnsureFrontendRequestsAreStateful::class,
|
||||
'auth:api,sanctum',
|
||||
'bindings',
|
||||
|
45
app/Http/Middleware/AcceptHeaders.php
Normal file
45
app/Http/Middleware/AcceptHeaders.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use FireflyIII\Exceptions\BadHttpHeaderException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Log;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class AcceptHeaders
|
||||
{
|
||||
/**
|
||||
* Handle the incoming requests.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param callable $next
|
||||
* @return Response
|
||||
* @throws BadHttpHeaderException
|
||||
*/
|
||||
public function handle($request, $next): mixed
|
||||
{
|
||||
$method = $request->getMethod();
|
||||
|
||||
if ('GET' === $method && !$request->accepts(['application/json', 'application/vdn.api+json'])) {
|
||||
throw new BadHttpHeaderException('Your request must accept either application/json or application/vdn.api+json.');
|
||||
}
|
||||
if (('POST' === $method || 'PUT' === $method) && 'application/json' !== (string)$request->header('Content-Type')) {
|
||||
$error = new BadHttpHeaderException('B');
|
||||
$error->statusCode = 415;
|
||||
throw $error;
|
||||
}
|
||||
|
||||
// throw bad request if trace id is not a UUID
|
||||
$uuid = $request->header('X-Trace-Id', null);
|
||||
if (is_string($uuid) && '' !== trim($uuid) && (preg_match('/^[a-f\d]{8}(-[a-f\d]{4}){4}[a-f\d]{8}$/i', trim($uuid)) !== 1)) {
|
||||
throw new BadRequestHttpException('Bad X-Trace-Id header.');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Passport\Passport;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use URL;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
@ -45,6 +46,20 @@ class AppServiceProvider extends ServiceProvider
|
||||
if ('heroku' === config('app.env')) {
|
||||
URL::forceScheme('https');
|
||||
}
|
||||
|
||||
Response::macro('api', function ($value) {
|
||||
$headers = [
|
||||
'Cache-Control' => 'no-store'
|
||||
];
|
||||
$uuid = (string) request()->header('X-Trace-Id');
|
||||
if ('' !== trim($uuid) && (preg_match('/^[a-f\d]{8}(-[a-f\d]{4}){4}[a-f\d]{8}$/i', trim($uuid)) === 1)) {
|
||||
$headers['X-Trace-Id'] = $uuid;
|
||||
}
|
||||
return response()
|
||||
->json($value)
|
||||
->withHeaders($headers);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,6 +119,9 @@ trait ConvertsDataTypes
|
||||
$secondSearch = $keepNewlines ? ["\r"] : ["\r", "\n", "\t", "\036", "\025"];
|
||||
$string = str_replace($secondSearch, '', $string);
|
||||
|
||||
// clear zalgo text (TODO also in API v2)
|
||||
$string = preg_replace('/\pM/u', '', $string);
|
||||
|
||||
return trim($string);
|
||||
}
|
||||
|
||||
|
@ -427,7 +427,7 @@ class FireflyValidator extends Validator
|
||||
return $this->validateByAccountTypeString($value, $parameters, $this->data['objectType']);
|
||||
}
|
||||
if (array_key_exists('type', $this->data)) {
|
||||
return $this->validateByAccountTypeString($value, $parameters, $this->data['type']);
|
||||
return $this->validateByAccountTypeString($value, $parameters, (string) $this->data['type']);
|
||||
}
|
||||
if (array_key_exists('account_type_id', $this->data)) {
|
||||
return $this->validateByAccountTypeId($value, $parameters);
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* V2 API route for TransactionSum API endpoints
|
||||
* TODO what to do with these routes
|
||||
*/
|
||||
Route::group(
|
||||
['namespace' => 'FireflyIII\Api\V2\Controllers\Transaction\Sum', 'prefix' => 'v2/transaction/sum',
|
||||
|
Loading…
Reference in New Issue
Block a user