diff --git a/app/Api/V1/Controllers/BudgetController.php b/app/Api/V1/Controllers/BudgetController.php index 96e0c14892..5b153f5027 100644 --- a/app/Api/V1/Controllers/BudgetController.php +++ b/app/Api/V1/Controllers/BudgetController.php @@ -46,7 +46,7 @@ class BudgetController extends Controller private $repository; /** - * BillController constructor. + * BudgetController constructor. */ public function __construct() { diff --git a/app/Api/V1/Controllers/CategoryController.php b/app/Api/V1/Controllers/CategoryController.php new file mode 100644 index 0000000000..672b044ea0 --- /dev/null +++ b/app/Api/V1/Controllers/CategoryController.php @@ -0,0 +1,176 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Controllers; + +use FireflyIII\Api\V1\Requests\CategoryRequest; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Category; +use FireflyIII\Repositories\Category\CategoryRepositoryInterface; +use FireflyIII\Transformers\CategoryTransformer; +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 CategoryController + */ +class CategoryController extends Controller +{ + /** @var CategoryRepositoryInterface */ + private $repository; + + /** + * CategoryController constructor. + */ + public function __construct() + { + parent::__construct(); + $this->middleware( + function ($request, $next) { + /** @var CategoryRepositoryInterface repository */ + $this->repository = app(CategoryRepositoryInterface::class); + $this->repository->setUser(auth()->user()); + + return $next($request); + } + ); + } + + /** + * Remove the specified resource from storage. + * + * @param Category $category + * + * @return JsonResponse + */ + public function delete(Category $category): JsonResponse + { + $this->repository->destroy($category); + + 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->getCategories(); + $count = $collection->count(); + $categories = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($categories, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.categories.index') . $this->buildParams()); + + // present to user. + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + $resource = new FractalCollection($categories, new CategoryTransformer($this->parameters), 'categories'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + + /** + * @param Request $request + * @param Category $category + * + * @return JsonResponse + */ + public function show(Request $request, Category $category): 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($category, new CategoryTransformer($this->parameters), 'categories'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + /** + * @param CategoryRequest $request + * + * @return JsonResponse + * @throws FireflyException + */ + public function store(CategoryRequest $request): JsonResponse + { + $category = $this->repository->store($request->getAll()); + if (null !== $category) { + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($category, new CategoryTransformer($this->parameters), 'categories'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + throw new FireflyException('Could not store new category.'); // @codeCoverageIgnore + } + + + /** + * @param CategoryRequest $request + * @param Category $category + * + * @return JsonResponse + */ + public function update(CategoryRequest $request, Category $category): JsonResponse + { + $data = $request->getAll(); + $bill = $this->repository->update($category, $data); + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($bill, new CategoryTransformer($this->parameters), 'categories'); + + 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/CategoryRequest.php b/app/Api/V1/Requests/CategoryRequest.php new file mode 100644 index 0000000000..b910674e54 --- /dev/null +++ b/app/Api/V1/Requests/CategoryRequest.php @@ -0,0 +1,75 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Requests; + +use FireflyIII\Models\Category; + +/** + * Class CategoryRequest + */ +class CategoryRequest 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'), + ]; + } + + /** + * @return array + */ + public function rules(): array + { + $rules = [ + 'name' => 'required|between:1,100|uniqueObjectForUser:categories,name', + 'active' => 'required|boolean', + ]; + switch ($this->method()) { + default: + break; + case 'PUT': + case 'PATCH': + /** @var Category $category */ + $category = $this->route()->parameter('category'); + $rules['name'] = sprintf('required|between:1,100|uniqueObjectForUser:categories,name,%d', $category->id); + break; + } + + return $rules; + } +} \ No newline at end of file diff --git a/app/Transformers/CategoryTransformer.php b/app/Transformers/CategoryTransformer.php index 3d7de337c9..421946e6b2 100644 --- a/app/Transformers/CategoryTransformer.php +++ b/app/Transformers/CategoryTransformer.php @@ -48,7 +48,7 @@ class CategoryTransformer extends TransformerAbstract * * @var array */ - protected $defaultIncludes = []; + protected $defaultIncludes = ['user']; /** @var ParameterBag */ protected $parameters; diff --git a/routes/api.php b/routes/api.php index 9ac1b78a0a..d04d0029f2 100644 --- a/routes/api.php +++ b/routes/api.php @@ -44,7 +44,7 @@ Route::group( ); Route::group( - ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'attachments', 'as' => 'api.v1.attachments.'], + ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'attachments', 'as' => 'api.v1.attachments.'], function () { // Attachment API routes: @@ -59,7 +59,8 @@ Route::group( ); Route::group( - ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'available_budgets', 'as' => 'api.v1.available_budgets.'], + ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'available_budgets', + 'as' => 'api.v1.available_budgets.'], function () { // Available Budget API routes: @@ -110,17 +111,31 @@ Route::group( } ); +Route::group( + ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'categories', 'as' => 'api.v1.categories.'], + function () { + + // Category API routes: + Route::get('', ['uses' => 'CategoryController@index', 'as' => 'index']); + Route::post('', ['uses' => 'CategoryController@store', 'as' => 'store']); + Route::get('{category}', ['uses' => 'CategoryController@show', 'as' => 'show']); + Route::put('{category}', ['uses' => 'CategoryController@update', 'as' => 'update']); + Route::delete('{category}', ['uses' => 'CategoryController@delete', 'as' => 'delete']); + } +); + Route::group( - ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'currencies', 'as' => 'api.v1.currencies.'], function () { + ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'currencies', 'as' => 'api.v1.currencies.'], + function () { - // Transaction currency API routes: - Route::get('', ['uses' => 'CurrencyController@index', 'as' => 'index']); - Route::post('', ['uses' => 'CurrencyController@store', 'as' => 'store']); - Route::get('{currency}', ['uses' => 'CurrencyController@show', 'as' => 'show']); - Route::put('{currency}', ['uses' => 'CurrencyController@update', 'as' => 'update']); - Route::delete('{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'delete']); -} + // Transaction currency API routes: + Route::get('', ['uses' => 'CurrencyController@index', 'as' => 'index']); + Route::post('', ['uses' => 'CurrencyController@store', 'as' => 'store']); + Route::get('{currency}', ['uses' => 'CurrencyController@show', 'as' => 'show']); + Route::put('{currency}', ['uses' => 'CurrencyController@update', 'as' => 'update']); + Route::delete('{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'delete']); + } ); Route::group( @@ -137,9 +152,9 @@ Route::group( ); - Route::group( - ['middleware' => ['auth:api', 'bindings', \FireflyIII\Http\Middleware\IsAdmin::class], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'users', 'as' => 'api.v1.users.'], + ['middleware' => ['auth:api', 'bindings', \FireflyIII\Http\Middleware\IsAdmin::class], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'users', + 'as' => 'api.v1.users.'], function () { // Users API routes: