QueryBuilder: Allow hiding tags

This commit is contained in:
rubenwardy 2024-06-11 19:37:05 +01:00
parent 1a74471b68
commit d5492cbb9b
2 changed files with 26 additions and 4 deletions

@ -194,7 +194,7 @@ Filter query parameters:
* `author`: Filter by author. * `author`: Filter by author.
* `tag`: Filter by tags. Multiple tags are AND-ed together. * `tag`: Filter by tags. Multiple tags are AND-ed together.
* `flag`: Filter to show packages with [Content Flags](/help/content_flags/). * `flag`: Filter to show packages with [Content Flags](/help/content_flags/).
* `hide`: Hide content based on [Content Flags](/help/content_flags/). * `hide`: Hide content based on tags or [Content Flags](/help/content_flags/).
* `license`: Filter by [license name](#licenses). Multiple licenses are OR-ed together, ie: `&license=MIT&license=LGPL-2.1-only` * `license`: Filter by [license name](#licenses). Multiple licenses are OR-ed together, ie: `&license=MIT&license=LGPL-2.1-only`
* `game`: Filter by [Game Support](/help/game_support/), ex: `Wuzzy/mineclone2`. (experimental, doesn't show items that support every game currently). * `game`: Filter by [Game Support](/help/game_support/), ex: `Wuzzy/mineclone2`. (experimental, doesn't show items that support every game currently).
* `lang`: Filter by translation support, eg: `en`/`de`/`ja`/`zh_TW`. * `lang`: Filter by translation support, eg: `en`/`de`/`ja`/`zh_TW`.

@ -28,6 +28,7 @@ from .utils import is_yes, get_int_or_abort
class QueryBuilder: class QueryBuilder:
emit_http_errors: bool
limit: Optional[int] limit: Optional[int]
lang: str = "en" lang: str = "en"
types: List[PackageType] types: List[PackageType]
@ -35,6 +36,7 @@ class QueryBuilder:
only_approved: bool = True only_approved: bool = True
licenses: List[License] licenses: List[License]
tags: List[Tag] tags: List[Tag]
hide_tags: List[Tag]
game: Optional[Package] game: Optional[Package]
author: Optional[str] author: Optional[str]
random: bool random: bool
@ -84,6 +86,8 @@ class QueryBuilder:
self.random or self.lucky or self.author or self.version or self.game or len(self.licenses) > 0) self.random or self.lucky or self.author or self.version or self.game or len(self.licenses) > 0)
def __init__(self, args, cookies: bool = False, lang: Optional[str] = None, emit_http_errors: bool = True): def __init__(self, args, cookies: bool = False, lang: Optional[str] = None, emit_http_errors: bool = True):
self.emit_http_errors = emit_http_errors
if lang is None: if lang is None:
locale = get_locale() locale = get_locale()
if locale: if locale:
@ -94,16 +98,29 @@ class QueryBuilder:
# Get request types # Get request types
types = args.getlist("type") types = args.getlist("type")
types = [PackageType.get(tname) for tname in types] types = [PackageType.get(tname) for tname in types]
types = [type for type in types if type is not None] if not emit_http_errors:
types = [type for type in types if type is not None]
elif any([type is None for type in types]):
abort(make_response("Unknown type"), 400)
# Get tags types # Get tags types
tags = args.getlist("tag") tags = args.getlist("tag")
tags = [Tag.query.filter_by(name=tname).first() for tname in tags] tags = [Tag.query.filter_by(name=tname).first() for tname in tags]
tags = [tag for tag in tags if tag is not None] if not emit_http_errors:
tags = [tag for tag in tags if tag is not None]
elif any([tag is None for tag in tags]):
abort(make_response("Unknown tag"), 400)
# Hide # Hide
self.hide_flags = set(args.getlist("hide")) self.hide_flags = set(args.getlist("hide"))
self.hide_tags = []
for flag in set(self.hide_flags):
tag = Tag.query.filter_by(name=flag).first()
if tag is not None:
self.hide_tags.append(tag)
self.hide_flags.remove(flag)
# Show flags # Show flags
self.flags = set(args.getlist("flag")) self.flags = set(args.getlist("flag"))
@ -231,7 +248,10 @@ class QueryBuilder:
query = query.filter(Package.translations.any(language_id=self.has_lang)) query = query.filter(Package.translations.any(language_id=self.has_lang))
for tag in self.tags: for tag in self.tags:
query = query.filter(Package.tags.any(Tag.id == tag.id)) query = query.filter(Package.tags.contains(tag))
for tag in self.hide_tags:
query = query.filter(~Package.tags.contains(tag))
if "*" in self.hide_flags: if "*" in self.hide_flags:
query = query.filter(~ Package.content_warnings.any()) query = query.filter(~ Package.content_warnings.any())
@ -240,6 +260,8 @@ class QueryBuilder:
warning = ContentWarning.query.filter_by(name=flag).first() warning = ContentWarning.query.filter_by(name=flag).first()
if warning: if warning:
query = query.filter(~ Package.content_warnings.any(ContentWarning.id == warning.id)) query = query.filter(~ Package.content_warnings.any(ContentWarning.id == warning.id))
elif self.emit_http_errors:
abort(make_response("Unknown tag or content warning " + flag), 400)
flags = set(self.flags) flags = set(self.flags)
if "nonfree" in flags: if "nonfree" in flags: