Skip to content

Commit 3531154

Browse files
committed
feat: add UI to expose curation curation
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 74d4448 commit 3531154

6 files changed

Lines changed: 134 additions & 36 deletions

File tree

vulnerabilities/forms.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from django.core.validators import validate_email
1313
from django_altcha import AltchaField
1414

15+
from vulnerabilities.models import ISSUE_TYPE_CHOICES
1516
from vulnerabilities.models import ApiUser
1617

1718

@@ -103,3 +104,32 @@ class PipelineSchedulePackageForm(forms.Form):
103104

104105
class AdminLoginForm(AdminAuthenticationForm):
105106
captcha = AltchaField(floating=True, hidefooter=True)
107+
108+
109+
class AdvisoryToDoForm(forms.Form):
110+
search = forms.CharField(
111+
required=False,
112+
label=False,
113+
widget=forms.TextInput(
114+
attrs={
115+
"placeholder": "Search ToDos...",
116+
"class": "input",
117+
},
118+
),
119+
)
120+
121+
resolved = forms.ChoiceField(
122+
required=False,
123+
choices=[
124+
("", "All"),
125+
("True", "Yes"),
126+
("False", "No"),
127+
],
128+
widget=forms.Select(attrs={"class": "select"}),
129+
)
130+
131+
issue_type = forms.ChoiceField(
132+
required=False,
133+
choices=[("", "All")] + ISSUE_TYPE_CHOICES,
134+
widget=forms.Select(attrs={"class": "select"}),
135+
)

vulnerabilities/templates/advisory_todos.html

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,17 @@ <h1>Advisory To-Dos</h1>
6161
</form>
6262

6363
<div class="box">
64-
<!-- <div class="column has-text-right">
65-
<p class="has-text-weight-semibold">
66-
{{ active_pipeline_count|default:0 }} active pipeline{{ active_pipeline_count|default:0|pluralize }},
67-
{{ disabled_pipeline_count|default:0 }} disabled pipeline{{ disabled_pipeline_count|default:0|pluralize }}
68-
</p>
69-
</div> -->
7064
<table class="table is-striped is-hoverable is-fullwidth">
7165
<thead>
7266
<tr>
7367
<th colspan="4">
7468
<div class="box is-small">
7569
<div class="columns is-vcentered">
76-
<div class="column has-text-centered" style="flex: 0 0 15%; font-weight: bold;">CVE</div>
77-
<div class="column has-text-centered" style="flex: 0 0 20%; font-weight: bold;">Aliases</div>
78-
<div class="column has-text-centered" style="flex: 0 0 15%; font-weight: bold;">Resolved</div>
79-
<div class="column has-text-centered" style="flex: 0 0 10%; font-weight: bold;"># Advisories</div>
80-
<div class="column has-text-centered" style="flex: 0 0 40%; font-weight: bold;">Issue</div>
70+
<div class="column has-text-left" style="flex: 0 0 20%; font-weight: bold;">Aliases</div>
71+
<div class="column has-text-left" style="flex: 0 0 20%; font-weight: bold;">Date</div>
72+
<div class="column has-text-left" style="flex: 0 0 10%; font-weight: bold;">Resolved</div>
73+
<div class="column has-text-left" style="flex: 0 0 10%; font-weight: bold;"># Advisories</div>
74+
<div class="column has-text-left" style="flex: 0 0 40%; font-weight: bold;">Issue Type</div>
8175
</div>
8276
</div>
8377
</th>
@@ -88,11 +82,11 @@ <h1>Advisory To-Dos</h1>
8882
<input type="hidden" name="search" value="{{ form.search.value|default:'' }}">
8983

9084
<div class="columns is-vcentered px-1">
91-
<div class="column has-text-centered" style="flex: 0 0 15%;"></div>
92-
<div class="column has-text-centered" style="flex: 0 0 20%;"></div>
85+
<div class="column has-text-left" style="flex: 0 0 20%;"></div>
86+
<div class="column has-text-left" style="flex: 0 0 20%;"></div>
9387

94-
<div class="column has-text-centered" style="flex: 0 0 15%;">
95-
<div class="select is-fullwidth">
88+
<div class="column " style="flex: 0 0 10%;">
89+
<div class="select is-half">
9690
<select name="resolved" onchange="this.form.submit()">
9791
{% for val, label in form.fields.resolved.choices %}
9892
<option value="{{ val }}"
@@ -104,10 +98,10 @@ <h1>Advisory To-Dos</h1>
10498
</div>
10599
</div>
106100

107-
<div class="column has-text-centered" style="flex: 0 0 10%;"></div>
101+
<div class="column has-text-left" style="flex: 0 0 10%;"></div>
108102

109-
<div class="column has-text-centered" style="flex: 0 0 40%;">
110-
<div class="select is-fullwidth">
103+
<div class="column" style="flex: 0 0 40%;">
104+
<div class="select is-half">
111105
<select name="issue_type" onchange="this.form.submit()">
112106
{% for val, label in form.fields.issue_type.choices %}
113107
<option value="{{ val }}"
@@ -128,25 +122,31 @@ <h1>Advisory To-Dos</h1>
128122
{% for todo in todo_list %}
129123
<tr>
130124
<td colspan="4">
131-
<a href="{% url 'todo-detail' todo_id=todo.todo_id %}" class="has-text-info">
132-
<div class="columns px-1 is-vcentered">
133-
<div class="column has-text-centered" style="flex: 0 0 15%;">
134-
{{ todo.alias }}
135-
</div>
136-
<div class="column has-text-centered" style="flex: 0 0 20%;">
137-
{{ todo.oldest_advisory_date|default:"NA" }}
138-
</div>
139-
<div class="column has-text-centered has-text-grey" style="flex: 0 0 15%;">
140-
{{ todo.is_resolved|yesno:"Yes,No" }}
141-
</div>
142-
<div class="column has-text-centered has-text-grey" style="flex: 0 0 10%;">
143-
{{ todo.advisories.all|length }}
144-
</div>
145-
<div class="column has-text-centered has-text-grey" style="flex: 0 0 40%;">
146-
{{ todo.get_issue_type_display }}
125+
{% with supported_curation="CONFLICTING_FIXED_BY_PACKAGES CONFLICTING_AFFECTED_PACKAGES CONFLICTING_AFFECTED_AND_FIXED_BY_PACKAGES" %}
126+
{% if todo.issue_type in supported_curation.split %}
127+
<a href="{% url 'todo-detail' todo_id=todo.todo_id %}" class="has-text-info">
128+
{% endif %}
129+
<div class="columns px-1 is-vcentered">
130+
<div class="column has-text-left" style="flex: 0 0 20%;">
131+
{{ todo.alias }}
132+
</div>
133+
<div class="column has-text-left" style="flex: 0 0 20%;">
134+
{{ todo.oldest_advisory_date|default:"NA" }}
135+
</div>
136+
<div class="column has-text-centered has-text-grey" style="flex: 0 0 10%;">
137+
{{ todo.is_resolved|yesno:"Yes,No" }}
138+
</div>
139+
<div class="column has-text-centered has-text-grey" style="flex: 0 0 10%;">
140+
{{ todo.advisories_count }}
141+
</div>
142+
<div class="column has-text-left has-text-grey" style="flex: 0 0 40%;">
143+
{{ todo.get_issue_type_display }}
144+
</div>
147145
</div>
148-
</div>
149-
</a>
146+
{% if todo.issue_type in supported_curation.split %}
147+
</a>
148+
{% endif %}
149+
{% endwith %}
150150
</td>
151151
</tr>
152152
{% empty %}

vulnerabilities/templates/navbar.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
</div>
3636
</div>
3737
<div class="navbar-end mr-3">
38+
<a class="navbar-item {% active_item 'todo-list' %}" href="{% url 'todo-list' %}">
39+
Advisory To-Dos
40+
</a>
3841
<a class="navbar-item {% active_item 'dashboard' %}" href="{% url 'dashboard' %}">
3942
Pipeline Dashboard
4043
</a>

vulnerabilities/templatetags/utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,16 @@ def active_item(context, url_name):
3939
@register.filter
4040
def get_item(dictionary, key):
4141
return dictionary.get(key)
42+
43+
44+
@register.simple_tag
45+
def querystring(request, **kwargs):
46+
query = request.GET.copy()
47+
48+
for key, value in kwargs.items():
49+
if value in [None, ""]:
50+
query.pop(key, None)
51+
continue
52+
query[key] = value
53+
54+
return query.urlencode()

vulnerabilities/views.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
9+
910
import logging
1011
from collections import defaultdict
1112
from typing import List
@@ -36,11 +37,14 @@
3637
from vulnerabilities import models
3738
from vulnerabilities.forms import AdminLoginForm
3839
from vulnerabilities.forms import AdvisorySearchForm
40+
from vulnerabilities.forms import AdvisoryToDoForm
3941
from vulnerabilities.forms import ApiUserCreationForm
4042
from vulnerabilities.forms import PackageSearchForm
4143
from vulnerabilities.forms import PipelineSchedulePackageForm
4244
from vulnerabilities.forms import VulnerabilitySearchForm
45+
from vulnerabilities.models import ISSUE_TYPE_CHOICES
4346
from vulnerabilities.models import AdvisorySetMember
47+
from vulnerabilities.models import AdvisoryToDoV2
4448
from vulnerabilities.models import AdvisoryV2
4549
from vulnerabilities.models import Group
4650
from vulnerabilities.models import GroupedAdvisory
@@ -1040,3 +1044,45 @@ def get_context_data(self, **kwargs):
10401044
context["site_title"] = "VulnerableCode site admin"
10411045
context["site_header"] = "VulnerableCode Administration"
10421046
return context
1047+
1048+
1049+
class AdvisoryToDoListView(ListView, FormMixin):
1050+
model = AdvisoryToDoV2
1051+
context_object_name = "todo_list"
1052+
template_name = "advisory_todos.html"
1053+
paginate_by = 20
1054+
form_class = AdvisoryToDoForm
1055+
1056+
def get_form_kwargs(self):
1057+
kwargs = super().get_form_kwargs()
1058+
kwargs["data"] = self.request.GET
1059+
return kwargs
1060+
1061+
def get_queryset(self):
1062+
form = self.form_class(self.request.GET)
1063+
resolved = self.request.GET.get("resolved")
1064+
issue_type = self.request.GET.get("issue_type")
1065+
1066+
qs = (
1067+
super()
1068+
.get_queryset()
1069+
.filter(is_todo_stale=False)
1070+
.order_by("-advisories_count", "-oldest_advisory_date")
1071+
)
1072+
if resolved in ["True", "False"]:
1073+
qs = qs.filter(is_resolved=(resolved == "True"))
1074+
1075+
if issue_type:
1076+
qs = qs.filter(issue_type=issue_type)
1077+
1078+
qs.prefetch_related("advisories__aliases")
1079+
if form.is_valid() and (search := form.cleaned_data.get("search")):
1080+
return qs.filter(advisories__aliases__alias__icontains=search)
1081+
1082+
return qs
1083+
1084+
def get_context_data(self, **kwargs):
1085+
context = super().get_context_data(**kwargs)
1086+
context["issue_choices"] = ISSUE_TYPE_CHOICES
1087+
1088+
return context

vulnerablecode/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from vulnerabilities.views import AdminLoginView
3333
from vulnerabilities.views import AdvisoryDetails
3434
from vulnerabilities.views import AdvisoryPackagesDetails
35+
from vulnerabilities.views import AdvisoryToDoListView
3536
from vulnerabilities.views import AffectedByAdvisoriesListView
3637
from vulnerabilities.views import ApiUserCreateView
3738
from vulnerabilities.views import FixingAdvisoriesListView
@@ -99,6 +100,11 @@ def __init__(self, *args, **kwargs):
99100
PipelineScheduleListView.as_view(),
100101
name="dashboard",
101102
),
103+
path(
104+
"advisories/todos/",
105+
AdvisoryToDoListView.as_view(),
106+
name="todo-list",
107+
),
102108
path(
103109
"pipelines/<str:pipeline_id>/runs/",
104110
PipelineRunListView.as_view(),

0 commit comments

Comments
 (0)