diff --git a/app/Policies/AlbumQueryPolicy.php b/app/Policies/AlbumQueryPolicy.php index 6f4a68952dd..5e3843b7f53 100644 --- a/app/Policies/AlbumQueryPolicy.php +++ b/app/Policies/AlbumQueryPolicy.php @@ -43,7 +43,7 @@ public function __construct(AlbumFactory $albumFactory, AlbumPolicy $albumPolicy * * - the user is an admin * - the user is the owner of the album - * - the album is shared with the user and the album does not require a direct link + * - the album is shared with the user * - the album is public and the album does not require a direct link * * @param AlbumBuilder|TagAlbumBuilder $query @@ -77,11 +77,7 @@ public function applyVisibilityFilter(AlbumBuilder|FixedQueryBuilder $query): Al if ($userID !== null) { $query2 ->orWhere('base_albums.owner_id', '=', $userID) - ->orWhere( - fn (AlbumBuilder|TagAlbumBuilder $q) => $q - ->where('base_albums.requires_link', '=', false) - ->where('user_base_album.user_id', '=', $userID) - ); + ->orWhere('user_base_album.user_id', '=', $userID); } }; @@ -153,7 +149,7 @@ public function appendAccessibilityConditions(BaseBuilder $query): BaseBuilder * * - the user is the admin, or * - the user is the owner, or - * - the album does not require a direct link and is shared with the user, or + * - the album is shared with the user, or * - the album does not require a direct link, is public and has no password set, or * - the album does not require a direct link, is public and has been unlocked * @@ -197,11 +193,7 @@ public function applyReachabilityFilter(AlbumBuilder $query): AlbumBuilder if ($userID !== null) { $query2 ->orWhere('base_albums.owner_id', '=', $userID) - ->orWhere( - fn (Builder $q) => $q - ->where('base_albums.requires_link', '=', false) - ->where('user_base_album.user_id', '=', $userID) - ); + ->orWhere('user_base_album.user_id', '=', $userID); } }; @@ -355,15 +347,11 @@ public function appendUnreachableAlbumsCondition(BaseBuilder $builder, int|strin if ($userID !== null) { $builder ->where('inner_base_albums.owner_id', '<>', $userID) - ->where( + ->whereNotExists( fn (BaseBuilder $q) => $q - ->where('inner_base_albums.requires_link', '=', true) - ->orWhereNotExists( - fn (BaseBuilder $q2) => $q2 - ->from('user_base_album', 'user_inner_base_album') - ->whereColumn('user_inner_base_album.base_album_id', '=', 'inner_base_albums.id') - ->where('user_inner_base_album.user_id', '=', $userID) - ) + ->from('user_base_album', 'user_inner_base_album') + ->whereColumn('user_inner_base_album.base_album_id', '=', 'inner_base_albums.id') + ->where('user_inner_base_album.user_id', '=', $userID) ); } diff --git a/tests/Feature/AlbumTest.php b/tests/Feature/AlbumTest.php index c3905b840d2..cf0f0f79f24 100644 --- a/tests/Feature/AlbumTest.php +++ b/tests/Feature/AlbumTest.php @@ -327,8 +327,8 @@ public function testTrueNegative(): void $this->albums_tests->set_description('-1', 'new description', 422); $this->albums_tests->set_description('abcdefghijklmnopqrstuvwx', 'new description', 404); - $this->albums_tests->set_protection_policy('-1', true, true, false, false, true, true, null, 422); - $this->albums_tests->set_protection_policy('abcdefghijklmnopqrstuvwx', true, true, false, false, true, true, null, 404); + $this->albums_tests->set_protection_policy(id: '-1', expectedStatusCode: 422); + $this->albums_tests->set_protection_policy(id: 'abcdefghijklmnopqrstuvwx', expectedStatusCode: 404); Auth::logout(); Session::flush(); diff --git a/tests/Feature/GeoDataTest.php b/tests/Feature/GeoDataTest.php index a109964120f..64a85ef368c 100644 --- a/tests/Feature/GeoDataTest.php +++ b/tests/Feature/GeoDataTest.php @@ -220,7 +220,7 @@ public function testThumbnailsInsideHiddenAlbum(): void TestCase::createUploadedFile(TestCase::SAMPLE_FILE_MONGOLIA_IMAGE), $albumID13 )->offsetGet('id'); - $this->albums_tests->set_protection_policy($albumID1, true, true, true); + $this->albums_tests->set_protection_policy(id: $albumID1, full_photo: true, public: true, requiresLink: true); // Sic! We do not make album 1.1 public to ensure that the // search filter does not include too much $this->albums_tests->set_protection_policy($albumID12); diff --git a/tests/Feature/PhotosOperationsTest.php b/tests/Feature/PhotosOperationsTest.php index bb12b98b560..9b94dd3b6b6 100644 --- a/tests/Feature/PhotosOperationsTest.php +++ b/tests/Feature/PhotosOperationsTest.php @@ -360,7 +360,7 @@ public function testThumbnailsInsideHiddenAlbum(): void TestCase::createUploadedFile(TestCase::SAMPLE_FILE_SUNSET_IMAGE), $albumID121 )->offsetGet('id'); - $this->albums_tests->set_protection_policy($albumID1, true, true, true); + $this->albums_tests->set_protection_policy(id: $albumID1, full_photo: true, public: true, requiresLink: true); $this->albums_tests->set_protection_policy($albumID11); $this->albums_tests->set_protection_policy($albumID12); $this->albums_tests->set_protection_policy($albumID121); diff --git a/tests/Feature/SharingSpecialTest.php b/tests/Feature/SharingSpecialTest.php index 065668c12e5..e8f9a3df702 100644 --- a/tests/Feature/SharingSpecialTest.php +++ b/tests/Feature/SharingSpecialTest.php @@ -111,12 +111,12 @@ protected function prepareSixAlbumsWithDifferentProtectionSettings(): void $this->photos_tests->set_title($this->photoID5, 'Abenddämmerung'); // we rename the duplicated images, such that we can ensure $this->photos_tests->set_title($this->photoID6, 'Zug'); // a deterministic, alphabetic order which makes testing easier - $this->albums_tests->set_protection_policy($this->albumID1, true, true, false, false, true, true, self::ALBUM_PWD_1); - $this->albums_tests->set_protection_policy($this->albumID2); - $this->albums_tests->set_protection_policy($this->albumID3, true, true, false, false, true, true, self::ALBUM_PWD_1); - $this->albums_tests->set_protection_policy($this->albumID4, true, true, true, false, true, true, self::ALBUM_PWD_1); - $this->albums_tests->set_protection_policy($this->albumID5, true, true, false, false, true, true, self::ALBUM_PWD_2); - $this->albums_tests->set_protection_policy($this->albumID6, true, true, true, false, true, true, self::ALBUM_PWD_2); + $this->albums_tests->set_protection_policy(id: $this->albumID1, password: self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID2); + $this->albums_tests->set_protection_policy(id: $this->albumID3, password: self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID4, requiresLink: true, password: self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID5, password: self::ALBUM_PWD_2); + $this->albums_tests->set_protection_policy(id: $this->albumID6, requiresLink: true, password: self::ALBUM_PWD_2); Auth::logout(); Session::flush(); diff --git a/tests/Feature/SharingTestScenariosAbstract.php b/tests/Feature/SharingTestScenariosAbstract.php index 60127853d55..8d44471e266 100644 --- a/tests/Feature/SharingTestScenariosAbstract.php +++ b/tests/Feature/SharingTestScenariosAbstract.php @@ -104,6 +104,16 @@ public function tearDown(): void parent::tearDown(); } + abstract protected function generateExpectedRootJson( + ?string $unsortedAlbumThumbID = null, + ?string $starredAlbumThumbID = null, + ?string $publicAlbumThumbID = null, + ?string $recentAlbumThumbID = null, + array $expectedAlbumJson = [] + ): array; + + abstract protected function generateExpectedTreeJson(array $expectedAlbums = []): array; + /** * Uploads an unsorted, private photo and logs out. * @@ -312,8 +322,8 @@ protected function preparePublicAlbumAndPasswordProtectedAlbum(): void $this->albumID2 = $this->albums_tests->add(null, self::ALBUM_TITLE_2)->offsetGet('id'); $this->photoID1 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_MONGOLIA_IMAGE), $this->albumID1)->offsetGet('id'); $this->photoID2 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_TRAIN_IMAGE), $this->albumID2)->offsetGet('id'); - $this->albums_tests->set_protection_policy($this->albumID1, true, true, false, false, true, true, self::ALBUM_PWD_1); - $this->albums_tests->set_protection_policy($this->albumID2); + $this->albums_tests->set_protection_policy(id: $this->albumID1, password: self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID2); Auth::logout(); Session::flush(); $this->clearCachedSmartAlbums(); @@ -446,7 +456,7 @@ protected function preparePublicAlbumAndPasswordProtectedAlbumWithStarredPhoto() $this->albumID2 = $this->albums_tests->add(null, self::ALBUM_TITLE_2)->offsetGet('id'); $this->photoID1 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_MONGOLIA_IMAGE), $this->albumID1)->offsetGet('id'); $this->photoID2 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_TRAIN_IMAGE), $this->albumID2)->offsetGet('id'); - $this->albums_tests->set_protection_policy($this->albumID1, true, true, false, false, true, true, self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID1, password: self::ALBUM_PWD_1); $this->albums_tests->set_protection_policy($this->albumID2); $this->photos_tests->set_star([$this->photoID1], true); Auth::logout(); @@ -586,8 +596,8 @@ protected function preparePublicAlbumAndHiddenAlbum(): void $this->albumID2 = $this->albums_tests->add(null, self::ALBUM_TITLE_2)->offsetGet('id'); $this->photoID1 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_MONGOLIA_IMAGE), $this->albumID1)->offsetGet('id'); $this->photoID2 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_TRAIN_IMAGE), $this->albumID2)->offsetGet('id'); - $this->albums_tests->set_protection_policy($this->albumID1); - $this->albums_tests->set_protection_policy($this->albumID2, true, true, true); + $this->albums_tests->set_protection_policy(id: $this->albumID1); + $this->albums_tests->set_protection_policy(id: $this->albumID2, requiresLink: true); $this->photos_tests->set_star([$this->photoID2], true); Auth::logout(); Session::flush(); @@ -668,8 +678,8 @@ protected function preparePublicAlbumAndHiddenPasswordProtectedAlbum(): void $this->albumID2 = $this->albums_tests->add(null, self::ALBUM_TITLE_2)->offsetGet('id'); $this->photoID1 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_MONGOLIA_IMAGE), $this->albumID1)->offsetGet('id'); $this->photoID2 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_TRAIN_IMAGE), $this->albumID2)->offsetGet('id'); - $this->albums_tests->set_protection_policy($this->albumID1); - $this->albums_tests->set_protection_policy($this->albumID2, true, true, true, false, true, true, self::ALBUM_PWD_2); + $this->albums_tests->set_protection_policy(id: $this->albumID1); + $this->albums_tests->set_protection_policy(id: $this->albumID2, requiresLink: true, password: self::ALBUM_PWD_2); $this->photos_tests->set_star([$this->photoID2], true); Auth::logout(); Session::flush(); @@ -792,18 +802,21 @@ public function testPublicAlbumAndHiddenPasswordProtectedUnlockedAlbum(): void } /** - * Creates two albums, puts a single photo in each, shares one - * album with a user and logs out. + * Creates three albums, puts a single photo in each, shares two + * album with a user, mark one as public with requireLink and logs out. * * @return void */ - protected function preparePhotosInSharedAndPrivateAlbum(): void + protected function preparePhotosInSharedAndPrivateAndRequireLinkAlbum(): void { $this->albumID1 = $this->albums_tests->add(null, self::ALBUM_TITLE_1)->offsetGet('id'); $this->albumID2 = $this->albums_tests->add(null, self::ALBUM_TITLE_2)->offsetGet('id'); + $this->albumID3 = $this->albums_tests->add(null, self::ALBUM_TITLE_3)->offsetGet('id'); $this->photoID1 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_MONGOLIA_IMAGE), $this->albumID1)->offsetGet('id'); $this->photoID2 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_TRAIN_IMAGE), $this->albumID2)->offsetGet('id'); - $this->sharing_tests->add([$this->albumID1], [$this->userID]); + $this->photoID3 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_SUNSET_IMAGE), $this->albumID3)->offsetGet('id'); + $this->sharing_tests->add([$this->albumID1, $this->albumID3], [$this->userID]); + $this->albums_tests->set_protection_policy(id: $this->albumID3, requiresLink: true); Auth::logout(); Session::flush(); $this->clearCachedSmartAlbums(); @@ -825,7 +838,7 @@ protected function preparePhotoInSharedPublicPasswordProtectedAlbum(): void { $this->albumID1 = $this->albums_tests->add(null, self::ALBUM_TITLE_1)->offsetGet('id'); $this->photoID1 = $this->photos_tests->upload(static::createUploadedFile(static::SAMPLE_FILE_MONGOLIA_IMAGE), $this->albumID1)->offsetGet('id'); - $this->albums_tests->set_protection_policy($this->albumID1, true, true, false, false, true, true, self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID1, password: self::ALBUM_PWD_1); $this->sharing_tests->add([$this->albumID1], [$this->userID]); Auth::logout(); Session::flush(); @@ -902,12 +915,8 @@ protected function prepareThreeAlbumsWithMixedSharingAndPasswordProtection(): vo // Sic! We use the same password for both albums here, because we want // to ensure that incidentally "unlocking" an album which is also // shared has no negative side effect. - $this->albums_tests->set_protection_policy( - $this->albumID2, true, true, false, true, true, true, self::ALBUM_PWD_1 - ); - $this->albums_tests->set_protection_policy( - $this->albumID3, true, true, false, true, true, true, self::ALBUM_PWD_1 - ); + $this->albums_tests->set_protection_policy(id: $this->albumID2, nsfw: true, password: self::ALBUM_PWD_1); + $this->albums_tests->set_protection_policy(id: $this->albumID3, nsfw: true, password: self::ALBUM_PWD_1); Auth::logout(); Session::flush(); diff --git a/tests/Feature/SharingWithAnonUserAbstract.php b/tests/Feature/SharingWithAnonUserAbstract.php index 7579777d9dd..856665f0131 100644 --- a/tests/Feature/SharingWithAnonUserAbstract.php +++ b/tests/Feature/SharingWithAnonUserAbstract.php @@ -26,7 +26,7 @@ abstract class SharingWithAnonUserAbstract extends SharingTestScenariosAbstract { public function testPhotosInSharedAndPrivateAlbum(): void { - $this->preparePhotosInSharedAndPrivateAlbum(); + $this->preparePhotosInSharedAndPrivateAndRequireLinkAlbum(); $responseForRoot = $this->root_album_tests->get(); $responseForRoot->assertJson($this->generateExpectedRootJson()); @@ -34,6 +34,8 @@ public function testPhotosInSharedAndPrivateAlbum(): void $responseForRoot->assertJsonMissing(['id' => $this->photoID1]); $responseForRoot->assertJsonMissing(['id' => $this->albumID2]); $responseForRoot->assertJsonMissing(['id' => $this->photoID2]); + $responseForRoot->assertJsonMissing(['id' => $this->albumID3]); + $responseForRoot->assertJsonMissing(['id' => $this->photoID3]); $responseForStarred = $this->albums_tests->get(StarredAlbum::ID); $responseForStarred->assertJson($this->generateExpectedSmartAlbumJson(true)); @@ -41,6 +43,8 @@ public function testPhotosInSharedAndPrivateAlbum(): void $responseForStarred->assertJsonMissing(['id' => $this->photoID1]); $responseForStarred->assertJsonMissing(['id' => $this->albumID2]); $responseForStarred->assertJsonMissing(['id' => $this->photoID2]); + $responseForStarred->assertJsonMissing(['id' => $this->albumID3]); + $responseForStarred->assertJsonMissing(['id' => $this->photoID3]); $responseForRecent = $this->albums_tests->get(RecentAlbum::ID); $responseForRecent->assertJson($this->generateExpectedSmartAlbumJson(true)); @@ -48,6 +52,8 @@ public function testPhotosInSharedAndPrivateAlbum(): void $responseForRecent->assertJsonMissing(['id' => $this->photoID1]); $responseForRecent->assertJsonMissing(['id' => $this->albumID2]); $responseForRecent->assertJsonMissing(['id' => $this->photoID2]); + $responseForRecent->assertJsonMissing(['id' => $this->albumID3]); + $responseForRecent->assertJsonMissing(['id' => $this->photoID3]); $responseForTree = $this->root_album_tests->getTree(); $responseForTree->assertJson($this->generateExpectedTreeJson()); @@ -55,6 +61,8 @@ public function testPhotosInSharedAndPrivateAlbum(): void $responseForTree->assertJsonMissing(['id' => $this->photoID1]); $responseForTree->assertJsonMissing(['id' => $this->albumID2]); $responseForTree->assertJsonMissing(['id' => $this->photoID2]); + $responseForTree->assertJsonMissing(['id' => $this->albumID3]); + $responseForTree->assertJsonMissing(['id' => $this->photoID3]); $this->albums_tests->get($this->albumID1, $this->getExpectedInaccessibleHttpStatusCode(), $this->getExpectedDefaultInaccessibleMessage(), self::EXPECTED_PASSWORD_REQUIRED_MSG); $this->photos_tests->get($this->photoID1, $this->getExpectedInaccessibleHttpStatusCode()); diff --git a/tests/Feature/SharingWithNonAdminUserAbstract.php b/tests/Feature/SharingWithNonAdminUserAbstract.php index 6620293c864..4565686eaa0 100644 --- a/tests/Feature/SharingWithNonAdminUserAbstract.php +++ b/tests/Feature/SharingWithNonAdminUserAbstract.php @@ -52,15 +52,16 @@ public function testTwoPhotosInPublicAlbum(): void public function testPhotosInSharedAndPrivateAlbum(): void { - $this->preparePhotosInSharedAndPrivateAlbum(); + $this->preparePhotosInSharedAndPrivateAndRequireLinkAlbum(); $responseForRoot = $this->root_album_tests->get(); $responseForRoot->assertJson($this->generateExpectedRootJson( null, null, null, - $this->photoID1, [ + $this->photoID3, [ self::generateExpectedAlbumJson($this->albumID1, self::ALBUM_TITLE_1, null, $this->photoID1), + self::generateExpectedAlbumJson($this->albumID3, self::ALBUM_TITLE_3, null, $this->photoID3), ] )); $responseForRoot->assertJsonMissing(['id' => $this->albumID2]); @@ -70,11 +71,14 @@ public function testPhotosInSharedAndPrivateAlbum(): void $responseForStarred->assertJson($this->generateExpectedSmartAlbumJson(true)); $responseForStarred->assertJsonMissing(['id' => $this->albumID1]); $responseForStarred->assertJsonMissing(['id' => $this->photoID1]); + $responseForStarred->assertJsonMissing(['id' => $this->albumID3]); + $responseForStarred->assertJsonMissing(['id' => $this->photoID3]); $responseForRecent = $this->albums_tests->get(RecentAlbum::ID); $responseForRecent->assertJson($this->generateExpectedSmartAlbumJson( true, - $this->photoID1, [ + $this->photoID3, [ + $this->generateExpectedPhotoJson(self::SAMPLE_FILE_SUNSET_IMAGE, $this->photoID3, $this->albumID3), $this->generateExpectedPhotoJson(self::SAMPLE_FILE_MONGOLIA_IMAGE, $this->photoID1, $this->albumID1), ] )); @@ -84,6 +88,7 @@ public function testPhotosInSharedAndPrivateAlbum(): void $responseForTree = $this->root_album_tests->getTree(); $responseForTree->assertJson($this->generateExpectedTreeJson([ self::generateExpectedAlbumJson($this->albumID1, self::ALBUM_TITLE_1, null, $this->photoID1), + self::generateExpectedAlbumJson($this->albumID3, self::ALBUM_TITLE_3, null, $this->photoID3), ])); $responseForTree->assertJsonMissing(['id' => $this->albumID2]); $responseForTree->assertJsonMissing(['id' => $this->photoID2]); @@ -96,6 +101,12 @@ public function testPhotosInSharedAndPrivateAlbum(): void $this->albums_tests->get($this->albumID2, $this->getExpectedInaccessibleHttpStatusCode(), $this->getExpectedDefaultInaccessibleMessage(), self::EXPECTED_PASSWORD_REQUIRED_MSG); $this->photos_tests->get($this->photoID2, $this->getExpectedInaccessibleHttpStatusCode()); + + $responseForAlbum3 = $this->albums_tests->get($this->albumID3); + $responseForAlbum3->assertJson(self::generateExpectedAlbumJson( + $this->albumID3, self::ALBUM_TITLE_3, null, $this->photoID3 + )); + $this->photos_tests->get($this->photoID3); } public function testPhotoInSharedPublicPasswordProtectedAlbum(): void @@ -146,7 +157,8 @@ public function testThreeAlbumsWithMixedSharingAndPasswordProtection(): void null, null, null, - $this->photoID1, [ // photo 1 is alphabetically first, as photo 3 is locked + $this->photoID1, // photo 1 is alphabetically first, as photo 3 is locked + [ $this->generateExpectedAlbumJson($this->albumID1, self::ALBUM_TITLE_1, null, $this->photoID1), $this->generateExpectedAlbumJson($this->albumID2, self::ALBUM_TITLE_2, null, $this->photoID2), $this->generateExpectedAlbumJson($this->albumID3, self::ALBUM_TITLE_3), // album 3 is locked, hence no thumb