diff --git a/CHANGELOG.md b/CHANGELOG.md index baa905c0..d67e5c30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Improvements - In monthly reports, no downtime stats for the current month (month has just started) - Add Microsoft Teams integration (#135) +- Add Profile.last_active_date field for more accurate inactive user detection ### Bug Fixes - On mobile, "My Checks" page, always show the gear (Details) button (#286) diff --git a/hc/accounts/migrations/0028_auto_20191119_1346.py b/hc/accounts/migrations/0028_auto_20191119_1346.py new file mode 100644 index 00000000..78b9ec28 --- /dev/null +++ b/hc/accounts/migrations/0028_auto_20191119_1346.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.6 on 2019-11-19 13:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0027_profile_deletion_notice_date'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='last_active_date', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AlterField( + model_name='profile', + name='sms_limit', + field=models.IntegerField(default=5), + ), + ] diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 9fab58ae..31994c60 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -60,6 +60,7 @@ class Profile(models.Model): team_limit = models.IntegerField(default=2) sort = models.CharField(max_length=20, default="created") deletion_notice_date = models.DateTimeField(null=True, blank=True) + last_active_date = models.DateTimeField(null=True, blank=True) objects = ProfileManager() diff --git a/hc/api/migrations/0064_auto_20191119_1346.py b/hc/api/migrations/0064_auto_20191119_1346.py new file mode 100644 index 00000000..dbf82959 --- /dev/null +++ b/hc/api/migrations/0064_auto_20191119_1346.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-11-19 13:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0063_auto_20190903_0901'), + ] + + operations = [ + migrations.AlterField( + model_name='channel', + name='kind', + field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('pagerteam', 'Pager Team'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk'), ('trello', 'Trello'), ('matrix', 'Matrix'), ('whatsapp', 'WhatsApp'), ('apprise', 'Apprise'), ('mattermost', 'Mattermost'), ('msteams', 'Microsoft Teams')], max_length=20), + ), + ] diff --git a/hc/front/tests/test_my_checks.py b/hc/front/tests/test_my_checks.py index 1d896ab8..5814c44b 100644 --- a/hc/front/tests/test_my_checks.py +++ b/hc/front/tests/test_my_checks.py @@ -18,6 +18,22 @@ class MyChecksTestCase(BaseTestCase): r = self.client.get(self.url) self.assertContains(r, "Alice Was Here", status_code=200) + # last_active_date should have been set + self.profile.refresh_from_db() + self.assertTrue(self.profile.last_active_date) + + def test_it_bumps_last_active_date(self): + self.profile.last_active_date = timezone.now() - td(days=10) + self.profile.save() + + self.client.login(username="alice@example.org", password="password") + self.client.get(self.url) + + # last_active_date should have been bumped + self.profile.refresh_from_db() + delta = timezone.now() - self.profile.last_active_date + self.assertTrue(delta.total_seconds() < 1) + def test_it_updates_current_project(self): self.profile.current_project = None self.profile.save() diff --git a/hc/front/views.py b/hc/front/views.py index 1d693274..98e9e499 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -115,8 +115,18 @@ def _get_project_for_user(request, project_code): raise Http404("not found") +def _refresh_last_active_date(profile): + """ Update last_active_date if it is more than a day old. """ + + now = timezone.now() + if profile.last_active_date is None or (now - profile.last_active_date).days > 0: + profile.last_active_date = now + profile.save() + + @login_required def my_checks(request, code): + _refresh_last_active_date(request.profile) project = _get_project_for_user(request, code) if request.GET.get("sort") in VALID_SORT_VALUES: @@ -470,6 +480,7 @@ def log(request, code): @login_required def details(request, code): + _refresh_last_active_date(request.profile) check = _get_check_for_user(request, code) channels = Channel.objects.filter(project=check.project)