From 05080bbf5b16bf838fbb371813083159ea5684e8 Mon Sep 17 00:00:00 2001 From: Roman P Date: Thu, 4 Jul 2019 18:36:24 +0400 Subject: [PATCH] User activity tracking Closes #299 --- backend/backend/settings/base.py | 1 + .../management/commands/metrics.py | 10 ++++---- backend/profile_page/middleware.py | 24 +++++++++++++++++++ .../migrations/0003_profile_last_active.py | 18 ++++++++++++++ backend/profile_page/models.py | 1 + backend/profile_page/tests.py | 2 ++ 6 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 backend/profile_page/middleware.py create mode 100644 backend/profile_page/migrations/0003_profile_last_active.py diff --git a/backend/backend/settings/base.py b/backend/backend/settings/base.py index 476765532..b064915dc 100644 --- a/backend/backend/settings/base.py +++ b/backend/backend/settings/base.py @@ -77,6 +77,7 @@ def check_ip_range(ipr): 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'profile_page.middleware.UserActivityMiddleware' ] ROOT_URLCONF = 'backend.urls' diff --git a/backend/device_registry/management/commands/metrics.py b/backend/device_registry/management/commands/metrics.py index af2a73f05..6ac65b26d 100644 --- a/backend/device_registry/management/commands/metrics.py +++ b/backend/device_registry/management/commands/metrics.py @@ -22,13 +22,15 @@ def average_trust_score(devices): return mean(scores) if scores else 0 now = timezone.now() - day_ago = now - timezone.timedelta(hours=24) + today = now.date() + month_ago_date = today - timezone.timedelta(days=30) + day_ago_date = today - timezone.timedelta(days=1) week_ago = now - timezone.timedelta(days=7) - month_ago = now - timezone.timedelta(days=30) + all_users = User.objects.count() all_devices = Device.objects.count() - active_users_monthly = User.objects.filter(last_login__gte=month_ago).count() - active_users_daily = User.objects.filter(last_login__gte=day_ago).count() + active_users_monthly = User.objects.filter(profile__last_active__gte=month_ago_date).count() + active_users_daily = User.objects.filter(profile__last_active__gte=day_ago_date).count() active_devices = Device.objects.filter(last_ping__gte=week_ago) inactive_devices = Device.objects.filter(last_ping__lt=week_ago) metrics = { diff --git a/backend/profile_page/middleware.py b/backend/profile_page/middleware.py new file mode 100644 index 000000000..73ac9d506 --- /dev/null +++ b/backend/profile_page/middleware.py @@ -0,0 +1,24 @@ +from django.utils import timezone + +from .models import Profile + + +class UserActivityMiddleware: + """ + Save user last activity date. + Do actual DB hitting only once a day. + """ + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + if request.user.is_authenticated: + today = timezone.localdate() + profile, _ = Profile.objects.get_or_create(user=request.user) + if profile.last_active != today: + profile.last_active = today + profile.save(update_fields=['last_active']) + + response = self.get_response(request) + return response diff --git a/backend/profile_page/migrations/0003_profile_last_active.py b/backend/profile_page/migrations/0003_profile_last_active.py new file mode 100644 index 000000000..dfba105ce --- /dev/null +++ b/backend/profile_page/migrations/0003_profile_last_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.10 on 2019-07-04 08:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('profile_page', '0002_auto_20190605_1012'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='last_active', + field=models.DateField(blank=True, null=True), + ), + ] diff --git a/backend/profile_page/models.py b/backend/profile_page/models.py index 2572ed5b6..20431752c 100644 --- a/backend/profile_page/models.py +++ b/backend/profile_page/models.py @@ -12,3 +12,4 @@ def user_save_lower(sender, instance, *args, **kwargs): class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) company_name = models.CharField(blank=True, null=True, max_length=128) + last_active = models.DateField(null=True, blank=True) diff --git a/backend/profile_page/tests.py b/backend/profile_page/tests.py index e14b4cf6e..986270766 100644 --- a/backend/profile_page/tests.py +++ b/backend/profile_page/tests.py @@ -1,6 +1,7 @@ from django.test import TestCase, RequestFactory from django.contrib.auth.models import User from django.urls import reverse +from django.utils import timezone class ProfileViewTest(TestCase): @@ -14,6 +15,7 @@ def test_get(self): response = self.client.get(reverse('profile')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Profile Settings') + self.assertEqual(self.user0.profile.last_active, timezone.localdate()) def test_comment(self): self.client.login(username='test', password='123')