From dca2dc4600cf798fd7ed07042b2e71a80343364a Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 24 Jun 2018 14:54:06 +0200 Subject: [PATCH] Add budgets to API. --- app/Api/V1/Controllers/BudgetController.php | 176 ++++++++++++++++++++ app/Api/V1/Requests/BudgetRequest.php | 76 +++++++++ app/Transformers/BudgetTransformer.php | 2 +- routes/api.php | 15 ++ 4 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 app/Api/V1/Controllers/BudgetController.php create mode 100644 app/Api/V1/Requests/BudgetRequest.php diff --git a/app/Api/V1/Controllers/BudgetController.php b/app/Api/V1/Controllers/BudgetController.php new file mode 100644 index 0000000000..96e0c14892 --- /dev/null +++ b/app/Api/V1/Controllers/BudgetController.php @@ -0,0 +1,176 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Controllers; + +use FireflyIII\Api\V1\Requests\BudgetRequest; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Budget; +use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; +use FireflyIII\Transformers\BudgetTransformer; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Pagination\LengthAwarePaginator; +use League\Fractal\Manager; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; +use League\Fractal\Resource\Collection as FractalCollection; +use League\Fractal\Resource\Item; +use League\Fractal\Serializer\JsonApiSerializer; + +/** + * Class BudgetController + */ +class BudgetController extends Controller +{ + /** @var BudgetRepositoryInterface */ + private $repository; + + /** + * BillController constructor. + */ + public function __construct() + { + parent::__construct(); + $this->middleware( + function ($request, $next) { + /** @var BudgetRepositoryInterface repository */ + $this->repository = app(BudgetRepositoryInterface::class); + $this->repository->setUser(auth()->user()); + + return $next($request); + } + ); + } + + /** + * Remove the specified resource from storage. + * + * @param Budget $budget + * + * @return JsonResponse + */ + public function delete(Budget $budget): JsonResponse + { + $this->repository->destroy($budget); + + return response()->json([], 204); + } + + /** + * Display a listing of the resource. + * + * @param Request $request + * + * @return JsonResponse + */ + public function index(Request $request): JsonResponse + { + // create some objects: + $manager = new Manager; + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + + // types to get, page size: + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + + // get list of budgets. Count it and split it. + $collection = $this->repository->getBudgets(); + $count = $collection->count(); + $budgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($budgets, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.budgets.index') . $this->buildParams()); + + // present to user. + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + $resource = new FractalCollection($budgets, new BudgetTransformer($this->parameters), 'budgets'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + + /** + * @param Request $request + * @param Budget $budget + * + * @return JsonResponse + */ + public function show(Request $request, Budget $budget): JsonResponse + { + $manager = new Manager(); + // add include parameter: + $include = $request->get('include') ?? ''; + $manager->parseIncludes($include); + + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + /** + * @param BudgetRequest $request + * + * @return JsonResponse + * @throws FireflyException + */ + public function store(BudgetRequest $request): JsonResponse + { + $budget = $this->repository->store($request->getAll()); + if (null !== $budget) { + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + throw new FireflyException('Could not store new budget.'); // @codeCoverageIgnore + } + + + /** + * @param BudgetRequest $request + * @param Budget $budget + * + * @return JsonResponse + */ + public function update(BudgetRequest $request, Budget $budget): JsonResponse + { + $data = $request->getAll(); + $bill = $this->repository->update($budget, $data); + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($bill, new BudgetTransformer($this->parameters), 'budgets'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + + } + +} \ No newline at end of file diff --git a/app/Api/V1/Requests/BudgetRequest.php b/app/Api/V1/Requests/BudgetRequest.php new file mode 100644 index 0000000000..e90866d505 --- /dev/null +++ b/app/Api/V1/Requests/BudgetRequest.php @@ -0,0 +1,76 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Requests; + +use FireflyIII\Models\Budget; + +/** + * Class BudgetRequest + */ +class BudgetRequest extends Request +{ + /** + * @return bool + */ + public function authorize(): bool + { + // Only allow authenticated users + return auth()->check(); + } + + /** + * @return array + */ + public function getAll(): array + { + return [ + 'name' => $this->string('name'), + 'active' => $this->boolean('active'), + 'order' => 0, + ]; + } + + /** + * @return array + */ + public function rules(): array + { + $rules = [ + 'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name', + 'active' => 'required|boolean', + ]; + switch ($this->method()) { + default: + break; + case 'PUT': + case 'PATCH': + /** @var Budget $budget */ + $budget = $this->route()->parameter('budget'); + $rules['name'] = sprintf('required|between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id); + break; + } + + return $rules; + } +} \ No newline at end of file diff --git a/app/Transformers/BudgetTransformer.php b/app/Transformers/BudgetTransformer.php index 698c3009b8..4b9562292a 100644 --- a/app/Transformers/BudgetTransformer.php +++ b/app/Transformers/BudgetTransformer.php @@ -48,7 +48,7 @@ class BudgetTransformer extends TransformerAbstract * * @var array */ - protected $defaultIncludes = []; + protected $defaultIncludes = ['user']; /** @var ParameterBag */ protected $parameters; diff --git a/routes/api.php b/routes/api.php index ae67e1232d..9ac1b78a0a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -97,6 +97,19 @@ Route::group( } ); +Route::group( + ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'budgets', 'as' => 'api.v1.budgets.'], + function () { + + // Budget API routes: + Route::get('', ['uses' => 'BudgetController@index', 'as' => 'index']); + Route::post('', ['uses' => 'BudgetController@store', 'as' => 'store']); + Route::get('{budget}', ['uses' => 'BudgetController@show', 'as' => 'show']); + Route::put('{budget}', ['uses' => 'BudgetController@update', 'as' => 'update']); + Route::delete('{budget}', ['uses' => 'BudgetController@delete', 'as' => 'delete']); + } +); + Route::group( ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'currencies', 'as' => 'api.v1.currencies.'], function () { @@ -123,6 +136,8 @@ Route::group( } ); + + Route::group( ['middleware' => ['auth:api', 'bindings', \FireflyIII\Http\Middleware\IsAdmin::class], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'users', 'as' => 'api.v1.users.'], function () {