Skip to content

Commit 33717e2

Browse files
committed
Refactor the relation filtering #688
Signed-off-by: Thomas Druez <tdruez@nexb.com>
1 parent 7976ce7 commit 33717e2

6 files changed

Lines changed: 64 additions & 22 deletions

File tree

scanpipe/filters.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def filter_queryset(self, queryset):
121121
for name, value in self.form.cleaned_data.items():
122122
field_name = self.filters[name].field_name
123123
if value == self.empty_value:
124+
print(name, value)
124125
queryset = queryset.filter(**{f"{field_name}__in": EMPTY_VALUES})
125126
elif value == self.other_value and hasattr(queryset, "less_common"):
126127
return queryset.less_common(name)
@@ -278,6 +279,26 @@ def filter(self, qs, value):
278279
return qs
279280

280281

282+
class RelationMatchTypeFilter(django_filters.ChoiceFilter):
283+
def __init__(self, *args, **kwargs):
284+
kwargs["choices"] = (
285+
("", "All"),
286+
("none", "No match"),
287+
("any", "Any match"),
288+
("java_to_class", "java to class"),
289+
("path", "path"),
290+
("sha1", "sha1"),
291+
)
292+
super().__init__(*args, **kwargs)
293+
294+
def filter(self, qs, value):
295+
if value == "none":
296+
return qs.has_no_relation()
297+
elif value == "any":
298+
return qs.has_relation()
299+
return super().filter(qs, value)
300+
301+
281302
class ResourceFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
282303
search = django_filters.CharFilter(
283304
label="Search",
@@ -297,6 +318,7 @@ class ResourceFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
297318
"mime_type",
298319
"tag",
299320
"compliance_alert",
321+
"related_from__match_type",
300322
],
301323
)
302324
license_key = JSONContainsFilter(
@@ -311,6 +333,10 @@ class ResourceFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
311333
choices=CodebaseResource.Compliance.choices + [("EMPTY", "EMPTY")]
312334
)
313335
in_package = InPackageFilter(label="In a Package")
336+
relation_match_type = RelationMatchTypeFilter(
337+
label="Relation match type",
338+
field_name="related_from__match_type",
339+
)
314340

315341
class Meta:
316342
model = CodebaseResource
@@ -341,8 +367,7 @@ class Meta:
341367
"emails",
342368
"urls",
343369
"in_package",
344-
# CodebaseRelation
345-
"related_from__match_type",
370+
"relation_match_type",
346371
]
347372

348373
@classmethod

scanpipe/models.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,18 +1419,14 @@ def to_codebase(self):
14191419
"""Resources in to/ directory"""
14201420
return self.filter(path__startswith="to/")
14211421

1422+
def has_relation(self):
1423+
"""Resources assigned to at least one CodebaseRelation"""
1424+
return self.filter(Q(related_from__isnull=False) | Q(related_to__isnull=False))
1425+
14221426
def has_no_relation(self):
14231427
"""Resources not part of any CodebaseRelation"""
14241428
return self.filter(related_from__isnull=True, related_to__isnull=True)
14251429

1426-
def missing_in_to(self):
1427-
"""Resources in from/ not found in to/"""
1428-
return self.from_codebase().filter(related_to__isnull=True)
1429-
1430-
def missing_in_from(self):
1431-
"""Resources in to/ not found in from/"""
1432-
return self.to_codebase().filter(related_from__isnull=True)
1433-
14341430
def has_value(self, field_name):
14351431
return self.filter(~Q((field_name, "")))
14361432

scanpipe/templates/scanpipe/includes/match_type_filter_dropdown.html

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99
<a href="?" class="dropdown-item">
1010
All
1111
</a>
12-
<a href="?missing_only=1" class="dropdown-item">
12+
<a href="?relation_match_type=none" class="dropdown-item">
1313
No match
1414
</a>
15-
<a href="?related_from__match_type=java_to_class" class="dropdown-item">
16-
java_to_class
15+
<a href="?relation_match_type=any" class="dropdown-item">
16+
Any match
1717
</a>
18-
<a href="?related_from__match_type=path" class="dropdown-item">
19-
path
18+
<a href="?relation_match_type=java_to_class" class="dropdown-item">
19+
Java to class
2020
</a>
21-
<a href="?related_from__match_type=sha1" class="dropdown-item">
22-
sha1
21+
<a href="?relation_match_type=path" class="dropdown-item">
22+
Path
23+
</a>
24+
<a href="?relation_match_type=sha1" class="dropdown-item">
25+
SHA1
2326
</a>
2427
</div>
2528
</div>

scanpipe/templates/scanpipe/relation_list.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
<tr>
2323
<th style="width: 45%">To resource</th>
2424
<th>
25-
Match type
25+
<a href="?sort={% if "-" not in filter.data.sort %}-{% endif %}related_from__match_type" class="is-black-link">Match type</a>
26+
{% if "related_from__match_type" in filter.data.sort %}
27+
<i class="fa fa-sort-{% if "-" in filter.data.sort %}down{% else %}up{% endif %}"></i>
28+
{% endif %}
2629
<div style="float: right">
2730
{% include 'scanpipe/includes/match_type_filter_dropdown.html' %}
2831
</div>
@@ -66,6 +69,12 @@
6669
<td></td>
6770
</tr>
6871
{% endfor %}
72+
{% empty %}
73+
<tr>
74+
<td colspan="10" class="has-text-centered p-3">
75+
No Relations found. <a href="?">Clear search and filters</a>
76+
</td>
77+
</tr>
6978
{% endfor %}
7079
</tbody>
7180
</table>

scanpipe/tests/test_models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from rq.job import JobStatus
4949

5050
from scancodeio import __version__ as scancodeio_version
51+
from scanpipe.models import CodebaseRelation
5152
from scanpipe.models import CodebaseResource
5253
from scanpipe.models import DiscoveredDependency
5354
from scanpipe.models import DiscoveredPackage
@@ -1081,6 +1082,17 @@ def test_scanpipe_codebase_resource_queryset_methods(self):
10811082
self.assertEqual(1, CodebaseResource.objects.in_package().count())
10821083
self.assertEqual(2, CodebaseResource.objects.not_in_package().count())
10831084

1085+
self.assertEqual(0, CodebaseResource.objects.has_relation().count())
1086+
self.assertEqual(3, CodebaseResource.objects.has_no_relation().count())
1087+
CodebaseRelation.objects.create(
1088+
project=self.project1,
1089+
from_resource=file,
1090+
to_resource=directory,
1091+
relationship=CodebaseRelation.Relationship.IDENTICAL,
1092+
)
1093+
self.assertEqual(2, CodebaseResource.objects.has_relation().count())
1094+
self.assertEqual(1, CodebaseResource.objects.has_no_relation().count())
1095+
10841096
def test_scanpipe_codebase_resource_queryset_licenses_categories(self):
10851097
CodebaseResource.objects.all().delete()
10861098

scanpipe/views.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -953,17 +953,14 @@ class CodebaseRelationListView(
953953
paginate_by = settings.SCANCODEIO_PAGINATE_BY.get("relation", 100)
954954

955955
def get_queryset(self):
956-
queryset = (
956+
return (
957957
super()
958958
.get_queryset()
959959
.files()
960960
.to_codebase()
961961
.prefetch_related("related_from__from_resource")
962962
.distinct()
963963
)
964-
if self.request.GET.get("missing_only"):
965-
queryset = queryset.has_no_relation()
966-
return queryset
967964

968965
@staticmethod
969966
def get_rows(qs):

0 commit comments

Comments
 (0)