diff --git a/app/Support/Binder/BudgetList.php b/app/Support/Binder/BudgetList.php index fd6031596d..f02cd32765 100644 --- a/app/Support/Binder/BudgetList.php +++ b/app/Support/Binder/BudgetList.php @@ -41,20 +41,29 @@ class BudgetList implements BinderInterface public static function routeBinder(string $value, Route $route): Collection { if (auth()->check()) { - $ids = explode(',', $value); - /** @var \Illuminate\Support\Collection $object */ - $object = Budget::where('active', 1) - ->whereIn('id', $ids) - ->where('user_id', auth()->user()->id) - ->get(); - - // add empty budget if applicable. - if (in_array('0', $ids)) { - $object->push(new Budget); + $list = []; + $incoming = explode(',', $value); + foreach ($incoming as $entry) { + $list[] = intval($entry); + } + $list = array_unique($list); + if (count($list) === 0) { + throw new NotFoundHttpException; // @codeCoverageIgnore } - if ($object->count() > 0) { - return $object; + /** @var \Illuminate\Support\Collection $collection */ + $collection = auth()->user()->budgets() + ->where('active', 1) + ->whereIn('id', $list) + ->get(); + + // add empty budget if applicable. + if (in_array(0, $list)) { + $collection->push(new Budget); + } + + if ($collection->count() > 0) { + return $collection; } } throw new NotFoundHttpException; diff --git a/app/Support/Binder/CategoryList.php b/app/Support/Binder/CategoryList.php index a62c43d6c7..3ce93ce553 100644 --- a/app/Support/Binder/CategoryList.php +++ b/app/Support/Binder/CategoryList.php @@ -41,19 +41,28 @@ class CategoryList implements BinderInterface public static function routeBinder(string $value, Route $route): Collection { if (auth()->check()) { - $ids = explode(',', $value); - /** @var \Illuminate\Support\Collection $object */ - $object = Category::whereIn('id', $ids) - ->where('user_id', auth()->user()->id) - ->get(); - - // add empty category if applicable. - if (in_array('0', $ids)) { - $object->push(new Category); + $list = []; + $incoming = explode(',', $value); + foreach ($incoming as $entry) { + $list[] = intval($entry); + } + $list = array_unique($list); + if (count($list) === 0) { + throw new NotFoundHttpException; // @codeCoverageIgnore } - if ($object->count() > 0) { - return $object; + /** @var \Illuminate\Support\Collection $collection */ + $collection = auth()->user()->categories() + ->whereIn('id', $list) + ->get(); + + // add empty category if applicable. + if (in_array(0, $list)) { + $collection->push(new Category); + } + + if ($collection->count() > 0) { + return $collection; } } throw new NotFoundHttpException; diff --git a/app/Support/Binder/Date.php b/app/Support/Binder/Date.php index 06d86a3ce2..7622b5d8b0 100644 --- a/app/Support/Binder/Date.php +++ b/app/Support/Binder/Date.php @@ -25,6 +25,7 @@ namespace FireflyIII\Support\Binder; use Carbon\Carbon; use Exception; use FireflyIII\Helpers\FiscalHelper; +use FireflyIII\Helpers\FiscalHelperInterface; use Illuminate\Routing\Route; use Log; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -42,7 +43,8 @@ class Date implements BinderInterface */ public static function routeBinder(string $value, Route $route): Carbon { - $fiscalHelper = new FiscalHelper; + /** @var FiscalHelperInterface $fiscalHelper */ + $fiscalHelper = app(FiscalHelperInterface::class); switch ($value) { default: diff --git a/app/Support/Binder/JournalList.php b/app/Support/Binder/JournalList.php index 1c44c8d5d4..ee556f9907 100644 --- a/app/Support/Binder/JournalList.php +++ b/app/Support/Binder/JournalList.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace FireflyIII\Support\Binder; -use FireflyIII\Models\TransactionJournal; use Illuminate\Routing\Route; use Illuminate\Support\Collection; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -41,14 +40,24 @@ class JournalList implements BinderInterface public static function routeBinder(string $value, Route $route): Collection { if (auth()->check()) { - $ids = explode(',', $value); - /** @var \Illuminate\Support\Collection $object */ - $object = TransactionJournal::whereIn('transaction_journals.id', $ids) - ->where('transaction_journals.user_id', auth()->user()->id) - ->get(['transaction_journals.*']); + $list = []; + $incoming = explode(',', $value); + foreach ($incoming as $entry) { + $list[] = intval($entry); + } + $list = array_unique($list); + if (count($list) === 0) { + throw new NotFoundHttpException; // @codeCoverageIgnore + } - if ($object->count() > 0) { - return $object; + /** @var \Illuminate\Support\Collection $collection */ + $collection = auth()->user()->transactionJournals() + ->whereIn('transaction_journals.id', $list) + ->where('transaction_journals.completed', 1) + ->get(['transaction_journals.*']); + + if ($collection->count() > 0) { + return $collection; } } throw new NotFoundHttpException; diff --git a/app/Support/Binder/TagList.php b/app/Support/Binder/TagList.php index 0cc154c961..60ec2f86dd 100644 --- a/app/Support/Binder/TagList.php +++ b/app/Support/Binder/TagList.php @@ -42,18 +42,27 @@ class TagList implements BinderInterface public static function routeBinder(string $value, Route $route): Collection { if (auth()->check()) { - $tags = explode(',', $value); + $list = []; + $incoming = explode(',', $value); + foreach ($incoming as $entry) { + $list[] = trim($entry); + } + $list = array_unique($list); + if (count($list) === 0) { + throw new NotFoundHttpException; // @codeCoverageIgnore + } /** @var TagRepositoryInterface $repository */ $repository = app(TagRepositoryInterface::class); $allTags = $repository->get(); - $set = $allTags->filter( - function (Tag $tag) use ($tags) { - return in_array($tag->tag, $tags); + + $collection = $allTags->filter( + function (Tag $tag) use ($list) { + return in_array($tag->tag, $list); } ); - if ($set->count() > 0) { - return $set; + if ($collection->count() > 0) { + return $collection; } } throw new NotFoundHttpException; diff --git a/tests/Unit/Middleware/BinderTest.php b/tests/Unit/Middleware/BinderTest.php index 753c3995c5..f91d13cd4a 100644 --- a/tests/Unit/Middleware/BinderTest.php +++ b/tests/Unit/Middleware/BinderTest.php @@ -21,10 +21,13 @@ declare(strict_types=1); -namespace Tests\Unit\Helpers; +namespace Tests\Unit\Middleware; +use Carbon\Carbon; +use FireflyIII\Helpers\FiscalHelperInterface; use FireflyIII\Http\Middleware\Binder; +use FireflyIII\Repositories\Tag\TagRepositoryInterface; use Illuminate\Support\Collection; use Route; use Symfony\Component\HttpFoundation\Response; @@ -129,7 +132,6 @@ class BinderTest extends TestCase $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); } - /** * @covers \FireflyIII\Http\Middleware\Binder::handle * @covers \FireflyIII\Http\Middleware\Binder::__construct @@ -354,6 +356,43 @@ class BinderTest extends TestCase $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); } + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\BudgetList::routeBinder + */ + public function testBudgetList() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{budgetList}', function (Collection $budgets) { + return 'count: ' . $budgets->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/0,1,2'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $response->assertSee('count: 3'); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\BudgetList::routeBinder + */ + public function testBudgetListInvalid() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{budgetList}', function (Collection $budgets) { + return 'count: ' . $budgets->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/-1'); + $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); + } + /** * @covers \FireflyIII\Http\Middleware\Binder::handle * @covers \FireflyIII\Http\Middleware\Binder::__construct @@ -410,6 +449,43 @@ class BinderTest extends TestCase $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); } + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\CategoryList::routeBinder + */ + public function testCategoryList() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{categoryList}', function (Collection $categories) { + return 'count: ' . $categories->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/0,1,2'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $response->assertSee('count: 3'); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\CategoryList::routeBinder + */ + public function testCategoryListInvalid() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{categoryList}', function (Collection $categories) { + return 'count: ' . $categories->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/-1'); + $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); + } + /** * @covers \FireflyIII\Http\Middleware\Binder::handle * @covers \FireflyIII\Http\Middleware\Binder::__construct @@ -503,6 +579,183 @@ class BinderTest extends TestCase $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); } + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDate() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/20170917'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $response->assertSee('date: 2017-09-17'); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateCurrentMonthEnd() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/currentMonthEnd'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $date = new Carbon; + $date->endOfMonth(); + $response->assertSee('date: ' . $date->format('Y-m-d')); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateCurrentMonthStart() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/currentMonthStart'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $date = new Carbon; + $date->startOfMonth(); + $response->assertSee('date: ' . $date->format('Y-m-d')); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateCurrentYearEnd() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/currentYearEnd'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $date = new Carbon; + $date->endOfYear(); + $response->assertSee('date: ' . $date->format('Y-m-d')); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateCurrentYearStart() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/currentYearStart'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $date = new Carbon; + $date->startOfYear(); + $response->assertSee('date: ' . $date->format('Y-m-d')); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateFiscalYearEnd() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + + $date = new Carbon; + $date->endOfYear(); + + // mock fiscal helper: + $helper = $this->mock(FiscalHelperInterface::class); + $helper->shouldReceive('endOfFiscalYear')->andReturn($date)->once(); + + $this->be($this->user()); + $response = $this->get('/_test/binder/currentFiscalYearEnd'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + + $response->assertSee('date: ' . $date->format('Y-m-d')); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateFiscalYearStart() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + + $date = new Carbon; + $date->startOfYear(); + + // mock fiscal helper: + $helper = $this->mock(FiscalHelperInterface::class); + $helper->shouldReceive('startOfFiscalYear')->andReturn($date)->once(); + + $this->be($this->user()); + $response = $this->get('/_test/binder/currentFiscalYearStart'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + + $response->assertSee('date: ' . $date->format('Y-m-d')); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\Date::routeBinder + */ + public function testDateInvalid() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{date}', function (Carbon $date) { + return 'date: ' . $date->format('Y-m-d'); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/fakedate'); + $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); + } + /** * @covers \FireflyIII\Http\Middleware\Binder::handle * @covers \FireflyIII\Http\Middleware\Binder::__construct @@ -633,6 +886,43 @@ class BinderTest extends TestCase $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); } + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\JournalList::routeBinder + */ + public function testJournalList() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{journalList}', function (Collection $journals) { + return 'count: ' . $journals->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/1,2'); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $response->assertSee('count: 2'); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\JournalList::routeBinder + */ + public function testJournalListEmpty() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{journalList}', function (Collection $journals) { + return 'count: ' . $journals->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/-1'); + $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); + } + /** * @covers \FireflyIII\Http\Middleware\Binder::handle * @covers \FireflyIII\Http\Middleware\Binder::__construct @@ -932,6 +1222,49 @@ class BinderTest extends TestCase $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); } + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\TagList::routeBinder + */ + public function testTagList() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{tagList}', function (Collection $tags) { + return 'count: ' . $tags->count(); + } + ); + $tags = $this->user()->tags()->whereIn('id', [1, 2])->get(['tags.*']); + $names = join(',', $tags->pluck('tag')->toArray()); + + $repository = $this->mock(TagRepositoryInterface::class); + $repository->shouldReceive('get')->once()->andReturn($tags); + + $this->be($this->user()); + $response = $this->get('/_test/binder/' . $names); + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $response->assertSee('count: 2'); + } + + /** + * @covers \FireflyIII\Http\Middleware\Binder::handle + * @covers \FireflyIII\Http\Middleware\Binder::__construct + * @covers \FireflyIII\Http\Middleware\Binder::performBinding + * @covers \FireflyIII\Support\Binder\TagList::routeBinder + */ + public function testTagListEmpty() + { + Route::middleware(Binder::class)->any( + '/_test/binder/{tagList}', function (Collection $tags) { + return 'count: ' . $tags->count(); + } + ); + $this->be($this->user()); + $response = $this->get('/_test/binder/noblaexista'); + $this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode()); + } + /** * @covers \FireflyIII\Http\Middleware\Binder::handle * @covers \FireflyIII\Http\Middleware\Binder::__construct