Dashboard: Hide old data (#215)

* filter card data by age

* add setting for hide_age

* add option to settings form

* fix name to consistently use hide_age

* rename filter, use setting for filter

* add test for old hiding old data

* fix migration to contain correct imports, remove month from timedelta

* remove months from timedelta, allow blank

* fix with block

* add settings test

* add test for filter

* mock localtime

* fix timezone issues with tests

* linting

* linting

* Adjust migration

Co-authored-by: Benjamin Häublein <benjaminh@debian.vm.hp>
Co-authored-by: Christopher C. Wells <git@chris-wells.net>
This commit is contained in:
Benjamin Häublein 2021-06-19 23:09:05 +02:00 committed by GitHub
parent c3dc4520fc
commit e8696a8b00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 3 deletions

View File

@ -14,7 +14,10 @@ class SettingsInline(admin.StackedInline):
can_delete = False
fieldsets = (
(_('Dashboard'), {
'fields': ('dashboard_refresh_rate', 'dashboard_hide_empty',)
'fields': (
'dashboard_refresh_rate',
'dashboard_hide_empty',
'dashboard_hide_age')
}),
)

View File

@ -44,6 +44,7 @@ class UserSettingsForm(forms.ModelForm):
fields = [
'dashboard_refresh_rate',
'dashboard_hide_empty',
'dashboard_hide_age',
'language',
'timezone'
]

View File

@ -0,0 +1,28 @@
from django.db import migrations, models
from django.utils import timezone
class Migration(migrations.Migration):
dependencies = [
('babybuddy', '0016_alter_settings_timezone'),
]
operations = [
migrations.AddField(
model_name='settings',
name='dashboard_hide_age',
field=models.DurationField(
choices=[
(None, 'show all data'),
(timezone.timedelta(days=1), '1 day'),
(timezone.timedelta(days=2), '2 days'),
(timezone.timedelta(days=3), '3 days'),
(timezone.timedelta(weeks=1), '1 week'),
(timezone.timedelta(weeks=4), '4 weeks')
],
default=None,
null=True,
verbose_name='Hide data older than'),
),
]

View File

@ -39,6 +39,21 @@ class Settings(models.Model):
default=False,
editable=True
)
dashboard_hide_age = models.DurationField(
verbose_name=_('Hide data older than'),
help_text=_('This setting controls which data will be shown '
'in the dashboard.'),
blank=True,
null=True,
default=None,
choices=[
(None, _('show all data')),
(timezone.timedelta(days=1), _('1 day')),
(timezone.timedelta(days=2), _('2 days')),
(timezone.timedelta(days=3), _('3 days')),
(timezone.timedelta(weeks=1), _('1 week')),
(timezone.timedelta(weeks=4), _('4 weeks')),
])
language = models.CharField(
choices=settings.LANGUAGES,
default=settings.LANGUAGE_CODE,

View File

@ -69,6 +69,11 @@
{% include 'babybuddy/form_field.html' %}
{% endwith %}
</div>
<div class="form-group row">
{% with form_settings.dashboard_hide_age as field %}
{% include 'babybuddy/form_field.html' %}
{% endwith %}
</div>
</fieldset>
<fieldset>
<legend>{% trans "API" %}</legend>

View File

@ -157,3 +157,15 @@ class FormsTestCase(TestCase):
self.user.refresh_from_db()
self.assertEqual(self.user.settings.dashboard_refresh_rate,
datetime.timedelta(seconds=300))
def test_user_settings_dashboard_hide_age(self):
self.c.login(**self.credentials)
params = self.settings_template.copy()
params['dashboard_hide_age'] = '1 day, 0:00:00'
page = self.c.post('/user/settings/', data=params, follow=True)
self.assertEqual(page.status_code, 200)
self.user.refresh_from_db()
self.assertEqual(self.user.settings.dashboard_hide_age,
datetime.timedelta(days=1))

View File

@ -16,6 +16,15 @@ def _hide_empty(context):
return context['request'].user.settings.dashboard_hide_empty
def _filter_data_age(context, keyword="end"):
filter = {}
if context['request'].user.settings.dashboard_hide_age:
now = timezone.localtime()
start_time = now - context['request'].user.settings.dashboard_hide_age
filter[keyword + "__range"] = (start_time, now)
return filter
@register.inclusion_tag('cards/diaperchange_last.html', takes_context=True)
def card_diaperchange_last(context, child):
"""
@ -23,8 +32,9 @@ def card_diaperchange_last(context, child):
:param child: an instance of the Child model.
:returns: a dictionary with the most recent Diaper Change instance.
"""
instance = models.DiaperChange.objects.filter(
child=child).order_by('-time').first()
instance = models.DiaperChange.objects.filter(child=child) \
.filter(**_filter_data_age(context, "time")) \
.order_by('-time').first()
empty = not instance
return {
@ -127,6 +137,7 @@ def card_feeding_last(context, child):
:returns: a dictionary with the most recent Feeding instance.
"""
instance = models.Feeding.objects.filter(child=child) \
.filter(**_filter_data_age(context)) \
.order_by('-end').first()
empty = not instance
@ -146,6 +157,7 @@ def card_feeding_last_method(context, child):
:returns: a dictionary with the most recent Feeding instances.
"""
instances = models.Feeding.objects.filter(child=child) \
.filter(**_filter_data_age(context)) \
.order_by('-end')[:3]
empty = len(instances) == 0
@ -166,6 +178,7 @@ def card_sleep_last(context, child):
:returns: a dictionary with the most recent Sleep instance.
"""
instance = models.Sleep.objects.filter(child=child) \
.filter(**_filter_data_age(context)) \
.order_by('-end').first()
empty = not instance
@ -496,6 +509,7 @@ def card_tummytime_last(context, child):
:returns: a dictionary with the most recent Tummy Time instance.
"""
instance = models.TummyTime.objects.filter(child=child) \
.filter(**_filter_data_age(context)) \
.order_by('-end').first()
empty = not instance

View File

@ -9,6 +9,8 @@ from babybuddy.models import Settings
from core import models
from dashboard.templatetags import cards
from unittest import mock
class MockUserRequest:
def __init__(self, user):
@ -39,6 +41,31 @@ class TemplateTagsTestCase(TestCase):
hide_empty = cards._hide_empty(context)
self.assertTrue(hide_empty)
def test_filter_data_age_none(self):
request = MockUserRequest(User.objects.first())
request.user.settings.dashboard_hide_age = None
context = {'request': request}
filter_data_age = cards._filter_data_age(context)
self.assertFalse(len(filter_data_age))
@mock.patch('dashboard.templatetags.cards.timezone')
def test_filter_data_age_one_day(self, mocked_timezone):
request = MockUserRequest(User.objects.first())
request.user.settings.dashboard_hide_age = timezone.timedelta(days=1)
context = {'request': request}
mocked_timezone.localtime.return_value = \
timezone.localtime().strptime('2017-11-18', '%Y-%m-%d')
filter_data_age = cards._filter_data_age(context, keyword="time")
self.assertIn("time__range", filter_data_age)
self.assertEqual(
filter_data_age["time__range"][0],
timezone.localtime().strptime('2017-11-17', '%Y-%m-%d'))
self.assertEqual(
filter_data_age["time__range"][1],
timezone.localtime().strptime('2017-11-18', '%Y-%m-%d'))
def test_card_diaperchange_last(self):
data = cards.card_diaperchange_last(self.context, self.child)
self.assertEqual(data['type'], 'diaperchange')
@ -47,6 +74,17 @@ class TemplateTagsTestCase(TestCase):
self.assertIsInstance(data['change'], models.DiaperChange)
self.assertEqual(data['change'], models.DiaperChange.objects.first())
@mock.patch('dashboard.templatetags.cards.timezone')
def test_card_diaperchange_last_filter_age(self, mocked_timezone):
request = MockUserRequest(User.objects.first())
request.user.settings.dashboard_hide_age = timezone.timedelta(days=1)
context = {'request': request}
time = timezone.localtime().strptime('2017-11-10', '%Y-%m-%d')
mocked_timezone.localtime.return_value = timezone.make_aware(time)
data = cards.card_diaperchange_last(context, self.child)
self.assertTrue(data['empty'])
def test_card_diaperchange_types(self):
data = cards.card_diaperchange_types(
self.context,