Skip to content

Commit

Permalink
Merge pull request #61 from CitoEngine/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
extremeunix committed Sep 2, 2015
2 parents 22b3fbb + f77aef9 commit cc27933
Show file tree
Hide file tree
Showing 24 changed files with 18,275 additions and 45 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ after_success:
notifications:
email:
- sysadmin@citoengine.org

sudo: false
2 changes: 1 addition & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.0.0"
__version__ = "1.1.0"
75 changes: 75 additions & 0 deletions app/cito_engine/forms/jira_form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import
import logging
from django import forms
from django.conf import settings
from jira import JIRA
import jira.resources

logger = logging.getLogger('main')


class JIRAForm(forms.Form):

project = forms.ChoiceField(label='JIRA Project', required=True)
summary = forms.CharField(label='Ticket Summary', max_length=100)
description = forms.CharField(widget=forms.Textarea)
issue_type = forms.ChoiceField(label='Issue Type', required=True)
component = forms.ChoiceField(label='Component', required=True)
incident_id = forms.IntegerField()
confirm = forms.BooleanField(label='Confirm', required=True)

def get_choice_fields(self, opt):
opt_string = settings.JIRA_OPTS.get(opt)
if ',' in opt_string:
opt_string = opt_string.split(',')
else:
opt_string = [opt_string]

CHOICES = []
for p in opt_string:
CHOICES.append([p.strip(), p.strip()])

return CHOICES

def __init__(self, *args, **kwargs):
super(JIRAForm, self).__init__(*args, **kwargs)
# Create choicefield for projects
self.fields['project'].choices = self.get_choice_fields('PROJECTS')
self.fields['component'].choices = self.get_choice_fields('COMPONENTS')
self.fields['issue_type'].choices = self.get_choice_fields('ISSUE_TYPES')

def create_jira(self, username):
options = {
'server': '%s' % settings.JIRA_OPTS['URL'],
'verify': settings.JIRA_OPTS.get('VERIFY_SSL', False)
}
project = self.cleaned_data.get('project')
summary = self.cleaned_data.get('summary')
issue_type = self.cleaned_data.get('issue_type')
component = self.cleaned_data.get('component')
description = self.cleaned_data.get('description')
description += '*JIRA Created by:* %s' % username

try:
jconn = JIRA(options, basic_auth=(settings.JIRA_OPTS['USER'], settings.JIRA_OPTS['PASSWORD']))
except Exception as e:
logger.error('Error creating JIRA ticket :%s' % e)
raise forms.ValidationError(u"Error connecting to JIRA ticket, please check the server logs")

try:
jira_ticket = jconn.create_issue(project=project, summary=summary, description=description,
issuetype={'name': issue_type}, components=[{'name': component}])
except Exception as e:
logger.error('Error creating JIRA ticket project=%s, summary=%s, issue_type=%s, description=%s,' % (project,
summary,
issue_type,
description))
logger.error('Server message %s' % e)
msg = u"Error creating JIRA ticket, please check the project name and issue type. If that doesn't work then check the server logs"
raise forms.ValidationError(msg)

if isinstance(jira_ticket, jira.resources.Issue):
return jira_ticket.key
else:
raise forms.ValidationError(u"Error creating JIRA ticket, JIRA server did not return a ticket key.")
26 changes: 26 additions & 0 deletions app/cito_engine/migrations/0002_jiratickets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cito_engine', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='JIRATickets',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('ticket', models.CharField(max_length=64, verbose_name=b'JIRA Ticket ID')),
('creation_time', models.DateTimeField(auto_now_add=True)),
('incident', models.ForeignKey(to='cito_engine.Incident')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
]
12 changes: 9 additions & 3 deletions app/cito_engine/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
from django.db import models
from django.contrib.auth.models import User

# ./manage.py schemamigration cito_engine --auto
# ./manage.py migrate cito_engine


class PluginServer(models.Model):
name = models.CharField(max_length=128)
Expand Down Expand Up @@ -230,3 +227,12 @@ class EventActionLog(models.Model):

def __unicode__(self):
return unicode('%s|%s' % (self.eventAction, self.dateAdded))

class JIRATickets(models.Model):
incident = models.ForeignKey(Incident)
user = models.ForeignKey(User)
ticket = models.CharField(verbose_name='JIRA Ticket ID', max_length=64)
creation_time = models.DateTimeField(auto_now_add=True)

def __unicode__(self):
return unicode('%s' % self.ticket)
33 changes: 31 additions & 2 deletions app/cito_engine/views/incidents.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
"""

from datetime import datetime, timedelta
from django.conf import settings
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.template import RequestContext
from django.shortcuts import redirect, render_to_response, get_object_or_404
from django.http import Http404
from django.utils import timezone
from cito_engine.models import EventActionLog, Incident, IncidentLog, Team
from cito_engine.models import EventActionLog, Incident, IncidentLog, Team, JIRATickets
from cito_engine.forms import incidents
from comments.models import Comments
from comments.forms import CommentsForm
Expand All @@ -41,6 +42,17 @@ def get_incident_stats(team_id=None):
return stats


def parse_order_by(order_by):
ordering_list = dict(a_fe='firstEventTime',
a_le='lastEventTime',
a_count='total_incidents',
d_fe='-firstEventTime',
d_le='-lastEventTime',
d_count='-total_incidents',
)

return ordering_list.get(order_by, None)

@login_required(login_url='/login/')
def view_all_incidents(request, team_id=None, incident_status='active'):
if request.user.perms.access_level > 4:
Expand All @@ -53,6 +65,8 @@ def view_all_incidents(request, team_id=None, incident_status='active'):
render_vars['incident_status'] = incident_status
query_params['status__iexact'] = incident_status

order_by = parse_order_by(request.GET.get('order_by'))

if not team_id:
render_vars['stats'] = get_incident_stats()
render_vars['redirect_to'] = '/incidents/view/%s' % incident_status
Expand All @@ -64,7 +78,11 @@ def view_all_incidents(request, team_id=None, incident_status='active'):
render_vars['redirect_to'] = '/incidents/view/%s/%s' % (team_id, incident_status)
render_vars['team'] = team

incident_list = Incident.objects.filter(**query_params)
if order_by:
incident_list = Incident.objects.filter(**query_params).order_by(order_by)
render_vars['order_by'] = request.GET.get('order_by')
else:
incident_list = Incident.objects.filter(**query_params)
# TODO: Convert 'Pages per result' into global and user setting
paginator = Paginator(incident_list, 25)
try:
Expand All @@ -78,6 +96,10 @@ def view_all_incidents(request, team_id=None, incident_status='active'):

render_vars['box_title'] = render_vars['page_title']
render_vars['auto_refresh_page'] = True
# JIRA stuff
if settings.JIRA_ENABLED:
render_vars['jira_enabled'] = True
render_vars['jira_url'] = '%s/browse/' % settings.JIRA_OPTS['URL']
return render_to_response('view_all_incidents.html', render_vars, context_instance=RequestContext(request))


Expand All @@ -86,6 +108,13 @@ def view_single_incident(request, incident_id):
if request.user.perms.access_level > 4:
return render_to_response('unauthorized.html', context_instance=RequestContext(request))
incident = get_object_or_404(Incident, pk=incident_id)
if settings.JIRA_ENABLED:
jira_enabled = True
jira_url = '%s/browse/' % settings.JIRA_OPTS.get('URL')
try:
jira = JIRATickets.objects.get(incident=incident)
except Exception as e:
pass
incidentlogs = IncidentLog.objects.filter(incident=incident).order_by('timestamp')
eventactionlogs = EventActionLog.objects.filter(incident=incident).order_by('dateAdded')
comments = Comments.objects.filter(incident=incident).order_by('date_added')
Expand Down
37 changes: 37 additions & 0 deletions app/cito_engine/views/jira.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import
import logging
from django.views.generic.edit import FormView, View
from django.conf import settings
from django.http import HttpResponse
from django.shortcuts import redirect
from cito_engine.forms.jira_form import JIRAForm
from cito_engine.models import JIRATickets, Incident
from braces.views import LoginRequiredMixin


class JIRAAddView(LoginRequiredMixin, FormView):
"""
View to add Supression
"""
template_name = 'generic_form.html'
form_class = JIRAForm
success_url = '/incidents/'

def get_context_data(self, **kwargs):
context = super(JIRAAddView, self).get_context_data(**kwargs)
context['page_title'] = context['box_title'] = 'Add JIRA'
return context

def form_valid(self, form):
try:
incident = Incident.objects.get(pk=form.cleaned_data.get('incident_id'))
except Incident.DoesNotExist, Incident.MultipleObjectsReturned:
redirect('/incidents/')
return
try:
ticket = form.create_jira(username=self.request.user.username)
except Exception as e:
return HttpResponse(status=500, content=e)
JIRATickets.objects.create(user=self.request.user, incident=incident, ticket=ticket)
return redirect('/incidents/view/%s/' % incident.id)
58 changes: 50 additions & 8 deletions app/reports/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import csv
from datetime import datetime, timedelta
from django.conf import settings
from django.db.models import Count, Sum
from django.utils import timezone
from django.http import HttpResponse
Expand Down Expand Up @@ -43,21 +44,62 @@ def update_reports(incident):
daily_data.save()


def get_report_all_incidents(days, event_id=None, team_id=None, severity=None):
def get_report_all_incidents(from_date, to_date, event_id=None, team_id=None, severity=None):
query = dict()
time_range = timezone.make_aware(datetime.today() - timedelta(days=days), timezone.get_current_timezone())
if team_id is not None:
query['team_id'] = team_id
if event_id is not None:
query['event_id'] = event_id
if severity != 'All' and severity is not None:
query['severity'] = severity
if days == 1:
query['hour__gte'] = time_range
return HourlyData.objects.filter(**query)
else:
query['day__gte'] = time_range
return DailyData.objects.filter(**query)

query['day__gte'] = from_date
query['day__lte'] = to_date

return DailyData.objects.filter(**query)

def get_detailed_report_of_all_incidents(from_date, to_date, event_id=None, team_id=None, severity=None):
query = dict()
# time_range = timezone.make_aware(datetime.today() - timedelta(days=days), timezone.get_current_timezone())

if team_id is not None:
query['event__team__id'] = team_id
if event_id is not None:
query['event_id'] = event_id
if severity != 'All' and severity is not None:
query['severity'] = severity

query['lastEventTime__gte'] = from_date
query['lastEventTime__lte'] = to_date

response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="citoengine_report.csv"'
writer = csv.writer(response)

report_header = ['severity', 'incident_id', 'event_id', 'event_summary', 'element',
'firstoccurence', 'lastoccurence', 'total_count', 'team', 'category',
'acknowledged_time', 'close_time', 'acknowledged_by', 'closed_by', 'is_suppressed']
if settings.JIRA_ENABLED:
report_header.append('jira_ticket')
report_header.append('jira_creation_time')
report_header.append('jira_created_by')

writer.writerow(report_header)
for i in Incident.objects.filter(**query):
csv_row = [i.event.severity, i.id, i.event.id, i.event.summary, i.element,
i.firstEventTime, i.lastEventTime, i.total_incidents, i.event.team, i.event.category,
i.acknowledged_time, i.close_time, i.acknowledged_by, i.closed_by, i.is_suppressed]
if settings.JIRA_ENABLED:
# Only one jira is allowed per incident, hence we fetch only one jiraticket
jira = i.jiratickets_set.last()
if jira:
csv_row.append(jira.ticket)
csv_row.append(jira.creation_time)
csv_row.append(jira.user.username)

writer.writerow(csv_row)
return response



def get_report_json_formatter(data, dimension):
Expand Down
25 changes: 19 additions & 6 deletions app/reports/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,12 @@
"""

from django.forms import Form, ChoiceField, IntegerField, BooleanField, CharField
from datetime import datetime
from cito_engine.models import Team


class AllIncidentsReportForm(Form):
time_choices = (
('1', 'Last 24hours'),
('7', 'Last week'),
('30', '4 weeks'),
)

status_choices = (
(u'All', u'All'),
(u'Active', u'Active'),
Expand All @@ -38,7 +35,8 @@ class AllIncidentsReportForm(Form):
)

team = ChoiceField(label="Team")
timerange = ChoiceField(choices=time_choices, label="Range")
from_date = CharField(label="From")
to_date = CharField(label="To")
severity = ChoiceField(choices=event_severity, label='Severity')
csv_export = BooleanField(label="Export as CSV", required=False)

Expand All @@ -49,6 +47,21 @@ def __init__(self, *args, **kwargs):
self.team_list.append((team.id, team.name))
self.fields['team'].choices = self.team_list

def clean(self):
cleaned_data = super(AllIncidentsReportForm, self).clean()
from_date = cleaned_data.get('from_date')
to_date = cleaned_data.get('to_date')
try:
datetime.strptime(from_date, '%Y-%m-%d')
except Exception as e:
self._errors["from_date"] = self.error_class(['Invalid date'])

try:
datetime.strptime(to_date, '%Y-%m-%d')
except Exception as e:
self._errors["to_date"] = self.error_class(['Invalid date'])

return cleaned_data


class EventsPerTeam(Form):
Expand Down
Loading

0 comments on commit cc27933

Please sign in to comment.