From 677b4086e5c9e3cde8182404b1c7d8dfca8f5321 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Sat, 10 Apr 2021 23:39:58 +0000 Subject: [PATCH] Add basic tracking of devices --- apiserver/apiserver/api/models.py | 10 ++++++ apiserver/apiserver/api/serializers.py | 13 ++++++++ apiserver/apiserver/api/views.py | 44 ++++++++++++++++++++------ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/apiserver/apiserver/api/models.py b/apiserver/apiserver/api/models.py index 40e0b0c..e503a64 100644 --- a/apiserver/apiserver/api/models.py +++ b/apiserver/apiserver/api/models.py @@ -155,6 +155,16 @@ class StatsSpaceActivity(models.Model): date = models.DateField(default=today_alberta_tz) card_scans = models.IntegerField() +class UsageTrack(models.Model): + user = models.ForeignKey(User, related_name='usages', blank=True, null=True, on_delete=models.SET_NULL) + username = models.CharField(max_length=64) + devicename = models.CharField(max_length=64) + + start_time = models.DateTimeField(auto_now_add=True) + num_seconds = models.IntegerField() + + history = HistoricalRecords(excluded_fields=['num_seconds']) + class HistoryIndex(models.Model): content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL) object_id = models.PositiveIntegerField() diff --git a/apiserver/apiserver/api/serializers.py b/apiserver/apiserver/api/serializers.py index a14932b..1f5cec6 100644 --- a/apiserver/apiserver/api/serializers.py +++ b/apiserver/apiserver/api/serializers.py @@ -14,6 +14,11 @@ import re from . import models, fields, utils, utils_ldap, utils_auth from .. import settings, secrets +class UsageSerializer(serializers.ModelSerializer): + class Meta: + model = models.UsageTrack + fields = '__all__' + class TransactionSerializer(serializers.ModelSerializer): # fields directly from old portal. replace with slugs we want account_type = serializers.ChoiceField([ @@ -262,6 +267,7 @@ class AdminSearchSerializer(serializers.Serializer): member = serializers.SerializerMethodField() training = serializers.SerializerMethodField() transactions = serializers.SerializerMethodField() + usages = serializers.SerializerMethodField() def get_member(self, obj): serializer = AdminMemberSerializer(obj) @@ -296,6 +302,12 @@ class AdminSearchSerializer(serializers.Serializer): serializer.is_valid() return serializer.data + def get_usages(self, obj): + queryset = obj.user.usages.order_by('-start_time') + serializer = UsageSerializer(data=queryset, many=True) + serializer.is_valid() + return serializer.data + class CardSerializer(serializers.ModelSerializer): card_number = serializers.CharField(validators=[UniqueValidator( @@ -445,6 +457,7 @@ class UserSerializer(serializers.ModelSerializer): 'is_staff', 'door_code', 'wifi_pass', + 'usages', ] depth = 1 diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index d3adadc..3176db5 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -3,6 +3,7 @@ logger = logging.getLogger(__name__) from django.contrib.auth.models import User, Group from django.shortcuts import get_object_or_404, redirect +from django.db import transaction from django.db.models import Max from django.http import HttpResponse, Http404, FileResponse from django.core.files.base import File @@ -501,20 +502,45 @@ class StatsViewSet(viewsets.ViewSet, List): except KeyError: raise exceptions.ValidationError(dict(data='This field is required.')) + @transaction.atomic @action(detail=False, methods=['post']) def track(self, request): - if 'name' in request.data: - track = cache.get('track', {}) + if 'name' not in request.data: + raise exceptions.ValidationError(dict(name='This field is required.')) - name = request.data['name'] - username = request.data.get('username', '') - username = username.split('.')[0].title() + if 'username' not in request.data: + raise exceptions.ValidationError(dict(username='This field is required.')) - track[name] = dict(time=time.time(), username=username) - cache.set('track', track) - return Response(200) + track = cache.get('track', {}) + + devicename = request.data['name'] + username = request.data['username'] + first_name = username.split('.')[0].title() + + track[devicename] = dict(time=time.time(), username=first_name) + cache.set('track', track) + + # update device usage + last_session = models.UsageTrack.objects.filter(devicename=devicename).last() + if not last_session or last_session.username != username: + try: + user = User.objects.get(username__iexact=username) + except User.DoesNotExist: + logging.error('Username not found: ' + username) + user = None + + models.UsageTrack.objects.create( + user=user, + username=username, + devicename=devicename, + num_seconds=10, + ) + logging.info('New ' + devicename + ' session created for: ' + username) else: - raise exceptions.ValidationError(dict(paste='This field is required.')) + last_session.num_seconds += 10 + last_session.save() + + return Response(200) class MemberCountViewSet(Base, List):