diff --git a/app/Policies/PhotoQueryPolicy.php b/app/Policies/PhotoQueryPolicy.php index ab37789882a..ec01cd27e1e 100644 --- a/app/Policies/PhotoQueryPolicy.php +++ b/app/Policies/PhotoQueryPolicy.php @@ -130,6 +130,34 @@ public function applySearchabilityFilter(FixedQueryBuilder $query, ?Album $origi }); } + /** + * Restricts the photo query to only non sensitive photos. + * + * @param FixedQueryBuilder $query + * @param Album|null $origin + * + * @return FixedQueryBuilder + */ + public function applySensitivityFilter(FixedQueryBuilder $query, ?Album $origin = null, bool $include_nsfw = true): FixedQueryBuilder + { + if ($include_nsfw) { + return $query; + } + + $this->prepareModelQueryOrFail($query, true, false); + + // If origin is set, also restrict the search result for admin + // to photos which are in albums below origin. + // This is not a security filter, but simply functional. + if ($origin !== null) { + $query + ->where('albums._lft', '>=', $origin->_lft) + ->where('albums._rgt', '<=', $origin->_rgt); + } + + return $query->where(fn (Builder $query) => $this->appendSensitivityConditions($query->getQuery(), $origin?->_lft, $origin?->_rgt)); + } + /** * Adds the conditions of _searchable_ photos to the query. * diff --git a/app/Relations/HasManyPhotosByTag.php b/app/Relations/HasManyPhotosByTag.php index 5b6c7e5b090..c006e80fe57 100644 --- a/app/Relations/HasManyPhotosByTag.php +++ b/app/Relations/HasManyPhotosByTag.php @@ -69,18 +69,33 @@ public function addEagerConstraints(array $albums): void $album = $albums[0]; $tags = $album->show_tags; - $this->photo_query_policy - ->applySearchabilityFilter( - $this->getRelationQuery(), - origin: null, - include_nsfw: !Configs::getValueAsBool('hide_nsfw_in_smart_albums') - ) - ->where(function (Builder $q) use ($tags): void { - // Filter for requested tags - foreach ($tags as $tag) { - $q->where('tags', 'like', '%' . trim($tag) . '%'); - } - }); + if (Configs::getValueAsBool('TA_override_visibility')) { + $this->photo_query_policy + ->applySensitivityFilter( + $this->getRelationQuery(), + origin: null, + include_nsfw: !Configs::getValueAsBool('hide_nsfw_in_smart_albums') + ) + ->where(function (Builder $q) use ($tags): void { + // Filter for requested tags + foreach ($tags as $tag) { + $q->where('tags', 'like', '%' . trim($tag) . '%'); + } + }); + } else { + $this->photo_query_policy + ->applySearchabilityFilter( + $this->getRelationQuery(), + origin: null, + include_nsfw: !Configs::getValueAsBool('hide_nsfw_in_smart_albums') + ) + ->where(function (Builder $q) use ($tags): void { + // Filter for requested tags + foreach ($tags as $tag) { + $q->where('tags', 'like', '%' . trim($tag) . '%'); + } + }); + } } /** diff --git a/app/SmartAlbums/BaseSmartAlbum.php b/app/SmartAlbums/BaseSmartAlbum.php index d4c9a5fa636..b5fd848713b 100644 --- a/app/SmartAlbums/BaseSmartAlbum.php +++ b/app/SmartAlbums/BaseSmartAlbum.php @@ -113,14 +113,18 @@ public function get_photos(): Collection */ public function photos(): Builder { - $query = $this->photo_query_policy - ->applySearchabilityFilter( - query: Photo::query()->with(['album', 'size_variants', 'statistics']), - origin: null, - include_nsfw: !Configs::getValueAsBool('hide_nsfw_in_smart_albums') - )->where($this->smart_photo_condition); - - return $query; + $base_query = Photo::query()->with(['album', 'size_variants', 'statistics']); + + if (!Configs::getValueAsBool('SA_override_visibility')) { + return $this->photo_query_policy + ->applySearchabilityFilter(query: $base_query, origin: null, include_nsfw: !Configs::getValueAsBool('hide_nsfw_in_smart_albums')) + ->where($this->smart_photo_condition); + } + + // If the smart album visibility override is enabled, we do not need to apply any security filter, as all photos are visible + // in this smart album. We still need to apply the smart album condition, though. + return $this->photo_query_policy->applySensitivityFilter(query: $base_query, origin: null, include_nsfw: !Configs::getValueAsBool('hide_nsfw_in_smart_albums')) + ->where($this->smart_photo_condition); } /** @@ -215,4 +219,4 @@ public function setPrivate(): void $this->public_permissions = null; $perm->delete(); } -} \ No newline at end of file +} diff --git a/database/migrations/2025_05_28_174009_add_visibility_override_smart_album.php b/database/migrations/2025_05_28_174009_add_visibility_override_smart_album.php new file mode 100644 index 00000000000..9d3243260a5 --- /dev/null +++ b/database/migrations/2025_05_28_174009_add_visibility_override_smart_album.php @@ -0,0 +1,43 @@ + 'SA_override_visibility', + 'value' => '0', + 'cat' => self::CAT, + 'type_range' => self::BOOL, + 'description' => 'Smart album visibility overrides the photo visibility.', + 'details' => ' This will make any photos matching the smart album condition visible.', + 'is_expert' => true, + 'is_secret' => false, + 'level' => 0, + 'order' => 10, + ], + [ + 'key' => 'TA_override_visibility', + 'value' => '0', + 'cat' => self::CAT, + 'type_range' => self::BOOL, + 'description' => 'Tag album visibility overrides the photo visibility.', + 'details' => ' This will make any photos matching the tag album condition visible.', + 'is_expert' => true, + 'is_secret' => false, + 'level' => 0, + 'order' => 11, + ], + ]; + } +}; \ No newline at end of file