mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 23:01:29 +00:00
Fix forum policies
This commit is contained in:
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use Illuminate\Foundation\Auth\User;
|
||||
use App\Models\User;
|
||||
use TeamTeaTime\Forum\Models\Category;
|
||||
|
||||
class CategoryPolicy extends \TeamTeaTime\Forum\Policies\CategoryPolicy
|
||||
@@ -19,57 +19,66 @@ class CategoryPolicy extends \TeamTeaTime\Forum\Policies\CategoryPolicy
|
||||
|
||||
public function manageThreads(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function deleteThreads(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function restoreThreads(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function enableThreads(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function moveThreadsFrom(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function moveThreadsTo(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function lockThreads(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function pinThreads(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function view(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasAnyRole(['Admin', 'Moderator']);
|
||||
return $this->canViewCategory($user);
|
||||
}
|
||||
|
||||
public function delete(mixed $user, Category $category): bool
|
||||
{
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
public function edit(User $user, Category $category): bool
|
||||
public function edit(mixed $user, Category $category): bool
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
return $user->hasRole('Admin');
|
||||
return $this->isAdmin($user);
|
||||
}
|
||||
|
||||
private function isAdmin(mixed $user): bool
|
||||
{
|
||||
return $user instanceof User && $user->hasRole('Admin');
|
||||
}
|
||||
|
||||
private function canViewCategory(mixed $user): bool
|
||||
{
|
||||
return $user instanceof User && $user->hasAnyRole(['Admin', 'Moderator']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use TeamTeaTime\Forum\Models\Post;
|
||||
|
||||
class PostPolicy extends \TeamTeaTime\Forum\Policies\PostPolicy
|
||||
@@ -11,18 +12,28 @@ class PostPolicy extends \TeamTeaTime\Forum\Policies\PostPolicy
|
||||
public function edit(mixed $user, Post $post): bool
|
||||
{
|
||||
// Admins can edit any post; users can edit their own
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isPostAuthor($user, $post);
|
||||
}
|
||||
|
||||
public function delete(mixed $user, Post $post): bool
|
||||
{
|
||||
// Admins can delete any post; users can delete their own
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isPostAuthor($user, $post);
|
||||
}
|
||||
|
||||
public function restore(mixed $user, Post $post): bool
|
||||
{
|
||||
// Admins can restore any post; users can restore their own
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isPostAuthor($user, $post);
|
||||
}
|
||||
|
||||
private function isAdmin(mixed $user): bool
|
||||
{
|
||||
return $user instanceof User && $user->hasRole('Admin');
|
||||
}
|
||||
|
||||
private function isPostAuthor(mixed $user, Post $post): bool
|
||||
{
|
||||
return $user instanceof User && $user->getKey() === $post->author_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,55 +4,78 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use TeamTeaTime\Forum\Models\Thread;
|
||||
|
||||
class ThreadPolicy extends \TeamTeaTime\Forum\Policies\ThreadPolicy
|
||||
{
|
||||
public function view(mixed $user, Thread $thread): bool
|
||||
{
|
||||
// Everyone (including Admin) can view by default
|
||||
return parent::view($user, $thread);
|
||||
// Guests can still view threads, but all mutating actions require auth.
|
||||
return $user === null || parent::view($user, $thread);
|
||||
}
|
||||
|
||||
public function rename(mixed $user, Thread $thread): bool
|
||||
{
|
||||
// Admins can rename any thread; users can rename their own
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isThreadAuthor($user, $thread);
|
||||
}
|
||||
|
||||
public function reply(mixed $user, Thread $thread): bool
|
||||
{
|
||||
if (! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Admins can reply even if locked; otherwise respect lock state
|
||||
return $user->hasRole('Admin') || (! $thread->locked);
|
||||
return $this->isAdmin($user) || (! $thread->locked);
|
||||
}
|
||||
|
||||
public function replyWithoutApproval(mixed $user, Thread $thread): bool
|
||||
{
|
||||
// Admins can reply to unapproved threads; otherwise only thread author
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isThreadAuthor($user, $thread);
|
||||
}
|
||||
|
||||
public function delete(mixed $user, Thread $thread): bool
|
||||
{
|
||||
// Admins can delete any thread; users can delete their own
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isThreadAuthor($user, $thread);
|
||||
}
|
||||
|
||||
public function restore(mixed $user, Thread $thread): bool
|
||||
{
|
||||
// Admins can restore any thread; users can restore their own
|
||||
return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound
|
||||
return $this->isAdmin($user) || $this->isThreadAuthor($user, $thread);
|
||||
}
|
||||
|
||||
public function deletePosts(mixed $user, Thread $thread): bool
|
||||
{
|
||||
if (! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Admins can delete posts in any thread; otherwise fall back to default (true)
|
||||
return $user->hasRole('Admin') || parent::deletePosts($user, $thread);
|
||||
return $this->isAdmin($user) || parent::deletePosts($user, $thread);
|
||||
}
|
||||
|
||||
public function restorePosts(mixed $user, Thread $thread): bool
|
||||
{
|
||||
if (! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Admins can restore posts in any thread; otherwise fall back to default (true)
|
||||
return $user->hasRole('Admin') || parent::restorePosts($user, $thread);
|
||||
return $this->isAdmin($user) || parent::restorePosts($user, $thread);
|
||||
}
|
||||
|
||||
private function isAdmin(mixed $user): bool
|
||||
{
|
||||
return $user instanceof User && $user->hasRole('Admin');
|
||||
}
|
||||
|
||||
private function isThreadAuthor(mixed $user, Thread $thread): bool
|
||||
{
|
||||
return $user instanceof User && $user->getKey() === $thread->author_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Policies;
|
||||
|
||||
use App\Policies\CategoryPolicy;
|
||||
use App\Policies\PostPolicy;
|
||||
use App\Policies\ThreadPolicy;
|
||||
use TeamTeaTime\Forum\Models\Category;
|
||||
use TeamTeaTime\Forum\Models\Post;
|
||||
use TeamTeaTime\Forum\Models\Thread;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ForumGuestPolicyTest extends TestCase
|
||||
{
|
||||
public function test_guest_category_actions_are_denied_without_throwing(): void
|
||||
{
|
||||
$policy = new CategoryPolicy;
|
||||
$category = new Category;
|
||||
|
||||
$this->assertFalse($policy->manageThreads(null, $category));
|
||||
$this->assertFalse($policy->deleteThreads(null, $category));
|
||||
$this->assertFalse($policy->restoreThreads(null, $category));
|
||||
$this->assertFalse($policy->lockThreads(null, $category));
|
||||
$this->assertFalse($policy->pinThreads(null, $category));
|
||||
$this->assertFalse($policy->moveThreadsFrom(null, $category));
|
||||
$this->assertFalse($policy->view(null, $category));
|
||||
}
|
||||
|
||||
public function test_guest_thread_actions_are_denied_but_threads_remain_viewable(): void
|
||||
{
|
||||
$policy = new ThreadPolicy;
|
||||
$thread = new Thread([
|
||||
'author_id' => 1,
|
||||
'locked' => false,
|
||||
]);
|
||||
|
||||
$this->assertTrue($policy->view(null, $thread));
|
||||
$this->assertFalse($policy->rename(null, $thread));
|
||||
$this->assertFalse($policy->reply(null, $thread));
|
||||
$this->assertFalse($policy->replyWithoutApproval(null, $thread));
|
||||
$this->assertFalse($policy->delete(null, $thread));
|
||||
$this->assertFalse($policy->restore(null, $thread));
|
||||
$this->assertFalse($policy->deletePosts(null, $thread));
|
||||
$this->assertFalse($policy->restorePosts(null, $thread));
|
||||
}
|
||||
|
||||
public function test_guest_post_actions_are_denied_without_throwing(): void
|
||||
{
|
||||
$policy = new PostPolicy;
|
||||
$post = new Post([
|
||||
'author_id' => 1,
|
||||
]);
|
||||
|
||||
$this->assertFalse($policy->edit(null, $post));
|
||||
$this->assertFalse($policy->delete(null, $post));
|
||||
$this->assertFalse($policy->restore(null, $post));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user