fix: lit/divi-node-copy from a library entry needs the insert rights (I-1, L5)

A library entry as source now requires LibraryAccess::canInsert() (add_library,
writable library group) and follows lit-library-insert's Tools-tab state
(disabled -> unsupported). DiviPageLoader::library() gets its caller.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 04:06:56 +02:00
co-authored by Claude Opus 5.5
parent 186f7af7ca
commit 1b42f9b640
5 changed files with 97 additions and 12 deletions
@@ -42,7 +42,8 @@ final class DiviNodeCopyAbilityTest extends TestCase
private function ability(
bool $diviWritable = true,
bool $unfiltered = false,
?LibraryAccess $access = null
?LibraryAccess $access = null,
bool $libraryInsert = true
): DiviNodeCopyAbility {
$access ??= LibraryFixtures::access();
$loader = LibraryFixtures::loader($access);
@@ -54,7 +55,8 @@ final class DiviNodeCopyAbilityTest extends TestCase
return new DiviNodeCopyAbility(
DiviWriterFixture::writer($this->saved, $failures, $unfiltered, $loader, $globals),
$loader,
static fn (): bool => $diviWritable
static fn (): bool => $diviWritable,
static fn (): bool => $libraryInsert
);
}
@@ -206,6 +208,49 @@ final class DiviNodeCopyAbilityTest extends TestCase
self::assertStringContainsString('Library-Blurb', $this->saved[0]);
}
/** @return array<string, mixed> */
private function librarySource(): array
{
return $this->input([
'source_post_id' => 1055,
'source_tree_rev' => Rev::of((string) LibraryFixtures::item(1055)->post_content),
'source_id' => 's0',
]);
}
public function testALibrarySourceNeedsAddLibrary(): void
{
$ability = $this->ability(access: LibraryFixtures::access(['add_library']));
self::assertToolError($ability->permission($this->librarySource()), 'forbidden');
self::assertToolError($ability->execute($this->librarySource()), 'forbidden');
self::assertSame([], $this->saved);
}
public function testALibrarySourceNeedsAWritableLibraryGroup(): void
{
$ability = $this->ability(access: LibraryFixtures::access(writable: false));
self::assertToolError($ability->execute($this->librarySource()), 'forbidden');
self::assertSame([], $this->saved);
}
public function testALibrarySourceFollowsLibraryInsertExposure(): void
{
$ability = $this->ability(libraryInsert: false);
self::assertToolError($ability->permission($this->librarySource()), 'unsupported');
self::assertToolError($ability->execute($this->librarySource()), 'unsupported');
self::assertSame([], $this->saved);
}
public function testPageSourcesNeedNeitherAddLibraryNorLibraryInsert(): void
{
$ability = $this->ability(access: LibraryFixtures::access(['add_library']), libraryInsert: false);
self::assertTrue($ability->execute($this->input())['ok']);
}
public function testAHiddenLibraryIsNoSource(): void
{
$item = LibraryFixtures::item(1055);