Skip to content

Commit

Permalink
Merge pull request #7577 from jutoft/bugfix/swagger_boolean_inputs
Browse files Browse the repository at this point in the history
Support true/false for boolean url query arguments.
  • Loading branch information
kozlovsky authored Aug 24, 2023
2 parents 7521758 + 62c2b03 commit e9301bb
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pathlib import Path

from aiohttp import ClientSession, ContentTypeError, web
from aiohttp_apispec import docs, json_schema
from aiohttp_apispec import docs, json_schema, querystring_schema
from ipv8.REST.schema import schema
from marshmallow.fields import Boolean, Integer, String
from pony.orm import db_session
Expand All @@ -17,13 +17,13 @@
from tribler.core.components.metadata_store.db.orm_bindings.channel_node import DIRTY_STATUSES, NEW
from tribler.core.components.metadata_store.db.serialization import CHANNEL_TORRENT, REGULAR_TORRENT
from tribler.core.components.metadata_store.restapi.metadata_endpoint_base import MetadataEndpointBase
from tribler.core.components.metadata_store.restapi.metadata_schema import ChannelSchema, MetadataSchema, TorrentSchema
from tribler.core.components.metadata_store.restapi.metadata_schema import ChannelSchema, MetadataParameters, MetadataSchema, TorrentSchema
from tribler.core.components.metadata_store.utils import NoChannelSourcesException, RequestTimeoutException
from tribler.core.components.restapi.rest.rest_endpoint import HTTP_BAD_REQUEST, HTTP_NOT_FOUND, RESTResponse
from tribler.core.components.restapi.rest.schema import HandledErrorSchema
from tribler.core.utilities.simpledefs import CHANNEL_STATE
from tribler.core.utilities.unicode import hexlify
from tribler.core.utilities.utilities import froze_it, parse_magnetlink
from tribler.core.utilities.utilities import froze_it, parse_bool, parse_magnetlink

ERROR_INVALID_MAGNET_LINK = "Invalid magnet link: %s"

Expand Down Expand Up @@ -102,9 +102,10 @@ def get_channel_from_request(self, request):
}
},
)
@querystring_schema(MetadataParameters)
async def get_channels(self, request):
sanitized = self.sanitize_parameters(request.query)
sanitized['subscribed'] = None if 'subscribed' not in request.query else bool(int(request.query['subscribed']))
sanitized['subscribed'] = None if 'subscribed' not in request.query else parse_bool(request.query['subscribed'])
include_total = request.query.get('include_total', '')
sanitized.update({"origin_id": 0})
sanitized['metadata_type'] = CHANNEL_TORRENT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from tribler.core.components.metadata_store.db.store import MetadataStore
from tribler.core.components.restapi.rest.rest_endpoint import RESTEndpoint

from tribler.core.utilities.utilities import parse_bool

# This dict is used to translate JSON fields into the columns used in Pony for _sorting_.
# id_ is not in the list because there is not index on it, so we never really want to sort on it.

Expand Down Expand Up @@ -55,16 +57,16 @@ def sanitize_parameters(cls, parameters):
"first": int(parameters.get('first', 1)),
"last": int(parameters.get('last', 50)),
"sort_by": json2pony_columns.get(parameters.get('sort_by')),
"sort_desc": bool(int(parameters.get('sort_desc', 1)) > 0),
"sort_desc": parse_bool(parameters.get('sort_desc', True)),
"txt_filter": parameters.get('txt_filter'),
"hide_xxx": bool(int(parameters.get('hide_xxx', 0)) > 0),
"hide_xxx": parse_bool(parameters.get('hide_xxx', False)),
"category": parameters.get('category'),
"exclude_deleted": bool(int(parameters.get('exclude_deleted', 0)) > 0),
"exclude_deleted": parse_bool(parameters.get('exclude_deleted', False)),
}
if 'tags' in parameters:
sanitized['tags'] = parameters.getall('tags')
if "remote" in parameters:
sanitized["remote"] = (bool(int(parameters.get('remote', 0)) > 0),)
sanitized["remote"] = (parse_bool(parameters.get('remote', False)),)
if 'metadata_type' in parameters:
mtypes = []
for arg in parameters.getall('metadata_type'):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ class MetadataParameters(Schema):
hide_xxx = Boolean(default=False, description='Toggles xxx filter')
category = String()
exclude_deleted = Boolean(default=False)
remote_query = Boolean(default=False)
metadata_type = List(String(description='Limits query to certain metadata types (e.g. "torrent" or "channel")'))


class SearchMetadataParameters(MetadataParameters):
include_total = Boolean(default=False, description='Include total rows found in query response, expensive if '
'there is many rows')
max_rowid = Integer(default=None, description='Only return results with rowid lesser than max_rowid')


class RemoteQueryParameters(MetadataParameters):
uuid = String()
channel_pk = String()
channel_pk = String(description='Channel to query, must also define origin_id')
origin_id = Integer(default=None, description='Peer id to query, must also define channel_pk')


class MetadataSchema(Schema):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from aiohttp import web
from aiohttp_apispec import docs, querystring_schema
from ipv8.REST.schema import schema
from marshmallow.fields import String
from marshmallow.fields import String, List
from pony.orm import db_session

from tribler.core.components.gigachannel.community.gigachannel_community import GigaChannelCommunity
Expand Down Expand Up @@ -43,7 +43,15 @@ def sanitize_parameters(self, parameters):
@docs(
tags=['Metadata'],
summary="Perform a search for a given query.",
responses={200: {'schema': schema(RemoteSearchResponse={'request_uuid': String()})}},
responses={200: {
'schema': schema(RemoteSearchResponse={'request_uuid': String(), 'peers': List(String())})},
"examples": {
'Success': {
"request_uuid": "268560c0-3f28-4e6e-9d85-d5ccb0269693",
"peers": ["50e9a2ce646c373985a8e827e328830e053025c6", "107c84e5d9636c17b46c88c3ddb54842d80081b0"]
}
}
},
)
@querystring_schema(RemoteQueryParameters)
async def create_remote_search_request(self, request):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from tribler.core.components.metadata_store.db.serialization import SNIPPET
from tribler.core.components.metadata_store.db.store import MetadataStore
from tribler.core.components.metadata_store.restapi.metadata_endpoint import MetadataEndpointBase
from tribler.core.components.metadata_store.restapi.metadata_schema import MetadataParameters, MetadataSchema
from tribler.core.components.metadata_store.restapi.metadata_schema import SearchMetadataParameters, MetadataSchema
from tribler.core.components.restapi.rest.rest_endpoint import HTTP_BAD_REQUEST, RESTResponse
from tribler.core.utilities.pony_utils import run_threaded
from tribler.core.utilities.utilities import froze_it
Expand Down Expand Up @@ -110,7 +110,7 @@ def build_snippets(self, search_results: List[Dict]) -> List[Dict]:
}
},
)
@querystring_schema(MetadataParameters)
@querystring_schema(SearchMetadataParameters)
async def search(self, request):
try:
sanitized = self.sanitize_parameters(request.query)
Expand Down
17 changes: 16 additions & 1 deletion src/tribler/core/utilities/tests/test_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from tribler.core.utilities.utilities import (Query, extract_tags, get_normally_distributed_positive_integers,
is_channel_public_key,
is_infohash, is_simple_match_query, is_valid_url, parse_magnetlink,
parse_query, random_infohash, show_system_popup, to_fts_query)
parse_query, parse_bool, random_infohash, show_system_popup, to_fts_query)


# pylint: disable=import-outside-toplevel, import-error, redefined-outer-name
Expand Down Expand Up @@ -187,6 +187,21 @@ def test_parse_query():
assert actual == expected


def test_parse_bool():
assert not parse_bool('')
assert not parse_bool('false')
assert not parse_bool('False')
assert not parse_bool('0')
assert not parse_bool(0)
assert not parse_bool(False)
assert parse_bool('true')
assert parse_bool('True')
assert parse_bool('1')
assert parse_bool('-1')
assert parse_bool(1)
assert parse_bool(True)


@patch_import(modules=['win32api'], MessageBox=MagicMock())
@patch('platform.system', new=MagicMock(return_value='Windows'))
@patch('tribler.core.utilities.utilities.print', new=MagicMock)
Expand Down
18 changes: 18 additions & 0 deletions src/tribler/core/utilities/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,24 @@ def to_fts_query(text):
return ' '.join(words)


def parse_bool(obj):
"""
Parse input to boolean True or False
Allow parsing text 'false', 'true' '1', '0' to boolean
:param obj: Object to parse
"""
if isinstance(obj, str):
if obj.lower() == "false":
return False

try:
return bool(int(obj))
except ValueError:
pass
return bool(obj)


def show_system_popup(title, text):
"""
Create a native pop-up without any third party dependency.
Expand Down

0 comments on commit e9301bb

Please sign in to comment.