''' models for storing different kinds of Activities ''' import urllib.parse from django.apps import apps from django.db import models from bookwyrm import activitypub from bookwyrm.settings import DOMAIN from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin from .base_model import BookWyrmModel from . import fields class Tag(OrderedCollectionMixin, BookWyrmModel): ''' freeform tags for books ''' name = fields.CharField(max_length=100, unique=True) identifier = models.CharField(max_length=100) @property def books(self): ''' count of books associated with this tag ''' edition_model = apps.get_model('bookwyrm.Edition', require_ready=True) return edition_model.objects.filter( usertag__tag__identifier=self.identifier ).order_by('-created_date').distinct() collection_queryset = books def get_remote_id(self): ''' tag should use identifier not id in remote_id ''' base_path = 'https://%s' % DOMAIN return '%s/tag/%s' % (base_path, self.identifier) def save(self, *args, **kwargs): ''' create a url-safe lookup key for the tag ''' if not self.id: # add identifiers to new tags self.identifier = urllib.parse.quote_plus(self.name) super().save(*args, **kwargs) class UserTag(CollectionItemMixin, BookWyrmModel): ''' an instance of a tag on a book by a user ''' user = fields.ForeignKey( 'User', on_delete=models.PROTECT, activitypub_field='actor') book = fields.ForeignKey( 'Edition', on_delete=models.PROTECT, activitypub_field='object') tag = fields.ForeignKey( 'Tag', on_delete=models.PROTECT, activitypub_field='target') activity_serializer = activitypub.Add object_field = 'book' collection_field = 'tag' class Meta: ''' unqiueness constraint ''' unique_together = ('user', 'book', 'tag')