mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-04 05:49:16 +02:00
Blacked the code
This commit is contained in:
parent
b6fc0051fa
commit
62ca3bd736
279 changed files with 8861 additions and 9527 deletions
|
@ -29,8 +29,10 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def remove_tags(text):
|
||||
logger.debug('Removing tags from %s', text)
|
||||
return ''.join(xml.etree.ElementTree.fromstring('<div>{}</div>'.format(text)).itertext())
|
||||
logger.debug("Removing tags from %s", text)
|
||||
return "".join(
|
||||
xml.etree.ElementTree.fromstring("<div>{}</div>".format(text)).itertext()
|
||||
)
|
||||
|
||||
|
||||
def get_actor_data(actor_url):
|
||||
|
@ -38,16 +40,13 @@ def get_actor_data(actor_url):
|
|||
actor_url,
|
||||
timeout=5,
|
||||
verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL,
|
||||
headers={
|
||||
'Accept': 'application/activity+json',
|
||||
}
|
||||
headers={"Accept": "application/activity+json"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
try:
|
||||
return response.json()
|
||||
except:
|
||||
raise ValueError(
|
||||
'Invalid actor payload: {}'.format(response.text))
|
||||
raise ValueError("Invalid actor payload: {}".format(response.text))
|
||||
|
||||
|
||||
def get_actor(actor_url):
|
||||
|
@ -56,7 +55,8 @@ def get_actor(actor_url):
|
|||
except models.Actor.DoesNotExist:
|
||||
actor = None
|
||||
fetch_delta = datetime.timedelta(
|
||||
minutes=preferences.get('federation__actor_fetch_delay'))
|
||||
minutes=preferences.get("federation__actor_fetch_delay")
|
||||
)
|
||||
if actor and actor.last_fetch_date > timezone.now() - fetch_delta:
|
||||
# cache is hot, we can return as is
|
||||
return actor
|
||||
|
@ -73,8 +73,7 @@ class SystemActor(object):
|
|||
|
||||
def get_request_auth(self):
|
||||
actor = self.get_actor_instance()
|
||||
return signing.get_auth(
|
||||
actor.private_key, actor.private_key_id)
|
||||
return signing.get_auth(actor.private_key, actor.private_key_id)
|
||||
|
||||
def serialize(self):
|
||||
actor = self.get_actor_instance()
|
||||
|
@ -88,42 +87,35 @@ class SystemActor(object):
|
|||
pass
|
||||
private, public = keys.get_key_pair()
|
||||
args = self.get_instance_argument(
|
||||
self.id,
|
||||
name=self.name,
|
||||
summary=self.summary,
|
||||
**self.additional_attributes
|
||||
self.id, name=self.name, summary=self.summary, **self.additional_attributes
|
||||
)
|
||||
args['private_key'] = private.decode('utf-8')
|
||||
args['public_key'] = public.decode('utf-8')
|
||||
args["private_key"] = private.decode("utf-8")
|
||||
args["public_key"] = public.decode("utf-8")
|
||||
return models.Actor.objects.create(**args)
|
||||
|
||||
def get_actor_url(self):
|
||||
return utils.full_url(
|
||||
reverse(
|
||||
'federation:instance-actors-detail',
|
||||
kwargs={'actor': self.id}))
|
||||
reverse("federation:instance-actors-detail", kwargs={"actor": self.id})
|
||||
)
|
||||
|
||||
def get_instance_argument(self, id, name, summary, **kwargs):
|
||||
p = {
|
||||
'preferred_username': id,
|
||||
'domain': settings.FEDERATION_HOSTNAME,
|
||||
'type': 'Person',
|
||||
'name': name.format(host=settings.FEDERATION_HOSTNAME),
|
||||
'manually_approves_followers': True,
|
||||
'url': self.get_actor_url(),
|
||||
'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})),
|
||||
'summary': summary.format(host=settings.FEDERATION_HOSTNAME)
|
||||
"preferred_username": id,
|
||||
"domain": settings.FEDERATION_HOSTNAME,
|
||||
"type": "Person",
|
||||
"name": name.format(host=settings.FEDERATION_HOSTNAME),
|
||||
"manually_approves_followers": True,
|
||||
"url": self.get_actor_url(),
|
||||
"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})
|
||||
),
|
||||
"summary": summary.format(host=settings.FEDERATION_HOSTNAME),
|
||||
}
|
||||
p.update(kwargs)
|
||||
return p
|
||||
|
@ -145,22 +137,19 @@ class SystemActor(object):
|
|||
Main entrypoint for handling activities posted to the
|
||||
actor's inbox
|
||||
"""
|
||||
logger.info('Received activity on %s inbox', self.id)
|
||||
logger.info("Received activity on %s inbox", self.id)
|
||||
|
||||
if actor is None:
|
||||
raise PermissionDenied('Actor not authenticated')
|
||||
raise PermissionDenied("Actor not authenticated")
|
||||
|
||||
serializer = serializers.ActivitySerializer(
|
||||
data=data, context={'actor': actor})
|
||||
serializer = serializers.ActivitySerializer(data=data, context={"actor": actor})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
ac = serializer.data
|
||||
try:
|
||||
handler = getattr(
|
||||
self, 'handle_{}'.format(ac['type'].lower()))
|
||||
handler = getattr(self, "handle_{}".format(ac["type"].lower()))
|
||||
except (KeyError, AttributeError):
|
||||
logger.debug(
|
||||
'No handler for activity %s', ac['type'])
|
||||
logger.debug("No handler for activity %s", ac["type"])
|
||||
return
|
||||
|
||||
return handler(data, actor)
|
||||
|
@ -168,9 +157,10 @@ class SystemActor(object):
|
|||
def handle_follow(self, ac, sender):
|
||||
system_actor = self.get_actor_instance()
|
||||
serializer = serializers.FollowSerializer(
|
||||
data=ac, context={'follow_actor': sender})
|
||||
data=ac, context={"follow_actor": sender}
|
||||
)
|
||||
if not serializer.is_valid():
|
||||
return logger.info('Invalid follow payload')
|
||||
return logger.info("Invalid follow payload")
|
||||
approved = True if not self.manually_approves_followers else None
|
||||
follow = serializer.save(approved=approved)
|
||||
if follow.approved:
|
||||
|
@ -179,26 +169,27 @@ class SystemActor(object):
|
|||
def handle_accept(self, ac, sender):
|
||||
system_actor = self.get_actor_instance()
|
||||
serializer = serializers.AcceptFollowSerializer(
|
||||
data=ac,
|
||||
context={'follow_target': sender, 'follow_actor': system_actor})
|
||||
data=ac, context={"follow_target": sender, "follow_actor": system_actor}
|
||||
)
|
||||
if not serializer.is_valid(raise_exception=True):
|
||||
return logger.info('Received invalid payload')
|
||||
return logger.info("Received invalid payload")
|
||||
|
||||
return serializer.save()
|
||||
|
||||
def handle_undo_follow(self, ac, sender):
|
||||
system_actor = self.get_actor_instance()
|
||||
serializer = serializers.UndoFollowSerializer(
|
||||
data=ac, context={'actor': sender, 'target': system_actor})
|
||||
data=ac, context={"actor": sender, "target": system_actor}
|
||||
)
|
||||
if not serializer.is_valid():
|
||||
return logger.info('Received invalid payload')
|
||||
return logger.info("Received invalid payload")
|
||||
serializer.save()
|
||||
|
||||
def handle_undo(self, ac, sender):
|
||||
if ac['object']['type'] != 'Follow':
|
||||
if ac["object"]["type"] != "Follow":
|
||||
return
|
||||
|
||||
if ac['object']['actor'] != sender.url:
|
||||
if ac["object"]["actor"] != sender.url:
|
||||
# not the same actor, permission issue
|
||||
return
|
||||
|
||||
|
@ -206,55 +197,52 @@ class SystemActor(object):
|
|||
|
||||
|
||||
class LibraryActor(SystemActor):
|
||||
id = 'library'
|
||||
name = '{host}\'s library'
|
||||
summary = 'Bot account to federate with {host}\'s library'
|
||||
additional_attributes = {
|
||||
'manually_approves_followers': True
|
||||
}
|
||||
id = "library"
|
||||
name = "{host}'s library"
|
||||
summary = "Bot account to federate with {host}'s library"
|
||||
additional_attributes = {"manually_approves_followers": True}
|
||||
|
||||
def serialize(self):
|
||||
data = super().serialize()
|
||||
urls = data.setdefault('url', [])
|
||||
urls.append({
|
||||
'type': 'Link',
|
||||
'mediaType': 'application/activity+json',
|
||||
'name': 'library',
|
||||
'href': utils.full_url(reverse('federation:music:files-list'))
|
||||
})
|
||||
urls = data.setdefault("url", [])
|
||||
urls.append(
|
||||
{
|
||||
"type": "Link",
|
||||
"mediaType": "application/activity+json",
|
||||
"name": "library",
|
||||
"href": utils.full_url(reverse("federation:music:files-list")),
|
||||
}
|
||||
)
|
||||
return data
|
||||
|
||||
@property
|
||||
def manually_approves_followers(self):
|
||||
return preferences.get('federation__music_needs_approval')
|
||||
return preferences.get("federation__music_needs_approval")
|
||||
|
||||
@transaction.atomic
|
||||
def handle_create(self, ac, sender):
|
||||
try:
|
||||
remote_library = models.Library.objects.get(
|
||||
actor=sender,
|
||||
federation_enabled=True,
|
||||
actor=sender, federation_enabled=True
|
||||
)
|
||||
except models.Library.DoesNotExist:
|
||||
logger.info(
|
||||
'Skipping import, we\'re not following %s', sender.url)
|
||||
logger.info("Skipping import, we're not following %s", sender.url)
|
||||
return
|
||||
|
||||
if ac['object']['type'] != 'Collection':
|
||||
if ac["object"]["type"] != "Collection":
|
||||
return
|
||||
|
||||
if ac['object']['totalItems'] <= 0:
|
||||
if ac["object"]["totalItems"] <= 0:
|
||||
return
|
||||
|
||||
try:
|
||||
items = ac['object']['items']
|
||||
items = ac["object"]["items"]
|
||||
except KeyError:
|
||||
logger.warning('No items in collection!')
|
||||
logger.warning("No items in collection!")
|
||||
return
|
||||
|
||||
item_serializers = [
|
||||
serializers.AudioSerializer(
|
||||
data=i, context={'library': remote_library})
|
||||
serializers.AudioSerializer(data=i, context={"library": remote_library})
|
||||
for i in items
|
||||
]
|
||||
now = timezone.now()
|
||||
|
@ -263,27 +251,21 @@ class LibraryActor(SystemActor):
|
|||
if s.is_valid():
|
||||
valid_serializers.append(s)
|
||||
else:
|
||||
logger.debug(
|
||||
'Skipping invalid item %s, %s', s.initial_data, s.errors)
|
||||
logger.debug("Skipping invalid item %s, %s", s.initial_data, s.errors)
|
||||
|
||||
lts = []
|
||||
for s in valid_serializers:
|
||||
lts.append(s.save())
|
||||
|
||||
if remote_library.autoimport:
|
||||
batch = music_models.ImportBatch.objects.create(
|
||||
source='federation',
|
||||
)
|
||||
batch = music_models.ImportBatch.objects.create(source="federation")
|
||||
for lt in lts:
|
||||
if lt.creation_date < now:
|
||||
# track was already in the library, we do not trigger
|
||||
# an import
|
||||
continue
|
||||
job = music_models.ImportJob.objects.create(
|
||||
batch=batch,
|
||||
library_track=lt,
|
||||
mbid=lt.mbid,
|
||||
source=lt.url,
|
||||
batch=batch, library_track=lt, mbid=lt.mbid, source=lt.url
|
||||
)
|
||||
funkwhale_utils.on_commit(
|
||||
music_tasks.import_job_run.delay,
|
||||
|
@ -293,15 +275,13 @@ class LibraryActor(SystemActor):
|
|||
|
||||
|
||||
class TestActor(SystemActor):
|
||||
id = 'test'
|
||||
name = '{host}\'s test account'
|
||||
id = "test"
|
||||
name = "{host}'s test account"
|
||||
summary = (
|
||||
'Bot account to test federation with {host}. '
|
||||
'Send me /ping and I\'ll answer you.'
|
||||
"Bot account to test federation with {host}. "
|
||||
"Send me /ping and I'll answer you."
|
||||
)
|
||||
additional_attributes = {
|
||||
'manually_approves_followers': False
|
||||
}
|
||||
additional_attributes = {"manually_approves_followers": False}
|
||||
manually_approves_followers = False
|
||||
|
||||
def get_outbox(self, data, actor=None):
|
||||
|
@ -309,15 +289,14 @@ class TestActor(SystemActor):
|
|||
"@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})),
|
||||
reverse("federation:instance-actors-outbox", kwargs={"actor": self.id})
|
||||
),
|
||||
"type": "OrderedCollection",
|
||||
"totalItems": 0,
|
||||
"orderedItems": []
|
||||
"orderedItems": [],
|
||||
}
|
||||
|
||||
def parse_command(self, message):
|
||||
|
@ -327,99 +306,86 @@ class TestActor(SystemActor):
|
|||
"""
|
||||
raw = remove_tags(message)
|
||||
try:
|
||||
return raw.split('/')[1]
|
||||
return raw.split("/")[1]
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
def handle_create(self, ac, sender):
|
||||
if ac['object']['type'] != 'Note':
|
||||
if ac["object"]["type"] != "Note":
|
||||
return
|
||||
|
||||
# we received a toot \o/
|
||||
command = self.parse_command(ac['object']['content'])
|
||||
logger.debug('Parsed command: %s', command)
|
||||
if command != 'ping':
|
||||
command = self.parse_command(ac["object"]["content"])
|
||||
logger.debug("Parsed command: %s", command)
|
||||
if command != "ping":
|
||||
return
|
||||
|
||||
now = timezone.now()
|
||||
test_actor = self.get_actor_instance()
|
||||
reply_url = 'https://{}/activities/note/{}'.format(
|
||||
reply_url = "https://{}/activities/note/{}".format(
|
||||
settings.FEDERATION_HOSTNAME, now.timestamp()
|
||||
)
|
||||
reply_content = '{} Pong!'.format(
|
||||
sender.mention_username
|
||||
)
|
||||
reply_content = "{} Pong!".format(sender.mention_username)
|
||||
reply_activity = {
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
{}
|
||||
{},
|
||||
],
|
||||
'type': 'Create',
|
||||
'actor': test_actor.url,
|
||||
'id': '{}/activity'.format(reply_url),
|
||||
'published': now.isoformat(),
|
||||
'to': ac['actor'],
|
||||
'cc': [],
|
||||
'object': {
|
||||
'type': 'Note',
|
||||
'content': 'Pong!',
|
||||
'summary': None,
|
||||
'published': now.isoformat(),
|
||||
'id': reply_url,
|
||||
'inReplyTo': ac['object']['id'],
|
||||
'sensitive': False,
|
||||
'url': reply_url,
|
||||
'to': [ac['actor']],
|
||||
'attributedTo': test_actor.url,
|
||||
'cc': [],
|
||||
'attachment': [],
|
||||
'tag': [{
|
||||
"type": "Mention",
|
||||
"href": ac['actor'],
|
||||
"name": sender.mention_username
|
||||
}]
|
||||
}
|
||||
"type": "Create",
|
||||
"actor": test_actor.url,
|
||||
"id": "{}/activity".format(reply_url),
|
||||
"published": now.isoformat(),
|
||||
"to": ac["actor"],
|
||||
"cc": [],
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"content": "Pong!",
|
||||
"summary": None,
|
||||
"published": now.isoformat(),
|
||||
"id": reply_url,
|
||||
"inReplyTo": ac["object"]["id"],
|
||||
"sensitive": False,
|
||||
"url": reply_url,
|
||||
"to": [ac["actor"]],
|
||||
"attributedTo": test_actor.url,
|
||||
"cc": [],
|
||||
"attachment": [],
|
||||
"tag": [
|
||||
{
|
||||
"type": "Mention",
|
||||
"href": ac["actor"],
|
||||
"name": sender.mention_username,
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
activity.deliver(
|
||||
reply_activity,
|
||||
to=[ac['actor']],
|
||||
on_behalf_of=test_actor)
|
||||
activity.deliver(reply_activity, to=[ac["actor"]], on_behalf_of=test_actor)
|
||||
|
||||
def handle_follow(self, ac, sender):
|
||||
super().handle_follow(ac, sender)
|
||||
# also, we follow back
|
||||
test_actor = self.get_actor_instance()
|
||||
follow_back = models.Follow.objects.get_or_create(
|
||||
actor=test_actor,
|
||||
target=sender,
|
||||
approved=None,
|
||||
actor=test_actor, target=sender, approved=None
|
||||
)[0]
|
||||
activity.deliver(
|
||||
serializers.FollowSerializer(follow_back).data,
|
||||
to=[follow_back.target.url],
|
||||
on_behalf_of=follow_back.actor)
|
||||
on_behalf_of=follow_back.actor,
|
||||
)
|
||||
|
||||
def handle_undo_follow(self, ac, sender):
|
||||
super().handle_undo_follow(ac, sender)
|
||||
actor = self.get_actor_instance()
|
||||
# we also unfollow the sender, if possible
|
||||
try:
|
||||
follow = models.Follow.objects.get(
|
||||
target=sender,
|
||||
actor=actor,
|
||||
)
|
||||
follow = models.Follow.objects.get(target=sender, actor=actor)
|
||||
except models.Follow.DoesNotExist:
|
||||
return
|
||||
undo = serializers.UndoFollowSerializer(follow).data
|
||||
follow.delete()
|
||||
activity.deliver(
|
||||
undo,
|
||||
to=[sender.url],
|
||||
on_behalf_of=actor)
|
||||
activity.deliver(undo, to=[sender.url], on_behalf_of=actor)
|
||||
|
||||
|
||||
SYSTEM_ACTORS = {
|
||||
'library': LibraryActor(),
|
||||
'test': TestActor(),
|
||||
}
|
||||
SYSTEM_ACTORS = {"library": LibraryActor(), "test": TestActor()}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue