mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-03-09 21:24:12 +00:00
First pass at recursively resolving foreign keys
This commit is contained in:
parent
5638597112
commit
ebb82287c2
3 changed files with 36 additions and 28 deletions
|
@ -5,7 +5,6 @@ import sys
|
||||||
from .base_activity import ActivityEncoder, PublicKey, Signature
|
from .base_activity import ActivityEncoder, PublicKey, Signature
|
||||||
from .base_activity import Link, Mention
|
from .base_activity import Link, Mention
|
||||||
from .base_activity import ActivitySerializerError
|
from .base_activity import ActivitySerializerError
|
||||||
from .base_activity import tag_formatter
|
|
||||||
from .image import Image
|
from .image import Image
|
||||||
from .note import Note, GeneratedNote, Article, Comment, Review, Quotation
|
from .note import Note, GeneratedNote, Article, Comment, Review, Quotation
|
||||||
from .note import Tombstone
|
from .note import Tombstone
|
||||||
|
|
|
@ -25,12 +25,13 @@ class ActivityEncoder(JSONEncoder):
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Link():
|
class Link:
|
||||||
''' for tagging a book in a status '''
|
''' for tagging a book in a status '''
|
||||||
href: str
|
href: str
|
||||||
name: str
|
name: str
|
||||||
type: str = 'Link'
|
type: str = 'Link'
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Mention(Link):
|
class Mention(Link):
|
||||||
''' a subtype of Link for mentioning an actor '''
|
''' a subtype of Link for mentioning an actor '''
|
||||||
|
@ -125,7 +126,7 @@ class ActivityObject:
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
if instance:
|
if instance:
|
||||||
# updating an existing model isntance
|
# updating an existing model instance
|
||||||
for k, v in mapped_fields.items():
|
for k, v in mapped_fields.items():
|
||||||
setattr(instance, k, v)
|
setattr(instance, k, v)
|
||||||
instance.save()
|
instance.save()
|
||||||
|
@ -133,6 +134,9 @@ class ActivityObject:
|
||||||
# creating a new model instance
|
# creating a new model instance
|
||||||
instance = model.objects.create(**mapped_fields)
|
instance = model.objects.create(**mapped_fields)
|
||||||
|
|
||||||
|
# --- these are all fields that can't be saved until after the
|
||||||
|
# instance has an id (after it's been saved). ---------------#
|
||||||
|
|
||||||
# add images
|
# add images
|
||||||
for (model_key, value) in image_fields.items():
|
for (model_key, value) in image_fields.items():
|
||||||
formatted_value = image_formatter(value)
|
formatted_value = image_formatter(value)
|
||||||
|
@ -140,9 +144,20 @@ class ActivityObject:
|
||||||
continue
|
continue
|
||||||
getattr(instance, model_key).save(*formatted_value, save=True)
|
getattr(instance, model_key).save(*formatted_value, save=True)
|
||||||
|
|
||||||
|
# add many to many fields
|
||||||
for (model_key, values) in many_to_many_fields.items():
|
for (model_key, values) in many_to_many_fields.items():
|
||||||
# mention books, mention users
|
# mention books, mention users
|
||||||
getattr(instance, model_key).set(values)
|
if values == MISSING:
|
||||||
|
continue
|
||||||
|
model_field = getattr(instance, model_key)
|
||||||
|
model = model_field.model
|
||||||
|
items = []
|
||||||
|
for link in values:
|
||||||
|
items.append(
|
||||||
|
resolve_foreign_key(model, link.get('href'))
|
||||||
|
)
|
||||||
|
getattr(instance, model_key).set(items)
|
||||||
|
|
||||||
|
|
||||||
# add one to many fields
|
# add one to many fields
|
||||||
for (model_key, values) in one_to_many_fields.items():
|
for (model_key, values) in one_to_many_fields.items():
|
||||||
|
@ -177,36 +192,30 @@ def resolve_foreign_key(model, remote_id):
|
||||||
if hasattr(model.objects, 'select_subclasses'):
|
if hasattr(model.objects, 'select_subclasses'):
|
||||||
result = result.select_subclasses()
|
result = result.select_subclasses()
|
||||||
|
|
||||||
|
# first, check for an existing copy in the database
|
||||||
result = result.filter(
|
result = result.filter(
|
||||||
remote_id=remote_id
|
remote_id=remote_id
|
||||||
).first()
|
).first()
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
|
||||||
if not result:
|
# failing that, load the data and create the object
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
remote_id,
|
||||||
|
headers={'Accept': 'application/json; charset=utf-8'},
|
||||||
|
)
|
||||||
|
except ConnectionError:
|
||||||
|
raise ActivitySerializerError(
|
||||||
|
'Could not connect to host for remote_id in %s model: %s' % \
|
||||||
|
(model.__name__, remote_id))
|
||||||
|
if not response.ok:
|
||||||
raise ActivitySerializerError(
|
raise ActivitySerializerError(
|
||||||
'Could not resolve remote_id in %s model: %s' % \
|
'Could not resolve remote_id in %s model: %s' % \
|
||||||
(model.__name__, remote_id))
|
(model.__name__, remote_id))
|
||||||
return result
|
|
||||||
|
|
||||||
|
item = model.activity_serializer(**response.json())
|
||||||
def tag_formatter(tags, tag_type):
|
return item.to_model(model)
|
||||||
''' helper function to extract foreign keys from tag activity json '''
|
|
||||||
if not isinstance(tags, list):
|
|
||||||
return []
|
|
||||||
items = []
|
|
||||||
types = {
|
|
||||||
'Book': models.Book,
|
|
||||||
'Mention': models.User,
|
|
||||||
}
|
|
||||||
for tag in [t for t in tags if t.get('type') == tag_type]:
|
|
||||||
if not tag_type in types:
|
|
||||||
continue
|
|
||||||
remote_id = tag.get('href')
|
|
||||||
try:
|
|
||||||
item = resolve_foreign_key(types[tag_type], remote_id)
|
|
||||||
except ActivitySerializerError:
|
|
||||||
continue
|
|
||||||
items.append(item)
|
|
||||||
return items
|
|
||||||
|
|
||||||
|
|
||||||
def image_formatter(image_slug):
|
def image_formatter(image_slug):
|
||||||
|
|
|
@ -80,12 +80,12 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
ActivityMapping(
|
ActivityMapping(
|
||||||
'tag', 'mention_books',
|
'tag', 'mention_books',
|
||||||
lambda x: tag_formatter(x, 'title', 'Book'),
|
lambda x: tag_formatter(x, 'title', 'Book'),
|
||||||
lambda x: activitypub.tag_formatter(x, 'Book')
|
lambda x: [i for i in x if x.get('type') == 'Book']
|
||||||
),
|
),
|
||||||
ActivityMapping(
|
ActivityMapping(
|
||||||
'tag', 'mention_users',
|
'tag', 'mention_users',
|
||||||
lambda x: tag_formatter(x, 'username', 'Mention'),
|
lambda x: tag_formatter(x, 'username', 'Mention'),
|
||||||
lambda x: activitypub.tag_formatter(x, 'Mention')
|
lambda x: [i for i in x if x.get('type') == 'Mention']
|
||||||
),
|
),
|
||||||
ActivityMapping(
|
ActivityMapping(
|
||||||
'attachment', 'attachments',
|
'attachment', 'attachments',
|
||||||
|
|
Loading…
Reference in a new issue