""" puttin' books on shelves """ import re from django.db import models from bookwyrm import activitypub from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin from .base_model import BookWyrmModel from . import fields class Shelf(OrderedCollectionMixin, BookWyrmModel): """ a list of books owned by a user """ name = fields.CharField(max_length=100) identifier = models.CharField(max_length=100) user = fields.ForeignKey( "User", on_delete=models.PROTECT, activitypub_field="owner" ) editable = models.BooleanField(default=True) privacy = fields.PrivacyField() books = models.ManyToManyField( "Edition", symmetrical=False, through="ShelfBook", through_fields=("shelf", "book"), ) activity_serializer = activitypub.Shelf def save(self, *args, **kwargs): """ set the identifier """ super().save(*args, **kwargs) if not self.identifier: slug = re.sub(r"[^\w]", "", self.name).lower() self.identifier = "%s-%d" % (slug, self.id) super().save(*args, **kwargs) @property def collection_queryset(self): """ list of books for this shelf, overrides OrderedCollectionMixin """ return self.books.all().order_by("shelfbook") def get_remote_id(self): """ shelf identifier instead of id """ base_path = self.user.remote_id return "%s/shelf/%s" % (base_path, self.identifier) class Meta: """ user/shelf unqiueness """ unique_together = ("user", "identifier") class ShelfBook(CollectionItemMixin, BookWyrmModel): """ many to many join table for books and shelves """ book = fields.ForeignKey( "Edition", on_delete=models.PROTECT, activitypub_field="object" ) shelf = fields.ForeignKey( "Shelf", on_delete=models.PROTECT, activitypub_field="target" ) user = fields.ForeignKey( "User", on_delete=models.PROTECT, activitypub_field="actor" ) activity_serializer = activitypub.Add object_field = "book" collection_field = "shelf" class Meta: """an opinionated constraint! you can't put a book on shelf twice""" unique_together = ("book", "shelf") ordering = ("-created_date",)