Merge branch 'main' into tour
Also fixes conflict
This commit is contained in:
commit
ab5e4128e6
129 changed files with 6239 additions and 2325 deletions
|
@ -3,7 +3,7 @@ from functools import reduce
|
|||
import operator
|
||||
|
||||
from django.apps import apps
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
@ -58,25 +58,20 @@ def automod_task():
|
|||
return
|
||||
reporter = AutoMod.objects.first().created_by
|
||||
reports = automod_users(reporter) + automod_statuses(reporter)
|
||||
if reports:
|
||||
admins = User.objects.filter(
|
||||
models.Q(user_permissions__name__in=["moderate_user", "moderate_post"])
|
||||
| models.Q(is_superuser=True)
|
||||
).all()
|
||||
notification_model = apps.get_model(
|
||||
"bookwyrm", "Notification", require_ready=True
|
||||
)
|
||||
if not reports:
|
||||
return
|
||||
|
||||
admins = User.objects.filter(
|
||||
models.Q(user_permissions__name__in=["moderate_user", "moderate_post"])
|
||||
| models.Q(is_superuser=True)
|
||||
).all()
|
||||
notification_model = apps.get_model("bookwyrm", "Notification", require_ready=True)
|
||||
with transaction.atomic():
|
||||
for admin in admins:
|
||||
notification_model.objects.bulk_create(
|
||||
[
|
||||
notification_model(
|
||||
user=admin,
|
||||
related_report=r,
|
||||
notification_type="REPORT",
|
||||
)
|
||||
for r in reports
|
||||
]
|
||||
notification, _ = notification_model.objects.get_or_create(
|
||||
user=admin, notification_type=notification_model.REPORT, read=False
|
||||
)
|
||||
notification.related_repors.add(reports)
|
||||
|
||||
|
||||
def automod_users(reporter):
|
||||
|
|
|
@ -132,7 +132,7 @@ class BookWyrmModel(models.Model):
|
|||
return
|
||||
|
||||
# but generally moderators can delete other people's stuff
|
||||
if self.user == viewer or viewer.has_perm("moderate_post"):
|
||||
if self.user == viewer or viewer.has_perm("bookwyrm.moderate_post"):
|
||||
return
|
||||
|
||||
raise PermissionDenied()
|
||||
|
|
|
@ -16,7 +16,7 @@ from django.utils.encoding import filepath_to_uri
|
|||
|
||||
from bookwyrm import activitypub
|
||||
from bookwyrm.connectors import get_image
|
||||
from bookwyrm.sanitize_html import InputHtmlParser
|
||||
from bookwyrm.utils.sanitizer import clean
|
||||
from bookwyrm.settings import MEDIA_FULL_URL
|
||||
|
||||
|
||||
|
@ -497,9 +497,7 @@ class HtmlField(ActivitypubFieldMixin, models.TextField):
|
|||
def field_from_activity(self, value):
|
||||
if not value or value == MISSING:
|
||||
return None
|
||||
sanitizer = InputHtmlParser()
|
||||
sanitizer.feed(value)
|
||||
return sanitizer.get_output()
|
||||
return clean(value)
|
||||
|
||||
|
||||
class ArrayField(ActivitypubFieldMixin, DjangoArrayField):
|
||||
|
|
|
@ -140,16 +140,6 @@ class GroupMemberInvitation(models.Model):
|
|||
# make an invitation
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
# now send the invite
|
||||
model = apps.get_model("bookwyrm.Notification", require_ready=True)
|
||||
notification_type = "INVITE"
|
||||
model.objects.create(
|
||||
user=self.user,
|
||||
related_user=self.group.user,
|
||||
related_group=self.group,
|
||||
notification_type=notification_type,
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def accept(self):
|
||||
"""turn this request into the real deal"""
|
||||
|
@ -157,25 +147,24 @@ class GroupMemberInvitation(models.Model):
|
|||
|
||||
model = apps.get_model("bookwyrm.Notification", require_ready=True)
|
||||
# tell the group owner
|
||||
model.objects.create(
|
||||
user=self.group.user,
|
||||
related_user=self.user,
|
||||
model.notify(
|
||||
self.group.user,
|
||||
self.user,
|
||||
related_group=self.group,
|
||||
notification_type="ACCEPT",
|
||||
notification_type=model.ACCEPT,
|
||||
)
|
||||
|
||||
# let the other members know about it
|
||||
for membership in self.group.memberships.all():
|
||||
member = membership.user
|
||||
if member not in (self.user, self.group.user):
|
||||
model.objects.create(
|
||||
user=member,
|
||||
related_user=self.user,
|
||||
model.notify(
|
||||
member,
|
||||
self.user,
|
||||
related_group=self.group,
|
||||
notification_type="JOIN",
|
||||
notification_type=model.JOIN,
|
||||
)
|
||||
|
||||
def reject(self):
|
||||
"""generate a Reject for this membership request"""
|
||||
|
||||
self.delete()
|
||||
|
|
|
@ -84,7 +84,7 @@ class LinkDomain(BookWyrmModel):
|
|||
)
|
||||
|
||||
def raise_not_editable(self, viewer):
|
||||
if viewer.has_perm("moderate_post"):
|
||||
if viewer.has_perm("bookwyrm.moderate_post"):
|
||||
return
|
||||
raise PermissionDenied()
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
""" make a list of books!! """
|
||||
import uuid
|
||||
|
||||
from django.apps import apps
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
|
@ -151,34 +150,12 @@ class ListItem(CollectionItemMixin, BookWyrmModel):
|
|||
collection_field = "book_list"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""create a notification too"""
|
||||
created = not bool(self.id)
|
||||
"""Update the list's date"""
|
||||
super().save(*args, **kwargs)
|
||||
# tick the updated date on the parent list
|
||||
self.book_list.updated_date = timezone.now()
|
||||
self.book_list.save(broadcast=False, update_fields=["updated_date"])
|
||||
|
||||
list_owner = self.book_list.user
|
||||
model = apps.get_model("bookwyrm.Notification", require_ready=True)
|
||||
# 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.objects.create(
|
||||
user=list_owner,
|
||||
related_user=self.user,
|
||||
related_list_item=self,
|
||||
notification_type="ADD",
|
||||
)
|
||||
|
||||
if self.book_list.group:
|
||||
for membership in self.book_list.group.memberships.all():
|
||||
if membership.user != self.user:
|
||||
model.objects.create(
|
||||
user=membership.user,
|
||||
related_user=self.user,
|
||||
related_list_item=self,
|
||||
notification_type="ADD",
|
||||
)
|
||||
|
||||
def raise_not_deletable(self, viewer):
|
||||
"""the associated user OR the list owner can delete"""
|
||||
if self.book_list.user == viewer:
|
||||
|
|
|
@ -1,77 +1,123 @@
|
|||
""" alert a user to activity """
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.dispatch import receiver
|
||||
from .base_model import BookWyrmModel
|
||||
from . import Boost, Favorite, ImportJob, Report, Status, User
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
NotificationType = models.TextChoices(
|
||||
"NotificationType",
|
||||
"FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT ADD REPORT INVITE ACCEPT JOIN LEAVE REMOVE GROUP_PRIVACY GROUP_NAME GROUP_DESCRIPTION",
|
||||
)
|
||||
from . import Boost, Favorite, GroupMemberInvitation, ImportJob, ListItem, Report
|
||||
from . import Status, User, UserFollowRequest
|
||||
|
||||
|
||||
class Notification(BookWyrmModel):
|
||||
"""you've been tagged, liked, followed, etc"""
|
||||
|
||||
# Status interactions
|
||||
FAVORITE = "FAVORITE"
|
||||
BOOST = "BOOST"
|
||||
REPLY = "REPLY"
|
||||
MENTION = "MENTION"
|
||||
TAG = "TAG"
|
||||
|
||||
# Relationships
|
||||
FOLLOW = "FOLLOW"
|
||||
FOLLOW_REQUEST = "FOLLOW_REQUEST"
|
||||
|
||||
# Imports
|
||||
IMPORT = "IMPORT"
|
||||
|
||||
# List activity
|
||||
ADD = "ADD"
|
||||
|
||||
# Admin
|
||||
REPORT = "REPORT"
|
||||
|
||||
# Groups
|
||||
INVITE = "INVITE"
|
||||
ACCEPT = "ACCEPT"
|
||||
JOIN = "JOIN"
|
||||
LEAVE = "LEAVE"
|
||||
REMOVE = "REMOVE"
|
||||
GROUP_PRIVACY = "GROUP_PRIVACY"
|
||||
GROUP_NAME = "GROUP_NAME"
|
||||
GROUP_DESCRIPTION = "GROUP_DESCRIPTION"
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
NotificationType = models.TextChoices(
|
||||
# there has got be a better way to do this
|
||||
"NotificationType",
|
||||
f"{FAVORITE} {REPLY} {MENTION} {TAG} {FOLLOW} {FOLLOW_REQUEST} {BOOST} {IMPORT} {ADD} {REPORT} {INVITE} {ACCEPT} {JOIN} {LEAVE} {REMOVE} {GROUP_PRIVACY} {GROUP_NAME} {GROUP_DESCRIPTION}",
|
||||
)
|
||||
|
||||
user = models.ForeignKey("User", on_delete=models.CASCADE)
|
||||
related_book = models.ForeignKey("Edition", on_delete=models.CASCADE, null=True)
|
||||
related_user = models.ForeignKey(
|
||||
"User", on_delete=models.CASCADE, null=True, related_name="related_user"
|
||||
read = models.BooleanField(default=False)
|
||||
notification_type = models.CharField(
|
||||
max_length=255, choices=NotificationType.choices
|
||||
)
|
||||
|
||||
related_users = models.ManyToManyField(
|
||||
"User", symmetrical=False, related_name="notifications"
|
||||
)
|
||||
related_group = models.ForeignKey(
|
||||
"Group", on_delete=models.CASCADE, null=True, related_name="notifications"
|
||||
)
|
||||
related_status = models.ForeignKey("Status", on_delete=models.CASCADE, null=True)
|
||||
related_import = models.ForeignKey("ImportJob", on_delete=models.CASCADE, null=True)
|
||||
related_list_item = models.ForeignKey(
|
||||
"ListItem", on_delete=models.CASCADE, null=True
|
||||
)
|
||||
related_report = models.ForeignKey("Report", on_delete=models.CASCADE, null=True)
|
||||
read = models.BooleanField(default=False)
|
||||
notification_type = models.CharField(
|
||||
max_length=255, choices=NotificationType.choices
|
||||
related_list_items = models.ManyToManyField(
|
||||
"ListItem", symmetrical=False, related_name="notifications"
|
||||
)
|
||||
related_reports = models.ManyToManyField("Report", symmetrical=False)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""save, but don't make dupes"""
|
||||
# there's probably a better way to do this
|
||||
if self.__class__.objects.filter(
|
||||
user=self.user,
|
||||
related_book=self.related_book,
|
||||
related_user=self.related_user,
|
||||
related_group=self.related_group,
|
||||
related_status=self.related_status,
|
||||
related_import=self.related_import,
|
||||
related_list_item=self.related_list_item,
|
||||
related_report=self.related_report,
|
||||
notification_type=self.notification_type,
|
||||
).exists():
|
||||
@classmethod
|
||||
@transaction.atomic
|
||||
def notify(cls, user, related_user, **kwargs):
|
||||
"""Create a notification"""
|
||||
if related_user and (not user.local or user == related_user):
|
||||
return
|
||||
super().save(*args, **kwargs)
|
||||
notification, _ = cls.objects.get_or_create(user=user, **kwargs)
|
||||
if related_user:
|
||||
notification.related_users.add(related_user)
|
||||
notification.read = False
|
||||
notification.save()
|
||||
|
||||
class Meta:
|
||||
"""checks if notifcation is in enum list for valid types"""
|
||||
|
||||
constraints = [
|
||||
models.CheckConstraint(
|
||||
check=models.Q(notification_type__in=NotificationType.values),
|
||||
name="notification_type_valid",
|
||||
@classmethod
|
||||
@transaction.atomic
|
||||
def notify_list_item(cls, user, list_item):
|
||||
"""Group the notifications around the list items, not the user"""
|
||||
related_user = list_item.user
|
||||
notification = cls.objects.filter(
|
||||
user=user,
|
||||
related_users=related_user,
|
||||
related_list_items__book_list=list_item.book_list,
|
||||
notification_type=Notification.ADD,
|
||||
).first()
|
||||
if not notification:
|
||||
notification = cls.objects.create(
|
||||
user=user, notification_type=Notification.ADD
|
||||
)
|
||||
]
|
||||
notification.related_users.add(related_user)
|
||||
notification.related_list_items.add(list_item)
|
||||
notification.read = False
|
||||
notification.save()
|
||||
|
||||
@classmethod
|
||||
def unnotify(cls, user, related_user, **kwargs):
|
||||
"""Remove a user from a notification and delete it if that was the only user"""
|
||||
try:
|
||||
notification = cls.objects.filter(user=user, **kwargs).get()
|
||||
except Notification.DoesNotExist:
|
||||
return
|
||||
notification.related_users.remove(related_user)
|
||||
if not notification.related_users.count():
|
||||
notification.delete()
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=Favorite)
|
||||
# pylint: disable=unused-argument
|
||||
def notify_on_fav(sender, instance, *args, **kwargs):
|
||||
"""someone liked your content, you ARE loved"""
|
||||
if not instance.status.user.local or instance.status.user == instance.user:
|
||||
return
|
||||
Notification.objects.create(
|
||||
user=instance.status.user,
|
||||
notification_type="FAVORITE",
|
||||
related_user=instance.user,
|
||||
Notification.notify(
|
||||
instance.status.user,
|
||||
instance.user,
|
||||
related_status=instance.status,
|
||||
notification_type=Notification.FAVORITE,
|
||||
)
|
||||
|
||||
|
||||
|
@ -81,15 +127,16 @@ def notify_on_unfav(sender, instance, *args, **kwargs):
|
|||
"""oops, didn't like that after all"""
|
||||
if not instance.status.user.local:
|
||||
return
|
||||
Notification.objects.filter(
|
||||
user=instance.status.user,
|
||||
related_user=instance.user,
|
||||
Notification.unnotify(
|
||||
instance.status.user,
|
||||
instance.user,
|
||||
related_status=instance.status,
|
||||
notification_type="FAVORITE",
|
||||
).delete()
|
||||
notification_type=Notification.FAVORITE,
|
||||
)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save)
|
||||
@transaction.atomic
|
||||
# pylint: disable=unused-argument
|
||||
def notify_user_on_mention(sender, instance, *args, **kwargs):
|
||||
"""creating and deleting statuses with @ mentions and replies"""
|
||||
|
@ -105,22 +152,23 @@ def notify_user_on_mention(sender, instance, *args, **kwargs):
|
|||
and instance.reply_parent.user != instance.user
|
||||
and instance.reply_parent.user.local
|
||||
):
|
||||
Notification.objects.create(
|
||||
user=instance.reply_parent.user,
|
||||
notification_type="REPLY",
|
||||
related_user=instance.user,
|
||||
Notification.notify(
|
||||
instance.reply_parent.user,
|
||||
instance.user,
|
||||
related_status=instance,
|
||||
notification_type=Notification.REPLY,
|
||||
)
|
||||
|
||||
for mention_user in instance.mention_users.all():
|
||||
# avoid double-notifying about this status
|
||||
if not mention_user.local or (
|
||||
instance.reply_parent and mention_user == instance.reply_parent.user
|
||||
):
|
||||
continue
|
||||
Notification.objects.create(
|
||||
user=mention_user,
|
||||
notification_type="MENTION",
|
||||
related_user=instance.user,
|
||||
Notification.notify(
|
||||
mention_user,
|
||||
instance.user,
|
||||
notification_type=Notification.MENTION,
|
||||
related_status=instance,
|
||||
)
|
||||
|
||||
|
@ -135,11 +183,11 @@ def notify_user_on_boost(sender, instance, *args, **kwargs):
|
|||
):
|
||||
return
|
||||
|
||||
Notification.objects.create(
|
||||
user=instance.boosted_status.user,
|
||||
Notification.notify(
|
||||
instance.boosted_status.user,
|
||||
instance.user,
|
||||
related_status=instance.boosted_status,
|
||||
related_user=instance.user,
|
||||
notification_type="BOOST",
|
||||
notification_type=Notification.BOOST,
|
||||
)
|
||||
|
||||
|
||||
|
@ -147,12 +195,12 @@ def notify_user_on_boost(sender, instance, *args, **kwargs):
|
|||
# pylint: disable=unused-argument
|
||||
def notify_user_on_unboost(sender, instance, *args, **kwargs):
|
||||
"""unboosting a status"""
|
||||
Notification.objects.filter(
|
||||
user=instance.boosted_status.user,
|
||||
Notification.unnotify(
|
||||
instance.boosted_status.user,
|
||||
instance.user,
|
||||
related_status=instance.boosted_status,
|
||||
related_user=instance.user,
|
||||
notification_type="BOOST",
|
||||
).delete()
|
||||
notification_type=Notification.BOOST,
|
||||
)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=ImportJob)
|
||||
|
@ -166,23 +214,92 @@ def notify_user_on_import_complete(
|
|||
return
|
||||
Notification.objects.create(
|
||||
user=instance.user,
|
||||
notification_type="IMPORT",
|
||||
notification_type=Notification.IMPORT,
|
||||
related_import=instance,
|
||||
)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=Report)
|
||||
@transaction.atomic
|
||||
# pylint: disable=unused-argument
|
||||
def notify_admins_on_report(sender, instance, *args, **kwargs):
|
||||
def notify_admins_on_report(sender, instance, created, *args, **kwargs):
|
||||
"""something is up, make sure the admins know"""
|
||||
if not created:
|
||||
# otherwise you'll get a notification when you resolve a report
|
||||
return
|
||||
|
||||
# moderators and superusers should be notified
|
||||
admins = User.objects.filter(
|
||||
models.Q(user_permissions__name__in=["moderate_user", "moderate_post"])
|
||||
| models.Q(is_superuser=True)
|
||||
).all()
|
||||
for admin in admins:
|
||||
Notification.objects.create(
|
||||
notification, _ = Notification.objects.get_or_create(
|
||||
user=admin,
|
||||
related_report=instance,
|
||||
notification_type="REPORT",
|
||||
notification_type=Notification.REPORT,
|
||||
read=False,
|
||||
)
|
||||
notification.related_reports.add(instance)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=GroupMemberInvitation)
|
||||
# pylint: disable=unused-argument
|
||||
def notify_user_on_group_invite(sender, instance, *args, **kwargs):
|
||||
"""Cool kids club here we come"""
|
||||
Notification.notify(
|
||||
instance.user,
|
||||
instance.group.user,
|
||||
related_group=instance.group,
|
||||
notification_type=Notification.INVITE,
|
||||
)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=ListItem)
|
||||
@transaction.atomic
|
||||
# pylint: disable=unused-argument
|
||||
def notify_user_on_list_item_add(sender, instance, created, *args, **kwargs):
|
||||
"""Someone added to your list"""
|
||||
if not created:
|
||||
return
|
||||
|
||||
list_owner = instance.book_list.user
|
||||
# create a notification if somoene ELSE added to a local user's list
|
||||
if list_owner.local and list_owner != instance.user:
|
||||
# keep the related_user singular, group the items
|
||||
Notification.notify_list_item(list_owner, instance)
|
||||
|
||||
if instance.book_list.group:
|
||||
for membership in instance.book_list.group.memberships.all():
|
||||
if membership.user != instance.user:
|
||||
Notification.notify_list_item(membership.user, instance)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=UserFollowRequest)
|
||||
@transaction.atomic
|
||||
# pylint: disable=unused-argument
|
||||
def notify_user_on_follow(sender, instance, created, *args, **kwargs):
|
||||
"""Someone added to your list"""
|
||||
if not created or not instance.user_object.local:
|
||||
return
|
||||
|
||||
manually_approves = instance.user_object.manually_approves_followers
|
||||
if manually_approves:
|
||||
# don't group notifications
|
||||
notification = Notification.objects.filter(
|
||||
user=instance.user_object,
|
||||
related_users=instance.user_subject,
|
||||
notification_type=Notification.FOLLOW_REQUEST,
|
||||
).first()
|
||||
if not notification:
|
||||
notification = Notification.objects.create(
|
||||
user=instance.user_object, notification_type=Notification.FOLLOW_REQUEST
|
||||
)
|
||||
notification.related_users.set([instance.user_subject])
|
||||
notification.read = False
|
||||
notification.save()
|
||||
else:
|
||||
Notification.notify(
|
||||
instance.user_object,
|
||||
instance.user_subject,
|
||||
notification_type=Notification.FOLLOW,
|
||||
)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
""" defines relationships between users """
|
||||
from django.apps import apps
|
||||
from django.core.cache import cache
|
||||
from django.db import models, transaction, IntegrityError
|
||||
from django.db.models import Q
|
||||
|
@ -148,14 +147,6 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
|
|||
if not manually_approves:
|
||||
self.accept()
|
||||
|
||||
model = apps.get_model("bookwyrm.Notification", require_ready=True)
|
||||
notification_type = "FOLLOW_REQUEST" if manually_approves else "FOLLOW"
|
||||
model.objects.create(
|
||||
user=self.user_object,
|
||||
related_user=self.user_subject,
|
||||
notification_type=notification_type,
|
||||
)
|
||||
|
||||
def get_accept_reject_id(self, status):
|
||||
"""get id for sending an accept or reject of a local user"""
|
||||
|
||||
|
@ -218,7 +209,7 @@ def clear_cache(user_subject, user_object):
|
|||
"""clear relationship cache"""
|
||||
cache.delete_many(
|
||||
[
|
||||
f"relationship-{user_subject.id}-{user_object.id}",
|
||||
f"relationship-{user_object.id}-{user_subject.id}",
|
||||
f"cached-relationship-{user_subject.id}-{user_object.id}",
|
||||
f"cached-relationship-{user_object.id}-{user_subject.id}",
|
||||
]
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ class Report(BookWyrmModel):
|
|||
"User", related_name="reporter", on_delete=models.PROTECT
|
||||
)
|
||||
note = models.TextField(null=True, blank=True)
|
||||
user = models.ForeignKey("User", on_delete=models.PROTECT)
|
||||
user = models.ForeignKey("User", on_delete=models.PROTECT, null=True, blank=True)
|
||||
status = models.ForeignKey(
|
||||
"Status",
|
||||
null=True,
|
||||
|
|
|
@ -103,12 +103,25 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
|
|||
if not self.user:
|
||||
self.user = self.shelf.user
|
||||
if self.id and self.user.local:
|
||||
cache.delete(f"book-on-shelf-{self.book.id}-{self.shelf.id}")
|
||||
# remove all caches related to all editions of this book
|
||||
cache.delete_many(
|
||||
[
|
||||
f"book-on-shelf-{book.id}-{self.shelf.id}"
|
||||
for book in self.book.parent_work.editions.all()
|
||||
]
|
||||
)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
if self.id and self.user.local:
|
||||
cache.delete(f"book-on-shelf-{self.book.id}-{self.shelf.id}")
|
||||
cache.delete_many(
|
||||
[
|
||||
f"book-on-shelf-{book}-{self.shelf.id}"
|
||||
for book in self.book.parent_work.editions.values_list(
|
||||
"id", flat=True
|
||||
)
|
||||
]
|
||||
)
|
||||
super().delete(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue