diff --git a/bookwyrm/migrations/0086_auto_20210827_1727.py b/bookwyrm/migrations/0086_auto_20210827_1727.py new file mode 100644 index 000000000..ef6af206b --- /dev/null +++ b/bookwyrm/migrations/0086_auto_20210827_1727.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.4 on 2021-08-27 17:27 + +from django.db import migrations, models +import django.db.models.expressions + + +def normalize_readthrough_dates(app_registry, schema_editor): + """Find any invalid dates and reset them""" + db_alias = schema_editor.connection.alias + app_registry.get_model("bookwyrm", "ReadThrough").objects.using(db_alias).filter( + start_date__gt=models.F("finish_date") + ).update(start_date=models.F("finish_date")) + + +def reverse_func(apps, schema_editor): + """nothing to do here""" + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0085_user_saved_lists"), + ] + + operations = [ + migrations.RunPython(normalize_readthrough_dates, reverse_func), + migrations.AlterModelOptions( + name="readthrough", + options={"ordering": ("-start_date",)}, + ), + migrations.AddConstraint( + model_name="readthrough", + constraint=models.CheckConstraint( + check=models.Q( + ("finish_date__gte", django.db.models.expressions.F("start_date")) + ), + name="chronology", + ), + ), + ] diff --git a/bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py b/bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py new file mode 100644 index 000000000..cd5311619 --- /dev/null +++ b/bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.4 on 2021-08-29 18:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0086_auto_20210827_1727"), + ("bookwyrm", "0086_auto_20210828_1724"), + ] + + operations = [] diff --git a/bookwyrm/models/readthrough.py b/bookwyrm/models/readthrough.py index df341c8b2..343d3c115 100644 --- a/bookwyrm/models/readthrough.py +++ b/bookwyrm/models/readthrough.py @@ -1,7 +1,8 @@ """ progress in a book """ -from django.db import models -from django.utils import timezone from django.core import validators +from django.db import models +from django.db.models import F, Q +from django.utils import timezone from .base_model import BookWyrmModel @@ -41,6 +42,16 @@ class ReadThrough(BookWyrmModel): ) return None + class Meta: + """Don't let readthroughs end before they start""" + + constraints = [ + models.CheckConstraint( + check=Q(finish_date__gte=F("start_date")), name="chronology" + ) + ] + ordering = ("-start_date",) + class ProgressUpdate(BookWyrmModel): """Store progress through a book in the database.""" diff --git a/bookwyrm/tests/models/test_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index 596753f79..2b6e4fdd2 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -1,7 +1,9 @@ """ testing models """ +import datetime from unittest.mock import patch from django.test import TestCase from django.core.exceptions import ValidationError +from django.utils import timezone from bookwyrm import models @@ -21,27 +23,79 @@ class ReadThrough(TestCase): title="Example Edition", parent_work=self.work ) - self.readthrough = models.ReadThrough.objects.create( - user=self.user, book=self.edition + def test_valid_date(self): + """can't finish a book before you start it""" + start = timezone.now() + finish = start + datetime.timedelta(days=1) + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + start_date=start, + finish_date=finish, + ) + + def test_valid_date_null_start(self): + """can't finish a book before you start it""" + start = timezone.now() + finish = start + datetime.timedelta(days=1) + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + finish_date=finish, + ) + + def test_valid_date_null_finish(self): + """can't finish a book before you start it""" + start = timezone.now() + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + start_date=start, + ) + + def test_valid_date_null(self): + """can't finish a book before you start it""" + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + ) + + def test_valid_date_same(self): + """can't finish a book before you start it""" + start = timezone.now() + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + start_date=start, + finish_date=start, ) def test_progress_update(self): """Test progress updates""" - self.readthrough.create_update() # No-op, no progress yet - self.readthrough.progress = 10 - self.readthrough.create_update() - self.readthrough.progress = 20 - self.readthrough.progress_mode = models.ProgressMode.PERCENT - self.readthrough.create_update() + readthrough = models.ReadThrough.objects.create( + user=self.user, book=self.edition + ) - updates = self.readthrough.progressupdate_set.order_by("created_date").all() + readthrough.create_update() # No-op, no progress yet + readthrough.progress = 10 + readthrough.create_update() + readthrough.progress = 20 + readthrough.progress_mode = models.ProgressMode.PERCENT + readthrough.create_update() + + updates = readthrough.progressupdate_set.order_by("created_date").all() self.assertEqual(len(updates), 2) self.assertEqual(updates[0].progress, 10) self.assertEqual(updates[0].mode, models.ProgressMode.PAGE) self.assertEqual(updates[1].progress, 20) self.assertEqual(updates[1].mode, models.ProgressMode.PERCENT) - self.readthrough.progress = -10 - self.assertRaises(ValidationError, self.readthrough.clean_fields) - update = self.readthrough.create_update() + readthrough.progress = -10 + self.assertRaises(ValidationError, readthrough.clean_fields) + update = readthrough.create_update() self.assertRaises(ValidationError, update.clean_fields) diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index bebd9f5a9..61464bc7f 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -107,7 +107,7 @@ class ReadingViews(TestCase): { "post-status": True, "privacy": "followers", - "finish_date": "2020-01-07", + "finish_date": timezone.now().isoformat(), "id": readthrough.id, }, )