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 @@
+