Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2020-12-20 11:42:28 -08:00
commit 44f764a34a
4 changed files with 58 additions and 51 deletions

View file

@ -63,7 +63,6 @@ class ActivityObject:
setattr(self, field.name, value)
@transaction.atomic
def to_model(self, model, instance=None, save=True):
''' convert from an activity to a model instance '''
if not isinstance(self, model.activity_serializer):
@ -91,13 +90,14 @@ class ActivityObject:
if not save:
return instance
# we can't set many to many and reverse fields on an unsaved object
instance.save()
with transaction.atomic():
# we can't set many to many and reverse fields on an unsaved object
instance.save()
# add many to many fields, which have to be set post-save
for field in instance.many_to_many_fields:
# mention books/users, for example
field.set_field_from_activity(instance, self)
# add many to many fields, which have to be set post-save
for field in instance.many_to_many_fields:
# mention books/users, for example
field.set_field_from_activity(instance, self)
# reversed relationships in the models
for (model_field_name, activity_field_name) in \
@ -106,20 +106,23 @@ class ActivityObject:
values = getattr(self, activity_field_name)
if values is None or values is MISSING:
continue
model_field = getattr(model, model_field_name)
try:
# this is for one to many
related_model = getattr(model, model_field_name).field.model
related_model = model_field.field.model
related_field_name = model_field.field.name
except AttributeError:
# it's a one to one or foreign key
related_model = getattr(model, model_field_name)\
.related.related_model
related_model = model_field.related.related_model
related_field_name = model_field.related.related_name
values = [values]
for item in values:
set_related_field.delay(
related_model.__name__,
instance.__class__.__name__,
instance.__class__.__name__.lower(),
related_field_name,
instance.remote_id,
item
)
@ -145,23 +148,25 @@ def set_related_field(
require_ready=True
)
if isinstance(data, str):
item = resolve_remote_id(model, data, save=False)
else:
# look for a match based on all the available data
item = model.find_existing(data)
if not item:
# create a new model instance
item = model.activity_serializer(**data)
item = item.to_model(model, save=False)
# this must exist because it's the object that triggered this function
instance = origin_model.find_existing_by_remote_id(related_remote_id)
if not instance:
raise ValueError('Invalid related remote id: %s' % related_remote_id)
with transaction.atomic():
if isinstance(data, str):
item = resolve_remote_id(model, data, save=False)
else:
# look for a match based on all the available data
item = model.find_existing(data)
if not item:
# create a new model instance
item = model.activity_serializer(**data)
item = item.to_model(model, save=False)
# this must exist because it's the object that triggered this function
instance = origin_model.find_existing_by_remote_id(related_remote_id)
if not instance:
raise ValueError(
'Invalid related remote id: %s' % related_remote_id)
# edition.parent_work = instance, for example
setattr(item, related_field_name, instance)
item.save()
# edition.parent_work = instance, for example
setattr(item, related_field_name, instance)
item.save()
def resolve_remote_id(model, remote_id, refresh=False, save=True):

View file

@ -11,11 +11,10 @@ from django.core.files.base import ContentFile
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from markdown import markdown
from bookwyrm import activitypub
from bookwyrm.connectors import get_image
from bookwyrm.sanitize_html import InputHtmlParser
from bookwyrm.settings import DOMAIN
from bookwyrm.connectors import get_image
def validate_remote_id(value):
@ -401,16 +400,6 @@ class HtmlField(ActivitypubFieldMixin, models.TextField):
sanitizer.feed(value)
return sanitizer.get_output()
def to_python(self, value):# pylint: disable=no-self-use
''' process markdown before save '''
if not value:
return value
content = markdown(value)
# sanitize resulting html
sanitizer = InputHtmlParser()
sanitizer.feed(content)
return sanitizer.get_output()
class ArrayField(ActivitypubFieldMixin, DjangoArrayField):
''' activitypub-aware array field '''
def field_to_activity(self, value):

View file

@ -4,12 +4,14 @@ import re
from django.db import IntegrityError, transaction
from django.http import HttpResponseNotFound, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from markdown import markdown
from requests import HTTPError
from bookwyrm import activitypub
from bookwyrm import models
from bookwyrm.connectors import get_data, ConnectorException
from bookwyrm.broadcast import broadcast
from bookwyrm.sanitize_html import InputHtmlParser
from bookwyrm.status import create_notification
from bookwyrm.status import create_generated_note
from bookwyrm.status import delete_status
@ -241,20 +243,17 @@ def handle_status(user, form):
related_user=user,
related_status=status
)
# add links
# add mentions
content = status.content
content = re.sub(
r'([^(href=")])(https?:\/\/([A-Za-z\.\-_\/]+' \
r'\.[A-Za-z]{2,}[A-Za-z\.\-_\/]+))',
r'\g<1><a href="\g<2>">\g<3></a>',
content)
for (username, url) in matches:
content = re.sub(
r'%s([^@])' % username,
r'<a href="%s">%s</a>\g<1>' % (url, username),
content)
status.content = content
if not isinstance(status, models.GeneratedNote):
status.content = to_markown(content)
if hasattr(status, 'quote'):
status.quote = to_markown(status.quote)
status.save()
# notify reply parent or tagged users
@ -273,6 +272,20 @@ def handle_status(user, form):
broadcast(user, remote_activity, software='other')
def to_markown(content):
''' catch links and convert to markdown '''
content = re.sub(
r'([^(href=")])(https?:\/\/([A-Za-z\.\-_\/]+' \
r'\.[A-Za-z]{2,}[A-Za-z\.\-_\/]+))',
r'\g<1><a href="\g<2>">\g<3></a>',
content)
content = markdown(content)
# sanitize resulting html
sanitizer = InputHtmlParser()
sanitizer.feed(content)
return sanitizer.get_output()
def handle_tag(user, tag):
''' tag a book '''
broadcast(user, tag.to_add_activity(user))

View file

@ -262,8 +262,8 @@ class Incoming(TestCase):
status = models.Quotation.objects.get()
self.assertEqual(
status.remote_id, 'https://example.com/user/mouse/quotation/13')
self.assertEqual(status.quote, '<p>quote body</p>')
self.assertEqual(status.content, '<p>commentary</p>')
self.assertEqual(status.quote, 'quote body')
self.assertEqual(status.content, 'commentary')
self.assertEqual(status.user, self.local_user)
self.assertEqual(models.Status.objects.count(), 2)
@ -284,7 +284,7 @@ class Incoming(TestCase):
incoming.handle_create(activity)
status = models.Status.objects.last()
self.assertEqual(status.content, '<p>test content in note</p>')
self.assertEqual(status.content, 'test content in note')
self.assertEqual(status.mention_users.first(), self.local_user)
self.assertTrue(
models.Notification.objects.filter(user=self.local_user).exists())
@ -306,7 +306,7 @@ class Incoming(TestCase):
incoming.handle_create(activity)
status = models.Status.objects.last()
self.assertEqual(status.content, '<p>test content in note</p>')
self.assertEqual(status.content, 'test content in note')
self.assertEqual(status.reply_parent, self.status)
self.assertTrue(
models.Notification.objects.filter(user=self.local_user))