Skip to content

Commit 8b41d3f

Browse files
dioxeviljeff
andauthored
Add additional filters to scanner query rules/results (#23984)
* Add additional filters to scanner query rules/results * Test filters list * More testing * Cleanup * Unused var * Missing </li> * Add no-op migration for files model change --------- Co-authored-by: Andrew Williamson <[email protected]>
1 parent ee412ea commit 8b41d3f

File tree

8 files changed

+346
-39
lines changed

8 files changed

+346
-39
lines changed

src/olympia/amo/admin.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
from django.utils.html import format_html, format_html_join
2323

2424
from django_vite.templatetags.django_vite import vite_hmr_client
25-
from rangefilter.filters import DateRangeFilter as DateRangeFilterBase
25+
from rangefilter.filters import (
26+
DateRangeFilter as DateRangeFilterBase,
27+
NumericRangeFilter as NumericRangeFilterBase,
28+
)
2629

2730
from olympia.activity.models import IPLog
2831
from olympia.amo.models import GroupConcat, Inet6Ntoa
@@ -642,6 +645,27 @@ def choices(self, changelist):
642645
yield all_choice
643646

644647

648+
class NumericRangeFilter(FakeChoicesMixin, NumericRangeFilterBase):
649+
"""
650+
Custom rangefilter.filters.NumericRangeFilter class without the need for
651+
inline CSS/JavaScript.
652+
653+
Needs FakeChoicesMixin for the fake choices the template will be using (the
654+
upstream implementation depends on inline JavaScript for this, which we
655+
want to avoid).
656+
"""
657+
658+
template = 'admin/amo/numeric_range_filter.html'
659+
660+
def choices(self, changelist):
661+
# We want a fake 'All' choice as per FakeChoicesMixin, but as of 0.3.15
662+
# rangefilter's implementation doesn't bother setting the selected
663+
# property, and our mixin calls super(), so we have to do it here.
664+
all_choice = next(super().choices(changelist))
665+
all_choice['selected'] = not any(self.used_parameters)
666+
yield all_choice
667+
668+
645669
class MultipleRelatedListFilter(admin.SimpleListFilter):
646670
template = 'admin/amo/multiple_filter.html'
647671

src/olympia/amo/templates/admin/amo/date_range_filter.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<h3>By {{ title }}</h3>
1+
<details data-filter-title="{{ title }}" open>
2+
<summary>By {{ title }}</summary>
23
{% with choices.0 as all_choice %}
34
<form method="GET" action=".">
45
<div>
@@ -24,3 +25,4 @@ <h3>By {{ title }}</h3>
2425
</ul>
2526
</form>
2627
{% endwith %}
28+
</details>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<details data-filter-title="{{ title }}" open>
2+
<summary>By {{ title }}</summary>
3+
{% with choices.0 as all_choice %}
4+
<form method="GET" action=".">
5+
<div>
6+
{# Use .params.lists to properly support multiple values - so that if a filter using this template is present multiple times on the page, its current values are all passed to the new page when submitting this form #}
7+
{% for key, values in all_choice.params.lists %}
8+
{% for value in values %}
9+
<input type="hidden" name="{{ key }}" value="{{ value }}" />
10+
{% endfor %}
11+
{% endfor %}
12+
</div>
13+
<ul>
14+
<li {% if all_choice.selected %}class="selected"{% endif %}>
15+
<a href="{{ all_choice.query_string }}">All</a>
16+
</li>
17+
<li>
18+
{% for field in spec.form %}
19+
{{ field.errors }}
20+
{{ field.label_tag }} {{ field }}
21+
{% endfor %}
22+
</li>
23+
<li>
24+
<input type="submit" value="Submit" />
25+
</li>
26+
</ul>
27+
</form>
28+
{% endwith %}
29+
</details>

src/olympia/amo/tests/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ def addon_factory(status=amo.STATUS_APPROVED, version_kw=None, file_kw=None, **k
767767

768768
# version_changed task will be triggered and will update last_updated in
769769
# database for this add-on depending on the state of the version / files.
770-
# We're calling the function it uses to compute the value ourselves and=
770+
# We're calling the function it uses to compute the value ourselves and
771771
# sticking that into the attribute ourselves so that we already have the
772772
# correct value in the instance we are going to return.
773773
# Note: the aim is to have the instance consistent with what will be in the
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 4.2.24 on 2025-10-03 17:51
2+
3+
from django.db import migrations, models
4+
import django.utils.timezone
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('files', '0035_remove_file_reviewed'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='file',
16+
name='datestatuschanged',
17+
field=models.DateTimeField(default=django.utils.timezone.now, null=True),
18+
),
19+
]

src/olympia/files/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from django.db import models
1212
from django.dispatch import receiver
1313
from django.urls import reverse
14+
from django.utils import timezone
1415
from django.utils.crypto import get_random_string
1516
from django.utils.encoding import force_str
1617
from django.utils.functional import cached_property
@@ -112,7 +113,7 @@ class File(OnChangeMixin, ModelBase):
112113
status = models.PositiveSmallIntegerField(
113114
choices=STATUS_CHOICES.items(), default=amo.STATUS_AWAITING_REVIEW
114115
)
115-
datestatuschanged = models.DateTimeField(null=True, auto_now_add=True)
116+
datestatuschanged = models.DateTimeField(null=True, default=timezone.now)
116117
strict_compatibility = models.BooleanField(default=False)
117118
approval_date = models.DateTimeField(null=True)
118119
# Serial number of the certificate use for the signature.

src/olympia/scanners/admin.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
from olympia import amo
1616
from olympia.access import acl
1717
from olympia.addons.models import Addon
18-
from olympia.amo.admin import AMOModelAdmin, MultipleRelatedListFilter
18+
from olympia.amo.admin import (
19+
AMOModelAdmin,
20+
DateRangeFilter,
21+
MultipleRelatedListFilter,
22+
NumericRangeFilter,
23+
)
1924
from olympia.amo.templatetags.jinja_helpers import vite_asset
2025
from olympia.amo.utils import is_safe_url
2126
from olympia.constants import scanners
@@ -202,6 +207,24 @@ def __init__(self, *args, **kwargs):
202207
self.title = 'version channel'
203208

204209

210+
class VersionCreatedFilter(DateRangeFilter):
211+
def __init__(self, *args, **kwargs):
212+
super().__init__(*args, **kwargs)
213+
self.title = 'version creation date'
214+
215+
216+
class AddonCreatedFilter(DateRangeFilter):
217+
def __init__(self, *args, **kwargs):
218+
super().__init__(*args, **kwargs)
219+
self.title = 'add-on creation date'
220+
221+
222+
class AddonLastUpdatedFilter(DateRangeFilter):
223+
def __init__(self, *args, **kwargs):
224+
super().__init__(*args, **kwargs)
225+
self.title = 'add-on last updated date'
226+
227+
205228
class AddonStatusFilter(admin.ChoicesFieldListFilter):
206229
def __init__(self, *args, **kwargs):
207230
super().__init__(*args, **kwargs)
@@ -230,6 +253,12 @@ def choices(self, changelist):
230253
}
231254

232255

256+
class AddonAverageDailyUsers(NumericRangeFilter):
257+
def __init__(self, *args, **kwargs):
258+
super().__init__(*args, **kwargs)
259+
self.title = 'add-on ADU'
260+
261+
233262
class FileStatusFilter(admin.ChoicesFieldListFilter):
234263
def __init__(self, *args, **kwargs):
235264
super().__init__(*args, **kwargs)
@@ -735,8 +764,12 @@ class ScannerQueryResultAdmin(AbstractScannerResultAdminMixin, AMOModelAdmin):
735764
list_filter = (
736765
('matched_rule', ScannerRuleListFilter),
737766
('version__channel', VersionChannelFilter),
767+
('version__created', VersionCreatedFilter),
738768
('version__addon__status', AddonStatusFilter),
769+
('version__addon__created', AddonCreatedFilter),
770+
('version__addon__last_updated', AddonLastUpdatedFilter),
739771
('version__addon__disabled_by_user', AddonVisibilityFilter),
772+
('version__addon__average_daily_users', AddonAverageDailyUsers),
740773
('version__file__status', FileStatusFilter),
741774
('version__file__is_signed', FileIsSignedFilter),
742775
('was_blocked', admin.BooleanFieldListFilter),
@@ -848,7 +881,10 @@ class ScannerQueryRuleAdmin(AbstractScannerRuleAdminMixin, AMOModelAdmin):
848881
'completion_rate',
849882
'matched_results_link',
850883
)
851-
list_filter = ('state',)
884+
list_filter = (
885+
'scanner',
886+
'state',
887+
)
852888
fields = (
853889
'scanner',
854890
'run_on_disabled_addons',

0 commit comments

Comments
 (0)