diff --git a/bookwyrm/migrations/0045_auto_20210210_2114.py b/bookwyrm/migrations/0045_auto_20210210_2114.py new file mode 100644 index 00000000..87b9a318 --- /dev/null +++ b/bookwyrm/migrations/0045_auto_20210210_2114.py @@ -0,0 +1,58 @@ +# Generated by Django 3.0.7 on 2021-02-10 21:14 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0044_auto_20210207_1924'), + ] + + operations = [ + migrations.RemoveConstraint( + model_name='notification', + name='notification_type_valid', + ), + migrations.AddField( + model_name='notification', + name='related_list_item', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.ListItem'), + ), + migrations.AlterField( + model_name='notification', + name='notification_type', + field=models.CharField(choices=[('FAVORITE', 'Favorite'), ('REPLY', 'Reply'), ('MENTION', 'Mention'), ('TAG', 'Tag'), ('FOLLOW', 'Follow'), ('FOLLOW_REQUEST', 'Follow Request'), ('BOOST', 'Boost'), ('IMPORT', 'Import'), ('ADD', 'Add')], max_length=255), + ), + migrations.AlterField( + model_name='notification', + name='related_book', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.Edition'), + ), + migrations.AlterField( + model_name='notification', + name='related_import', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.ImportJob'), + ), + migrations.AlterField( + model_name='notification', + name='related_status', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.Status'), + ), + migrations.AlterField( + model_name='notification', + name='related_user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='related_user', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='notification', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddConstraint( + model_name='notification', + constraint=models.CheckConstraint(check=models.Q(notification_type__in=['FAVORITE', 'REPLY', 'MENTION', 'TAG', 'FOLLOW', 'FOLLOW_REQUEST', 'BOOST', 'IMPORT', 'ADD']), name='notification_type_valid'), + ), + ] diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py index 5004a9b0..db8c1af6 100644 --- a/bookwyrm/models/list.py +++ b/bookwyrm/models/list.py @@ -1,4 +1,5 @@ ''' make a list of books!! ''' +from django.apps import apps from django.db import models from bookwyrm import activitypub @@ -71,6 +72,22 @@ class ListItem(CollectionItemMixin, BookWyrmModel): object_field = 'book' collection_field = 'book_list' + def save(self, *args, **kwargs): + ''' create a notification too ''' + created = not bool(self.id) + super().save(*args, **kwargs) + list_owner = self.book_list.user + # create a notification if somoene ELSE added to a local user's list + if created and list_owner.local and list_owner != self.user: + model = apps.get_model('bookwyrm.Notification', require_ready=True) + model.objects.create( + user=list_owner, + related_user=self.user, + related_list_item=self, + notification_type='ADD', + ) + + class Meta: ''' an opinionated constraint! you can't put a book on a list twice ''' unique_together = ('book', 'book_list') diff --git a/bookwyrm/models/notification.py b/bookwyrm/models/notification.py index 4ce5dcea..b4c91f61 100644 --- a/bookwyrm/models/notification.py +++ b/bookwyrm/models/notification.py @@ -5,20 +5,22 @@ from .base_model import BookWyrmModel NotificationType = models.TextChoices( 'NotificationType', - 'FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT') + 'FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT ADD') class Notification(BookWyrmModel): ''' you've been tagged, liked, followed, etc ''' - user = models.ForeignKey('User', on_delete=models.PROTECT) + user = models.ForeignKey('User', on_delete=models.CASCADE) related_book = models.ForeignKey( - 'Edition', on_delete=models.PROTECT, null=True) + 'Edition', on_delete=models.CASCADE, null=True) related_user = models.ForeignKey( 'User', - on_delete=models.PROTECT, null=True, related_name='related_user') + on_delete=models.CASCADE, null=True, related_name='related_user') related_status = models.ForeignKey( - 'Status', on_delete=models.PROTECT, null=True) + 'Status', on_delete=models.CASCADE, null=True) related_import = models.ForeignKey( - 'ImportJob', on_delete=models.PROTECT, null=True) + 'ImportJob', on_delete=models.CASCADE, null=True) + related_list_item = models.ForeignKey( + 'ListItem', on_delete=models.CASCADE, null=True) read = models.BooleanField(default=False) notification_type = models.CharField( max_length=255, choices=NotificationType.choices) diff --git a/bookwyrm/templates/lists/list.html b/bookwyrm/templates/lists/list.html index 7899d593..4bd71284 100644 --- a/bookwyrm/templates/lists/list.html +++ b/bookwyrm/templates/lists/list.html @@ -26,7 +26,7 @@
{% include 'snippets/book_titleby.html' with book=item.book %} {% include 'snippets/stars.html' with rating=item.book|rating:request.user %} - {% include 'snippets/shelve_button.html' with book=item.book %} + {% include 'snippets/shelve_button/shelve_button.html' with book=item.book %}
@@ -36,33 +38,34 @@

{# DESCRIPTION #} {% if notification.related_user %} - {% include 'snippets/avatar.html' with user=notification.related_user %} - {% include 'snippets/username.html' with user=notification.related_user %} - {% if notification.notification_type == 'FAVORITE' %} - favorited your - {{ related_status | status_preview_name|safe }} + {% include 'snippets/avatar.html' with user=notification.related_user %} + {% include 'snippets/username.html' with user=notification.related_user %} + {% if notification.notification_type == 'FAVORITE' %} + favorited your + {{ related_status | status_preview_name|safe }} - {% elif notification.notification_type == 'MENTION' %} - mentioned you in a - {{ related_status | status_preview_name|safe }} + {% elif notification.notification_type == 'MENTION' %} + mentioned you in a + {{ related_status | status_preview_name|safe }} - {% elif notification.notification_type == 'REPLY' %} - replied - to your - {{ related_status | status_preview_name|safe }} - {% elif notification.notification_type == 'FOLLOW' %} - followed you - {% include 'snippets/follow_button.html' with user=notification.related_user %} - {% elif notification.notification_type == 'FOLLOW_REQUEST' %} - sent you a follow request -

- {% include 'snippets/follow_request_buttons.html' with user=notification.related_user %} -
- - {% elif notification.notification_type == 'BOOST' %} - boosted your {{ related_status | status_preview_name|safe }} - {% endif %} - {% else %} + {% elif notification.notification_type == 'REPLY' %} + replied + to your + {{ related_status | status_preview_name|safe }} + {% elif notification.notification_type == 'FOLLOW' %} + followed you + {% include 'snippets/follow_button.html' with user=notification.related_user %} + {% elif notification.notification_type == 'FOLLOW_REQUEST' %} + sent you a follow request +
+ {% include 'snippets/follow_request_buttons.html' with user=notification.related_user %} +
+ {% elif notification.notification_type == 'BOOST' %} + boosted your {{ related_status | status_preview_name|safe }} + {% elif notification.notification_type == 'ADD' %} + {% if notification.related_list_item.approved %}added{% else %}suggested adding{% endif %} {% include 'snippets/book_titleby.html' with book=notification.related_list_item.book %} to your list "{{ notification.related_list_item.book_list.name }}" + {% endif %} + {% elif notification.related_import %} your import completed. {% endif %}

diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index 64efc166..cfdf6d76 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -1,6 +1,7 @@ ''' book list views''' from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator +from django.db import IntegrityError from django.db.models import Count, Q from django.http import HttpResponseNotFound, HttpResponseBadRequest from django.shortcuts import get_object_or_404, redirect @@ -181,24 +182,28 @@ def add_book(request, list_id): book = get_object_or_404(models.Edition, id=request.POST.get('book')) # do you have permission to add to the list? - if request.user == book_list.user or book_list.curation == 'open': - # go ahead and add it - models.ListItem.objects.create( - book=book, - book_list=book_list, - user=request.user, - ) - elif book_list.curation == 'curated': - # make a pending entry - models.ListItem.objects.create( - approved=False, - book=book, - book_list=book_list, - user=request.user, - ) - else: - # you can't add to this list, what were you THINKING - return HttpResponseBadRequest() + try: + if request.user == book_list.user or book_list.curation == 'open': + # go ahead and add it + models.ListItem.objects.create( + book=book, + book_list=book_list, + user=request.user, + ) + elif book_list.curation == 'curated': + # make a pending entry + models.ListItem.objects.create( + approved=False, + book=book, + book_list=book_list, + user=request.user, + ) + else: + # you can't add to this list, what were you THINKING + return HttpResponseBadRequest() + except IntegrityError: + # if the book is already on the list, don't flip out + pass return redirect('list', list_id)