Add basic tracking of devices

This commit is contained in:
Tanner Collin 2021-04-10 23:39:58 +00:00
parent 0763174494
commit 677b4086e5
3 changed files with 58 additions and 9 deletions

View File

@ -155,6 +155,16 @@ class StatsSpaceActivity(models.Model):
date = models.DateField(default=today_alberta_tz) date = models.DateField(default=today_alberta_tz)
card_scans = models.IntegerField() 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): class HistoryIndex(models.Model):
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL) content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL)
object_id = models.PositiveIntegerField() object_id = models.PositiveIntegerField()

View File

@ -14,6 +14,11 @@ import re
from . import models, fields, utils, utils_ldap, utils_auth from . import models, fields, utils, utils_ldap, utils_auth
from .. import settings, secrets from .. import settings, secrets
class UsageSerializer(serializers.ModelSerializer):
class Meta:
model = models.UsageTrack
fields = '__all__'
class TransactionSerializer(serializers.ModelSerializer): class TransactionSerializer(serializers.ModelSerializer):
# fields directly from old portal. replace with slugs we want # fields directly from old portal. replace with slugs we want
account_type = serializers.ChoiceField([ account_type = serializers.ChoiceField([
@ -262,6 +267,7 @@ class AdminSearchSerializer(serializers.Serializer):
member = serializers.SerializerMethodField() member = serializers.SerializerMethodField()
training = serializers.SerializerMethodField() training = serializers.SerializerMethodField()
transactions = serializers.SerializerMethodField() transactions = serializers.SerializerMethodField()
usages = serializers.SerializerMethodField()
def get_member(self, obj): def get_member(self, obj):
serializer = AdminMemberSerializer(obj) serializer = AdminMemberSerializer(obj)
@ -296,6 +302,12 @@ class AdminSearchSerializer(serializers.Serializer):
serializer.is_valid() serializer.is_valid()
return serializer.data 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): class CardSerializer(serializers.ModelSerializer):
card_number = serializers.CharField(validators=[UniqueValidator( card_number = serializers.CharField(validators=[UniqueValidator(
@ -445,6 +457,7 @@ class UserSerializer(serializers.ModelSerializer):
'is_staff', 'is_staff',
'door_code', 'door_code',
'wifi_pass', 'wifi_pass',
'usages',
] ]
depth = 1 depth = 1

View File

@ -3,6 +3,7 @@ logger = logging.getLogger(__name__)
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.db import transaction
from django.db.models import Max from django.db.models import Max
from django.http import HttpResponse, Http404, FileResponse from django.http import HttpResponse, Http404, FileResponse
from django.core.files.base import File from django.core.files.base import File
@ -501,20 +502,45 @@ class StatsViewSet(viewsets.ViewSet, List):
except KeyError: except KeyError:
raise exceptions.ValidationError(dict(data='This field is required.')) raise exceptions.ValidationError(dict(data='This field is required.'))
@transaction.atomic
@action(detail=False, methods=['post']) @action(detail=False, methods=['post'])
def track(self, request): def track(self, request):
if 'name' in request.data: if 'name' not in request.data:
track = cache.get('track', {}) raise exceptions.ValidationError(dict(name='This field is required.'))
name = request.data['name'] if 'username' not in request.data:
username = request.data.get('username', '') raise exceptions.ValidationError(dict(username='This field is required.'))
username = username.split('.')[0].title()
track[name] = dict(time=time.time(), username=username) track = cache.get('track', {})
cache.set('track', track)
return Response(200) 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: 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): class MemberCountViewSet(Base, List):