Add hiccup statistic page
diff --git a/crashreports/serializers.py b/crashreports/serializers.py
new file mode 100644
index 0000000..c551198
--- /dev/null
+++ b/crashreports/serializers.py
@@ -0,0 +1,10 @@
+from rest_framework import serializers
+from models import Crashreport
+from rest_framework import permissions
+
+class CrashReportSerializer(serializers.ModelSerializer):
+    permission_classes = (permissions.IsAuthenticated)
+    class Meta:
+        model = Crashreport
+        fields = ('pk','uuid', 'uptime', 'build_fingerprint', 'boot_reason',
+        'power_on_reason', 'power_off_reason', 'aux_data', 'date')
diff --git a/crashreports/static/crashreports/style.css b/crashreports/static/crashreports/style.css
new file mode 100644
index 0000000..8d4af5f
--- /dev/null
+++ b/crashreports/static/crashreports/style.css
@@ -0,0 +1,28 @@
+h2 {
+  margin-top:60px;
+}
+h1 {
+  margin-top:50px;
+}
+
+#container {
+  margin: auto;
+  width: 90%;
+  
+}
+
+div.chart {
+  margin: 5px;
+  width: 500px;
+  height: 500px;
+  float: left;
+  -webkit-box-shadow: 7px 10px 26px 0px rgba(0,0,0,0.15);
+  -moz-box-shadow: 7px 10px 26px 0px rgba(0,0,0,0.15);
+  box-shadow: 7px 10px 26px 0px rgba(0,0,0,0.15);
+}
+
+body { 
+  font-family: sans-serif;
+  text-align: center;
+  background-color: #eee;
+}
diff --git a/crashreports/templates/crashreports/hiccup_stats.html b/crashreports/templates/crashreports/hiccup_stats.html
new file mode 100644
index 0000000..d390324
--- /dev/null
+++ b/crashreports/templates/crashreports/hiccup_stats.html
@@ -0,0 +1,159 @@
+<html>
+<head>
+  <meta charset="utf-8">
+  <META HTTP-EQUIV="refresh" CONTENT="300">
+    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.2/nv.d3.min.css" charset="utf-8" >
+    <link rel="stylesheet" type="text/css" href="/static/crashreports/style.css" charset="utf-8" >
+    
+    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
+    <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.2/nv.d3.min.js" charset="utf-8"></script>
+    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
+    
+  </head>
+  
+  <body>
+    <h1> Hiccup Stats </h1>
+    <div id="container">
+      <div id = "all_fingerprints" class="chart">
+      </div>
+      <div id = "probable_crashes" class="chart">
+      </div >
+      <div id = "Crash_Distribution" class="chart">
+      </div >
+      <div id = "Crash_Distribution_crashes" class="chart">
+      </div >
+      <div id = "SMPL_chart" class="chart">
+      </div >
+    </div>
+    <script>
+    
+    console.log("test");
+    
+    // Load the Visualization API and the corechart package.
+    google.charts.load('current', {'packages':['corechart']});
+    
+    // Set a callback to run when the Google Visualization API is loaded.
+    google.charts.setOnLoadCallback(drawChart);
+    
+    function aggregate_build_fingerprints(data) {
+      totals = {}
+      data = clear_fake_crashes(data)
+      for (var entry in data) {
+        key = ""
+        if (data[entry].build_fingerprint.includes("a:user")) {
+          key = "DDRFIX";
+        } else {
+          key = "Normal"
+        }
+        if (!totals[key]) {
+          console.log(data[entry].build_fingerprint);
+          totals[key] = 0;
+        } 
+        totals[key] += 1;
+      }
+      ret = []
+      for (var entry in totals) {
+        ret.push([entry, totals[entry]])
+      }
+      return ret;
+    } 
+    
+    function aggregate_uuid(data) {
+      data = clear_fake_crashes(data)
+      totals = {}
+      for (var entry in data) {
+        if (!totals[data[entry].uuid]) {
+          console.log(data[entry].uuid);
+          totals[data[entry].uuid] = 0;
+        } 
+        totals[data[entry].uuid] += 1;
+      }
+      ret = []
+      for (var entry in totals) {
+        ret.push([entry, totals[entry]])
+      }
+      return ret;
+    }
+    
+
+    function clear_fake_crashes(data) {
+      ret = {}
+      for (var entry in data) {
+        if (data[entry].boot_reason=="FAKECRASH") {
+          continue;
+        }
+        ret[entry]=data[entry];
+      }
+      return ret;
+    }
+    
+    function aggregate_SMPL(data) {
+      totals = {}
+      data = clear_fake_crashes(data)
+      for (var entry in data) {
+        key = ""
+        if (data[entry].power_on_reason.includes("SMPL")) {
+          key = "SMPL";
+        } else if (data[entry].power_off_reason.includes("SOFT")) {
+          key = "Crash";        
+        } else {
+          continue;
+        }
+        if (!totals[key]) {
+          console.log(data[entry].build_fingerprint);
+          totals[key] = 0;
+        } 
+        totals[key] += 1;
+      }
+      ret = []
+      for (var entry in totals) {
+        ret.push([entry, totals[entry]])
+      }
+      return ret;
+    } 
+    
+    function drawChart() {
+      drawChartFromDate("2016-09-09","");
+    }
+    
+    function drawChartFromDate(startDate,endDate) {
+      drawChartFingerprints("/hiccup/crashreports/?format=json&start_date="+startDate+"&end_date="+endDate, "All Crashreports", 'all_fingerprints',aggregate_build_fingerprints);
+      drawChartFingerprints("/hiccup/crashreports/?format=json&start_date="+startDate+"&end_date="+endDate+"&boot_reason=keyboard+power+on", "Probable Crashes", 'probable_crashes', aggregate_build_fingerprints);
+      drawChartFingerprints("/hiccup/crashreports/?format=json&start_date="+startDate+"&end_date="+endDate, "SMPL or Crash", 'SMPL_chart', aggregate_SMPL);
+      drawUuidHistogram("/hiccup/crashreports/?format=json&start_date="+startDate+"&end_date="+endDate, "Crash Distribution", 'Crash_Distribution');
+      drawUuidHistogram("/hiccup/crashreports/?format=json&start_date="+startDate+"&end_date="+endDate+"&boot_reason=keyboard+power+on", "Crash Distribution (probable Crashes)", 'Crash_Distribution_crashes');
+    }
+    
+    function drawChartFingerprints(url, title, element, aggregate_function) { $.getJSON( url, function( data ) {
+      var totals_fingerprint = aggregate_function(data);
+      var options = {
+        title: title,
+        pieHole: 0.4,
+      };
+      var chart = new google.visualization.PieChart(document.getElementById(element));
+      var data = new google.visualization.DataTable();
+      data.addColumn('string', 'Build Fingerprint');
+      data.addColumn('number', 'Number of Crashreports');
+      data.addRows(totals_fingerprint);
+      chart.draw(data, options);
+    });
+    }
+  
+  function drawUuidHistogram(url, title, element) { $.getJSON( url, function( data ) {
+    var totals_fingerprint = aggregate_uuid(data);
+    var options = {
+      title: title,
+      pieHole: 0.4,
+    };
+    var chart = new google.visualization.Histogram(document.getElementById(element));
+    var data = new google.visualization.DataTable();
+    data.addColumn('string', 'Build Fingerprint');
+    data.addColumn('number', 'Number of Crashreports');
+    data.addRows(totals_fingerprint);
+    chart.draw(data, options);
+  });
+ }
+</script>
+</body>
+</html>
diff --git a/crashreports/templates/registration/login.html b/crashreports/templates/registration/login.html
new file mode 100644
index 0000000..397eadf
--- /dev/null
+++ b/crashreports/templates/registration/login.html
@@ -0,0 +1,66 @@
+{% extends "admin/base_site.html" %}
+{% load i18n static %}
+
+{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/login.css" %}" />
+{{ form.media }}
+{% endblock %}
+
+{% block bodyclass %}{{ block.super }} login{% endblock %}
+
+{% block usertools %}{% endblock %}
+
+{% block nav-global %}{% endblock %}
+
+{% block content_title %}{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+{% if form.errors and not form.non_field_errors %}
+<p class="errornote">
+{% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
+</p>
+{% endif %}
+
+{% if form.non_field_errors %}
+{% for error in form.non_field_errors %}
+<p class="errornote">
+    {{ error }}
+</p>
+{% endfor %}
+{% endif %}
+
+<div id="content-main">
+
+{% if user.is_authenticated %}
+<p class="errornote">
+{% blocktrans trimmed %}
+    You are authenticated as {{ username }}, but are not authorized to
+    access this page. Would you like to login to a different account?
+{% endblocktrans %}
+</p>
+{% endif %}
+
+<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
+  <div class="form-row">
+    {{ form.username.errors }}
+    {{ form.username.label_tag }} {{ form.username }}
+  </div>
+  <div class="form-row">
+    {{ form.password.errors }}
+    {{ form.password.label_tag }} {{ form.password }}
+    <input type="hidden" name="next" value="{{ next }}" />
+  </div>
+  {% url 'admin_password_reset' as password_reset_url %}
+  {% if password_reset_url %}
+  <div class="password-reset-link">
+    <a href="{{ password_reset_url }}">{% trans 'Forgotten your password or username?' %}</a>
+  </div>
+  {% endif %}
+  <div class="submit-row">
+    <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
+  </div>
+</form>
+
+</div>
+{% endblock %}
diff --git a/crashreports/urls.py b/crashreports/urls.py
index 66ad6e1..e121032 100644
--- a/crashreports/urls.py
+++ b/crashreports/urls.py
@@ -1,7 +1,13 @@
-from django.conf.urls import url
+from django.conf.urls import url, include
 from . import views
+from rest_framework import routers
+from rest_framework import filters
+
+router = routers.DefaultRouter()
+router.register(r'crashreports', views.CrashreportViewSet)
 
 urlpatterns = [
     url(r'^crashreport/', views.index, name='index'),
-    url(r'^get_crash_statistic', views.get_crash_statistic, name='get_crash_statistic'),
-    url(r'', views.empty, name='empty'),]
+    url(r'^crashreports/hiccup_stats/', views.hiccup_stats, name='home'),
+    url(r'^', include(router.urls)),
+]
diff --git a/crashreports/views.py b/crashreports/views.py
index 5beff69..54a09f0 100644
--- a/crashreports/views.py
+++ b/crashreports/views.py
@@ -12,10 +12,21 @@
 
 from django.contrib.auth.decorators import login_required
 from django.db.models import Count
+from rest_framework import viewsets
+from serializers import CrashReportSerializer
+from rest_framework.permissions import BasePermission
+from rest_framework import filters
+from rest_framework import generics
+import django_filters
+from django.template import loader
+
 
 import datetime
 import time
 
+from ratelimit.decorators import ratelimit
+
+@ratelimit( key='ip', rate='100/h')
 @csrf_exempt
 def index(request):
     # Handle file upload`
@@ -40,19 +51,36 @@
         else:
             return HttpResponse(status=400)
     else:
-        return HttpResponse(status=400) 
+        return HttpResponse(status=400)
+
+class IsCreationOrIsAuthenticated(BasePermission):
+    def has_permission(self, request, view):
+        if not request.user.is_authenticated():
+            if view.action == 'create':
+                return True
+            else:
+                return False
+        else:
+            return True
+
+class ListFilter(django_filters.Filter):
+    def filter(self, qs, value):
+        value_list = value.split(u',')
+        return super(ListFilter, self).filter(qs, django_filters.fields.Lookup(value_list, 'in'))
 
 
-def empty(request):
-    return HttpResponse(status=204)
+class CrashreportFilter(filters.FilterSet):
+    start_date = django_filters.DateTimeFilter(name="date", lookup_expr='gte')
+    end_date = django_filters.DateTimeFilter(name="date", lookup_expr='lte')
+    boot_reason = ListFilter(name='boot_reason')
+    class Meta:
+        model = Crashreport
+        fields = ['build_fingerprint','boot_reason', 'power_on_reason', 'power_off_reason']
 
-@login_required
-def get_crash_statistic(request):
-    from_date = request.GET.get('from_date', "2016-01-01")
-    to_date = request.GET.get('to_date', "2017-01-01")
-    entries = Crashreport.objects.filter(date__range=[from_date, to_date]).extra({'date_created' : "date(date)"}).values('date_created').annotate(created_count=Count('id'))
-    for entry in entries:
-        entry['date_created']=time.mktime(datetime.datetime.strptime(entry['date_created'], "%Y-%m-%d").timetuple())*1000
-    return  render_to_response('crashreports/json/crashreport_by_day.html/', {
-        'entries' : entries
-    })
+
+class CrashreportViewSet(viewsets.ModelViewSet):
+    queryset = Crashreport.objects.all()
+    serializer_class =  CrashReportSerializer
+    permission_classes = [IsCreationOrIsAuthenticated]
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_class = CrashreportFilter
diff --git a/hiccup/settings.py b/hiccup/settings.py
index 7727902..e5deb5b 100644
--- a/hiccup/settings.py
+++ b/hiccup/settings.py
@@ -40,6 +40,7 @@
     'rest_framework',
     'crashreports',
     'psensor',
+    'crispy_forms',
 ]
 
 MIDDLEWARE_CLASSES = [
@@ -117,7 +118,8 @@
 REST_FRAMEWORK = {
     'DEFAULT_PERMISSION_CLASSES': (
         'rest_framework.permissions.IsAuthenticated',
-    )
+    ),
+    'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)
 }
 
 # Static files (CSS, JavaScript, Images)
diff --git a/hiccup/urls.py b/hiccup/urls.py
index ad8e0c0..c2dbf41 100644
--- a/hiccup/urls.py
+++ b/hiccup/urls.py
@@ -1,9 +1,12 @@
 from django.conf.urls import include, url
 from django.contrib import admin
-
+from django.views.generic.base import RedirectView
+from django.contrib.auth import views as auth_views
 
 urlpatterns = [
     url(r'^hiccup/admin/', admin.site.urls),
     url(r'^psensor/', include('psensor.urls')),
     url(r'^hiccup/', include('crashreports.urls')),
+    url(r'^accounts/login/$', auth_views.login),
+    url(r'^.*$', RedirectView.as_view(url='https://fairphone.com', permanent=False), name='index')
 ]
diff --git a/hiccup/views.py b/hiccup/views.py
new file mode 100644
index 0000000..f5f4673
--- /dev/null
+++ b/hiccup/views.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+from django.shortcuts import render_to_response
+from django.shortcuts import render
+from django.http import HttpResponseRedirect
+from django.http import HttpResponse
+from django.core.urlresolvers import reverse
+
+from crashreports.models import Crashreport
+from crashreports.forms import CrashreportForm
+from django.views.decorators.csrf import csrf_exempt
+from django.http import Http404
+
+from django.contrib.auth.decorators import login_required
+from django.db.models import Count
+
+import datetime
+import time
+
+@csrf_exempt
+def index(request):
+    # Handle file upload`
+    if request.method == 'POST':
+        form = CrashreportForm(request.POST, request.FILES)
+        if form.is_valid():
+            print form.cleaned_data['uuid'];
+            print form.cleaned_data['aux_data'];
+            print form.cleaned_data['boot_reason'];
+            print form.cleaned_data['build_fingerprint'];
+            print form.cleaned_data['date'];
+            new_cr = Crashreport(uuid=form.cleaned_data['uuid'],
+                        aux_data=form.cleaned_data['aux_data'],
+                        uptime=form.cleaned_data['uptime'],
+                        boot_reason=form.cleaned_data['boot_reason'],
+                        power_on_reason=form.cleaned_data['power_on_reason'],
+                        power_off_reason=form.cleaned_data['power_off_reason'],
+                        build_fingerprint=form.cleaned_data['build_fingerprint'],
+                        date= form.cleaned_data['date'])
+            try:
+                new_cr.crashreport_file = request.FILES['crashreport']
+            except:
+                new_cr.crashreport_file = None
+            new_cr.save()
+            # Redirect to the document list after POST
+            return HttpResponse(status=204)
+        else:
+             return HttpResponse(status=204)
+    else:
+        raise HttpResponse(status=204) 
+
+
+# @login_required
+# def list_crash_reports(request):
+#     context = {
+#         'request':request,
+#         'crashreport_count':  Crashreport.objects.count(),
+#         'unique_devices': Crashreport.objects.values("uuid").distinct().count(),
+#         'log_count': Crashreport.objects.exclude(crashreport_file='').count(),
+#         'crashreport_hist' : Crashreport.objects.all().order_by('-date')[:5]
+#        }
+#     return render_to_response('crashreports/list.html',context)
+
+
+@login_required
+def get_crash_statistic(request):
+    from_date = request.GET.get('from_date', "2016-01-01")
+    to_date = request.GET.get('to_date', "2017-01-01")
+    print from_date
+    print to_date
+    entries = Crashreport.objects.filter(date__range=[from_date, to_date]).extra({'date_created' : "date(date)"}).values('date_created').annotate(created_count=Count('id'))
+    for entry in entries:
+        entry['date_created']=time.mktime(datetime.datetime.strptime(entry['date_created'], "%Y-%m-%d").timetuple())*1000
+    return  render_to_response('crashreports/json/crashreport_by_day.html/', {
+        'entries' : entries
+    })
diff --git a/psensor/views.py b/psensor/views.py
index 80c8f8f..553c598 100644
--- a/psensor/views.py
+++ b/psensor/views.py
@@ -1,7 +1,6 @@
 from models import PSensorSetting
 from rest_framework import viewsets
 from serializers import PSensorSettingSerializer
-from rest_framework.decorators import detail_route, list_route
 from rest_framework.permissions import BasePermission
 
 class IsCreationOrIsAuthenticated(BasePermission):
@@ -16,7 +15,6 @@
             return True
 
 
-
 class PSensorSettingViewSet(viewsets.ModelViewSet):
     queryset = PSensorSetting.objects.all()
     serializer_class =  PSensorSettingSerializer
diff --git a/requirements.txt b/requirements.txt
index 71d6b04..b83ecca 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,11 @@
 Django==1.9.7
+django-appconf==1.0.2
+django-bootstrap-form==3.2.1
+django-crispy-forms==1.6.0
+django-filter==0.14.0
+django-ratelimit==1.0.0
+django-user-accounts==1.3.1
+djangorestframework==3.4.6
+pinax-theme-bootstrap==7.10.2
+pytz==2016.6.1
 wheel==0.24.0