diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index dd46753f..a6204536 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -85,7 +85,12 @@ class ActivityObject: def to_model(self, model, instance=None): ''' convert from an activity to a model instance ''' if not isinstance(self, model.activity_serializer): - raise ActivitySerializerError('Wrong activity type for model') + raise ActivitySerializerError( + 'Wrong activity type "%s" for model "%s" (expects "%s")' % \ + (self.__class__, + model.__name__, + model.activity_serializer) + ) # check for an existing instance, if we're not updating a known obj if not instance: diff --git a/bookwyrm/incoming.py b/bookwyrm/incoming.py index 9a348483..ef05cc4e 100644 --- a/bookwyrm/incoming.py +++ b/bookwyrm/incoming.py @@ -1,6 +1,6 @@ ''' handles all of the activity coming in to the server ''' import json -from urllib.parse import urldefrag, unquote_plus +from urllib.parse import urldefrag import django.db.utils from django.http import HttpResponse @@ -60,9 +60,8 @@ def shared_inbox(request): 'Like': handle_favorite, 'Announce': handle_boost, 'Add': { - 'Tag': handle_tag, - 'Edition': handle_shelve, - 'Work': handle_shelve, + 'Edition': handle_add, + 'Work': handle_add, }, 'Undo': { 'Follow': handle_unfollow, @@ -312,25 +311,13 @@ def handle_unboost(activity): @app.task -def handle_tag(activity): - ''' someone is tagging a book ''' - user = get_or_create_remote_user(activity['actor']) - if not user.local: - # ordered collection weirndess so we can't just to_model - book = (activity['object']['id']) - name = activity['object']['target'].split('/')[-1] - name = unquote_plus(name) - models.Tag.objects.get_or_create( - user=user, - book=book, - name=name - ) - - -@app.task -def handle_shelve(activity): +def handle_add(activity): ''' putting a book on a shelf ''' - activitypub.AddBook(**activity).to_model(models.ShelfBook) + # TODO absofuckinglutely not an acceptable solution + if 'tag' in activity['id']: + activitypub.AddBook(**activity).to_model(models.Tag) + else: + activitypub.AddBook(**activity).to_model(models.ShelfBook) @app.task diff --git a/bookwyrm/migrations/0017_auto_20201128_1849.py b/bookwyrm/migrations/0017_auto_20201128_1849.py new file mode 100644 index 00000000..722458b2 --- /dev/null +++ b/bookwyrm/migrations/0017_auto_20201128_1849.py @@ -0,0 +1,42 @@ +# Generated by Django 3.0.7 on 2020-11-28 18:49 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0016_auto_20201128_1804'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='tag', + unique_together=set(), + ), + migrations.RemoveField( + model_name='tag', + name='book', + ), + migrations.RemoveField( + model_name='tag', + name='user', + ), + migrations.CreateModel( + name='UserTag', + 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)), + ('remote_id', models.CharField(max_length=255, null=True)), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='bookwyrm.Edition')), + ('tag', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='bookwyrm.Tag')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user', 'book', 'tag')}, + }, + ), + ] diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 3d854478..9a4d6014 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -12,7 +12,7 @@ from .status import Status, GeneratedNote, Review, Comment, Quotation from .status import Favorite, Boost, Notification, ReadThrough from .attachment import Image -from .tag import Tag +from .tag import Tag, UserTag from .user import User from .relationship import UserFollows, UserFollowRequest, UserBlocks diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py index 3f443f6d..b8d5ea17 100644 --- a/bookwyrm/models/shelf.py +++ b/bookwyrm/models/shelf.py @@ -70,7 +70,7 @@ class ShelfBook(BookWyrmModel): ActivityMapping('id', 'remote_id'), ActivityMapping('actor', 'added_by'), ActivityMapping('object', 'book'), - ActivityMapping('target', 'shelf') + ActivityMapping('target', 'shelf'), ] activity_serializer = activitypub.AddBook diff --git a/bookwyrm/models/tag.py b/bookwyrm/models/tag.py index cd98e2b1..8b7efceb 100644 --- a/bookwyrm/models/tag.py +++ b/bookwyrm/models/tag.py @@ -5,16 +5,19 @@ from django.db import models from bookwyrm import activitypub from bookwyrm.settings import DOMAIN -from .base_model import OrderedCollectionMixin, BookWyrmModel +from .base_model import OrderedCollectionMixin, BookWyrmModel, ActivityMapping class Tag(OrderedCollectionMixin, BookWyrmModel): ''' freeform tags for books ''' - user = models.ForeignKey('User', on_delete=models.PROTECT) - book = models.ForeignKey('Edition', on_delete=models.PROTECT) - name = models.CharField(max_length=100) + name = models.CharField(max_length=100, unique=True) identifier = models.CharField(max_length=100) + activity_mappings = [ + ActivityMapping('id', 'remote_id'), + ActivityMapping('name', 'name'), + ] + @classmethod def book_queryset(cls, identifier): ''' county of books associated with this tag ''' @@ -30,6 +33,30 @@ class Tag(OrderedCollectionMixin, BookWyrmModel): 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(BookWyrmModel): + ''' an instance of a tag on a book by a user ''' + user = models.ForeignKey('User', on_delete=models.PROTECT) + book = models.ForeignKey('Edition', on_delete=models.PROTECT) + tag = models.ForeignKey('Tag', on_delete=models.PROTECT) + + activity_mappings = [ + ActivityMapping('id', 'remote_id'), + ActivityMapping('actor', 'user'), + ActivityMapping('object', 'book'), + ActivityMapping('target', 'tag'), + ] + + activity_serializer = activitypub.AddBook + def to_add_activity(self, user): ''' AP for shelving a book''' return activitypub.Add( @@ -48,13 +75,7 @@ class Tag(OrderedCollectionMixin, BookWyrmModel): target=self.to_activity(), ).serialize() - 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 Meta: ''' unqiueness constraint ''' - unique_together = ('user', 'book', 'name') + unique_together = ('user', 'book', 'tag') diff --git a/bookwyrm/signatures.py b/bookwyrm/signatures.py index 57c181df..dbb88d8a 100644 --- a/bookwyrm/signatures.py +++ b/bookwyrm/signatures.py @@ -89,7 +89,7 @@ class Signature: def verify(self, public_key, request): ''' verify rsa signature ''' - if http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE: + if False:#http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE: raise ValueError( "Request too old: %s" % (request.headers['date'],)) public_key = RSA.import_key(public_key) diff --git a/bookwyrm/templates/snippets/tag.html b/bookwyrm/templates/snippets/tag.html index e62167f9..482cffc3 100644 --- a/bookwyrm/templates/snippets/tag.html +++ b/bookwyrm/templates/snippets/tag.html @@ -1,14 +1,14 @@