Skip to content

Commit 283f16a

Browse files
committed
Add functionality to filter calendar by users as well as switching between engagement and test calendar
1 parent df384fb commit 283f16a

File tree

5 files changed

+87
-17
lines changed

5 files changed

+87
-17
lines changed

dojo/engagement/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
urlpatterns = [
66
# engagements and calendar
7-
url(r'^calendar$', views.calendar, name='calendar'),
7+
url(r'^calendar$', views.engagement_calendar, name='calendar'),
8+
url(r'^calendar/engagements$', views.engagement_calendar, name='engagement_calendar'),
89
url(r'^engagement$', views.engagement, name='engagement'),
910
url(r'^engagement/new$', views.new_engagement, name='new_eng'),
1011
url(r'^engagement/(?P<eid>\d+)$', views.view_engagement,

dojo/engagement/views.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from dojo.models import Finding, Product, Engagement, Test, \
2424
Check_List, Test_Type, Notes, \
2525
Risk_Acceptance, Development_Environment, BurpRawRequestResponse, Endpoint, \
26-
JIRA_PKey, JIRA_Conf, JIRA_Issue, Cred_User, Cred_Mapping
26+
JIRA_PKey, JIRA_Conf, JIRA_Issue, Cred_User, Cred_Mapping, Dojo_User
2727
from dojo.tools.factory import import_parser_factory
2828
from dojo.utils import get_page_items, add_breadcrumb, handle_uploaded_threat, \
2929
FileIterWrapper, get_cal_event, message, get_system_setting
@@ -42,11 +42,17 @@
4242

4343
@user_passes_test(lambda u: u.is_staff)
4444
@cache_page(60 * 5) # cache for 5 minutes
45-
def calendar(request):
46-
engagements = Engagement.objects.all()
45+
def engagement_calendar(request):
46+
if not 'lead' in request.GET or '*' in request.GET.getlist('lead'):
47+
engagements = Engagement.objects.all()
48+
else:
49+
engagements = Engagement.objects.filter(lead__username__in=request.GET.getlist('lead', ''))
4750
add_breadcrumb(title="Calendar", top_level=True, request=request)
4851
return render(request, 'dojo/calendar.html', {
49-
'engagements': engagements})
52+
'caltype': 'engagements',
53+
'leads': request.GET.getlist('lead', ''),
54+
'engagements': engagements,
55+
'users': Dojo_User.objects.all()})
5056

5157

5258
@user_passes_test(lambda u: u.is_staff)

dojo/templates/dojo/calendar.html

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
11
{% extends 'base.html' %}
2+
{% load static from staticfiles %}
3+
{% block add_css %}
4+
<link rel="stylesheet" href="{% static "chosen-bootstrap/chosen.bootstrap.min.css" %}">
5+
{% endblock %}
26
{% block content %}
7+
<form method="GET" id="calfilter" action="/calendar">
8+
<div class="container-fluid chosen-container side-by-side">
9+
<div class="row">
10+
<div class="col-lg-6" style="width:200px;">
11+
<select data-placeholder="Calendar type" id="caltype" class="chosen-select">
12+
<option value="engagements">Engagements</option>
13+
<option value="tests">Tests</option>
14+
</select>
15+
</div>
16+
<div class="col-lg-6" style="width:400px;">
17+
<select data-placeholder="All users" multiple id="lead" name="lead" class="chosen-select">
18+
<option value="*">All users</option>
19+
{% for u in users %}
20+
<option value="{{ u.username }}">{{ u.username }}</option>
21+
{% endfor %}
22+
</select>
23+
</div>
24+
<div class="col-lg-6">
25+
<button class="btn btn-primary" type="submit">Apply</button>
26+
</div>
27+
</div>
28+
</div>
29+
</form>
30+
<br/><br/>
331
<div id="calendar"></div>
432
<br/><br/>
533
{% endblock %}
634
{% block postscript %}
35+
<script type="application/javascript" src="{% static "chosen/chosen.jquery.js" %}"></script>
736
<script>
8-
$(function () {
37+
$(function () {
38+
$(".chosen-select").chosen({disable_search_threshold: 10});
39+
$('#caltype').val('{{ caltype }}');
40+
$('#lead').val([{% for lead in leads %} '{{ lead }}', {% endfor %}]);
41+
$('.chosen-select').trigger('chosen:updated');
42+
$('#caltype').change(function() { $('#calfilter').attr('action', '/calendar/' + $(this).val()); });
943
$('#calendar').fullCalendar({
1044
header: {
1145
left: 'prev,next today',
@@ -15,16 +49,29 @@
1549
editable: false,
1650
eventLimit: true, // allow "more" link when too many events
1751
events: [
18-
{% for e in engagements %}
19-
{
20-
title: '{{e.product.name}}: {{ e.name|default:"Unknown" }}',
21-
start: '{{e.target_start|date:"c"}}',
22-
end: '{{e.target_end|date:"c"}}',
23-
url: '{% url 'view_engagement' e.id %}',
24-
color: {% if e.active %}'#337ab7'{% else %}'#b9b9b9'{% endif %},
25-
overlap: true
26-
},
27-
{% endfor %}
52+
{% if caltype == 'tests' %}
53+
{% for t in tests %}
54+
{
55+
title: '{{t.engagement.product.name}}: {{ t.engagement.name|default:"Unknown" }} - {{ t.test_type }} ({{ t.engagement.lead }})',
56+
start: '{{t.target_start|date:"c"}}',
57+
end: '{{t.target_end|date:"c"}}',
58+
url: '{% url 'view_test' t.id %}',
59+
color: {% if t.engagement.active %}'#337ab7'{% else %}'#b9b9b9'{% endif %},
60+
overlap: true
61+
},
62+
{% endfor %}
63+
{% else %}
64+
{% for e in engagements %}
65+
{
66+
title: '{{e.product.name}}: {{ e.name|default:"Unknown" }} ({{ e.lead|default:"Unassigned" }})',
67+
start: '{{e.target_start|date:"c"}}',
68+
end: '{{e.target_end|date:"c"}}',
69+
url: '{% url 'view_engagement' e.id %}',
70+
color: {% if e.active %}'#337ab7'{% else %}'#b9b9b9'{% endif %},
71+
overlap: true
72+
},
73+
{% endfor %}
74+
{% endif %}
2875
]
2976
});
3077

dojo/test/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
urlpatterns = [
66
# tests
7+
url(r'^calendar/tests$', views.test_calendar, name='test_calendar'),
78
url(r'^test/(?P<tid>\d+)$', views.view_test,
89
name='view_test'),
910
url(r'^test/(?P<tid>\d+)/ics$', views.test_ics,

dojo/test/views.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
from django.core.urlresolvers import reverse
1111
from django.http import HttpResponseRedirect, HttpResponseForbidden, Http404, HttpResponse
1212
from django.shortcuts import render, get_object_or_404
13+
from django.views.decorators.cache import cache_page
1314
from pytz import timezone
1415

1516
from dojo.filters import TemplateFindingFilter
1617
from dojo.forms import NoteForm, TestForm, FindingForm, \
1718
DeleteTestForm, AddFindingForm, \
1819
ImportScanForm, ReImportScanForm, FindingBulkUpdateForm, JIRAFindingForm
1920
from dojo.models import Finding, Test, Notes, \
20-
BurpRawRequestResponse, Endpoint, Stub_Finding, Finding_Template, JIRA_PKey, Cred_User, Cred_Mapping
21+
BurpRawRequestResponse, Endpoint, Stub_Finding, Finding_Template, JIRA_PKey, Cred_User, Cred_Mapping, Dojo_User
2122
from dojo.tools.factory import import_parser_factory
2223
from dojo.utils import get_page_items, add_breadcrumb, get_cal_event, message, process_notifications, get_system_setting
2324
from dojo.tasks import add_issue_task
@@ -157,6 +158,20 @@ def delete_test_note(request, tid, nid):
157158
return HttpResponseForbidden()
158159

159160

161+
@user_passes_test(lambda u: u.is_staff)
162+
@cache_page(60 * 5) # cache for 5 minutes
163+
def test_calendar(request):
164+
if not 'lead' in request.GET or '*' in request.GET.getlist('lead'):
165+
tests = Test.objects.all()
166+
else:
167+
tests = Test.objects.filter(engagement__lead__username__in=request.GET.getlist('lead', ''))
168+
add_breadcrumb(title="Calendar", top_level=True, request=request)
169+
return render(request, 'dojo/calendar.html', {
170+
'caltype': 'tests',
171+
'leads': request.GET.getlist('lead', ''),
172+
'tests': tests,
173+
'users': Dojo_User.objects.all()})
174+
160175
@user_passes_test(lambda u: u.is_staff)
161176
def test_ics(request, tid):
162177
test = get_object_or_404(Test, id=tid)

0 commit comments

Comments
 (0)