Follow request approve/refuse logic
This commit is contained in:
parent
cb9309c298
commit
e0dcb87f15
|
@ -97,6 +97,15 @@ class FollowFactory(factory.DjangoModelFactory):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@registry.register
|
||||||
|
class FollowRequestFactory(factory.DjangoModelFactory):
|
||||||
|
target = factory.SubFactory(ActorFactory)
|
||||||
|
actor = factory.SubFactory(ActorFactory)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.FollowRequest
|
||||||
|
|
||||||
|
|
||||||
@registry.register(name='federation.Note')
|
@registry.register(name='federation.Note')
|
||||||
class NoteFactory(factory.Factory):
|
class NoteFactory(factory.Factory):
|
||||||
type = 'Note'
|
type = 'Note'
|
||||||
|
|
|
@ -35,6 +35,13 @@ class Actor(models.Model):
|
||||||
last_fetch_date = models.DateTimeField(
|
last_fetch_date = models.DateTimeField(
|
||||||
default=timezone.now)
|
default=timezone.now)
|
||||||
manually_approves_followers = models.NullBooleanField(default=None)
|
manually_approves_followers = models.NullBooleanField(default=None)
|
||||||
|
followers = models.ManyToManyField(
|
||||||
|
to='self',
|
||||||
|
symmetrical=False,
|
||||||
|
through='Follow',
|
||||||
|
through_fields=('target', 'actor'),
|
||||||
|
related_name='following',
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ['domain', 'preferred_username']
|
unique_together = ['domain', 'preferred_username']
|
||||||
|
@ -65,6 +72,10 @@ class Actor(models.Model):
|
||||||
|
|
||||||
super().save(**kwargs)
|
super().save(**kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_local(self):
|
||||||
|
return self.domain == settings.FEDERATION_HOSTNAME
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_system(self):
|
def is_system(self):
|
||||||
from . import actors
|
from . import actors
|
||||||
|
@ -121,3 +132,28 @@ class FollowRequest(models.Model):
|
||||||
last_modification_date = models.DateTimeField(
|
last_modification_date = models.DateTimeField(
|
||||||
default=timezone.now)
|
default=timezone.now)
|
||||||
approved = models.NullBooleanField(default=None)
|
approved = models.NullBooleanField(default=None)
|
||||||
|
|
||||||
|
def approve(self):
|
||||||
|
from . import activity
|
||||||
|
from . import serializers
|
||||||
|
self.approved = True
|
||||||
|
self.save(update_fields=['approved'])
|
||||||
|
Follow.objects.get_or_create(
|
||||||
|
target=self.target,
|
||||||
|
actor=self.actor
|
||||||
|
)
|
||||||
|
if self.target.is_local:
|
||||||
|
follow = {
|
||||||
|
'@context': serializers.AP_CONTEXT,
|
||||||
|
'actor': self.actor.url,
|
||||||
|
'id': self.actor.url + '#follows/{}'.format(uuid.uuid4()),
|
||||||
|
'object': self.target.url,
|
||||||
|
'type': 'Follow'
|
||||||
|
}
|
||||||
|
activity.accept_follow(
|
||||||
|
self.target, follow, self.actor
|
||||||
|
)
|
||||||
|
|
||||||
|
def refuse(self):
|
||||||
|
self.approved = False
|
||||||
|
self.save(update_fields=['approved'])
|
||||||
|
|
|
@ -351,7 +351,7 @@ def test_library_actor_handles_follow_manual_approval(
|
||||||
|
|
||||||
def test_library_actor_handles_follow_auto_approval(
|
def test_library_actor_handles_follow_auto_approval(
|
||||||
settings, mocker, factories):
|
settings, mocker, factories):
|
||||||
settings.FEDERATION_MUSIC_NEEDS_APPROVAL = True
|
settings.FEDERATION_MUSIC_NEEDS_APPROVAL = False
|
||||||
actor = factories['federation.Actor']()
|
actor = factories['federation.Actor']()
|
||||||
accept_follow = mocker.patch(
|
accept_follow = mocker.patch(
|
||||||
'funkwhale_api.federation.activity.accept_follow')
|
'funkwhale_api.federation.activity.accept_follow')
|
||||||
|
@ -363,3 +363,8 @@ def test_library_actor_handles_follow_auto_approval(
|
||||||
'object': library_actor.url,
|
'object': library_actor.url,
|
||||||
}
|
}
|
||||||
library_actor.system_conf.post_inbox(data, actor=actor)
|
library_actor.system_conf.post_inbox(data, actor=actor)
|
||||||
|
|
||||||
|
assert library_actor.received_follow_requests.count() == 0
|
||||||
|
accept_follow.assert_called_once_with(
|
||||||
|
library_actor, data, actor
|
||||||
|
)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
import uuid
|
||||||
|
|
||||||
from django import db
|
from django import db
|
||||||
|
|
||||||
from funkwhale_api.federation import models
|
from funkwhale_api.federation import models
|
||||||
|
from funkwhale_api.federation import serializers
|
||||||
|
|
||||||
|
|
||||||
def test_cannot_duplicate_actor(factories):
|
def test_cannot_duplicate_actor(factories):
|
||||||
|
@ -30,3 +32,47 @@ def test_follow_federation_url(factories):
|
||||||
follow.actor.url, follow.uuid)
|
follow.actor.url, follow.uuid)
|
||||||
|
|
||||||
assert follow.get_federation_url() == expected
|
assert follow.get_federation_url() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_follow_request_approve(mocker, factories):
|
||||||
|
uid = uuid.uuid4()
|
||||||
|
mocker.patch('uuid.uuid4', return_value=uid)
|
||||||
|
accept_follow = mocker.patch(
|
||||||
|
'funkwhale_api.federation.activity.accept_follow')
|
||||||
|
fr = factories['federation.FollowRequest'](target__local=True)
|
||||||
|
fr.approve()
|
||||||
|
|
||||||
|
follow = {
|
||||||
|
'@context': serializers.AP_CONTEXT,
|
||||||
|
'actor': fr.actor.url,
|
||||||
|
'id': fr.actor.url + '#follows/{}'.format(uid),
|
||||||
|
'object': fr.target.url,
|
||||||
|
'type': 'Follow'
|
||||||
|
}
|
||||||
|
|
||||||
|
assert fr.approved is True
|
||||||
|
assert list(fr.target.followers.all()) == [fr.actor]
|
||||||
|
accept_follow.assert_called_once_with(
|
||||||
|
fr.target, follow, fr.actor
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_follow_request_approve_non_local(mocker, factories):
|
||||||
|
uid = uuid.uuid4()
|
||||||
|
mocker.patch('uuid.uuid4', return_value=uid)
|
||||||
|
accept_follow = mocker.patch(
|
||||||
|
'funkwhale_api.federation.activity.accept_follow')
|
||||||
|
fr = factories['federation.FollowRequest']()
|
||||||
|
fr.approve()
|
||||||
|
|
||||||
|
assert fr.approved is True
|
||||||
|
assert list(fr.target.followers.all()) == [fr.actor]
|
||||||
|
accept_follow.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_follow_request_refused(mocker, factories):
|
||||||
|
fr = factories['federation.FollowRequest']()
|
||||||
|
fr.refuse()
|
||||||
|
|
||||||
|
assert fr.approved is False
|
||||||
|
assert fr.target.followers.count() == 0
|
||||||
|
|
Loading…
Reference in New Issue