From b8acb0d51e8ff1017b06386ed1a1ff8cea644c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Tue, 2 Feb 2016 11:43:32 +0100 Subject: [PATCH] Fix #3846: Exclude private projects in discover calls --- taiga/projects/api.py | 5 ++-- taiga/projects/filters.py | 19 ++++++++++-- .../test_projects_resource.py | 30 +++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 2346ae29..2b04085e 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -70,8 +70,9 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, admin_serializer_class = serializers.ProjectDetailAdminSerializer list_serializer_class = serializers.ProjectSerializer permission_classes = (permissions.ProjectPermission, ) - filter_backends = (project_filters.QFilter, - project_filters.CanViewProjectObjFilterBackend) + filter_backends = (project_filters.QFilterBackend, + project_filters.CanViewProjectObjFilterBackend, + project_filters.DiscoverModeFilterBackend) filter_fields = (("member", "members"), "is_looking_for_people", diff --git a/taiga/projects/filters.py b/taiga/projects/filters.py index dbc5b557..5868a6be 100644 --- a/taiga/projects/filters.py +++ b/taiga/projects/filters.py @@ -27,6 +27,21 @@ from taiga.base.utils.db import to_tsquery logger = logging.getLogger(__name__) +class DiscoverModeFilterBackend(FilterBackend): + def filter_queryset(self, request, queryset, view): + qs = queryset + + if "discover_mode" in request.QUERY_PARAMS: + field_data = request.QUERY_PARAMS["discover_mode"] + discover_mode = self._special_values_dict.get(field_data, field_data) + + if discover_mode: + # discover_mode enabled + qs = qs.filter(anon_permissions__contains=["view_project"]) + + return super().filter_queryset(request, qs.distinct(), view) + + class CanViewProjectObjFilterBackend(FilterBackend): def filter_queryset(self, request, queryset, view): project_id = None @@ -49,7 +64,7 @@ class CanViewProjectObjFilterBackend(FilterBackend): # superuser qs = qs elif request.user.is_authenticated(): - # projet members + # authenticated user & project member membership_model = apps.get_model("projects", "Membership") memberships_qs = membership_model.objects.filter(user=request.user) if project_id: @@ -68,7 +83,7 @@ class CanViewProjectObjFilterBackend(FilterBackend): return super().filter_queryset(request, qs.distinct(), view) -class QFilter(FilterBackend): +class QFilterBackend(FilterBackend): def filter_queryset(self, request, queryset, view): # NOTE: See migtration 0033_text_search_indexes q = request.QUERY_PARAMS.get('q', None) diff --git a/tests/integration/resources_permissions/test_projects_resource.py b/tests/integration/resources_permissions/test_projects_resource.py index f90c10b7..f05b04e5 100644 --- a/tests/integration/resources_permissions/test_projects_resource.py +++ b/tests/integration/resources_permissions/test_projects_resource.py @@ -575,3 +575,33 @@ def test_project_action_unwatch(client, data): assert results == [404, 404, 200, 200] results = helper_test_http_method(client, 'post', blocked_url, None, users) assert results == [404, 404, 451, 451] + + +def test_project_list_with_discover_mode_enabled(client, data): + url = "{}?{}".format(reverse('projects-list'), "discover_mode=true") + + response = client.get(url) + projects_data = json.loads(response.content.decode('utf-8')) + assert len(projects_data) == 2 + assert response.status_code == 200 + + client.login(data.registered_user) + + response = client.get(url) + projects_data = json.loads(response.content.decode('utf-8')) + assert len(projects_data) == 2 + assert response.status_code == 200 + + client.login(data.project_member_with_perms) + + response = client.get(url) + projects_data = json.loads(response.content.decode('utf-8')) + assert len(projects_data) == 2 + assert response.status_code == 200 + + client.login(data.project_owner) + + response = client.get(url) + projects_data = json.loads(response.content.decode('utf-8')) + assert len(projects_data) == 2 + assert response.status_code == 200