diff --git a/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php b/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php new file mode 100644 index 0000000000..4c8f56315d --- /dev/null +++ b/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php @@ -0,0 +1,56 @@ +middleware( + function ($request, $next) { + /** @var User $user */ + $user = auth()->user(); + + $this->repository = app(LinkTypeRepositoryInterface::class); + + $this->repository->setUser($user); + + return $next($request); + } + ); + } + + /** + * Delete the resource. + * + * @param TransactionJournalLink $link + * + * @return JsonResponse + * @codeCoverageIgnore + */ + public function destroy(TransactionJournalLink $link): JsonResponse + { + $this->repository->destroyLink($link); + + return response()->json([], 204); + } + +} \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php b/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php new file mode 100644 index 0000000000..925127adbb --- /dev/null +++ b/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php @@ -0,0 +1,108 @@ +middleware( + function ($request, $next) { + /** @var User $user */ + $user = auth()->user(); + + $this->repository = app(LinkTypeRepositoryInterface::class); + + $this->repository->setUser($user); + + return $next($request); + } + ); + } + + /** + * List all of the transaction links there are. + * + * @param Request $request + * + * @return JsonResponse + * @codeCoverageIgnore + */ + public function index(Request $request): JsonResponse + { + // create some objects: + $manager = $this->getManager(); + // read type from URI + $name = $request->get('name'); + + // types to get, page size: + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $linkType = $this->repository->findByName($name); + + // get list of transaction links. Count it and split it. + $collection = $this->repository->getJournalLinks($linkType); + $count = $collection->count(); + $journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($journalLinks, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.transaction_links.index') . $this->buildParams()); + + /** @var TransactionLinkTransformer $transformer */ + $transformer = app(TransactionLinkTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new FractalCollection($journalLinks, $transformer, 'transaction_links'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); + + } + + + /** + * List single resource. + * + * @param TransactionJournalLink $journalLink + * + * @return JsonResponse + * @codeCoverageIgnore + */ + public function show(TransactionJournalLink $journalLink): JsonResponse + { + $manager = $this->getManager(); + + /** @var TransactionLinkTransformer $transformer */ + $transformer = app(TransactionLinkTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new Item($journalLink, $transformer, 'transaction_links'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); + + } + + +} \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php b/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php new file mode 100644 index 0000000000..856dd39e34 --- /dev/null +++ b/app/Api/V1/Controllers/Models/TransactionLink/StoreController.php @@ -0,0 +1,79 @@ +middleware( + function ($request, $next) { + /** @var User $user */ + $user = auth()->user(); + + $this->repository = app(LinkTypeRepositoryInterface::class); + $this->journalRepository = app(JournalRepositoryInterface::class); + + $this->repository->setUser($user); + $this->journalRepository->setUser($user); + + return $next($request); + } + ); + } + + + /** + * Store new object. + * + * @param StoreRequest $request + * + * @return JsonResponse + * @throws FireflyException + */ + public function store(StoreRequest $request): JsonResponse + { + $manager = $this->getManager(); + $data = $request->getAll(); + $inward = $this->journalRepository->findNull($data['inward_id'] ?? 0); + $outward = $this->journalRepository->findNull($data['outward_id'] ?? 0); + if (null === $inward || null === $outward) { + throw new FireflyException('200024: Source or destination does not exist.'); + } + $data['direction'] = 'inward'; + + $journalLink = $this->repository->storeLink($data, $inward, $outward); + + /** @var TransactionLinkTransformer $transformer */ + $transformer = app(TransactionLinkTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new Item($journalLink, $transformer, 'transaction_links'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); + } +} \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/TransactionLink/UpdateController.php b/app/Api/V1/Controllers/Models/TransactionLink/UpdateController.php new file mode 100644 index 0000000000..85aa3f4ee4 --- /dev/null +++ b/app/Api/V1/Controllers/Models/TransactionLink/UpdateController.php @@ -0,0 +1,78 @@ +middleware( + function ($request, $next) { + /** @var User $user */ + $user = auth()->user(); + + $this->repository = app(LinkTypeRepositoryInterface::class); + $this->journalRepository = app(JournalRepositoryInterface::class); + + $this->repository->setUser($user); + $this->journalRepository->setUser($user); + + return $next($request); + } + ); + } + + /** + * Update object. + * + * @param UpdateRequest $request + * @param TransactionJournalLink $journalLink + * + * @return JsonResponse + * @throws FireflyException + */ + public function update(UpdateRequest $request, TransactionJournalLink $journalLink): JsonResponse + { + $manager = $this->getManager(); + $data = $request->getAll(); + $data['inward'] = $this->journalRepository->findNull($data['inward_id'] ?? 0); + $data['outward'] = $this->journalRepository->findNull($data['outward_id'] ?? 0); + if (null === $data['inward'] || null === $data['outward']) { + throw new FireflyException('200024: Source or destination does not exist.'); + } + $data['direction'] = 'inward'; + $journalLink = $this->repository->updateLink($journalLink, $data); + + /** @var TransactionLinkTransformer $transformer */ + $transformer = app(TransactionLinkTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new Item($journalLink, $transformer, 'transaction_links'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); + + } +} \ No newline at end of file diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php new file mode 100644 index 0000000000..c6f89b4044 --- /dev/null +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php @@ -0,0 +1,15 @@ +middleware( - function ($request, $next) { - /** @var User $user */ - $user = auth()->user(); - - $this->repository = app(LinkTypeRepositoryInterface::class); - $this->journalRepository = app(JournalRepositoryInterface::class); - - $this->repository->setUser($user); - $this->journalRepository->setUser($user); - - return $next($request); - } - ); - } - - /** - * Delete the resource. - * - * @param TransactionJournalLink $link - * - * @return JsonResponse - * @codeCoverageIgnore - */ - public function delete(TransactionJournalLink $link): JsonResponse - { - $this->repository->destroyLink($link); - - return response()->json([], 204); - } - - /** - * List all of them. - * - * @param Request $request - * - * @return JsonResponse - * @codeCoverageIgnore - */ - public function index(Request $request): JsonResponse - { - // create some objects: - $manager = $this->getManager(); - // read type from URI - $name = $request->get('name'); - - // types to get, page size: - $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - $linkType = $this->repository->findByName($name); - - // get list of transaction links. Count it and split it. - $collection = $this->repository->getJournalLinks($linkType); - $count = $collection->count(); - $journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); - - // make paginator: - $paginator = new LengthAwarePaginator($journalLinks, $count, $pageSize, $this->parameters->get('page')); - $paginator->setPath(route('api.v1.transaction_links.index') . $this->buildParams()); - - /** @var TransactionLinkTransformer $transformer */ - $transformer = app(TransactionLinkTransformer::class); - $transformer->setParameters($this->parameters); - - $resource = new FractalCollection($journalLinks, $transformer, 'transaction_links'); - $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); - - return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); - - } - - /** - * List single resource. - * - * @param TransactionJournalLink $journalLink - * - * @return JsonResponse - * @codeCoverageIgnore - */ - public function show(TransactionJournalLink $journalLink): JsonResponse - { - $manager = $this->getManager(); - - /** @var TransactionLinkTransformer $transformer */ - $transformer = app(TransactionLinkTransformer::class); - $transformer->setParameters($this->parameters); - - $resource = new Item($journalLink, $transformer, 'transaction_links'); - - return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); - - } - - /** - * Store new object. - * - * @param TransactionLinkRequest $request - * - * @return JsonResponse - * @throws FireflyException - */ - public function store(TransactionLinkRequest $request): JsonResponse - { - $manager = $this->getManager(); - $data = $request->getAll(); - $inward = $this->journalRepository->findNull($data['inward_id'] ?? 0); - $outward = $this->journalRepository->findNull($data['outward_id'] ?? 0); - if (null === $inward || null === $outward) { - throw new FireflyException('200024: Source or destination does not exist.'); - } - $data['direction'] = 'inward'; - - $journalLink = $this->repository->storeLink($data, $inward, $outward); - - /** @var TransactionLinkTransformer $transformer */ - $transformer = app(TransactionLinkTransformer::class); - $transformer->setParameters($this->parameters); - - $resource = new Item($journalLink, $transformer, 'transaction_links'); - - return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); - } - - /** - * Update object. - * - * @param TransactionLinkRequest $request - * @param TransactionJournalLink $journalLink - * - * @return JsonResponse - * @throws FireflyException - */ - public function update(TransactionLinkRequest $request, TransactionJournalLink $journalLink): JsonResponse - { - $manager = $this->getManager(); - $data = $request->getAll(); - $data['inward'] = $this->journalRepository->findNull($data['inward_id'] ?? 0); - $data['outward'] = $this->journalRepository->findNull($data['outward_id'] ?? 0); - if (null === $data['inward'] || null === $data['outward']) { - throw new FireflyException('200024: Source or destination does not exist.'); - } - $data['direction'] = 'inward'; - $journalLink = $this->repository->updateLink($journalLink, $data); - - /** @var TransactionLinkTransformer $transformer */ - $transformer = app(TransactionLinkTransformer::class); - $transformer->setParameters($this->parameters); - - $resource = new Item($journalLink, $transformer, 'transaction_links'); - - return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); - - } } diff --git a/app/Api/V1/Requests/todo/TransactionLinkRequest.php b/app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php similarity index 97% rename from app/Api/V1/Requests/todo/TransactionLinkRequest.php rename to app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php index 00c94d7306..1b8540728f 100644 --- a/app/Api/V1/Requests/todo/TransactionLinkRequest.php +++ b/app/Api/V1/Requests/Models/TransactionLink/StoreRequest.php @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace FireflyIII\Api\V1\Requests; +namespace FireflyIII\Api\V1\Requests\Models\TransactionLink; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface; @@ -32,14 +32,12 @@ use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Validator; /** - * Class TransactionLinkRequest + * Class StoreRequest */ -class TransactionLinkRequest extends FormRequest +class StoreRequest extends FormRequest { use ConvertsDataTypes, ChecksLogin; - - /** * Get all data from the request. * diff --git a/app/Api/V1/Requests/Models/TransactionLink/UpdateRequest.php b/app/Api/V1/Requests/Models/TransactionLink/UpdateRequest.php new file mode 100644 index 0000000000..041d498aa6 --- /dev/null +++ b/app/Api/V1/Requests/Models/TransactionLink/UpdateRequest.php @@ -0,0 +1,130 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Requests\Models\TransactionLink; + +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface; +use FireflyIII\Support\Request\ChecksLogin; +use FireflyIII\Support\Request\ConvertsDataTypes; +use FireflyIII\User; +use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Validator; + +/** + * Class UpdateRequest + */ +class UpdateRequest extends FormRequest +{ + use ConvertsDataTypes, ChecksLogin; + + /** + * Get all data from the request. + * + * @return array + */ + public function getAll(): array + { + return [ + 'link_type_id' => $this->integer('link_type_id'), + 'link_type_name' => $this->string('link_type_name'), + 'inward_id' => $this->integer('inward_id'), + 'outward_id' => $this->integer('outward_id'), + 'notes' => $this->nlString('notes'), + ]; + } + + /** + * The rules that the incoming request must be matched against. + * + * @return array + */ + public function rules(): array + { + return [ + 'link_type_id' => 'exists:link_types,id', + 'link_type_name' => 'exists:link_types,name', + 'inward_id' => 'belongsToUser:transaction_journals,id|different:outward_id', + 'outward_id' => 'belongsToUser:transaction_journals,id|different:inward_id', + 'notes' => 'between:0,65000', + ]; + } + + /** + * Configure the validator instance. + * + * @param Validator $validator + * + * @return void + */ + public function withValidator(Validator $validator): void + { + $validator->after( + function (Validator $validator) { + $this->validateExistingLink($validator); + } + ); + } + + /** + * @param Validator $validator + */ + private function validateExistingLink(Validator $validator): void + { + /** @var User $user */ + $user = auth()->user(); + /** @var LinkTypeRepositoryInterface $repository */ + $repository = app(LinkTypeRepositoryInterface::class); + $repository->setUser($user); + + /** @var JournalRepositoryInterface $journalRepos */ + $journalRepos = app(JournalRepositoryInterface::class); + $journalRepos->setUser($user); + + $data = $validator->getData(); + $inwardId = (int) ($data['inward_id'] ?? 0); + $outwardId = (int) ($data['outward_id'] ?? 0); + $inward = $journalRepos->findNull($inwardId); + $outward = $journalRepos->findNull($outwardId); + + if (null === $inward) { + $validator->errors()->add('inward_id', 'Invalid inward ID.'); + + return; + } + if (null === $outward) { + $validator->errors()->add('outward_id', 'Invalid outward ID.'); + + return; + } + + if ($repository->findLink($inward, $outward)) { + // only if not updating: + $link = $this->route()->parameter('journalLink'); + if (null === $link) { + $validator->errors()->add('outward_id', 'Already have a link between inward and outward.'); + $validator->errors()->add('inward_id', 'Already have a link between inward and outward.'); + } + } + } +} diff --git a/app/Repositories/LinkType/LinkTypeRepository.php b/app/Repositories/LinkType/LinkTypeRepository.php index 99be363dce..d1f3276ad8 100644 --- a/app/Repositories/LinkType/LinkTypeRepository.php +++ b/app/Repositories/LinkType/LinkTypeRepository.php @@ -328,9 +328,9 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface */ public function updateLink(TransactionJournalLink $journalLink, array $data): TransactionJournalLink { - $journalLink->source_id = $data['inward']->id; - $journalLink->destination_id = $data['outward']->id; - $journalLink->link_type_id = $data['link_type_id']; + $journalLink->source_id = $data['inward'] ? $data['inward']->id : $journalLink->source_id; + $journalLink->destination_id = $data['outward'] ? $data['outward']->id : $journalLink->destination_id; + $journalLink->link_type_id = $data['link_type_id'] ? $data['link_type_id'] : $journalLink->link_type_id; $journalLink->save(); $this->setNoteText($journalLink, $data['notes']); diff --git a/routes/api.php b/routes/api.php index 75bb44924e..f7ca44d212 100644 --- a/routes/api.php +++ b/routes/api.php @@ -431,7 +431,19 @@ Route::group( } ); +// Transaction Links API routes: +Route::group( + ['namespace' => 'FireflyIII\Api\V1\Controllers\Models\TransactionLink', 'prefix' => 'transaction_links', + 'as' => 'api.v1.transaction_links.',], + static function () { + Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']); + Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']); + Route::get('{journalLink}', ['uses' => 'ShowController@show', 'as' => 'show']); + Route::put('{journalLink}', ['uses' => 'UpdateController@update', 'as' => 'update']); + Route::delete('{journalLink}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']); + } +); @@ -565,21 +577,7 @@ Route::group( // Route::get('{linkType}/transactions', ['uses' => 'LinkTypeController@transactions', 'as' => 'transactions']); // } //); -// -//// TODO VERIFY API DOCS -//Route::group( -// ['namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'transaction_links', -// 'as' => 'api.v1.transaction_links.',], -// static function () { -// -// // Transaction Links API routes: -// Route::get('', ['uses' => 'TransactionLinkController@index', 'as' => 'index']); -// Route::post('', ['uses' => 'TransactionLinkController@store', 'as' => 'store']); -// Route::get('{journalLink}', ['uses' => 'TransactionLinkController@show', 'as' => 'show']); -// Route::put('{journalLink}', ['uses' => 'TransactionLinkController@update', 'as' => 'update']); -// Route::delete('{journalLink}', ['uses' => 'TransactionLinkController@delete', 'as' => 'delete']); -// } -//); + // //