diff --git a/app/Api/V1/Controllers/ObjectGroupController.php b/app/Api/V1/Controllers/ObjectGroupController.php new file mode 100644 index 0000000000..a078c61e93 --- /dev/null +++ b/app/Api/V1/Controllers/ObjectGroupController.php @@ -0,0 +1,196 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Controllers; + +use FireflyIII\Api\V1\Requests\ObjectGroupUpdateRequest; +use FireflyIII\Models\Account; +use FireflyIII\Models\ObjectGroup; +use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface; +use FireflyIII\Transformers\ObjectGroupTransformer; +use FireflyIII\Transformers\PiggyBankTransformer; +use FireflyIII\User; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Pagination\LengthAwarePaginator; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; +use League\Fractal\Resource\Collection as FractalCollection; +use League\Fractal\Resource\Item; + +/** + * Class GroupController. + * + */ +class ObjectGroupController extends Controller +{ + private ObjectGroupRepositoryInterface $repository; + + /** + * ObjectGroupController constructor. + * + * @codeCoverageIgnore + */ + public function __construct() + { + parent::__construct(); + $this->middleware( + function ($request, $next) { + /** @var User $user */ + $user = auth()->user(); + $this->repository = app(ObjectGroupRepositoryInterface::class); + $this->repository->setUser($user); + + return $next($request); + } + ); + } + + /** + * Remove the specified resource from storage. + * + * @param ObjectGroup $objectGroup + * + * @codeCoverageIgnore + * @return JsonResponse + */ + public function delete(ObjectGroup $objectGroup): JsonResponse + { + $this->repository->destroy($objectGroup); + + return response()->json([], 204); + } + + /** + * Display a listing of the resource. + * + * @param Request $request + * + * @codeCoverageIgnore + * @return JsonResponse + */ + public function index(Request $request): JsonResponse + { + $manager = $this->getManager(); + + // types to get, page size: + $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + + // get list of accounts. Count it and split it. + $collection = $this->repository->get(); + $count = $collection->count(); + $objectGroups = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($objectGroups, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.object-groups.index') . $this->buildParams()); + + /** @var ObjectGroupTransformer $transformer */ + $transformer = app(ObjectGroupTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new FractalCollection($objectGroups, $transformer, 'object_groups'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + + /** + * List all piggies under the object group. + * + * @param ObjectGroup $objectGroup + * + * @return JsonResponse + * @codeCoverageIgnore + * + */ + public function piggyBanks(ObjectGroup $objectGroup): JsonResponse + { + // create some objects: + $manager = $this->getManager(); + + // types to get, page size: + $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + + // get list of piggy banks. Count it and split it. + $collection = $this->repository->getPiggyBanks($objectGroup); + $count = $collection->count(); + $piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.object-groups.piggy_banks', [$objectGroup->id]) . $this->buildParams()); + + /** @var PiggyBankTransformer $transformer */ + $transformer = app(PiggyBankTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + + } + + /** + * Show single instance. + * + * @param ObjectGroup $objectGroup + * + * @return JsonResponse + */ + public function show(ObjectGroup $objectGroup): JsonResponse + { + $manager = $this->getManager(); + + /** @var ObjectGroupTransformer $transformer */ + $transformer = app(ObjectGroupTransformer::class); + $transformer->setParameters($this->parameters); + $resource = new Item($objectGroup, $transformer, 'object_groups'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + /** + * Update object. + * + * @param ObjectGroupUpdateRequest $request + * @param Account $account + * + * @return JsonResponse + */ + public function update(ObjectGroupUpdateRequest $request, ObjectGroup $objectGroup): JsonResponse + { + $data = $request->getUpdateData(); + $this->repository->update($objectGroup, $data); + $this->repository->sort(); + $manager = $this->getManager(); + + /** @var ObjectGroupTransformer $transformer */ + $transformer = app(ObjectGroupTransformer::class); + $transformer->setParameters($this->parameters); + $resource = new Item($objectGroup, $transformer, 'object_groups'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } +} diff --git a/app/Api/V1/Requests/ObjectGroupUpdateRequest.php b/app/Api/V1/Requests/ObjectGroupUpdateRequest.php new file mode 100644 index 0000000000..57cabc7fe8 --- /dev/null +++ b/app/Api/V1/Requests/ObjectGroupUpdateRequest.php @@ -0,0 +1,71 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Requests; + +/** + * Class AccountObjectGroupUpdateRequestUpdateRequest + * + * @codeCoverageIgnore + */ +class ObjectGroupUpdateRequest extends Request +{ + + /** + * Authorize logged in users. + * + * @return bool + */ + public function authorize(): bool + { + // Only allow authenticated users + return auth()->check(); + } + + /** + * @return array + */ + public function getUpdateData(): array + { + return [ + 'title' => $this->string('title'), + 'order' => $this->integer('order'), + ]; + } + + /** + * The rules that the incoming request must be matched against. + * + * @return array + */ + public function rules(): array + { + $objectGroup = $this->route()->parameter('objectGroup'); + + return [ + 'title' => sprintf('min:1|uniqueObjectGroup:%d', $objectGroup->id), + 'order' => 'numeric', + ]; + } +} diff --git a/app/Models/ObjectGroup.php b/app/Models/ObjectGroup.php index a00f35d020..953fafde0e 100644 --- a/app/Models/ObjectGroup.php +++ b/app/Models/ObjectGroup.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace FireflyIII\Models; +use FireflyIII\User; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -33,6 +35,19 @@ class ObjectGroup extends Model { protected $fillable = ['title', 'order', 'user_id']; + /** + * The attributes that should be casted to native types. + * + * @var array + */ + protected $casts + = [ + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + 'user_id' => 'integer', + 'deleted_at' => 'datetime', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ @@ -61,4 +76,13 @@ class ObjectGroup extends Model } throw new NotFoundHttpException; } + + /** + * @return BelongsTo + * @codeCoverageIgnore + */ + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } } diff --git a/app/Repositories/ObjectGroup/ObjectGroupRepository.php b/app/Repositories/ObjectGroup/ObjectGroupRepository.php index be1eba5db9..b1beb1d4f8 100644 --- a/app/Repositories/ObjectGroup/ObjectGroupRepository.php +++ b/app/Repositories/ObjectGroup/ObjectGroupRepository.php @@ -107,6 +107,12 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface public function update(ObjectGroup $objectGroup, array $data): ObjectGroup { $objectGroup->title = $data['title']; + + if (isset($data['order'])) { + $order = 0 === $data['order'] ? 1 : $data['order']; + $objectGroup->order = $order; + } + $objectGroup->save(); return $objectGroup; @@ -128,4 +134,11 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface $this->user = $user; } + /** + * @inheritDoc + */ + public function getPiggyBanks(ObjectGroup $objectGroup): Collection + { + return $objectGroup->piggyBanks; + } } diff --git a/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php b/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php index b8f42b842b..4d190c007b 100644 --- a/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php +++ b/app/Repositories/ObjectGroup/ObjectGroupRepositoryInterface.php @@ -28,6 +28,13 @@ interface ObjectGroupRepositoryInterface */ public function deleteEmpty(): void; + /** + * @param ObjectGroup $objectGroup + * + * @return Collection + */ + public function getPiggyBanks(ObjectGroup $objectGroup): Collection; + /** * Sort */ diff --git a/app/Transformers/ObjectGroupTransformer.php b/app/Transformers/ObjectGroupTransformer.php new file mode 100644 index 0000000000..c2f50a4216 --- /dev/null +++ b/app/Transformers/ObjectGroupTransformer.php @@ -0,0 +1,81 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Transformers; + + +use Carbon\Carbon; +use FireflyIII\Models\Account; +use FireflyIII\Models\ObjectGroup; +use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface; +use Log; + +/** + * Class AccountTransformer + */ +class ObjectGroupTransformer extends AbstractTransformer +{ + protected ObjectGroupRepositoryInterface $repository; + + /** + * + * AccountTransformer constructor. + * + * @codeCoverageIgnore + */ + public function __construct() + { + if ('testing' === config('app.env')) { + Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this))); + } + + $this->repository = app(ObjectGroupRepositoryInterface::class); + } + + /** + * Transform the account. + * + * @param ObjectGroup $objectGroup + * + * @return array + */ + public function transform(ObjectGroup $objectGroup): array + { + $this->repository->setUser($objectGroup->user); + + return [ + 'id' => (int) $objectGroup->id, + 'created_at' => $objectGroup->created_at->toAtomString(), + 'updated_at' => $objectGroup->updated_at->toAtomString(), + 'title' => $objectGroup->title, + 'order' => $objectGroup->order, + 'links' => [ + [ + 'rel' => 'self', + 'uri' => '/groups/' . $objectGroup->id, + ], + ], + ]; + } + +} diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 97d9c38dc2..098a54d18a 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -85,7 +85,7 @@ class PiggyBankTransformer extends AbstractTransformer $notes = '' === $notes ? null : $notes; $objectGroupId = null; - $objectGroupOrder = 0; + $objectGroupOrder = null; $objectGroupTitle = null; /** @var ObjectGroup $objectGroup */ $objectGroup = $piggyBank->objectGroups->first(); diff --git a/config/firefly.php b/config/firefly.php index 70bd0d3dea..b96dd479ea 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -144,7 +144,7 @@ return [ 'encryption' => null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'), 'version' => '5.3.0', - 'api_version' => '1.1.0', + 'api_version' => '1.2.0', 'db_version' => 14, 'maxUploadSize' => 15242880, 'send_error_message' => env('SEND_ERROR_MESSAGE', true), diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 235f54bd4c..1fb1b3eacf 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -1684,5 +1684,6 @@ return [ 'update_object_group' => 'Update group', 'updated_object_group' => 'Succesfully updated group ":title"', 'deleted_object_group' => 'Succesfully deleted group ":title"', + 'object_group' => 'Group', ]; diff --git a/resources/views/v1/piggy-banks/show.twig b/resources/views/v1/piggy-banks/show.twig index 9988da9c50..2030114f22 100644 --- a/resources/views/v1/piggy-banks/show.twig +++ b/resources/views/v1/piggy-banks/show.twig @@ -36,6 +36,12 @@