We are now able to receive a toot and react to it
This commit is contained in:
parent
6fbf8fa44c
commit
3cf1a17087
12 changed files with 396 additions and 46 deletions
|
|
@ -1,14 +1,23 @@
|
|||
import requests
|
||||
import xml
|
||||
|
||||
from django.urls import reverse
|
||||
from django.conf import settings
|
||||
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
from dynamic_preferences.registries import global_preferences_registry
|
||||
|
||||
from . import activity
|
||||
from . import models
|
||||
from . import serializers
|
||||
from . import utils
|
||||
|
||||
|
||||
def remove_tags(text):
|
||||
return ''.join(xml.etree.ElementTree.fromstring(text).itertext())
|
||||
|
||||
|
||||
def get_actor_data(actor_url):
|
||||
response = requests.get(
|
||||
actor_url,
|
||||
|
|
@ -23,39 +32,132 @@ def get_actor_data(actor_url):
|
|||
raise ValueError(
|
||||
'Invalid actor payload: {}'.format(response.text))
|
||||
|
||||
|
||||
class SystemActor(object):
|
||||
additional_attributes = {}
|
||||
|
||||
def get_actor_instance(self):
|
||||
a = models.Actor(
|
||||
**self.get_instance_argument(
|
||||
self.id,
|
||||
name=self.name,
|
||||
summary=self.summary,
|
||||
**self.additional_attributes
|
||||
)
|
||||
)
|
||||
a.pk = self.id
|
||||
return a
|
||||
|
||||
def get_instance_argument(self, id, name, summary, **kwargs):
|
||||
preferences = global_preferences_registry.manager()
|
||||
p = {
|
||||
'preferred_username': id,
|
||||
'domain': settings.FEDERATION_HOSTNAME,
|
||||
'type': 'Person',
|
||||
'name': name.format(host=settings.FEDERATION_HOSTNAME),
|
||||
'manually_approves_followers': True,
|
||||
'url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-detail',
|
||||
kwargs={'actor': id})),
|
||||
'shared_inbox_url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-inbox',
|
||||
kwargs={'actor': id})),
|
||||
'inbox_url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-inbox',
|
||||
kwargs={'actor': id})),
|
||||
'outbox_url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-outbox',
|
||||
kwargs={'actor': id})),
|
||||
'public_key': preferences['federation__public_key'],
|
||||
'summary': summary.format(host=settings.FEDERATION_HOSTNAME)
|
||||
}
|
||||
p.update(kwargs)
|
||||
return p
|
||||
|
||||
def get_inbox(self, data, actor=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def post_inbox(self, data, actor=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_outbox(self, data, actor=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def post_outbox(self, data, actor=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LibraryActor(SystemActor):
|
||||
id = 'library'
|
||||
name = '{host}\'s library'
|
||||
summary = 'Bot account to federate with {host}\'s library'
|
||||
additional_attributes = {
|
||||
'manually_approves_followers': True
|
||||
}
|
||||
|
||||
|
||||
class TestActor(SystemActor):
|
||||
id = 'test'
|
||||
name = '{host}\'s test account'
|
||||
summary = (
|
||||
'Bot account to test federation with {host}. '
|
||||
'Send me /ping and I\'ll answer you.'
|
||||
)
|
||||
additional_attributes = {
|
||||
'manually_approves_followers': False
|
||||
}
|
||||
|
||||
def get_outbox(self, data, actor=None):
|
||||
return {
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
{}
|
||||
],
|
||||
"id": utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-outbox',
|
||||
kwargs={'actor': self.id})),
|
||||
"type": "OrderedCollection",
|
||||
"totalItems": 0,
|
||||
"orderedItems": []
|
||||
}
|
||||
|
||||
def post_inbox(self, data, actor=None):
|
||||
if actor is None:
|
||||
raise PermissionDenied('Actor not authenticated')
|
||||
|
||||
serializer = serializers.ActivitySerializer(
|
||||
data=data, context={'actor': actor})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
ac = serializer.validated_data
|
||||
if ac['type'] == 'Create' and ac['object']['type'] == 'Note':
|
||||
# we received a toot \o/
|
||||
command = self.parse_command(ac['object']['content'])
|
||||
if command == 'ping':
|
||||
activity.deliver(
|
||||
content='Pong!',
|
||||
to=[ac['actor']],
|
||||
on_behalf_of=self.get_actor_instance())
|
||||
|
||||
def parse_command(self, message):
|
||||
"""
|
||||
Remove any links or fancy markup to extract /command from
|
||||
a note message.
|
||||
"""
|
||||
raw = remove_tags(message)
|
||||
try:
|
||||
return raw.split('/')[1]
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
|
||||
SYSTEM_ACTORS = {
|
||||
'library': {
|
||||
'get_actor': lambda: models.Actor(**get_base_system_actor_arguments('library')),
|
||||
}
|
||||
'library': LibraryActor(),
|
||||
'test': TestActor(),
|
||||
}
|
||||
|
||||
|
||||
def get_base_system_actor_arguments(name):
|
||||
preferences = global_preferences_registry.manager()
|
||||
return {
|
||||
'preferred_username': name,
|
||||
'domain': settings.FEDERATION_HOSTNAME,
|
||||
'type': 'Person',
|
||||
'name': '{}\'s library'.format(settings.FEDERATION_HOSTNAME),
|
||||
'manually_approves_followers': True,
|
||||
'url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-detail',
|
||||
kwargs={'actor': name})),
|
||||
'shared_inbox_url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-inbox',
|
||||
kwargs={'actor': name})),
|
||||
'inbox_url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-inbox',
|
||||
kwargs={'actor': name})),
|
||||
'outbox_url': utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-outbox',
|
||||
kwargs={'actor': name})),
|
||||
'public_key': preferences['federation__public_key'],
|
||||
'summary': 'Bot account to federate with {}\'s library'.format(
|
||||
settings.FEDERATION_HOSTNAME
|
||||
),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue