From c2da6796dbb2eac0fddbfabc1e4d64986b4a5be5 Mon Sep 17 00:00:00 2001 From: tdruez Date: Wed, 8 Jan 2025 10:29:23 +0100 Subject: [PATCH] Add labels to Project level search #1520 Signed-off-by: tdruez --- CHANGELOG.rst | 4 ++++ scanpipe/filters.py | 10 +++++++--- scanpipe/tests/test_api.py | 6 +++--- scanpipe/tests/test_filters.py | 9 +++++++-- scanpipe/tests/test_models.py | 6 +++--- scanpipe/tests/test_views.py | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6db4e23f3..3574e8a7d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,10 @@ v34.9.4 (unreleased) - Add a download action on project list to enable bulk download of Project output files. https://github.com/aboutcode-org/scancode.io/issues/1518 +- Add labels to Project level search. + The labels are now always presented in alphabetical order for consistency. + https://github.com/aboutcode-org/scancode.io/issues/1520 + v34.9.3 (2024-12-31) -------------------- diff --git a/scanpipe/filters.py b/scanpipe/filters.py index 320a84e42..97972e3eb 100644 --- a/scanpipe/filters.py +++ b/scanpipe/filters.py @@ -245,15 +245,19 @@ def filter_queryset(self, queryset): `empty_value` to any filters. """ for name, value in self.form.cleaned_data.items(): - field_name = self.filters[name].field_name - if value == self.empty_value: + filter_field = self.filters[name] + field_name = filter_field.field_name + + if isinstance(filter_field, QuerySearchFilter): + queryset = filter_field.filter(queryset, value) + elif value == self.empty_value: queryset = queryset.filter(**{f"{field_name}__in": EMPTY_VALUES}) elif value == self.any_value: queryset = queryset.filter(~Q(**{f"{field_name}__in": EMPTY_VALUES})) elif value == self.other_value and hasattr(queryset, "less_common"): return queryset.less_common(name) else: - queryset = self.filters[name].filter(queryset, value) + queryset = filter_field.filter(queryset, value) return queryset diff --git a/scanpipe/tests/test_api.py b/scanpipe/tests/test_api.py index 9ae4b905f..d91087946 100644 --- a/scanpipe/tests/test_api.py +++ b/scanpipe/tests/test_api.py @@ -489,13 +489,13 @@ def test_scanpipe_api_project_create_pipeline_old_name_compatibility(self): def test_scanpipe_api_project_create_labels(self): data = { "name": "Project1", - "labels": ["label1", "label2"], + "labels": ["label2", "label1"], } response = self.csrf_client.post(self.project_list_url, data) self.assertEqual(status.HTTP_201_CREATED, response.status_code) - self.assertEqual(data["labels"], sorted(response.data["labels"])) + self.assertEqual(sorted(data["labels"]), response.data["labels"]) project = Project.objects.get(name=data["name"]) - self.assertEqual(data["labels"], sorted(project.labels.names())) + self.assertEqual(sorted(data["labels"]), list(project.labels.names())) def test_scanpipe_api_project_create_pipeline_groups(self): data = { diff --git a/scanpipe/tests/test_filters.py b/scanpipe/tests/test_filters.py index 30a882def..7a8a098be 100644 --- a/scanpipe/tests/test_filters.py +++ b/scanpipe/tests/test_filters.py @@ -95,6 +95,11 @@ def test_scanpipe_filters_project_filterset_labels(self): filterset = ProjectFilterSet(data={"label": "label2"}) self.assertEqual(0, len(filterset.qs)) + filterset = ProjectFilterSet(data={"search": "label1"}) + self.assertEqual([self.project1], list(filterset.qs)) + filterset = ProjectFilterSet(data={"search": "lab"}) + self.assertEqual([self.project1], list(filterset.qs)) + def test_scanpipe_filters_filter_queryset_empty_values(self): resource1 = CodebaseResource.objects.create( project=self.project1, @@ -276,7 +281,7 @@ def test_scanpipe_filters_parse_query_string_to_lookups(self): inputs = { "LICENSE": "(AND: ('name__icontains', 'LICENSE'))", "two words": ( - "(AND: ('name__icontains', 'two'), ('name__icontains', 'words'))" + "(OR: ('name__icontains', 'two'), ('name__icontains', 'words'))" ), "'two words'": "(AND: ('name__icontains', 'two words'))", "na me:LICENSE": ( @@ -306,7 +311,7 @@ def test_scanpipe_filters_parse_query_string_to_lookups(self): } for query_string, expected in inputs.items(): - lookups = parse_query_string_to_lookups(query_string, "icontains", "name") + lookups = parse_query_string_to_lookups(query_string, "icontains", ["name"]) self.assertEqual(expected, str(lookups)) def test_scanpipe_filters_filter_advanced_search_query_string(self): diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 9c365fde9..71064fcdf 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -816,13 +816,13 @@ def test_scanpipe_project_get_ignored_vulnerabilities_set(self): self.assertEqual(expected, self.project1.get_ignored_vulnerabilities_set()) def test_scanpipe_project_model_labels(self): - self.project1.labels.add("label1", "label2") + self.project1.labels.add("label2", "label1") self.assertEqual(2, UUIDTaggedItem.objects.count()) - self.assertEqual(["label1", "label2"], sorted(self.project1.labels.names())) + self.assertEqual(["label1", "label2"], list(self.project1.labels.names())) self.project1.labels.remove("label1") self.assertEqual(1, UUIDTaggedItem.objects.count()) - self.assertEqual(["label2"], sorted(self.project1.labels.names())) + self.assertEqual(["label2"], list(self.project1.labels.names())) self.project1.labels.clear() self.assertEqual(0, UUIDTaggedItem.objects.count()) diff --git a/scanpipe/tests/test_views.py b/scanpipe/tests/test_views.py index 8d5f507b1..6b3eb14f6 100644 --- a/scanpipe/tests/test_views.py +++ b/scanpipe/tests/test_views.py @@ -358,7 +358,7 @@ def test_scanpipe_views_project_details_add_labels(self): data["add-labels-submit"] = "" response = self.client.post(url, data, follow=True) self.assertContains(response, "Label(s) added.") - self.assertEqual(["label1", "label2"], sorted(self.project1.labels.names())) + self.assertEqual(["label1", "label2"], list(self.project1.labels.names())) def test_scanpipe_views_project_delete_label(self): self.project1.labels.add("label1")