Skip to content

Commit

Permalink
Add optional "onlyListed" query param for SafeApps filtering (#1111)
Browse files Browse the repository at this point in the history
- Adds `onlyListed` query parameter. When it's `false`, both `visible: true` and `visible: false` Safe Apps are returned in the endpoint response. When it's `true` only `visible: true` Safe Apps are returned.
  • Loading branch information
hectorgomezv authored Apr 25, 2024
1 parent 5d33bc6 commit 6c2665f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/safe_apps/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class AccessControlPolicy(str, Enum):
DOMAIN_ALLOWLIST = "DOMAIN_ALLOWLIST"

app_id = models.BigAutoField(primary_key=True)
# TODO: rename "visible" to "listed" across the service
visible = models.BooleanField(
default=True
) # True if this safe-app should be visible from the view. False otherwise
Expand Down
48 changes: 46 additions & 2 deletions src/safe_apps/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,10 +656,54 @@ def test_visible_safe_app_is_shown(self) -> None:
self.assertEqual(response.status_code, 200)
self.assertCountEqual(response.json(), json_response)

def test_not_visible_safe_app_is_not_shown(self) -> None:
def test_not_visible_safe_app_is_shown_if_only_listed_is_not_set(self) -> None:
not_visible_safe_app = SafeAppFactory.create(visible=False)
visible_safe_app = SafeAppFactory.create(visible=True)
json_response = [
{
"id": not_visible_safe_app.app_id,
"url": not_visible_safe_app.url,
"name": not_visible_safe_app.name,
"iconUrl": f"http://testserver{not_visible_safe_app.icon_url.url}",
"description": not_visible_safe_app.description,
"chainIds": not_visible_safe_app.chain_ids,
"provider": None,
"accessControl": {
"type": "NO_RESTRICTIONS",
},
"tags": [],
"features": [],
"developerWebsite": not_visible_safe_app.developer_website,
"socialProfiles": [],
},
{
"id": visible_safe_app.app_id,
"url": visible_safe_app.url,
"name": visible_safe_app.name,
"iconUrl": f"http://testserver{visible_safe_app.icon_url.url}",
"description": visible_safe_app.description,
"chainIds": visible_safe_app.chain_ids,
"provider": None,
"accessControl": {
"type": "NO_RESTRICTIONS",
},
"tags": [],
"features": [],
"developerWebsite": visible_safe_app.developer_website,
"socialProfiles": [],
},
]
url = reverse("v1:safe-apps:list")

response = self.client.get(path=url, data=None, format="json")

self.assertEqual(response.status_code, 200)
self.assertCountEqual(response.json(), json_response)

def test_not_visible_safe_app_is_not_shown_if_only_listed_is_set(self) -> None:
SafeAppFactory.create(visible=False)
json_response: List[Dict[str, Any]] = []
url = reverse("v1:safe-apps:list")
url = reverse("v1:safe-apps:list") + f'{"?onlyListed=true"}'

response = self.client.get(path=url, data=None, format="json")

Expand Down
23 changes: 21 additions & 2 deletions src/safe_apps/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any
from typing import Any, Union

from django.db.models import Q, QuerySet
from django.utils.decorators import method_decorator
Expand All @@ -13,6 +13,10 @@
from .serializers import SafeAppsResponseSerializer


def parse_boolean_query_param(value: Union[bool, str, int]) -> bool:
return value in (True, "True", "true", "1", 1)


class SafeAppsListView(ListAPIView): # type: ignore[type-arg]
serializer_class = SafeAppsResponseSerializer
pagination_class = None
Expand All @@ -36,12 +40,21 @@ class SafeAppsListView(ListAPIView): # type: ignore[type-arg]
type=openapi.TYPE_STRING,
)

_swagger_only_listed_param = openapi.Parameter(
"onlyListed",
openapi.IN_QUERY,
description="If true, only listed/visible Safe Apps will be included. Else, all Safe Apps will be included",
type=openapi.TYPE_BOOLEAN,
default=False,
)

@method_decorator(cache_page(60 * 10, cache="safe-apps")) # Cache 10 minutes
@swagger_auto_schema(
manual_parameters=[
_swagger_chain_id_param,
_swagger_client_url_param,
_swagger_url_param,
_swagger_only_listed_param,
]
) # type: ignore[misc]
def get(self, request: Request, *args: Any, **kwargs: Any) -> Response:
Expand All @@ -52,7 +65,13 @@ def get(self, request: Request, *args: Any, **kwargs: Any) -> Response:
return super().get(request, *args, **kwargs)

def get_queryset(self) -> QuerySet[SafeApp]:
queryset = SafeApp.objects.filter(visible=True)
only_listed = parse_boolean_query_param(
self.request.query_params.get("onlyListed", False)
)
if only_listed:
queryset = SafeApp.objects.filter(visible=True)
else:
queryset = SafeApp.objects.all()

chain_id = self.request.query_params.get("chainId")
if chain_id is not None and chain_id.isdigit():
Expand Down

0 comments on commit 6c2665f

Please sign in to comment.