mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-11-23 01:16:46 -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;
|
$bag = new ParameterBag;
|
||||||
$page = (int)request()->get('page');
|
$page = (int)request()->get('page');
|
||||||
if (0 === $page) {
|
|
||||||
|
if ($page < 1) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
}
|
}
|
||||||
|
if ($page > (2^16)) {
|
||||||
|
$page = (2^16);
|
||||||
|
}
|
||||||
$bag->set('page', $page);
|
$bag->set('page', $page);
|
||||||
|
|
||||||
// some date fields:
|
// some date fields:
|
||||||
|
@ -62,7 +62,7 @@ class AboutController extends Controller
|
|||||||
'driver' => $currentDriver,
|
'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');
|
$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');
|
$type = $this->convertString('type');
|
||||||
$rules = [
|
$rules = [
|
||||||
'name' => 'required|min:1|uniqueAccountForUser',
|
'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)],
|
'iban' => ['iban', 'nullable', new UniqueIban(null, $type)],
|
||||||
'bic' => 'bic|nullable',
|
'bic' => 'bic|nullable',
|
||||||
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber(null, $type)],
|
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber(null, $type)],
|
||||||
|
@ -59,7 +59,7 @@ class SumController extends Controller
|
|||||||
$converted = $this->cerSum($result);
|
$converted = $this->cerSum($result);
|
||||||
|
|
||||||
// convert to JSON response:
|
// convert to JSON response:
|
||||||
return response()->json($converted);
|
return response()->api($converted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,6 +73,6 @@ class SumController extends Controller
|
|||||||
$converted = $this->cerSum($result);
|
$converted = $this->cerSum($result);
|
||||||
|
|
||||||
// convert to JSON response:
|
// convert to JSON response:
|
||||||
return response()->json($converted);
|
return response()->api($converted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@ class DateRequest extends FormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'start' => 'required|date',
|
'start' => 'required|date|after:1900-01-01|before:2099-12-31',
|
||||||
'end' => 'required|date|after:start',
|
'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 Illuminate\Validation\ValidationException as LaravelValidationException;
|
||||||
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
|
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
@ -94,8 +96,19 @@ class Handler extends ExceptionHandler
|
|||||||
// somehow Laravel handler does not catch this:
|
// somehow Laravel handler does not catch this:
|
||||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
|
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()) {
|
if ($request->expectsJson()) {
|
||||||
|
$errorCode = 500;
|
||||||
|
$errorCode = $e instanceof MethodNotAllowedHttpException ? 405: $errorCode;
|
||||||
|
|
||||||
$isDebug = config('app.debug', false);
|
$isDebug = config('app.debug', false);
|
||||||
if ($isDebug) {
|
if ($isDebug) {
|
||||||
return response()->json(
|
return response()->json(
|
||||||
@ -106,12 +119,13 @@ class Handler extends ExceptionHandler
|
|||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'trace' => $e->getTrace(),
|
'trace' => $e->getTrace(),
|
||||||
],
|
],
|
||||||
500
|
$errorCode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(
|
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;
|
namespace FireflyIII\Http;
|
||||||
|
|
||||||
|
use FireflyIII\Http\Middleware\AcceptHeaders;
|
||||||
use FireflyIII\Http\Middleware\Authenticate;
|
use FireflyIII\Http\Middleware\Authenticate;
|
||||||
use FireflyIII\Http\Middleware\Binder;
|
use FireflyIII\Http\Middleware\Binder;
|
||||||
use FireflyIII\Http\Middleware\EncryptCookies;
|
use FireflyIII\Http\Middleware\EncryptCookies;
|
||||||
@ -177,6 +178,7 @@ class Kernel extends HttpKernel
|
|||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
|
AcceptHeaders::class,
|
||||||
EnsureFrontendRequestsAreStateful::class,
|
EnsureFrontendRequestsAreStateful::class,
|
||||||
'auth:api,sanctum',
|
'auth:api,sanctum',
|
||||||
'bindings',
|
'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\Passport\Passport;
|
||||||
use Laravel\Sanctum\Sanctum;
|
use Laravel\Sanctum\Sanctum;
|
||||||
use URL;
|
use URL;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
@ -45,6 +46,20 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
if ('heroku' === config('app.env')) {
|
if ('heroku' === config('app.env')) {
|
||||||
URL::forceScheme('https');
|
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"];
|
$secondSearch = $keepNewlines ? ["\r"] : ["\r", "\n", "\t", "\036", "\025"];
|
||||||
$string = str_replace($secondSearch, '', $string);
|
$string = str_replace($secondSearch, '', $string);
|
||||||
|
|
||||||
|
// clear zalgo text (TODO also in API v2)
|
||||||
|
$string = preg_replace('/\pM/u', '', $string);
|
||||||
|
|
||||||
return trim($string);
|
return trim($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +427,7 @@ class FireflyValidator extends Validator
|
|||||||
return $this->validateByAccountTypeString($value, $parameters, $this->data['objectType']);
|
return $this->validateByAccountTypeString($value, $parameters, $this->data['objectType']);
|
||||||
}
|
}
|
||||||
if (array_key_exists('type', $this->data)) {
|
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)) {
|
if (array_key_exists('account_type_id', $this->data)) {
|
||||||
return $this->validateByAccountTypeId($value, $parameters);
|
return $this->validateByAccountTypeId($value, $parameters);
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* V2 API route for TransactionSum API endpoints
|
* V2 API route for TransactionSum API endpoints
|
||||||
|
* TODO what to do with these routes
|
||||||
*/
|
*/
|
||||||
Route::group(
|
Route::group(
|
||||||
['namespace' => 'FireflyIII\Api\V2\Controllers\Transaction\Sum', 'prefix' => 'v2/transaction/sum',
|
['namespace' => 'FireflyIII\Api\V2\Controllers\Transaction\Sum', 'prefix' => 'v2/transaction/sum',
|
||||||
|
Loading…
Reference in New Issue
Block a user