diff --git a/fedireads/goodreads_import.py b/fedireads/goodreads_import.py index adcbad3ce..884cd76ac 100644 --- a/fedireads/goodreads_import.py +++ b/fedireads/goodreads_import.py @@ -2,9 +2,10 @@ import re import csv import itertools +import dateutil.parser from fedireads import books_manager -from fedireads.models import Edition +from fedireads.models import Edition, ReadThrough # Mapping goodreads -> fedireads shelf titles. @@ -99,6 +100,25 @@ class GoodreadsItem: def rating(self): return int(self.line['My Rating']) + @property + def date_added(self): + if self.line['Date Added']: + return dateutil.parser.parse(self.line['Date Added']) + + @property + def date_read(self): + if self.line['Date Read']: + return dateutil.parser.parse(self.line['Date Read']) + + @property + def reads(self): + return [ReadThrough( + # Date added isn't the start date, but it's (perhaps) better than nothing. + start_date=self.date_added, + finish_date=self.date_read, + pages_read=None, + )] + def __repr__(self): return "".format(self.line['Title']) diff --git a/fedireads/migrations/0031_readthrough.py b/fedireads/migrations/0031_readthrough.py new file mode 100644 index 000000000..1bd748421 --- /dev/null +++ b/fedireads/migrations/0031_readthrough.py @@ -0,0 +1,31 @@ +# Generated by Django 3.0.3 on 2020-04-15 12:24 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('fedireads', '0030_quotation'), + ] + + operations = [ + migrations.CreateModel( + name='ReadThrough', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), + ('pages_read', models.IntegerField(blank=True, null=True)), + ('start_date', models.DateTimeField(blank=True, null=True)), + ('finish_date', models.DateTimeField(blank=True, null=True)), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='fedireads.Book')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/fedireads/models/__init__.py b/fedireads/models/__init__.py index 26c7c6cc8..87891e01c 100644 --- a/fedireads/models/__init__.py +++ b/fedireads/models/__init__.py @@ -2,6 +2,6 @@ from .book import Connector, Book, Work, Edition, Author from .shelf import Shelf, ShelfBook from .status import Status, Review, Comment, Quotation -from .status import Favorite, Boost, Tag, Notification +from .status import Favorite, Boost, Tag, Notification, ReadThrough from .user import User, UserFollows, UserFollowRequest, UserBlocks from .user import FederatedServer diff --git a/fedireads/models/status.py b/fedireads/models/status.py index 6e4c3868b..6f19fe28c 100644 --- a/fedireads/models/status.py +++ b/fedireads/models/status.py @@ -134,6 +134,21 @@ class Tag(FedireadsModel): unique_together = ('user', 'book', 'name') +class ReadThrough(FedireadsModel): + ''' Store progress through a book in the database. ''' + user = models.ForeignKey('User', on_delete=models.PROTECT) + book = models.ForeignKey('Book', on_delete=models.PROTECT) + pages_read = models.IntegerField( + null=True, + blank=True) + start_date = models.DateTimeField( + blank=True, + null=True) + finish_date = models.DateTimeField( + blank=True, + null=True) + + NotificationType = models.TextChoices( 'NotificationType', 'FAVORITE REPLY TAG FOLLOW FOLLOW_REQUEST BOOST') diff --git a/fedireads/outgoing.py b/fedireads/outgoing.py index 53e1410c4..6e808e0ce 100644 --- a/fedireads/outgoing.py +++ b/fedireads/outgoing.py @@ -1,4 +1,5 @@ ''' handles all the activity coming out of the server ''' +from datetime import datetime from urllib.parse import urlencode from django.db import IntegrityError, transaction @@ -138,6 +139,25 @@ def handle_shelve(user, book, shelf): status.status_type = 'Update' status.save() + if shelf.identifier == 'reading': + read = models.ReadThrough( + user=user, + book=book, + start_date=datetime.now()) + read.save() + elif shelf.identifier == 'read': + read = models.ReadThrough.objects.filter( + user=user, + book=book, + finish_date=None).order_by('-created_date').first() + if not read: + read = models.ReadThrough( + user=user, + book=book, + start_date=datetime.now()) + read.finish_date = datetime.now() + read.save() + activity = activitypub.get_status(status) create_activity = activitypub.get_create(user, activity) @@ -177,6 +197,11 @@ def handle_import_books(user, items): recipients = get_recipients(user, 'public') broadcast(user, activity, recipients) + for read in item.reads: + read.book = item.book + read.user = user + read.save() + if new_books: message = 'imported {} books'.format(len(new_books)) status = create_status(user, message, mention_books=new_books) diff --git a/fedireads/templates/snippets/shelf.html b/fedireads/templates/snippets/shelf.html index e6044cb62..9293fc59e 100644 --- a/fedireads/templates/snippets/shelf.html +++ b/fedireads/templates/snippets/shelf.html @@ -18,6 +18,12 @@ Shelved + + Started + + + Finished + External links @@ -44,6 +50,13 @@ {{ book.created_date | naturalday }} + {% latest_read_through book user as read_through %} + + {{ read_through.start_date | naturalday |default_if_none:""}} + + + {{ read_through.finish_date | naturalday |default_if_none:""}} + OpenLibrary diff --git a/fedireads/templatetags/fr_display.py b/fedireads/templatetags/fr_display.py index 8a81776a2..0b9e9867d 100644 --- a/fedireads/templatetags/fr_display.py +++ b/fedireads/templatetags/fr_display.py @@ -168,3 +168,8 @@ def current_shelf(context, book): return None return shelf.name +@register.simple_tag(takes_context=False) +def latest_read_through(book, user): + return models.ReadThrough.objects.filter( + user=user, + book=book).order_by('-created_date').first()