diff --git a/etiquette/exceptions.py b/etiquette/exceptions.py index 4ce9034..e29e628 100644 --- a/etiquette/exceptions.py +++ b/etiquette/exceptions.py @@ -193,6 +193,13 @@ class FeatureDisabled(EtiquetteException): ''' error_message = 'This feature has been disabled. Requires {}.' +class NoYields(EtiquetteException): + ''' + For when all of the yield_* arguments have been provided as False, and thus + there is nothing for the called function to yield. + ''' + error_message = 'At least one of {} must be selected.' + class NotExclusive(EtiquetteException): ''' For when two or more mutually exclusive actions have been requested. diff --git a/etiquette/photodb.py b/etiquette/photodb.py index 964ced8..076db60 100644 --- a/etiquette/photodb.py +++ b/etiquette/photodb.py @@ -559,6 +559,7 @@ class PDBPhotoMixin: give_back_parameters=False, yield_albums=True, + yield_photos=True, ): ''' PHOTO PROPERTIES @@ -683,6 +684,7 @@ class PDBPhotoMixin: mimetype = searchhelpers.normalize_extension(mimetype) within_directory = searchhelpers.normalize_within_directory(within_directory, warning_bag=warning_bag) yield_albums = searchhelpers.normalize_yield_albums(yield_albums) + yield_photos = searchhelpers.normalize_yield_photos(yield_photos) if has_tags is False: tag_musts = None @@ -773,9 +775,19 @@ class PDBPhotoMixin: 'offset': offset or None, 'orderby': giveback_orderby or None, 'yield_albums': yield_albums, + 'yield_photos': yield_photos, } yield parameters + if not yield_albums and not yield_photos: + exc = exceptions.NoYields(['yield_albums', 'yield_photos']) + if warning_bag: + warning_bag.add(exc) + yield warning_bag + return + else: + raise exceptions.NoYields(['yield_albums', 'yield_photos']) + photo_tag_rel_exist_clauses = searchhelpers.photo_tag_rel_exist_clauses( tag_musts, tag_mays, @@ -826,6 +838,9 @@ class PDBPhotoMixin: if has_tags is False: wheres.append('NOT EXISTS (SELECT 1 FROM photo_tag_rel WHERE photoid == photos.id)') + if yield_albums and not yield_photos: + wheres.append('EXISTS (SELECT 1 FROM album_photo_rel WHERE photoid == photos.id)') + if has_thumbnail is True: notnulls.add('thumbnail') elif has_thumbnail is False: @@ -875,7 +890,7 @@ class PDBPhotoMixin: #print('\n'.join(str(x) for x in explain.fetchall())) generator = self.sql_select(query, bindings) seen_albums = set() - photos_received = 0 + results_received = 0 for row in generator: photo = self.get_cached_instance('photo', row) @@ -898,16 +913,18 @@ class PDBPhotoMixin: offset -= 1 continue - if limit is not None and photos_received >= limit: + if limit is not None and results_received >= limit: break if yield_albums: new_albums = photo.get_containing_albums().difference(seen_albums) yield from new_albums + results_received += len(new_albums) seen_albums.update(new_albums) - photos_received += 1 - yield photo + if yield_photos: + yield photo + results_received += 1 if warning_bag and warning_bag.warnings: yield warning_bag diff --git a/etiquette/searchhelpers.py b/etiquette/searchhelpers.py index a8aed61..35bf8ac 100644 --- a/etiquette/searchhelpers.py +++ b/etiquette/searchhelpers.py @@ -422,6 +422,12 @@ def normalize_yield_albums(yield_albums): ''' return helpers.truthystring(yield_albums) +def normalize_yield_photos(yield_photos): + ''' + See etiquette.helpers.truthystring. + ''' + return helpers.truthystring(yield_photos) + EXIST_FORMAT = ''' {operator} ( SELECT 1 FROM photo_tag_rel WHERE photos.id == photo_tag_rel.photoid diff --git a/frontends/etiquette_flask/backend/endpoints/photo_endpoints.py b/frontends/etiquette_flask/backend/endpoints/photo_endpoints.py index eb39b19..69b383f 100644 --- a/frontends/etiquette_flask/backend/endpoints/photo_endpoints.py +++ b/frontends/etiquette_flask/backend/endpoints/photo_endpoints.py @@ -326,6 +326,7 @@ def get_search_core(): mimetype = request.args.get('mimetype') is_searchhidden = request.args.get('is_searchhidden', False) yield_albums = request.args.get('yield_albums', True) + yield_photos = request.args.get('yield_photos', True) limit = request.args.get('limit') # This is being pre-processed because the site enforces a maximum value @@ -382,6 +383,7 @@ def get_search_core(): 'give_back_parameters': True, 'yield_albums': yield_albums, + 'yield_photos': yield_photos, } # print(search_kwargs) search_generator = common.P.search(**search_kwargs) @@ -394,14 +396,11 @@ def get_search_core(): warnings = set() search_results = [] - search_results_photo_count = 0 for item in search_generator: if isinstance(item, etiquette.objects.WarningBag): warnings.update(item.warnings) continue search_results.append(item) - if isinstance(item, etiquette.objects.Photo): - search_results_photo_count += 1 # TAGS ON THIS PAGE total_tags = set() @@ -415,7 +414,7 @@ def get_search_core(): original_params = request.args.to_dict() original_params['limit'] = limit - if limit and search_results_photo_count >= limit: + if limit and len(search_results) >= limit: next_params = original_params.copy() next_params['offset'] = offset + limit next_params = helpers.dict_to_params(next_params) diff --git a/frontends/etiquette_flask/templates/search.html b/frontends/etiquette_flask/templates/search.html index 00eec33..5f2f0b3 100644 --- a/frontends/etiquette_flask/templates/search.html +++ b/frontends/etiquette_flask/templates/search.html @@ -298,6 +298,10 @@ +