From: Dan Brown Date: Mon, 24 Nov 2025 20:04:55 +0000 (+0000) Subject: Slugs: Added test to cover history lookup permission usage X-Git-Url: http://source.bookstackapp.com/bookstack/commitdiff_plain/cdd164e3e3e0fb1bcd40329043503b1bea849cab Slugs: Added test to cover history lookup permission usage --- diff --git a/app/Entities/Models/SlugHistory.php b/app/Entities/Models/SlugHistory.php index 2731fe749..4041cedd9 100644 --- a/app/Entities/Models/SlugHistory.php +++ b/app/Entities/Models/SlugHistory.php @@ -4,6 +4,7 @@ namespace BookStack\Entities\Models; use BookStack\App\Model; use BookStack\Permissions\Models\JointPermission; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; /** @@ -15,6 +16,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany; */ class SlugHistory extends Model { + use HasFactory; + protected $table = 'slug_history'; public function jointPermissions(): HasMany diff --git a/database/factories/Entities/Models/SlugHistoryFactory.php b/database/factories/Entities/Models/SlugHistoryFactory.php new file mode 100644 index 000000000..c8c57e09c --- /dev/null +++ b/database/factories/Entities/Models/SlugHistoryFactory.php @@ -0,0 +1,29 @@ + + */ +class SlugHistoryFactory extends Factory +{ + protected $model = \BookStack\Entities\Models\SlugHistory::class; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'sluggable_id' => Book::factory(), + 'sluggable_type' => 'book', + 'slug' => $this->faker->slug(), + 'parent_slug' => null, + ]; + } +} diff --git a/tests/Entity/SlugTest.php b/tests/Entity/SlugTest.php index e8565d00f..51cf34e5d 100644 --- a/tests/Entity/SlugTest.php +++ b/tests/Entity/SlugTest.php @@ -2,6 +2,7 @@ namespace Tests\Entity; +use BookStack\Entities\Models\SlugHistory; use Tests\TestCase; class SlugTest extends TestCase @@ -111,6 +112,27 @@ class SlugTest extends TestCase ->assertRedirect("/books/super-test-book/chapter/{$chapter->slug}"); } + public function test_slug_lookup_controlled_by_permissions() + { + $editor = $this->users->editor(); + $pageA = $this->entities->page(); + $pageB = $this->entities->page(); + + SlugHistory::factory()->create(['sluggable_id' => $pageA->id, 'sluggable_type' => 'page', 'slug' => 'monkey', 'parent_slug' => 'animals', 'created_at' => now()]); + SlugHistory::factory()->create(['sluggable_id' => $pageB->id, 'sluggable_type' => 'page', 'slug' => 'monkey', 'parent_slug' => 'animals', 'created_at' => now()->subDay()]); + + // Defaults to latest where visible + $this->actingAs($editor)->get("/books/animals/page/monkey")->assertRedirect($pageA->getUrl()); + + $this->permissions->disableEntityInheritedPermissions($pageA); + + // Falls back to other entry where the latest is not visible + $this->actingAs($editor)->get("/books/animals/page/monkey")->assertRedirect($pageB->getUrl()); + + // Original still accessible where permissions allow + $this->asAdmin()->get("/books/animals/page/monkey")->assertRedirect($pageA->getUrl()); + } + public function test_slugs_recorded_in_history_on_page_update() { $page = $this->entities->page();