Skip to content
Snippets Groups Projects
Verified Commit 3ad1fe17 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Test bot can now unfollow

parent 81e7f03f
Branches
Tags
No related merge requests found
...@@ -130,7 +130,7 @@ class SystemActor(object): ...@@ -130,7 +130,7 @@ class SystemActor(object):
'No handler for activity %s', ac['type']) 'No handler for activity %s', ac['type'])
return return
return handler(ac, actor) return handler(data, actor)
class LibraryActor(SystemActor): class LibraryActor(SystemActor):
...@@ -269,6 +269,40 @@ class TestActor(SystemActor): ...@@ -269,6 +269,40 @@ class TestActor(SystemActor):
to=[ac['actor']], to=[ac['actor']],
on_behalf_of=test_actor) on_behalf_of=test_actor)
def handle_undo(self, ac, sender):
if ac['object']['type'] != 'Follow':
return
if ac['object']['actor'] != sender.url:
# not the same actor, permission issue
return
test_actor = self.get_actor_instance()
models.Follow.objects.filter(
actor=sender,
target=test_actor,
).delete()
# we also unfollow the sender, if possible
try:
follow = models.Follow.objects.get(
target=sender,
actor=test_actor,
)
except models.Follow.DoesNotExist:
return
undo = {
'@context': serializers.AP_CONTEXT,
'type': 'Undo',
'id': follow.get_federation_url() + '/undo',
'actor': test_actor.url,
'object': serializers.FollowSerializer(follow).data,
}
follow.delete()
activity.deliver(
undo,
to=[sender.url],
on_behalf_of=test_actor)
SYSTEM_ACTORS = { SYSTEM_ACTORS = {
'library': LibraryActor(), 'library': LibraryActor(),
'test': TestActor(), 'test': TestActor(),
......
...@@ -3,6 +3,7 @@ import requests ...@@ -3,6 +3,7 @@ import requests
import requests_http_signature import requests_http_signature
from django.utils import timezone from django.utils import timezone
from django.conf import settings
from funkwhale_api.factories import registry from funkwhale_api.factories import registry
...@@ -65,6 +66,12 @@ class ActorFactory(factory.DjangoModelFactory): ...@@ -65,6 +66,12 @@ class ActorFactory(factory.DjangoModelFactory):
class Meta: class Meta:
model = models.Actor model = models.Actor
class Params:
local = factory.Trait(
domain=factory.LazyAttribute(
lambda o: settings.FEDERATION_HOSTNAME)
)
@classmethod @classmethod
def _generate(cls, create, attrs): def _generate(cls, create, attrs):
has_public = attrs.get('public_key') is not None has_public = attrs.get('public_key') is not None
...@@ -84,6 +91,11 @@ class FollowFactory(factory.DjangoModelFactory): ...@@ -84,6 +91,11 @@ class FollowFactory(factory.DjangoModelFactory):
class Meta: class Meta:
model = models.Follow model = models.Follow
class Params:
local = factory.Trait(
actor=factory.SubFactory(ActorFactory, local=True)
)
@registry.register(name='federation.Note') @registry.register(name='federation.Note')
class NoteFactory(factory.Factory): class NoteFactory(factory.Factory):
......
...@@ -14,6 +14,8 @@ TYPE_CHOICES = [ ...@@ -14,6 +14,8 @@ TYPE_CHOICES = [
class Actor(models.Model): class Actor(models.Model):
ap_type = 'Actor'
url = models.URLField(unique=True, max_length=500, db_index=True) url = models.URLField(unique=True, max_length=500, db_index=True)
outbox_url = models.URLField(max_length=500) outbox_url = models.URLField(max_length=500)
inbox_url = models.URLField(max_length=500) inbox_url = models.URLField(max_length=500)
...@@ -79,6 +81,8 @@ class Actor(models.Model): ...@@ -79,6 +81,8 @@ class Actor(models.Model):
class Follow(models.Model): class Follow(models.Model):
ap_type = 'Follow'
uuid = models.UUIDField(default=uuid.uuid4, unique=True) uuid = models.UUIDField(default=uuid.uuid4, unique=True)
actor = models.ForeignKey( actor = models.ForeignKey(
Actor, Actor,
...@@ -96,3 +100,6 @@ class Follow(models.Model): ...@@ -96,3 +100,6 @@ class Follow(models.Model):
class Meta: class Meta:
unique_together = ['actor', 'target'] unique_together = ['actor', 'target']
def get_federation_url(self):
return '{}#follows/{}'.format(self.actor.url, self.uuid)
...@@ -169,11 +169,7 @@ def test_test_post_inbox_handles_create_note( ...@@ -169,11 +169,7 @@ def test_test_post_inbox_handles_create_note(
}] }]
) )
expected_activity = { expected_activity = {
'@context': [ '@context': serializers.AP_CONTEXT,
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
{}
],
'actor': test_actor.url, 'actor': test_actor.url,
'id': 'https://{}/activities/note/{}/activity'.format( 'id': 'https://{}/activities/note/{}/activity'.format(
settings.FEDERATION_HOSTNAME, now.timestamp() settings.FEDERATION_HOSTNAME, now.timestamp()
...@@ -288,11 +284,7 @@ def test_test_actor_handles_follow( ...@@ -288,11 +284,7 @@ def test_test_actor_handles_follow(
}, },
} }
expected_follow = { expected_follow = {
'@context': [ '@context': serializers.AP_CONTEXT,
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
{}
],
'actor': test_actor.url, 'actor': test_actor.url,
'id': test_actor.url + '#follows/{}'.format(uid), 'id': test_actor.url + '#follows/{}'.format(uid),
'object': actor.url, 'object': actor.url,
...@@ -317,3 +309,38 @@ def test_test_actor_handles_follow( ...@@ -317,3 +309,38 @@ def test_test_actor_handles_follow(
follow = test_actor.received_follows.first() follow = test_actor.received_follows.first()
assert follow.actor == actor assert follow.actor == actor
assert follow.target == test_actor assert follow.target == test_actor
def test_test_actor_handles_undo_follow(
settings, mocker, factories):
deliver = mocker.patch(
'funkwhale_api.federation.activity.deliver')
test_actor = actors.SYSTEM_ACTORS['test'].get_actor_instance()
follow = factories['federation.Follow'](target=test_actor)
reverse_follow = factories['federation.Follow'](
actor=test_actor, target=follow.actor)
follow_serializer = serializers.FollowSerializer(follow)
reverse_follow_serializer = serializers.FollowSerializer(
reverse_follow)
undo = {
'@context': serializers.AP_CONTEXT,
'type': 'Undo',
'id': follow_serializer.data['id'] + '/undo',
'actor': follow.actor.url,
'object': follow_serializer.data,
}
expected_undo = {
'@context': serializers.AP_CONTEXT,
'type': 'Undo',
'id': reverse_follow_serializer.data['id'] + '/undo',
'actor': reverse_follow.actor.url,
'object': reverse_follow_serializer.data,
}
actors.SYSTEM_ACTORS['test'].post_inbox(undo, actor=follow.actor)
deliver.assert_called_once_with(
expected_undo,
to=[follow.actor.url],
on_behalf_of=test_actor,)
assert models.Follow.objects.count() == 0
...@@ -3,7 +3,7 @@ from funkwhale_api.federation import keys ...@@ -3,7 +3,7 @@ from funkwhale_api.federation import keys
from funkwhale_api.federation import signing from funkwhale_api.federation import signing
def test_authenticate(nodb_factories, mocker, api_request): def test_authenticate(factories, mocker, api_request):
private, public = keys.get_key_pair() private, public = keys.get_key_pair()
actor_url = 'https://test.federation/actor' actor_url = 'https://test.federation/actor'
mocker.patch( mocker.patch(
...@@ -18,7 +18,7 @@ def test_authenticate(nodb_factories, mocker, api_request): ...@@ -18,7 +18,7 @@ def test_authenticate(nodb_factories, mocker, api_request):
'id': actor_url + '#main-key', 'id': actor_url + '#main-key',
} }
}) })
signed_request = nodb_factories['federation.SignedRequest']( signed_request = factories['federation.SignedRequest'](
auth__key=private, auth__key=private,
auth__key_id=actor_url + '#main-key', auth__key_id=actor_url + '#main-key',
auth__headers=[ auth__headers=[
......
...@@ -23,3 +23,10 @@ def test_cannot_duplicate_follow(factories): ...@@ -23,3 +23,10 @@ def test_cannot_duplicate_follow(factories):
target=follow.target, target=follow.target,
actor=follow.actor, actor=follow.actor,
) )
def test_follow_federation_url(factories):
follow = factories['federation.Follow'](local=True)
expected = '{}#follows/{}'.format(
follow.actor.url, follow.uuid)
assert follow.get_federation_url() == expected
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment