Convert activitypub Image into model ImageField
This commit is contained in:
parent
5526b4773e
commit
e2debd855c
|
@ -4,7 +4,8 @@ import sys
|
||||||
|
|
||||||
from .base_activity import ActivityEncoder, Image, PublicKey, Signature
|
from .base_activity import ActivityEncoder, Image, PublicKey, Signature
|
||||||
from .base_activity import Link, Mention
|
from .base_activity import Link, Mention
|
||||||
from .base_activity import ActivitySerializerError, tag_formatter
|
from .base_activity import ActivitySerializerError
|
||||||
|
from .base_activity import tag_formatter, image_formatter
|
||||||
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
|
||||||
from .interaction import Boost, Like
|
from .interaction import Boost, Like
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
''' basics for an activitypub serializer '''
|
''' basics for an activitypub serializer '''
|
||||||
from dataclasses import dataclass, fields, MISSING
|
from dataclasses import dataclass, fields, MISSING
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from bookwyrm import books_manager, models
|
from django.core.files.base import ContentFile
|
||||||
|
|
||||||
from django.db.models.fields.related_descriptors \
|
from django.db.models.fields.related_descriptors \
|
||||||
import ForwardManyToOneDescriptor, ManyToManyDescriptor
|
import ForwardManyToOneDescriptor, ManyToManyDescriptor
|
||||||
|
from django.db.models.fields.files import ImageFileDescriptor
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from bookwyrm import books_manager, models
|
||||||
|
|
||||||
|
|
||||||
class ActivitySerializerError(ValueError):
|
class ActivitySerializerError(ValueError):
|
||||||
|
@ -91,6 +95,7 @@ class ActivityObject:
|
||||||
model_fields = [m.name for m in model._meta.get_fields()]
|
model_fields = [m.name for m in model._meta.get_fields()]
|
||||||
mapped_fields = {}
|
mapped_fields = {}
|
||||||
many_to_many_fields = {}
|
many_to_many_fields = {}
|
||||||
|
image_fields = {}
|
||||||
|
|
||||||
for mapping in model.activity_mappings:
|
for mapping in model.activity_mappings:
|
||||||
if mapping.model_key not in model_fields:
|
if mapping.model_key not in model_fields:
|
||||||
|
@ -110,12 +115,13 @@ class ActivityObject:
|
||||||
formatted_value = mapping.model_formatter(value)
|
formatted_value = mapping.model_formatter(value)
|
||||||
if isinstance(model_field, ManyToManyDescriptor):
|
if isinstance(model_field, ManyToManyDescriptor):
|
||||||
many_to_many_fields[mapping.model_key] = formatted_value
|
many_to_many_fields[mapping.model_key] = formatted_value
|
||||||
|
elif isinstance(model_field, ImageFileDescriptor):
|
||||||
|
image_fields[mapping.model_key] = formatted_value
|
||||||
else:
|
else:
|
||||||
mapped_fields[mapping.model_key] = formatted_value
|
mapped_fields[mapping.model_key] = formatted_value
|
||||||
|
|
||||||
|
|
||||||
# updating an existing model isntance
|
|
||||||
if instance:
|
if instance:
|
||||||
|
# updating an existing model isntance
|
||||||
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()
|
||||||
|
@ -123,9 +129,14 @@ class ActivityObject:
|
||||||
# creating a new model instance
|
# creating a new model instance
|
||||||
instance = model.objects.create(**mapped_fields)
|
instance = model.objects.create(**mapped_fields)
|
||||||
|
|
||||||
|
# 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():
|
||||||
getattr(instance, model_key).set(values)
|
getattr(instance, model_key).set(values)
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
||||||
|
# add images
|
||||||
|
for (model_key, value) in image_fields.items():
|
||||||
|
getattr(instance, model_key).save(*value, save=True)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,3 +185,21 @@ def tag_formatter(tags):
|
||||||
continue
|
continue
|
||||||
items.append(item)
|
items.append(item)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def image_formatter(image_json):
|
||||||
|
''' helper function to load images and format them for a model '''
|
||||||
|
url = image_json.get('url')
|
||||||
|
if not url:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url)
|
||||||
|
except ConnectionError:
|
||||||
|
return None
|
||||||
|
if not response.ok:
|
||||||
|
return None
|
||||||
|
|
||||||
|
image_name = str(uuid4()) + '.' + url.split('.')[-1]
|
||||||
|
image_content = ContentFile(response.content)
|
||||||
|
return [image_name, image_content]
|
||||||
|
|
|
@ -114,7 +114,8 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||||
),
|
),
|
||||||
ActivityMapping(
|
ActivityMapping(
|
||||||
'icon', 'avatar',
|
'icon', 'avatar',
|
||||||
lambda x: image_formatter(x, '/static/images/default_avi.jpg')
|
lambda x: image_formatter(x, '/static/images/default_avi.jpg'),
|
||||||
|
activitypub.image_formatter
|
||||||
),
|
),
|
||||||
ActivityMapping(
|
ActivityMapping(
|
||||||
'manuallyApprovesFollowers',
|
'manuallyApprovesFollowers',
|
||||||
|
|
|
@ -25,11 +25,6 @@ def get_or_create_remote_user(actor):
|
||||||
user = create_remote_user(data)
|
user = create_remote_user(data)
|
||||||
user.federated_server = get_or_create_remote_server(actor_parts.netloc)
|
user.federated_server = get_or_create_remote_server(actor_parts.netloc)
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
avatar = get_avatar(data)
|
|
||||||
if avatar:
|
|
||||||
user.avatar.save(*avatar)
|
|
||||||
|
|
||||||
if user.bookwyrm_user:
|
if user.bookwyrm_user:
|
||||||
get_remote_reviews.delay(user.id)
|
get_remote_reviews.delay(user.id)
|
||||||
return user
|
return user
|
||||||
|
@ -69,21 +64,6 @@ def refresh_remote_user(user):
|
||||||
activity.to_model(models.User, instance=user)
|
activity.to_model(models.User, instance=user)
|
||||||
|
|
||||||
|
|
||||||
def get_avatar(data):
|
|
||||||
''' find the icon attachment and load the image from the remote sever '''
|
|
||||||
icon_blob = data.get('icon')
|
|
||||||
if not icon_blob or not icon_blob.get('url'):
|
|
||||||
return None
|
|
||||||
|
|
||||||
response = requests.get(icon_blob['url'])
|
|
||||||
if not response.ok:
|
|
||||||
return None
|
|
||||||
|
|
||||||
image_name = str(uuid4()) + '.' + icon_blob['url'].split('.')[-1]
|
|
||||||
image_content = ContentFile(response.content)
|
|
||||||
return [image_name, image_content]
|
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def get_remote_reviews(user_id):
|
def get_remote_reviews(user_id):
|
||||||
''' ingest reviews by a new remote bookwyrm user '''
|
''' ingest reviews by a new remote bookwyrm user '''
|
||||||
|
|
Loading…
Reference in New Issue