Fixed a few bugs for the stats functions and created a few tests. 46/69746/8
authorSean <ssmith@iol.unh.edu>
Tue, 3 Mar 2020 15:54:20 +0000 (10:54 -0500)
committerSean <ssmith@iol.unh.edu>
Mon, 16 Mar 2020 18:50:00 +0000 (14:50 -0400)
Signed-off-by: Sean <ssmith@iol.unh.edu>
Change-Id: I2e4598811bddabe5b7447c3a92d39d16acb77a03
Signed-off-by: Sean <ssmith@iol.unh.edu>
src/booking/stats.py
src/booking/tests/test_stats.py [new file with mode: 0644]
src/templates/base/booking/stats.html

index 47de80b..bdb478a 100644 (file)
@@ -1,5 +1,5 @@
 ##############################################################################
-# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
+# Copyright (c) 2020 Parker Berberian, Sawyer Bergeron, Sean Smith and others.
 #
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Apache License, Version 2.0
@@ -7,7 +7,7 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 from booking.models import Booking
-import datetime
+from datetime import datetime, timedelta
 import pytz
 
 
@@ -18,43 +18,41 @@ class StatisticsManager(object):
         """
         Calculate Booking usage data points.
 
-        Will return a dictionary of names and 2-D array of x and y data points.
-        e.g. {"plot1": [["x1", "x2", "x3"],["y1", "y2", "y3]]}
-        x values will be dates in string
-        every change (booking start / end) will be reflected,
-        instead of one data point per day
-        y values are the integer number of bookings/users active at
-        some point in the given date span is the number of days to plot.
-        The last x value will always be the current time
+        Gathers all active bookings that fall in interval [(now - span), (now + 1 week)].
+        x data points are every 12 hours
+        y values are the integer number of bookings/users active at time
         """
-        data = []
+
         x = []
         y = []
         users = []
-        now = datetime.datetime.now(pytz.utc)
-        delta = datetime.timedelta(days=span)
-        end = now - delta
-        bookings = Booking.objects.filter(start__lte=now, end__gte=end).prefetch_related("collaborators")
-        for booking in bookings:  # collect data from each booking
-            user_list = [u.pk for u in booking.collaborators.all()]
-            user_list.append(booking.owner.pk)
-            data.append((booking.start, 1, user_list))
-            data.append((booking.end, -1, user_list))
-
-        # sort based on time
-        data.sort(key=lambda i: i[0])
-
-        # collect data
-        count = 0
-        active_users = {}
-        for datum in data:
-            x.append(str(datum[0]))  # time
-            count += datum[1]  # booking count
-            y.append(count)
-            for pk in datum[2]:  # maintain count of each user's active bookings
-                active_users[pk] = active_users.setdefault(pk, 0) + datum[1]
-                if active_users[pk] == 0:
-                    del active_users[pk]
-            users.append(len([x for x in active_users.values() if x > 0]))
+
+        now = datetime.now(pytz.utc)
+        delta = timedelta(days=span)
+        start = now - delta
+        end = now + timedelta(weeks=1)
+
+        bookings = Booking.objects.filter(
+            start__lte=end,
+            end__gte=start
+        ).prefetch_related("collaborators")
+
+        # get data
+        while start <= end:
+            active_users = 0
+
+            books = bookings.filter(
+                start__lte=start,
+                end__gte=start
+            ).prefetch_related("collaborators")
+
+            for booking in books:
+                active_users += booking.collaborators.all().count() + 1
+
+            x.append(str(start))
+            y.append(books.count())
+            users.append(active_users)
+
+            start += timedelta(hours=12)
 
         return {"booking": [x, y], "user": [x, users]}
diff --git a/src/booking/tests/test_stats.py b/src/booking/tests/test_stats.py
new file mode 100644 (file)
index 0000000..5501355
--- /dev/null
@@ -0,0 +1,59 @@
+#############################################################################
+# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, Sean Smith, and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import pytz
+from datetime import timedelta, datetime
+
+from django.test import TestCase
+
+from booking.models import Booking
+from booking.stats import StatisticsManager as sm
+from dashboard.testing_utils import make_user
+
+
+class StatsTestCases(TestCase):
+
+    def test_no_booking_outside_span(self):
+        now = datetime.now(pytz.utc)
+
+        bad_date = now + timedelta(days=1200)
+        Booking.objects.create(start=now, end=bad_date, owner=make_user(username='jj'))
+
+        actual = sm.getContinuousBookingTimeSeries()
+        dates = actual['booking'][0]
+
+        for date in dates:
+            self.assertNotEqual(date, bad_date)
+
+    def check_booking_and_user_counts(self):
+        now = datetime.now(pytz.utc)
+
+        for i in range(20):
+            Booking.objects.create(
+                start=now,
+                end=now + timedelta(weeks=3),
+                owner=make_user(username='a'))
+
+        for i in range(30):
+            Booking.objects.create(
+                start=now + timedelta(days=5),
+                end=now + timedelta(weeks=3, days=5),
+                owner=make_user(username='a'))
+
+        for i in range(120):
+            Booking.objects.create(
+                start=now + timedelta(weeks=1),
+                end=now + timedelta(weeks=4),
+                owner=make_user(username='a'))
+
+        dates = [[now, 20], [now + timedelta(days=5), 30], [now + timedelta(weeks=1), 120]]
+        actual = sm.getContinuousBookingTimeSeries()
+
+        for date in dates:
+            self.assertEqual(date[1], actual['booking'][date[0]])
+            self.assertEqual(date[1], actual['booking'][date[1]])
index a78f793..4c06b71 100644 (file)
@@ -5,20 +5,26 @@
 {{ block.super }}
 <script src="{% static "node_modules/plotly.js-dist/plotly.js" %}"></script>
 <script>
+
 function drawGraph(data, graph_id, graph_title){
     var container = document.getElementById(graph_id);
     var plot_data = { x: data[0],
         y: data[1],
-        fill: "tonexty",
+        line: {shape: "hv"},
         type: "scatter",
-        mode: "none",
+        mode: "lines+makers",
     };
     var layout = {
-        title: graph_title
+        title: graph_title,
+        yaxis: {
+            rangemode: 'tozero',
+            autorange: true
+        }
     };
     Plotly.newPlot(container, [plot_data], layout);
 }
-function getData(){
+
+function getData() {
     var req = new XMLHttpRequest();
     var url = "/booking/stats/json";
     var day_input = document.getElementById("number_days");
@@ -37,6 +43,7 @@ function getData(){
     req.open("GET", url, true);
     req.send();
 }
+
 </script>
 {% endblock %}