Skip to content

Commit 85e90fe

Browse files
authored
Implementation of Finding Group View/Edit (DefectDojo#7566)
* Implemented Finding Group View/Edit * flake8 fix * More flake8 fixes * Attempt to fix unit test failures
1 parent 074d845 commit 85e90fe

8 files changed

Lines changed: 165 additions & 82 deletions

File tree

dojo/finding_group/urls.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
urlpatterns = [
66
# finding group
77
re_path(r'^finding_group/(?P<fgid>\d+)$', views.view_finding_group, name='view_finding_group'),
8-
re_path(r'^finding_group/(?P<fgid>\d+)/edit$', views.edit_finding_group, name='edit_finding_group'),
98
re_path(r'^finding_group/(?P<fgid>\d+)/delete$', views.delete_finding_group, name='delete_finding_group'),
10-
119
re_path(r'^finding_group/(?P<fgid>\d+)/jira/push$', views.push_to_jira, name='finding_group_push_to_jira'),
1210
re_path(r'^finding_group/(?P<fgid>\d+)/jira/unlink$', views.unlink_jira, name='finding_group_unlink_jira'),
1311
]

dojo/finding_group/views.py

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,93 @@
1-
# # findings
2-
from dojo.utils import Product_Tab
3-
from dojo.forms import DeleteFindingGroupForm
1+
from dojo.utils import Product_Tab, add_breadcrumb, get_words_for_field, get_page_items
2+
from dojo.forms import DeleteFindingGroupForm, EditFindingGroupForm, FindingBulkUpdateForm
43
from dojo.notifications.helper import create_notification
4+
from dojo.finding.views import prefetch_for_findings
5+
from dojo.filters import FindingFilter
56
from django.contrib import messages
67
from django.contrib.admin.utils import NestedObjects
78
from django.db.utils import DEFAULT_DB_ALIAS
89
from django.http.response import HttpResponse, HttpResponseRedirect, JsonResponse
910
from django.shortcuts import get_object_or_404, render
1011
from django.urls.base import reverse
1112
from django.views.decorators.http import require_POST
12-
from dojo.models import Finding_Group
13+
from dojo.models import Finding_Group, Product, Engagement, Finding, GITHUB_PKey
1314
import logging
1415
import dojo.jira_link.helper as jira_helper
1516
from dojo.authorization.authorization_decorators import user_is_authorized
1617
from dojo.authorization.roles_permissions import Permissions
18+
from dojo.authorization.authorization import user_has_permission_or_403
1719

1820
logger = logging.getLogger(__name__)
1921

2022

2123
@user_is_authorized(Finding_Group, Permissions.Finding_Group_View, 'fgid')
2224
def view_finding_group(request, fgid):
23-
logger.debug('view finding group: %s', fgid)
24-
return HttpResponse('Not implemented yet')
25-
25+
finding_group = get_object_or_404(Finding_Group, pk=fgid)
26+
findings = finding_group.findings.all()
27+
edit_finding_group_form = EditFindingGroupForm(instance=finding_group)
28+
29+
show_product_column = True
30+
custom_breadcrumb = None
31+
product_tab = None
32+
jira_project = None
33+
github_config = None
34+
35+
if finding_group.test.engagement.product.id:
36+
pid = finding_group.test.engagement.product.id
37+
product = get_object_or_404(Product, id=pid)
38+
user_has_permission_or_403(request.user, product, Permissions.Product_View)
39+
product_tab = Product_Tab(product, title="Findings", tab="findings")
40+
jira_project = jira_helper.get_jira_project(product)
41+
github_config = GITHUB_PKey.objects.filter(product=pid).first()
42+
findings_filter = FindingFilter(request.GET, findings, user=request.user, pid=pid)
43+
elif finding_group.test.engagement.id:
44+
eid = finding_group.test.engagement.id
45+
engagement = get_object_or_404(Engagement, id=eid)
46+
user_has_permission_or_403(request.user, engagement, Permissions.Engagement_View)
47+
product_tab = Product_Tab(engagement.product, title=engagement.name, tab="engagements")
48+
jira_project = jira_helper.get_jira_project(engagement)
49+
github_config = GITHUB_PKey.objects.filter(product__engagement=eid).first()
50+
findings_filter = FindingFilter(request.GET, findings, user=request.user, eid=eid)
51+
52+
title_words = get_words_for_field(Finding, 'title')
53+
component_words = get_words_for_field(Finding, 'component_name')
54+
55+
paged_findings = get_page_items(request, findings_filter.qs, 25)
56+
paged_findings.object_list = prefetch_for_findings(paged_findings.object_list, 'all')
57+
58+
bulk_edit_form = FindingBulkUpdateForm(request.GET)
59+
60+
if github_config:
61+
github_config = github_config.git_conf_id
62+
63+
filter_name = finding_group.name
2664

27-
@user_is_authorized(Finding_Group, Permissions.Finding_Group_Edit, 'fgid')
28-
def edit_finding_group(request, fgid):
29-
logger.debug('edit finding group: %s', fgid)
30-
return HttpResponse('Not implemented yet')
65+
if request.method == 'POST':
66+
edit_finding_group_form = EditFindingGroupForm(request.POST, instance=finding_group)
67+
if edit_finding_group_form.is_valid():
68+
finding_group.name = edit_finding_group_form.cleaned_data.get('name', '')
69+
finding_group.save()
70+
return HttpResponseRedirect(reverse('view_test', args=(finding_group.test.id,)))
71+
72+
add_breadcrumb(title=finding_group.name, top_level=not len(request.GET), request=request)
73+
return render(request, 'dojo/view_finding_group.html', {
74+
'show_product_column': show_product_column,
75+
'product_tab': product_tab,
76+
'findings': paged_findings,
77+
'filtered': findings_filter,
78+
'title_words': title_words,
79+
'component_words': component_words,
80+
'custom_breadcrumb': custom_breadcrumb,
81+
'filter_name': filter_name,
82+
'jira_project': jira_project,
83+
'bulk_edit_form': bulk_edit_form,
84+
'edit_finding_group_form': edit_finding_group_form,
85+
})
3186

3287

3388
@user_is_authorized(Finding_Group, Permissions.Finding_Group_Delete, 'fgid')
3489
@require_POST
3590
def delete_finding_group(request, fgid):
36-
logger.debug('delete finding group: %s', fgid)
3791
finding_group = get_object_or_404(Finding_Group, pk=fgid)
3892
form = DeleteFindingGroupForm(instance=finding_group)
3993

@@ -61,12 +115,12 @@ def delete_finding_group(request, fgid):
61115
rels = collector.nested()
62116
product_tab = Product_Tab(finding_group.test.engagement.product, title="Product", tab="settings")
63117

64-
return render(request, 'dojo/delete_finding_group.html',
65-
{'finding_group': finding_group,
66-
'form': form,
67-
'product_tab': product_tab,
68-
'rels': rels,
69-
})
118+
return render(request, 'dojo/delete_finding_group.html', {
119+
'finding_group': finding_group,
120+
'form': form,
121+
'product_tab': product_tab,
122+
'rels': rels,
123+
})
70124

71125

72126
@user_is_authorized(Finding_Group, Permissions.Finding_Group_Edit, 'fgid')
@@ -113,7 +167,7 @@ def push_to_jira(request, fgid):
113167
logger.info('trying to push %d:%s to JIRA to create or update JIRA issue', group.id, group.name)
114168
logger.debug('pushing to jira from group.push_to-jira()')
115169

116-
# it may look like succes here, but the push_to_jira are swallowing exceptions
170+
# it may look like success here, but the push_to_jira are swallowing exceptions
117171
# but cant't change too much now without having a test suite, so leave as is for now with the addition warning message to check alerts for background errors.
118172
if jira_helper.push_to_jira(group, sync=True):
119173
messages.add_message(
@@ -138,4 +192,3 @@ def push_to_jira(request, fgid):
138192
'Error pushing to JIRA',
139193
extra_tags='alert-danger')
140194
return HttpResponse(status=500)
141-
# return redirect_to_return_url_or_else(request, reverse('view_finding', args=(group.id,)))

dojo/forms.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,14 @@ class Meta:
277277
fields = ['id']
278278

279279

280+
class EditFindingGroupForm(forms.ModelForm):
281+
name = forms.CharField(max_length=255, required=True, label='Finding Group Name')
282+
283+
class Meta:
284+
model = Finding_Group
285+
fields = ['name']
286+
287+
280288
class DeleteFindingGroupForm(forms.ModelForm):
281289
id = forms.IntegerField(required=True,
282290
widget=forms.widgets.HiddenInput())

dojo/templates/dojo/findings_list_snippet.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ <h3 class="has-filters">
124124

125125
{% if 'is_finding_groups_enabled'|system_setting_enabled %}
126126
<label><b>Group</b></label>
127-
<span style="font-size: 80%;">(Only available in per test for now)</span><br/>
127+
<label style="font-size: 80%; font-weight: normal; display: block">
128+
<input id="id_bulk_finding_group_remove" name="finding_group_remove" class="finding_group_option" type="checkbox"/> <span>Remove from any group</span>
129+
</label>
128130
{% endif %}
129131

130132
<br>

dojo/templates/dojo/view_eng.html

Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -260,60 +260,58 @@ <h4>
260260
{% for test in tests %}
261261
<tr>
262262
<td>
263-
<ul>
264-
<li class="dropdown" style="list-style:none;position:absolute">
265-
<a href="#" id='test-menu' class="dropdown-toggle" data-toggle="dropdown" aria-expanded="true">&nbsp;<b class="fa-solid fa-ellipsis-vertical"></b>&nbsp;</a>
266-
<ul class="dropdown-menu">
263+
<div class="dropdown">
264+
<a href="#" id="test-menu" class="dropdown-toggle pull-left" data-toggle="dropdown">&nbsp;<i class="fa-solid fa-ellipsis-vertical"></i>&nbsp;</a>
265+
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
266+
<li>
267+
<a class="" href="{% url 'view_test' test.id %}">
268+
<i class="fa-solid fa-rectangle-list"></i> View</a>
269+
</li>
270+
{% if test|has_object_permission:"Test_Edit" %}
267271
<li>
268-
<a class="" href="{% url 'view_test' test.id %}">
269-
<i class="fa-solid fa-rectangle-list"></i> View</a>
272+
<a class="" href="{% url 'edit_test' test.id %}">
273+
<i class="fa-solid fa-pen-to-square"></i> Edit</a>
270274
</li>
271-
{% if test|has_object_permission:"Test_Edit" %}
272-
<li>
273-
<a class="" href="{% url 'edit_test' test.id %}">
274-
<i class="fa-solid fa-pen-to-square"></i> Edit</a>
275-
</li>
276-
<li>
277-
<a class="" href="{% url 'copy_test' test.id %}">
278-
<i class="fa-solid fa-copy"></i> Copy</a>
279-
</li>
280-
{% endif %}
281-
{% if test|has_object_permission:"Finding_Add" %}
282-
<li class="divider"></li>
283-
<li>
284-
<a class="" href="{% url 'add_findings' test.id %}">
285-
<i class="fa-solid fa-plus"></i> Add Finding to Test
286-
</a>
287-
</li>
288-
<li>
289-
<a title="Add Finding from Template" href="{% url 'search' test.id %}">
290-
<span class="icon-add-template"></span> Finding From Template
291-
</a>
292-
</li>
293-
{% endif %}
294-
{% if test|has_object_permission:"Import_Scan_Result" %}
295-
<li class="divider"></li>
296-
<li><a class="" href="{% url 're_import_scan_results' test.id %}">
297-
<i class="fa-solid fa-upload"></i> Re-Upload Scan Results
298-
</a>
299-
</li>
300-
{% endif %}
275+
<li>
276+
<a class="" href="{% url 'copy_test' test.id %}">
277+
<i class="fa-solid fa-copy"></i> Copy</a>
278+
</li>
279+
{% endif %}
280+
{% if test|has_object_permission:"Finding_Add" %}
301281
<li class="divider"></li>
302-
<li role="presentation">
303-
<a href="{% url 'test_report' test.id %}?title=&active=1&verified=1&false_p=2&duplicate=2">
304-
<i class="fa-solid fa-file-lines"></i> Test Report
282+
<li>
283+
<a class="" href="{% url 'add_findings' test.id %}">
284+
<i class="fa-solid fa-plus"></i> Add Finding to Test
305285
</a>
306286
</li>
307-
{% if test|has_object_permission:"Test_Delete" %}
308-
<li class="divider"></li>
309-
<li>
310-
<a class="text-danger" href="{% url 'delete_test' test.id %}">
311-
<i class="fa-solid fa-trash"></i> Delete</a>
312-
</li>
313-
{% endif %}
314-
</ul>
315-
</li>
316-
</ul>
287+
<li>
288+
<a title="Add Finding from Template" href="{% url 'search' test.id %}">
289+
<span class="icon-add-template"></span> Finding From Template
290+
</a>
291+
</li>
292+
{% endif %}
293+
{% if test|has_object_permission:"Import_Scan_Result" %}
294+
<li class="divider"></li>
295+
<li><a class="" href="{% url 're_import_scan_results' test.id %}">
296+
<i class="fa-solid fa-upload"></i> Re-Upload Scan Results
297+
</a>
298+
</li>
299+
{% endif %}
300+
<li class="divider"></li>
301+
<li role="presentation">
302+
<a href="{% url 'test_report' test.id %}?title=&active=1&verified=1&false_p=2&duplicate=2">
303+
<i class="fa-solid fa-file-lines"></i> Test Report
304+
</a>
305+
</li>
306+
{% if test|has_object_permission:"Test_Delete" %}
307+
<li class="divider"></li>
308+
<li>
309+
<a class="text-danger" href="{% url 'delete_test' test.id %}">
310+
<i class="fa-solid fa-trash"></i> Delete</a>
311+
</li>
312+
{% endif %}
313+
</ul>
314+
</div>
317315
</td>
318316
<td><a title="{{ test.description }}" href="{% url 'view_test' test.id %}">{{ test }}</a>
319317
{% if test.version %}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{% extends "base.html" %}
2+
{% load navigation_tags %}
3+
{% load display_tags %}
4+
{% load static %}
5+
{% block content %}
6+
{% comment %} include inherits the current context so findings, filtered and other variables {% endcomment %}
7+
{% include "dojo/findings_list_snippet.html" %}
8+
<br />
9+
<div class="row">
10+
<div class="col-md-12">
11+
<div class="panel panel-default">
12+
<div class="panel-heading tight">
13+
<h3 class="has-filters">
14+
Edit {{ filter_name }}
15+
</h3>
16+
</div>
17+
</div>
18+
<form class="form-horizontal" method="post">
19+
{% csrf_token %}
20+
{% include "dojo/form_fields.html" with form=edit_finding_group_form %}
21+
22+
<div class="form-group">
23+
<div class="col-sm-offset-2 col-sm-10">
24+
<input class="btn btn-primary" type="submit" value="Submit"/>
25+
</div>
26+
</div>
27+
</form>
28+
</div>
29+
</div>
30+
{% endblock %}

0 commit comments

Comments
 (0)