API refinements for activity stream
This commit is contained in:
parent
d509c090d3
commit
a6da10be41
|
@ -3,6 +3,7 @@ from rest_framework import serializers
|
||||||
|
|
||||||
class ModelSerializer(serializers.ModelSerializer):
|
class ModelSerializer(serializers.ModelSerializer):
|
||||||
id = serializers.CharField(source='get_activity_url')
|
id = serializers.CharField(source='get_activity_url')
|
||||||
|
local_id = serializers.IntegerField(source='id')
|
||||||
# url = serializers.SerializerMethodField()
|
# url = serializers.SerializerMethodField()
|
||||||
|
|
||||||
def get_url(self, obj):
|
def get_url(self, obj):
|
||||||
|
|
|
@ -4,17 +4,15 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from funkwhale_api.activity import serializers as activity_serializers
|
from funkwhale_api.activity import serializers as activity_serializers
|
||||||
from funkwhale_api.music.serializers import TrackSerializerNested
|
from funkwhale_api.music.serializers import TrackSerializerNested
|
||||||
|
from funkwhale_api.music.serializers import TrackActivitySerializer
|
||||||
from funkwhale_api.users.serializers import UserActivitySerializer
|
from funkwhale_api.users.serializers import UserActivitySerializer
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TrackFavoriteActivitySerializer(activity_serializers.ModelSerializer):
|
class TrackFavoriteActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
type = serializers.SerializerMethodField()
|
type = serializers.SerializerMethodField()
|
||||||
object = serializers.CharField(source='track.get_activity_url')
|
object = TrackActivitySerializer(source='track')
|
||||||
actor = UserActivitySerializer(source='user')
|
actor = UserActivitySerializer(source='user')
|
||||||
published = serializers.DateTimeField(source='creation_date')
|
published = serializers.DateTimeField(source='creation_date')
|
||||||
|
|
||||||
|
@ -22,6 +20,7 @@ class TrackFavoriteActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
model = models.TrackFavorite
|
model = models.TrackFavorite
|
||||||
fields = [
|
fields = [
|
||||||
'id',
|
'id',
|
||||||
|
'local_id',
|
||||||
'object',
|
'object',
|
||||||
'type',
|
'type',
|
||||||
'actor',
|
'actor',
|
||||||
|
@ -34,9 +33,6 @@ class TrackFavoriteActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
def get_type(self, obj):
|
def get_type(self, obj):
|
||||||
return 'Like'
|
return 'Like'
|
||||||
|
|
||||||
def get_object(self, obj):
|
|
||||||
return obj.track.get_activity_url()
|
|
||||||
|
|
||||||
|
|
||||||
class UserTrackFavoriteSerializer(serializers.ModelSerializer):
|
class UserTrackFavoriteSerializer(serializers.ModelSerializer):
|
||||||
# track = TrackSerializerNested(read_only=True)
|
# track = TrackSerializerNested(read_only=True)
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
from funkwhale_api.common import channels
|
||||||
|
from funkwhale_api.activity import record
|
||||||
|
|
||||||
|
from . import serializers
|
||||||
|
|
||||||
|
record.registry.register_serializer(
|
||||||
|
serializers.ListeningActivitySerializer)
|
||||||
|
|
||||||
|
|
||||||
|
@record.registry.register_consumer('history.Listening')
|
||||||
|
def broadcast_listening_to_instance_activity(data, obj):
|
||||||
|
if obj.user.privacy_level not in ['instance', 'everyone']:
|
||||||
|
return
|
||||||
|
|
||||||
|
channels.group_send('instance_activity', {
|
||||||
|
'type': 'event.send',
|
||||||
|
'text': '',
|
||||||
|
'data': data
|
||||||
|
})
|
|
@ -25,3 +25,8 @@ class Listening(models.Model):
|
||||||
raise ValidationError('Cannot have both session_key and user empty for listening')
|
raise ValidationError('Cannot have both session_key and user empty for listening')
|
||||||
|
|
||||||
super().save(**kwargs)
|
super().save(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def get_activity_url(self):
|
||||||
|
return '{}/listenings/tracks/{}'.format(
|
||||||
|
self.user.get_activity_url(), self.pk)
|
||||||
|
|
|
@ -1,9 +1,37 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from funkwhale_api.activity import serializers as activity_serializers
|
||||||
from funkwhale_api.music.serializers import TrackSerializerNested
|
from funkwhale_api.music.serializers import TrackSerializerNested
|
||||||
|
from funkwhale_api.music.serializers import TrackActivitySerializer
|
||||||
|
from funkwhale_api.users.serializers import UserActivitySerializer
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
class ListeningActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
|
type = serializers.SerializerMethodField()
|
||||||
|
object = TrackActivitySerializer(source='track')
|
||||||
|
actor = UserActivitySerializer(source='user')
|
||||||
|
published = serializers.DateTimeField(source='end_date')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Listening
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'local_id',
|
||||||
|
'object',
|
||||||
|
'type',
|
||||||
|
'actor',
|
||||||
|
'published'
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_actor(self, obj):
|
||||||
|
return UserActivitySerializer(obj.user).data
|
||||||
|
|
||||||
|
def get_type(self, obj):
|
||||||
|
return 'Listen'
|
||||||
|
|
||||||
|
|
||||||
class ListeningSerializer(serializers.ModelSerializer):
|
class ListeningSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -3,8 +3,9 @@ from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.decorators import detail_route
|
from rest_framework.decorators import detail_route
|
||||||
|
|
||||||
from funkwhale_api.music.serializers import TrackSerializerNested
|
from funkwhale_api.activity import record
|
||||||
from funkwhale_api.common.permissions import ConditionalAuthentication
|
from funkwhale_api.common.permissions import ConditionalAuthentication
|
||||||
|
from funkwhale_api.music.serializers import TrackSerializerNested
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from . import serializers
|
from . import serializers
|
||||||
|
@ -17,6 +18,12 @@ class ListeningViewSet(mixins.CreateModelMixin,
|
||||||
queryset = models.Listening.objects.all()
|
queryset = models.Listening.objects.all()
|
||||||
permission_classes = [ConditionalAuthentication]
|
permission_classes = [ConditionalAuthentication]
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
r = super().perform_create(serializer)
|
||||||
|
if self.request.user.is_authenticated:
|
||||||
|
record.send(serializer.instance)
|
||||||
|
return r
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
if self.request.user.is_authenticated:
|
if self.request.user.is_authenticated:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from taggit.models import Tag
|
from taggit.models import Tag
|
||||||
|
|
||||||
|
from funkwhale_api.activity import serializers as activity_serializers
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,3 +129,24 @@ class ImportBatchSerializer(serializers.ModelSerializer):
|
||||||
model = models.ImportBatch
|
model = models.ImportBatch
|
||||||
fields = ('id', 'jobs', 'status', 'creation_date', 'import_request')
|
fields = ('id', 'jobs', 'status', 'creation_date', 'import_request')
|
||||||
read_only_fields = ('creation_date',)
|
read_only_fields = ('creation_date',)
|
||||||
|
|
||||||
|
|
||||||
|
class TrackActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
|
type = serializers.SerializerMethodField()
|
||||||
|
name = serializers.CharField(source='title')
|
||||||
|
artist = serializers.CharField(source='artist.name')
|
||||||
|
album = serializers.CharField(source='album.title')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Track
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'local_id',
|
||||||
|
'name',
|
||||||
|
'type',
|
||||||
|
'artist',
|
||||||
|
'album',
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_type(self, obj):
|
||||||
|
return 'Audio'
|
||||||
|
|
|
@ -8,11 +8,13 @@ from . import models
|
||||||
class UserActivitySerializer(activity_serializers.ModelSerializer):
|
class UserActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
type = serializers.SerializerMethodField()
|
type = serializers.SerializerMethodField()
|
||||||
name = serializers.CharField(source='username')
|
name = serializers.CharField(source='username')
|
||||||
|
local_id = serializers.CharField(source='username')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.User
|
model = models.User
|
||||||
fields = [
|
fields = [
|
||||||
'id',
|
'id',
|
||||||
|
'local_id',
|
||||||
'name',
|
'name',
|
||||||
'type'
|
'type'
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from funkwhale_api.users.serializers import UserActivitySerializer
|
from funkwhale_api.users.serializers import UserActivitySerializer
|
||||||
|
from funkwhale_api.music.serializers import TrackActivitySerializer
|
||||||
from funkwhale_api.favorites import serializers
|
from funkwhale_api.favorites import serializers
|
||||||
from funkwhale_api.favorites import activities
|
from funkwhale_api.favorites import activities
|
||||||
|
|
||||||
|
@ -18,9 +19,10 @@ def test_activity_favorite_serializer(factories):
|
||||||
field = serializers.serializers.DateTimeField()
|
field = serializers.serializers.DateTimeField()
|
||||||
expected = {
|
expected = {
|
||||||
"type": "Like",
|
"type": "Like",
|
||||||
|
"local_id": favorite.pk,
|
||||||
"id": favorite.get_activity_url(),
|
"id": favorite.get_activity_url(),
|
||||||
"actor": actor,
|
"actor": actor,
|
||||||
"object": favorite.track.get_activity_url(),
|
"object": TrackActivitySerializer(favorite.track).data,
|
||||||
"published": field.to_representation(favorite.creation_date),
|
"published": field.to_representation(favorite.creation_date),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +50,8 @@ def test_broadcast_track_favorite_to_instance_activity(
|
||||||
data = serializers.TrackFavoriteActivitySerializer(favorite).data
|
data = serializers.TrackFavoriteActivitySerializer(favorite).data
|
||||||
consumer = activities.broadcast_track_favorite_to_instance_activity
|
consumer = activities.broadcast_track_favorite_to_instance_activity
|
||||||
message = {
|
message = {
|
||||||
"type": 'event',
|
"type": 'event.send',
|
||||||
|
"text": '',
|
||||||
"data": data
|
"data": data
|
||||||
}
|
}
|
||||||
consumer(data=data, obj=favorite)
|
consumer(data=data, obj=favorite)
|
||||||
|
@ -64,7 +67,8 @@ def test_broadcast_track_favorite_to_instance_activity_private(
|
||||||
data = serializers.TrackFavoriteActivitySerializer(favorite).data
|
data = serializers.TrackFavoriteActivitySerializer(favorite).data
|
||||||
consumer = activities.broadcast_track_favorite_to_instance_activity
|
consumer = activities.broadcast_track_favorite_to_instance_activity
|
||||||
message = {
|
message = {
|
||||||
"type": 'event',
|
"type": 'event.send',
|
||||||
|
"text": '',
|
||||||
"data": data
|
"data": data
|
||||||
}
|
}
|
||||||
consumer(data=data, obj=favorite)
|
consumer(data=data, obj=favorite)
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
from funkwhale_api.users.serializers import UserActivitySerializer
|
||||||
|
from funkwhale_api.music.serializers import TrackActivitySerializer
|
||||||
|
from funkwhale_api.history import serializers
|
||||||
|
from funkwhale_api.history import activities
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_listening_activity_url(settings, factories):
|
||||||
|
listening = factories['history.Listening']()
|
||||||
|
user_url = listening.user.get_activity_url()
|
||||||
|
expected = '{}/listenings/tracks/{}'.format(
|
||||||
|
user_url, listening.pk)
|
||||||
|
assert listening.get_activity_url() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_activity_listening_serializer(factories):
|
||||||
|
listening = factories['history.Listening']()
|
||||||
|
|
||||||
|
actor = UserActivitySerializer(listening.user).data
|
||||||
|
field = serializers.serializers.DateTimeField()
|
||||||
|
expected = {
|
||||||
|
"type": "Listen",
|
||||||
|
"local_id": listening.pk,
|
||||||
|
"id": listening.get_activity_url(),
|
||||||
|
"actor": actor,
|
||||||
|
"object": TrackActivitySerializer(listening.track).data,
|
||||||
|
"published": field.to_representation(listening.end_date),
|
||||||
|
}
|
||||||
|
|
||||||
|
data = serializers.ListeningActivitySerializer(listening).data
|
||||||
|
|
||||||
|
assert data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_track_listening_serializer_is_connected(activity_registry):
|
||||||
|
conf = activity_registry['history.Listening']
|
||||||
|
assert conf['serializer'] == serializers.ListeningActivitySerializer
|
||||||
|
|
||||||
|
|
||||||
|
def test_track_listening_serializer_instance_activity_consumer(
|
||||||
|
activity_registry):
|
||||||
|
conf = activity_registry['history.Listening']
|
||||||
|
consumer = activities.broadcast_listening_to_instance_activity
|
||||||
|
assert consumer in conf['consumers']
|
||||||
|
|
||||||
|
|
||||||
|
def test_broadcast_listening_to_instance_activity(
|
||||||
|
factories, mocker):
|
||||||
|
p = mocker.patch('funkwhale_api.common.channels.group_send')
|
||||||
|
listening = factories['history.Listening']()
|
||||||
|
data = serializers.ListeningActivitySerializer(listening).data
|
||||||
|
consumer = activities.broadcast_listening_to_instance_activity
|
||||||
|
message = {
|
||||||
|
"type": 'event.send',
|
||||||
|
"text": '',
|
||||||
|
"data": data
|
||||||
|
}
|
||||||
|
consumer(data=data, obj=listening)
|
||||||
|
p.assert_called_once_with('instance_activity', message)
|
||||||
|
|
||||||
|
|
||||||
|
def test_broadcast_listening_to_instance_activity_private(
|
||||||
|
factories, mocker):
|
||||||
|
p = mocker.patch('funkwhale_api.common.channels.group_send')
|
||||||
|
listening = factories['history.Listening'](
|
||||||
|
user__privacy_level='me'
|
||||||
|
)
|
||||||
|
data = serializers.ListeningActivitySerializer(listening).data
|
||||||
|
consumer = activities.broadcast_listening_to_instance_activity
|
||||||
|
message = {
|
||||||
|
"type": 'event.send',
|
||||||
|
"text": '',
|
||||||
|
"data": data
|
||||||
|
}
|
||||||
|
consumer(data=data, obj=listening)
|
||||||
|
p.assert_not_called()
|
|
@ -28,7 +28,8 @@ def test_anonymous_user_can_create_listening_via_api(client, factories, settings
|
||||||
assert listening.session_key == client.session.session_key
|
assert listening.session_key == client.session.session_key
|
||||||
|
|
||||||
|
|
||||||
def test_logged_in_user_can_create_listening_via_api(logged_in_client, factories):
|
def test_logged_in_user_can_create_listening_via_api(
|
||||||
|
logged_in_client, factories, activity_muted):
|
||||||
track = factories['music.Track']()
|
track = factories['music.Track']()
|
||||||
|
|
||||||
url = reverse('api:v1:history:listenings-list')
|
url = reverse('api:v1:history:listenings-list')
|
||||||
|
@ -40,3 +41,17 @@ def test_logged_in_user_can_create_listening_via_api(logged_in_client, factories
|
||||||
|
|
||||||
assert listening.track == track
|
assert listening.track == track
|
||||||
assert listening.user == logged_in_client.user
|
assert listening.user == logged_in_client.user
|
||||||
|
|
||||||
|
|
||||||
|
def test_adding_listening_calls_activity_record(
|
||||||
|
factories, logged_in_client, activity_muted):
|
||||||
|
track = factories['music.Track']()
|
||||||
|
|
||||||
|
url = reverse('api:v1:history:listenings-list')
|
||||||
|
response = logged_in_client.post(url, {
|
||||||
|
'track': track.pk,
|
||||||
|
})
|
||||||
|
|
||||||
|
listening = models.Listening.objects.latest('id')
|
||||||
|
|
||||||
|
activity_muted.assert_called_once_with(listening)
|
|
@ -13,6 +13,7 @@ def test_activity_user_serializer(factories):
|
||||||
expected = {
|
expected = {
|
||||||
"type": "Person",
|
"type": "Person",
|
||||||
"id": user.get_activity_url(),
|
"id": user.get_activity_url(),
|
||||||
|
"local_id": user.username,
|
||||||
"name": user.username,
|
"name": user.username,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue