fix: lit/library-list search by title, own entries for authors, cursor without hidden rows (L3)

search uses search_columns post_title; users without edit_others_posts on
et_pb_layout query their own entries only (PostGuard::ownPostsOnly); the
cursor counts the entries shown, never the rows left out.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 04:18:04 +02:00
co-authored by Claude Opus 5.5
parent ce4dc776e5
commit d8d7bb67be
4 changed files with 83 additions and 15 deletions
@@ -86,6 +86,8 @@ final class DiviLibraryStoreTest extends TestCase
self::assertSame(21, $captured['posts_per_page']);
self::assertSame(40, $captured['offset']);
self::assertSame('Kopf', $captured['s']);
self::assertSame(['post_title'], $captured['search_columns'], 'audit L3: the title only');
self::assertArrayNotHasKey('author', $captured);
self::assertSame(
[
'relation' => 'AND',
@@ -97,6 +99,21 @@ final class DiviLibraryStoreTest extends TestCase
);
}
/** Audit L3: users without edit_others_posts query their own entries only. */
public function testFindRestrictsToAnAuthor(): void
{
$captured = [];
Functions\when('get_posts')->alias(static function (array $args) use (&$captured): array {
$captured = $args;
return [];
});
(new DiviLibraryStore())->find(['author' => 12], 20, 0);
self::assertSame(12, $captured['author']);
}
public function testReportsMissingTaxonomies(): void
{
Functions\when('taxonomy_exists')->alias(static fn (string $taxonomy): bool => $taxonomy !== 'scope');
@@ -133,6 +133,44 @@ final class LibraryListAbilityTest extends TestCase
self::assertSame(['items', 'next_cursor'], array_keys($first));
}
/**
* Audit L3: the cursor counts only the entries this user was shown – how many hidden entries
* match a search (and sort before) stays unknown.
*/
public function testTheCursorCountsNoHiddenEntries(): void
{
LibraryFixtures::given([]);
self::withoutEditPostOn([1054, 1055]);
$ids = [1054, 1055, 1056, 1057, 1058];
$first = $this->ability([], $ids)->execute(['limit' => 1]);
$second = $this->ability([], $ids)->execute(['limit' => 1, 'cursor' => $first['next_cursor']]);
self::assertSame([1056], array_column($first['items'], 'id'));
self::assertSame(Cursor::encode(1), $first['next_cursor']);
self::assertSame([1057], array_column($second['items'], 'id'));
self::assertSame(Cursor::encode(2), $second['next_cursor']);
}
/** Audit L3 (author oracle): without edit_others_posts the query itself holds only the own entries. */
public function testAnAuthorQueriesOnlyTheirOwnEntries(): void
{
LibraryFixtures::given([]);
Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap !== 'edit_others_posts');
Functions\when('get_current_user_id')->justReturn(12);
$store = LibraryFixtures::store();
$store->expects('find')->with(['search' => 'Geheim', 'author' => 12], 20, 0)->andReturn([]);
$access = LibraryFixtures::access([], true, $store);
$ability = new LibraryListAbility(
$access,
LibraryFixtures::loader($access),
DiviWriterFixture::designReader(),
LibraryFixtures::usages([])
);
self::assertSame(['items' => [], 'next_cursor' => null], $ability->execute(['search' => 'Geheim']));
}
public function testNoNextCursorWhenOnlyHiddenEntriesFollow(): void
{
LibraryFixtures::given([]);