shynet/shynet/analytics/models.py
2021-03-28 19:15:03 +00:00

114 lines
3.5 KiB
Python

import json
import uuid
from django.conf import settings
from django.db import models
from django.shortcuts import reverse
from django.utils import timezone
from core.models import Service
def _default_uuid():
return str(uuid.uuid4())
class Session(models.Model):
uuid = models.UUIDField(default=_default_uuid, primary_key=True)
service = models.ForeignKey(Service, on_delete=models.CASCADE, db_index=True)
# Cross-session identification; optional, and provided by the service
identifier = models.TextField(blank=True, db_index=True)
# Time
start_time = models.DateTimeField(default=timezone.now, db_index=True)
last_seen = models.DateTimeField(default=timezone.now, db_index=True)
# Core request information
user_agent = models.TextField()
browser = models.TextField()
device = models.TextField()
device_type = models.CharField(
max_length=7,
choices=[
("PHONE", "Phone"),
("TABLET", "Tablet"),
("DESKTOP", "Desktop"),
("ROBOT", "Robot"),
("OTHER", "Other"),
],
default="OTHER",
)
os = models.TextField()
ip = models.GenericIPAddressField(db_index=True, null=True)
# GeoIP data
asn = models.TextField(blank=True)
country = models.TextField(blank=True)
longitude = models.FloatField(null=True)
latitude = models.FloatField(null=True)
time_zone = models.TextField(blank=True)
class Meta:
ordering = ["-start_time"]
indexes = [
models.Index(fields=["service", "-start_time"]),
models.Index(fields=["service", "-last_seen"]),
models.Index(fields=["service", "identifier"]),
]
@property
def is_currently_active(self):
return timezone.now() - self.last_seen < timezone.timedelta(
milliseconds=settings.SCRIPT_HEARTBEAT_FREQUENCY * 2
)
@property
def duration(self):
return self.last_seen - self.start_time
def __str__(self):
return f"{self.identifier if self.identifier != '' else 'Anonymous'} @ {self.service.name} [{str(self.uuid)[:6]}]"
def get_absolute_url(self):
return reverse(
"dashboard:service_session",
kwargs={"pk": self.service.pk, "session_pk": self.uuid},
)
class Hit(models.Model):
session = models.ForeignKey(Session, on_delete=models.CASCADE, db_index=True)
initial = models.BooleanField(default=True, db_index=True)
# Base request information
start_time = models.DateTimeField(default=timezone.now, db_index=True)
last_seen = models.DateTimeField(default=timezone.now)
heartbeats = models.IntegerField(default=0)
tracker = models.TextField(
choices=[("JS", "JavaScript"), ("PIXEL", "Pixel (noscript)")]
) # Tracking pixel or JS
# Advanced page information
location = models.TextField(blank=True, db_index=True)
referrer = models.TextField(blank=True, db_index=True)
load_time = models.FloatField(null=True)
class Meta:
ordering = ["-start_time"]
indexes = [
models.Index(fields=["session", "-start_time"]),
models.Index(fields=["session", "location"]),
models.Index(fields=["session", "referrer"]),
]
@property
def duration(self):
return self.last_seen - self.start_time
def get_absolute_url(self):
return reverse(
"dashboard:service_session",
kwargs={"pk": self.session.service.pk, "session_pk": self.session.pk},
)