diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index 3965bbd2..e8c6f62d 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -142,6 +142,8 @@ public function vote(Request $request, $projectId, $itemId) $item = $project->items()->visibleForCurrentUser()->findOrfail($itemId); + abort_if($item->board?->block_votes, 403); + $item->toggleUpvote(); return redirect()->back(); diff --git a/app/Livewire/Item/VoteButton.php b/app/Livewire/Item/VoteButton.php index d009139f..bf12124c 100644 --- a/app/Livewire/Item/VoteButton.php +++ b/app/Livewire/Item/VoteButton.php @@ -2,6 +2,7 @@ namespace App\Livewire\Item; +use App\Models\Item; use App\Models\Vote; use Livewire\Component; use Illuminate\Support\Collection; @@ -24,6 +25,8 @@ public function mount(bool $hideSubscribeOption = false) public function toggleUpvote() { + abort_if($this->model instanceof Item && $this->model->board?->block_votes, 403); + $this->model->toggleUpvote(); $this->refreshModel(); } diff --git a/app/Livewire/Project/ItemCard.php b/app/Livewire/Project/ItemCard.php index ee08200e..d4a19a15 100644 --- a/app/Livewire/Project/ItemCard.php +++ b/app/Livewire/Project/ItemCard.php @@ -19,6 +19,8 @@ public function mount() public function toggleUpvote() { + abort_if($this->item->board?->block_votes, 403); + $this->item->toggleUpvote(); $this->item = $this->item->refresh(); } diff --git a/app/Models/Item.php b/app/Models/Item.php index 7473e469..8fae757e 100644 --- a/app/Models/Item.php +++ b/app/Models/Item.php @@ -9,6 +9,8 @@ use Illuminate\Support\Str; use App\Enums\InboxWorkflow; use App\Settings\GeneralSettings; +use Illuminate\Routing\Redirector; +use Illuminate\Http\RedirectResponse; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; @@ -22,7 +24,10 @@ class Item extends Model { - use HasFactory, Sluggable, HasOgImage, HasUpvote, HasTags; + use HasFactory, Sluggable, HasOgImage, HasTags; + use HasUpvote { + toggleUpvote as private toggleUpvoteWithoutBoardGuard; + } public $fillable = [ 'slug', @@ -88,6 +93,15 @@ public function board(): BelongsTo return $this->belongsTo(Board::class); } + public function toggleUpvote(?User $user = null): Vote|Model|RedirectResponse|bool|Redirector + { + if ($this->board?->block_votes) { + return false; + } + + return $this->toggleUpvoteWithoutBoardGuard($user); + } + public function user(): BelongsTo { return $this->belongsTo(User::class); diff --git a/tests/Feature/Item/VoteOnItemTest.php b/tests/Feature/Item/VoteOnItemTest.php index 1a860249..78b466e7 100644 --- a/tests/Feature/Item/VoteOnItemTest.php +++ b/tests/Feature/Item/VoteOnItemTest.php @@ -97,22 +97,24 @@ $this->assertTrue($user->hasAdminAccess()); }); -test('A user cant vote on an item that belongs to a board which disables voting', function () { +test('A user cannot vote on an item that belongs to a board which disables voting', function () { $user = User::first(); - $board = Board::factory()->create(['block_votes' => true]); + $project = Project::factory()->create(); + $board = Board::factory()->for($project)->create(['block_votes' => true]); $item = Item::factory()->create([ - 'project_id' => $board->getAttributeValue('project_id'), - 'board_id' => $board->getAttributeValue('id'), - ]); + 'project_id' => $project->id, + 'board_id' => $board->id, + ]); $this->assertEquals(0, $item->votes()->count()); $this->actingAs($user) ->post(route('projects.items.vote', [ 'item' => $item->getKey(), - 'project' => $board->getKey(), - ])); + 'project' => $project->getKey(), + ])) + ->assertForbidden(); $this->assertAuthenticatedAs($user); $this->assertEquals(0, $item->votes()->count());