Add version overview page
diff --git a/crashreport_stats/admin.py b/crashreport_stats/admin.py
index 8c38f3f..777a09e 100644
--- a/crashreport_stats/admin.py
+++ b/crashreport_stats/admin.py
@@ -1,3 +1,11 @@
 from django.contrib import admin
+from crashreport_stats.models import *
 
-# Register your models here.
+@admin.register(Version)
+class VersionAdmin(admin.ModelAdmin):
+    pass
+
+@admin.register(VersionDaily)
+class VersionDailyAdmin(admin.ModelAdmin):
+    list_display=('version','date')
+    pass
diff --git a/crashreport_stats/migrations/0001_initial.py b/crashreport_stats/migrations/0001_initial.py
new file mode 100644
index 0000000..b87395e
--- /dev/null
+++ b/crashreport_stats/migrations/0001_initial.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.2 on 2017-05-09 13:01
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+from django.db import connection
+from datetime import date, timedelta
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Version',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('build_fingerprint', models.CharField(max_length=200, unique=True)),
+                ('is_official_release', models.BooleanField(default=False)),
+                ('is_beta_release', models.BooleanField(default=False)),
+                ('first_seen_on', models.DateField()),
+                ('released_on', models.DateField()),
+                ('heartbeats', models.IntegerField()),
+                ('prob_crashes', models.IntegerField()),
+                ('smpl', models.IntegerField()),
+                ('other', models.IntegerField()),
+            ],
+        ),
+        migrations.CreateModel(
+            name='VersionDaily',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('date', models.DateField()),
+                ('heartbeats', models.IntegerField()),
+                ('prob_crashes', models.IntegerField()),
+                ('smpl', models.IntegerField()),
+                ('other', models.IntegerField()),
+                ('version', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='daily_stats', to='crashreport_stats.Version')),
+            ],
+        ),
+    ]
diff --git a/crashreport_stats/models.py b/crashreport_stats/models.py
index 71a8362..04f38ab 100644
--- a/crashreport_stats/models.py
+++ b/crashreport_stats/models.py
@@ -1,3 +1,76 @@
 from django.db import models
+from crashreports.models import *
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+import datetime
 
-# Create your models here.
+
+def getVersion(build_fingerprint):
+    v= None
+    try: 
+        v = Version.objects.get(build_fingerprint=build_fingerprint)
+    except Version.DoesNotExist:
+        v =Version(build_fingerprint=build_fingerprint,
+            first_seen_on=datetime.date.today(),
+            released_on=datetime.date.today(),
+            heartbeats=0, prob_crashes=0, smpl=0, other=0)
+        v.save()
+    return v
+
+def getVersionDaily(version,day):
+    try: 
+        v = VersionDaily.objects.get(version=version, date=day)
+    except VersionDaily.DoesNotExist:
+        v =VersionDaily(version=version, date=day,
+            heartbeats=0, prob_crashes=0, smpl=0, other=0)
+    return v
+
+@receiver(post_save, sender=Crashreport)
+def on_crashreport_create(sender, **kwargs):
+    crashreport = kwargs.get('instance')
+    v= getVersion(crashreport.build_fingerprint)
+    vd = getVersionDaily(v, crashreport.date.date())
+    if crashreport.boot_reason == "RTC alarm":
+        v.smpl = v.smpl + 1
+        vd.smpl = vd.smpl + 1
+    elif crashreport.boot_reason in ["UNKNOWN", "keyboard power on"]:
+        v.prob_crashes = v.prob_crashes + 1
+        vd.prob_crashes = vd.prob_crashes + 1
+    else:
+        v.other = v.other + 1
+        vd.other = vd.other + 1
+    v.save()
+    vd.save()
+
+@receiver(post_save, sender=HeartBeat)
+def on_heartbeat_create(sender, **kwargs):
+    hb = kwargs.get('instance')
+    v  = getVersion(hb.build_fingerprint)
+    vd = getVersionDaily(v, hb.date)
+    v.heartbeats = v.heartbeats + 1
+    vd.heartbeats = vd.heartbeats + 1
+    v.save()
+    vd.save()
+
+
+class Version(models.Model):
+    build_fingerprint    = models.CharField(max_length=200,  unique=True)
+    is_official_release = models.BooleanField(default=False)
+    is_beta_release     = models.BooleanField(default=False)
+    first_seen_on        = models.DateField()
+    released_on          = models.DateField()
+    heartbeats           = models.IntegerField()
+    prob_crashes         = models.IntegerField()
+    smpl                 = models.IntegerField()
+    other                = models.IntegerField()
+    def __str__(self):
+        return self.build_fingerprint
+    
+    
+class VersionDaily(models.Model):
+    version        = models.ForeignKey(Version, db_index=True, related_name='daily_stats', on_delete=models.CASCADE)
+    date           = models.DateField()
+    heartbeats     = models.IntegerField()
+    prob_crashes   = models.IntegerField()
+    smpl           = models.IntegerField()
+    other          = models.IntegerField()
diff --git a/crashreport_stats/rest_endpoints.py b/crashreport_stats/rest_endpoints.py
index e4f9ae8..b7c07dc 100644
--- a/crashreport_stats/rest_endpoints.py
+++ b/crashreport_stats/rest_endpoints.py
@@ -5,8 +5,12 @@
 from crashreports.permissions import HasRightsOrIsDeviceOwnerDeviceCreation
 from django.db import connection
 from . import raw_querys
+from crashreport_stats.models import *
 import zipfile
 from crashreports.models import *
+from django.db.models.expressions import F
+import django_filters
+from rest_framework import filters
 
 def dictfetchall(cursor):
     "Returns all rows from a cursor as a dict"
@@ -74,3 +78,51 @@
             fo = zf.open(f)
             ret[f.filename] = fo.read()
         return Response(ret)
+        
+
+class VersionFilter(filters.FilterSet):
+    first_seen_before = django_filters.DateFilter(name="first_seen_on", lookup_expr='lte')
+    first_seen_after   = django_filters.DateFilter(name="first_seen_on", lookup_expr='gte')
+    released_before = django_filters.DateFilter(name="released_on", lookup_expr='lte')
+    released_after   = django_filters.DateFilter(name="released_on", lookup_expr='gte')
+    class Meta:
+        model = Version
+
+class VersionSerializer(serializers.ModelSerializer):
+    permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation, )
+    class Meta:
+        model = Version
+
+class VersionListView(generics.ListAPIView):
+
+    queryset = Version.objects.all().order_by('-heartbeats')
+    permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation, )
+    serializer_class = VersionSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_class = (VersionFilter)
+
+
+class VersionDailyFilter(filters.FilterSet):
+    date_start = django_filters.DateFilter(name="date", lookup_expr='gte')
+    date_end   = django_filters.DateFilter(name="date", lookup_expr='lte')
+    version__build_fingerprint = django_filters.CharFilter()
+    version__is_official_release = django_filters.BooleanFilter()
+    version__is_beta_release = django_filters.BooleanFilter()
+    class Meta:
+        model = VersionDaily
+
+
+class VersionDailySerializer(serializers.ModelSerializer):
+    permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation, )
+    build_fingerprint  = serializers.CharField()
+    class Meta:
+        model = VersionDaily
+
+
+class VersionDailyListView(generics.ListAPIView):
+    queryset = VersionDaily.objects.annotate(build_fingerprint=F('version__build_fingerprint')).all()
+    permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation, )
+    filter_backends = (filters.DjangoFilterBackend,)
+    serializer_class = VersionDailySerializer
+    filter_class = (VersionDailyFilter)
+    filter_fields = ('version__build_fingerprint','version__is_official_release','version__is_beta_release',)
diff --git a/crashreport_stats/templates/crashreport_stats/tags/versions_area_chart.html b/crashreport_stats/templates/crashreport_stats/tags/versions_area_chart.html
new file mode 100644
index 0000000..8935239
--- /dev/null
+++ b/crashreport_stats/templates/crashreport_stats/tags/versions_area_chart.html
@@ -0,0 +1,68 @@
+<div id = "{{element_name}}" class="panel line_chart"> </div>
+<script>
+google.charts.setOnLoadCallback(drawChartReportPerDay);
+
+var groupByDate = function(xs) {
+  key = 'date'
+  return xs.reduce(function(rv, x) {
+    (rv[x[key]] = rv[x[key]] || []).push(x);
+    return rv;
+  }, {});
+};
+
+function drawChartReportPerDay(element) {
+  element = "heartbeats"
+  var chart = new google.visualization.AreaChart(document.getElementById("{{element_name}}"));
+  var data = new google.visualization.DataTable();
+  var options = {
+    title: "{{ title }}",
+    isStacked: 'relative',
+    chartArea: {
+      left:0,
+      right:0,
+      top:50,
+      bottom:50,
+    },
+    legend : {
+      position:'top',
+    }
+  };
+  $.getJSON( "{% url 'hiccup_stats_api_v1_version_daily' %}",
+    {
+      version__is_official_release: "{{ is_official_release }}",
+      version__is_beta_release: "{{ is_beta_release }}",
+      limit:10000,
+      date_start: "2017-01-01",
+      date_end: new Date(new Date().setDate(new Date().getDate())).toISOString().split('T')[0],
+    },
+    function( json_response ) {
+      res = [];
+      if (json_response.results)
+        res = json_response.results;
+      else
+        res = json_response;
+      tmp = {}
+      res.forEach(function(n){
+        tmp[n.date]={}
+        res.forEach(function(m){
+          tmp[n.date][m.build_fingerprint] = 0;
+        });
+      });
+      res.forEach(function(n){
+        all_fingerprints= Object.keys(tmp[n.date]);
+        tmp[n.date][n.build_fingerprint] = n.heartbeats;
+      });
+      reformated_array = []
+      all_dates = Object.keys(tmp);
+      all_dates.forEach(function(date) {
+        reformated_array.push([new Date(date),].concat(all_fingerprints.map(function(o){return tmp[date][o]})));
+      });
+      data.addColumn('date', 'date');
+      all_fingerprints.forEach(function(fingerprint){
+        data.addColumn('number', fingerprint.split('/')[4]);
+      });
+      data.addRows(reformated_array);
+      chart.draw(data,  options);
+    });
+}
+</script>
diff --git a/crashreport_stats/templates/crashreport_stats/tags/versions_bar_chart.html b/crashreport_stats/templates/crashreport_stats/tags/versions_bar_chart.html
new file mode 100644
index 0000000..d90df30
--- /dev/null
+++ b/crashreport_stats/templates/crashreport_stats/tags/versions_bar_chart.html
@@ -0,0 +1,49 @@
+<div id = "{{element_name}}" class="panel line_chart"> </div>
+<script>
+google.charts.setOnLoadCallback(drawChartReportPerDay);
+
+var groupByDate = function(xs) {
+  key = 'date'
+  return xs.reduce(function(rv, x) {
+    (rv[x[key]] = rv[x[key]] || []).push(x);
+    return rv;
+  }, {});
+};
+
+function drawChartReportPerDay(element) {
+  element = "heartbeats"
+  var chart = new google.visualization.BarChart(document.getElementById("{{element_name}}"));
+  var data = new google.visualization.DataTable();
+  var options = {
+    title: "{{ title }}",
+    chartArea: {
+      left:100,
+      right:0,
+      top:50,
+      bottom:50,
+    },
+    legend : {
+      position:'top',
+    }
+  };
+  $.getJSON( "{% url 'hiccup_stats_api_v1_versions' %}",
+   { limit: 5,
+     is_official_release: "{{ is_official_release }}",
+     is_beta_release: "{{ is_beta_release }}"
+   }, function( json_response ) {
+    res = [];
+    if (json_response.results)
+      res = json_response.results;
+    else
+      res = json_response;
+    reformated_array = res.map(function(obj) {
+        ret =  [obj.build_fingerprint.split('/')[4], obj.prob_crashes/(obj.heartbeats*1.0)];
+        return ret;
+    });
+    data.addColumn('string', 'Version');
+    data.addColumn('number', 'Prob. Crashes');
+    data.addRows(reformated_array);
+    chart.draw(data,  options);
+  });
+}
+</script>
diff --git a/crashreport_stats/templates/crashreport_stats/tags/versions_pie_chart.html b/crashreport_stats/templates/crashreport_stats/tags/versions_pie_chart.html
new file mode 100644
index 0000000..1108c58
--- /dev/null
+++ b/crashreport_stats/templates/crashreport_stats/tags/versions_pie_chart.html
@@ -0,0 +1,44 @@
+<div id = "{{element_name}}" class="panel line_chart"> </div>
+<script>
+google.charts.setOnLoadCallback(drawChartReportPerDay);
+
+function drawChartReportPerDay(element) {
+  element = "heartbeats"
+  var chart = new google.visualization.PieChart(document.getElementById("{{element_name}}"));
+  var data = new google.visualization.DataTable();
+  var options = {
+    title: "{{ title }}",
+    pieHole: 0.4,
+    sliceVisibilityThreshold: .01,
+    legend: {
+      position: "labeled",
+    },
+    chartArea: {
+      left:0,
+      right:0,
+      top:50,
+      bottom:0,
+    },
+  };
+  $.getJSON( "{% url 'hiccup_stats_api_v1_version_daily' %}",
+   {
+     date: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().split('T')[0],
+     version__is_official_release: "{{ is_official_release }}",
+     version__is_beta_release: "{{ is_beta_release }}",
+   }, function( json_response ) {
+    res = [];
+    if (json_response.results)
+      res = json_response.results;
+    else
+      res = json_response;
+    reformated_array = res.map(function(obj) {
+        ret =  [obj.build_fingerprint.split('/')[4], obj.heartbeats];
+        return ret;
+    });
+    data.addColumn('string', 'Version');
+    data.addColumn('number', 'Heartbeats');
+    data.addRows(reformated_array);
+    chart.draw(data,  options);
+  });
+}
+</script>
diff --git a/crashreport_stats/templates/crashreport_stats/tags/versions_table.html b/crashreport_stats/templates/crashreport_stats/tags/versions_table.html
new file mode 100644
index 0000000..5767aba
--- /dev/null
+++ b/crashreport_stats/templates/crashreport_stats/tags/versions_table.html
@@ -0,0 +1,47 @@
+<div class="panel datatable" >
+  <h2>{{ title }}</h2>
+  <table id = "{{element_name}}"  class="display table table-striped" ></table>
+ </div>
+<script>
+
+$(document).ready(function() {
+  console.log("Generating report table");
+  $.getJSON( "{% url 'hiccup_stats_api_v1_versions' %}",
+  {
+    limit:200,
+    is_official_release: "{{ is_official_release }}",
+    is_beta_release: "{{ is_beta_release }}",
+  }, function(json_response) {
+    console.log("Generating update history table");
+    console.log(json_response);
+    dataSet = json_response.results.map(function(obj) {
+        ret = [
+              obj.build_fingerprint.split('/')[4],
+              obj.heartbeats,
+              (obj.prob_crashes/(obj.heartbeats * 1.0)),
+              (obj.smpl/(obj.heartbeats * 1.0)),
+             ];
+        return ret;
+    });
+
+    $('#{{element_name}}').DataTable( {
+        data: dataSet,
+        columns: [
+          { title: "Version" },
+          { title: "HB"},
+          { title: "PC",
+            render: function(n) {
+              return n.toFixed(2);
+            }
+          },
+          { title: "SMPLs",
+            render: function(n) {
+              return n.toFixed(2);
+            }
+          },
+        ]
+    } );
+});
+});
+
+</script>
diff --git a/crashreport_stats/templates/crashreport_stats/versions.html b/crashreport_stats/templates/crashreport_stats/versions.html
new file mode 100644
index 0000000..3863b2c
--- /dev/null
+++ b/crashreport_stats/templates/crashreport_stats/versions.html
@@ -0,0 +1,21 @@
+{% extends "base.html" %}
+    {% block content %}
+    {% load crashreport_stats_tags %}
+    <h1> Versions Overview </h1>
+    <div class="row">
+      <div class="col-md-6">
+        {% versions_table is_official_release=is_official_release%}
+      </div>
+      <div class="col-md-6">
+          {% versions_pie_chart is_official_release=is_official_release%}
+      </div>
+      <div class="col-md-6">
+          {% versions_bar_chart is_official_release=is_official_release%}
+      </div>
+      <div class="col-md-6">
+      </div>
+    </div>
+    <div class="col-md-12">
+        {% versions_area_chart is_official_release=is_official_release%}
+    </div>
+ {% endblock content %}
diff --git a/crashreport_stats/templatetags/crashreport_stats_tags.py b/crashreport_stats/templatetags/crashreport_stats_tags.py
index c653f9c..235175d 100644
--- a/crashreport_stats/templatetags/crashreport_stats_tags.py
+++ b/crashreport_stats/templatetags/crashreport_stats_tags.py
@@ -34,3 +34,36 @@
         'uuid': uuid,
         "title": title,
         "element_name": "device_report_history"})
+
+
+@register.simple_tag
+def versions_table(title = "FP2 OS Versions",  is_official_release="1"):
+    t = template.loader.get_template('crashreport_stats/tags/versions_table.html')
+    return t.render({
+        "title": title,
+        "is_official_release":is_official_release,
+        "element_name": "versions_overview_table"})
+
+@register.simple_tag
+def versions_pie_chart(title = "FP2 Version Distribution", is_official_release="1"):
+    t = template.loader.get_template('crashreport_stats/tags/versions_pie_chart.html')
+    return t.render({
+        "title": title,
+        "is_official_release":is_official_release,
+        "element_name": "versions_overview_pie_chart"})
+
+@register.simple_tag
+def versions_area_chart(title = "FP2 Version Distribution",  is_official_release="1"):
+    t = template.loader.get_template('crashreport_stats/tags/versions_area_chart.html')
+    return t.render({
+        "title": title,
+        "is_official_release":is_official_release,
+        "element_name": "versions_overview_area_chart"})
+
+@register.simple_tag
+def versions_bar_chart(title = "Version Stability", is_official_release="1"):
+    t = template.loader.get_template('crashreport_stats/tags/versions_bar_chart.html')
+    return t.render({
+        "title": title,
+        "is_official_release":is_official_release,
+        "element_name": "versions_overview_bar_chart"})
diff --git a/crashreport_stats/urls.py b/crashreport_stats/urls.py
index de8c55b..a80425c 100644
--- a/crashreport_stats/urls.py
+++ b/crashreport_stats/urls.py
@@ -10,6 +10,12 @@
     url(r'^$',
         views.home,
         name='device'),
+    url(r'^versions/$',
+        views.versions_overview,
+        name='hiccup_stats_versions'),
+    url(r'^versions/all/$',
+        views.versions_all_overview,
+        name='hiccup_stats_versions_all'),
     url(r'^api/v1/device_overview/(?P<uuid>[a-f0-9-]+)/$',
         rest_endpoints.DeviceStat.as_view(),
         name='hiccup_stats_api_v1_device_overview'),
@@ -19,7 +25,16 @@
     url(r'^api/v1/device_report_history/(?P<uuid>[a-f0-9-]+)/$',
         rest_endpoints.DeviceReportHistory.as_view(),
         name='hiccup_stats_api_v1_device_report_history'),
+
     url(r'^api/v1/logfile_download/(?P<id>[0-9]+)/$',
         rest_endpoints.LogFileDownload.as_view(),
         name='hiccup_stats_api_v1_logfile_download'),
+        
+    url(r'^api/v1/versions/$',
+        rest_endpoints.VersionListView.as_view(),
+        name='hiccup_stats_api_v1_versions'),
+    
+    url(r'^api/v1/version_daily/$',
+        rest_endpoints.VersionDailyListView.as_view(),
+        name='hiccup_stats_api_v1_version_daily'),
 ]
diff --git a/crashreport_stats/util.py b/crashreport_stats/util.py
new file mode 100644
index 0000000..316ab53
--- /dev/null
+++ b/crashreport_stats/util.py
@@ -0,0 +1,80 @@
+from django.db import migrations, models
+import django.db.models.deletion
+
+from django.db import connection
+from datetime import date, timedelta
+
+from . import models as myModels
+
+from django.db import transaction
+
+def dictfetchall(cursor):
+    "Returns all rows from a cursor as a dict"
+    desc = cursor.description
+    return [
+        dict(zip([col[0] for col in desc], row))
+        for row in cursor.fetchall()
+    ]
+
+@transaction.atomic
+def fill_version_data():
+    myModels.Version.objects.all().delete()
+    query = '''
+        SELECT fingerprint as build_fingerprint,
+        ( select count(id) from crashreports_crashreport where boot_reason in ("RTC alarm")  and crashreports_crashreport.build_fingerprint = fingerprint) as SMPL,
+        ( select count(id) from crashreports_crashreport where boot_reason in ("UNKNOWN", "keyboard power on")  and crashreports_crashreport.build_fingerprint = fingerprint) as prob_crashes,
+        ( select count(id) from crashreports_crashreport where boot_reason not in ("RTC alarm", "UNKNOWN", "keyboard power on")  and crashreports_crashreport.build_fingerprint = fingerprint) as other,
+        ( select count(id) from crashreports_heartbeat where  crashreports_heartbeat.build_fingerprint = fingerprint) as heartbeats,
+        ( select min(crashreports_heartbeat.created_at) from crashreports_heartbeat where  crashreports_heartbeat.build_fingerprint = fingerprint) as first_seen
+        from  (select distinct(build_fingerprint) as fingerprint
+        from crashreports_heartbeat) group by fingerprint order by heartbeats;'''
+    cursor = connection.cursor()
+    cursor.execute(query,[])
+    desc = cursor.description
+    for row in cursor.fetchall():
+        i = dict(zip([col[0] for col in desc], row))
+        version = myModels.Version(
+            build_fingerprint = i['build_fingerprint'],
+            first_seen_on = i['first_seen'].split()[0],
+            released_on = i['first_seen'].split()[0],
+            heartbeats= i['heartbeats'],
+            prob_crashes = i['prob_crashes'],
+            smpl = i['SMPL'],
+            other = i['other']
+        )
+        version.save()
+
+@transaction.atomic
+def fill_version_daily_data():
+    myModels.VersionDaily.objects.all().delete()
+    query = '''
+        SELECT build_fingerprint, count(id) as heartbeats,
+        strftime("%%Y-%%m-%%d",crashreports_heartbeat.date) as date,
+        ( select count(id) from crashreports_crashreport where boot_reason in ("RTC alarm")  and crashreports_crashreport.build_fingerprint = crashreports_heartbeat.build_fingerprint and  crashreports_crashreport.date >= %s and  crashreports_crashreport.date < %s) as SMPL,
+        ( select count(id) from crashreports_crashreport where boot_reason in ("UNKNOWN", "keyboard power on")  and crashreports_crashreport.build_fingerprint =  crashreports_heartbeat.build_fingerprint and crashreports_crashreport.date >= %s and  crashreports_crashreport.date < %s) as prob_crashes,
+        ( select count(id) from crashreports_crashreport where boot_reason not in ("RTC alarm", "UNKNOWN", "keyboard power on")  and crashreports_crashreport.build_fingerprint =  crashreports_heartbeat.build_fingerprint and crashreports_crashreport.date >= %s and  crashreports_crashreport.date < %s) as other
+         from crashreports_heartbeat where  crashreports_heartbeat.date >= %s and  crashreports_heartbeat.date < %s
+         group by build_fingerprint'''
+    start = date(2016, 8, 1)
+    end   = date.today() + timedelta(days=5)
+    delta = end - start
+    for d in range(delta.days + 1):
+        day = start + timedelta(days=d)
+        print("Getting Stats for " + str(day))
+        cursor = connection.cursor()
+        cursor.execute(query,[str(day), str(day+timedelta(days=1))]*4)
+        desc = cursor.description
+        for row in cursor.fetchall():
+            i = dict(zip([col[0] for col in desc], row))
+            try:
+                version_daily = myModels.VersionDaily(
+                    version = myModels.Version.objects.get(build_fingerprint=i['build_fingerprint']),
+                    heartbeats= i['heartbeats'],
+                    date=day,
+                    prob_crashes = i['prob_crashes'],
+                    smpl = i['SMPL'],
+                    other = i['other']
+                )
+            except:
+                print("Skipping entry for {} {}".format(i['build_fingerprint'],day))
+            version_daily.save()
diff --git a/crashreport_stats/views.py b/crashreport_stats/views.py
index 193133f..49313eb 100644
--- a/crashreport_stats/views.py
+++ b/crashreport_stats/views.py
@@ -25,7 +25,17 @@
     if not Device.objects.filter(uuid=uuid).exists():
         raise Http404("Device doesn't exist.")
     return HttpResponse(template.render({'uuid':uuid}, request))
-    
+
+@user_passes_test(is_fairphone_staff)
+def versions_all_overview(request):
+    template = loader.get_template('crashreport_stats/versions.html')
+    return HttpResponse(template.render({"is_official_release":"1"}, request))
+
+@user_passes_test(is_fairphone_staff)
+def versions_overview(request):
+    template = loader.get_template('crashreport_stats/versions.html')
+    return HttpResponse(template.render({"is_official_release":"2"}, request))
+
 @user_passes_test(is_fairphone_staff)
 def home(request):
     if request.method == 'POST':
diff --git a/crashreports/admin.py b/crashreports/admin.py
index a507218..7133070 100644
--- a/crashreports/admin.py
+++ b/crashreports/admin.py
@@ -5,7 +5,6 @@
 from crashreports.models import LogFile
 
 
-
 @admin.register(Crashreport)
 class CrashreportAdmin(admin.ModelAdmin):
     pass