mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-10 10:59:30 +00:00
refactors tag model to fit ordered collection structure
This commit is contained in:
parent
a93b5cf5bc
commit
fd7e476c9b
10 changed files with 110 additions and 52 deletions
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
42
bookwyrm/migrations/0017_auto_20201128_1849.py
Normal file
42
bookwyrm/migrations/0017_auto_20201128_1849.py
Normal file
|
@ -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')},
|
||||
},
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<div class="control">
|
||||
<form name="tag" action="/{% if tag.identifier in user_tags %}untag{% else %}tag{% endif %}/" method="post">
|
||||
<form name="tag" action="/{% if tag.tag.identifier in user_tags %}untag{% else %}tag{% endif %}/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="book" value="{{ book.id }}">
|
||||
<input type="hidden" name="name" value="{{ tag.name }}">
|
||||
<input type="hidden" name="name" value="{{ tag.tag.name }}">
|
||||
|
||||
<div class="tags has-addons">
|
||||
<a class="tag" href="/tag/{{ tag.identifier|urlencode }}">
|
||||
{{ tag.name }}
|
||||
<a class="tag" href="/tag/{{ tag.tag.identifier|urlencode }}">
|
||||
{{ tag.tag.name }}
|
||||
</a>
|
||||
{% if tag.identifier in user_tags %}
|
||||
{% if tag.tag.identifier in user_tags %}
|
||||
<button class="tag is-delete" type="submit">
|
||||
<span class="is-sr-only">remove tag</span>
|
||||
</button>
|
||||
|
|
|
@ -531,12 +531,15 @@ def tag(request):
|
|||
book = get_object_or_404(models.Edition, id=book_id)
|
||||
tag_obj, created = models.Tag.objects.get_or_create(
|
||||
name=name,
|
||||
)
|
||||
user_tag = models.UserTag.objects.get_or_create(
|
||||
user=request.user,
|
||||
book=book,
|
||||
user=request.user
|
||||
tag=tag_obj,
|
||||
)
|
||||
|
||||
if created:
|
||||
outgoing.handle_tag(request.user, tag_obj)
|
||||
outgoing.handle_tag(request.user, user_tag)
|
||||
return redirect('/book/%s' % book_id)
|
||||
|
||||
|
||||
|
|
|
@ -560,9 +560,9 @@ def book_page(request, book_id):
|
|||
user_tags = []
|
||||
readthroughs = []
|
||||
if request.user.is_authenticated:
|
||||
user_tags = models.Tag.objects.filter(
|
||||
user_tags = models.UserTag.objects.filter(
|
||||
book=book, user=request.user
|
||||
).values_list('identifier', flat=True)
|
||||
).values_list('tag__identifier', flat=True)
|
||||
|
||||
readthroughs = models.ReadThrough.objects.filter(
|
||||
user=request.user,
|
||||
|
@ -570,11 +570,9 @@ def book_page(request, book_id):
|
|||
).order_by('start_date')
|
||||
|
||||
rating = reviews.aggregate(Avg('rating'))
|
||||
tags = models.Tag.objects.filter(
|
||||
book=book
|
||||
).values(
|
||||
'book', 'name', 'identifier'
|
||||
).distinct().all()
|
||||
tags = models.UserTag.objects.filter(
|
||||
book=book,
|
||||
)
|
||||
|
||||
data = {
|
||||
'title': book.title,
|
||||
|
@ -664,7 +662,9 @@ def tag_page(request, tag_id):
|
|||
return JsonResponse(
|
||||
tag_obj.to_activity(**request.GET), encoder=ActivityEncoder)
|
||||
|
||||
books = models.Edition.objects.filter(tag__identifier=tag_id).distinct()
|
||||
books = models.Edition.objects.filter(
|
||||
usertag__tag__identifier=tag_id
|
||||
).distinct()
|
||||
data = {
|
||||
'title': tag_obj.name,
|
||||
'books': books,
|
||||
|
|
Loading…
Reference in a new issue