Test bot can now unfollow
This commit is contained in:
parent
81e7f03f77
commit
3ad1fe17d5
|
@ -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):
|
||||||
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
|
||||||
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):
|
||||||
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):
|
||||||
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 = [
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
|
|
||||||
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(
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
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(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
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(
|
||||||
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
|
||||||
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):
|
||||||
'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):
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue