diff --git a/api/funkwhale_api/instance/stats.py b/api/funkwhale_api/instance/stats.py new file mode 100644 index 000000000..167b333d6 --- /dev/null +++ b/api/funkwhale_api/instance/stats.py @@ -0,0 +1,51 @@ +from django.db.models import Sum + +from funkwhale_api.favorites.models import TrackFavorite +from funkwhale_api.history.models import Listening +from funkwhale_api.music import models +from funkwhale_api.users.models import User + + +def get(): + return { + 'users': get_users(), + 'tracks': get_tracks(), + 'albums': get_albums(), + 'artists': get_artists(), + 'track_favorites': get_track_favorites(), + 'listenings': get_listenings(), + 'music_duration': get_music_duration(), + } + + +def get_users(): + return User.objects.count() + + +def get_listenings(): + return Listening.objects.count() + + +def get_track_favorites(): + return TrackFavorite.objects.count() + + +def get_tracks(): + return models.Track.objects.count() + + +def get_albums(): + return models.Album.objects.count() + + +def get_artists(): + return models.Artist.objects.count() + + +def get_music_duration(): + seconds = models.TrackFile.objects.aggregate( + d=Sum('duration'), + )['d'] + if seconds: + return seconds / 3600 + return 0 diff --git a/api/funkwhale_api/instance/urls.py b/api/funkwhale_api/instance/urls.py index 2f2b46b87..af23e7e08 100644 --- a/api/funkwhale_api/instance/urls.py +++ b/api/funkwhale_api/instance/urls.py @@ -1,7 +1,11 @@ from django.conf.urls import url +from django.views.decorators.cache import cache_page + from . import views urlpatterns = [ url(r'^settings/$', views.InstanceSettings.as_view(), name='settings'), + url(r'^stats/$', + cache_page(60 * 5)(views.InstanceStats.as_view()), name='stats'), ] diff --git a/api/funkwhale_api/instance/views.py b/api/funkwhale_api/instance/views.py index 44ee22873..7f8f393c9 100644 --- a/api/funkwhale_api/instance/views.py +++ b/api/funkwhale_api/instance/views.py @@ -4,6 +4,8 @@ from rest_framework.response import Response from dynamic_preferences.api import serializers from dynamic_preferences.registries import global_preferences_registry +from . import stats + class InstanceSettings(views.APIView): permission_classes = [] @@ -23,3 +25,12 @@ class InstanceSettings(views.APIView): data = serializers.GlobalPreferenceSerializer( api_preferences, many=True).data return Response(data, status=200) + + +class InstanceStats(views.APIView): + permission_classes = [] + authentication_classes = [] + + def get(self, request, *args, **kwargs): + data = stats.get() + return Response(data, status=200) diff --git a/api/tests/instance/test_stats.py b/api/tests/instance/test_stats.py new file mode 100644 index 000000000..6eaad76f7 --- /dev/null +++ b/api/tests/instance/test_stats.py @@ -0,0 +1,84 @@ +from django.urls import reverse + +from funkwhale_api.instance import stats + + +def test_can_get_stats_via_api(db, api_client, mocker): + stats = { + 'foo': 'bar' + } + mocker.patch('funkwhale_api.instance.stats.get', return_value=stats) + url = reverse('api:v1:instance:stats') + response = api_client.get(url) + assert response.data == stats + + +def test_get_users(mocker): + mocker.patch( + 'funkwhale_api.users.models.User.objects.count', return_value=42) + + assert stats.get_users() == 42 + + +def test_get_music_duration(factories): + factories['music.TrackFile'].create_batch(size=5, duration=360) + + # duration is in hours + assert stats.get_music_duration() == 0.5 + + +def test_get_listenings(mocker): + mocker.patch( + 'funkwhale_api.history.models.Listening.objects.count', + return_value=42) + assert stats.get_listenings() == 42 + + +def test_get_track_favorites(mocker): + mocker.patch( + 'funkwhale_api.favorites.models.TrackFavorite.objects.count', + return_value=42) + assert stats.get_track_favorites() == 42 + + +def test_get_tracks(mocker): + mocker.patch( + 'funkwhale_api.music.models.Track.objects.count', + return_value=42) + assert stats.get_tracks() == 42 + + +def test_get_albums(mocker): + mocker.patch( + 'funkwhale_api.music.models.Album.objects.count', + return_value=42) + assert stats.get_albums() == 42 + + +def test_get_artists(mocker): + mocker.patch( + 'funkwhale_api.music.models.Artist.objects.count', + return_value=42) + assert stats.get_artists() == 42 + + +def test_get(mocker): + keys = [ + 'users', + 'tracks', + 'albums', + 'artists', + 'track_favorites', + 'listenings', + 'music_duration', + ] + mocks = [ + mocker.patch.object(stats, 'get_{}'.format(k), return_value=i) + for i, k in enumerate(keys) + ] + + expected = { + k: i for i, k in enumerate(keys) + } + + assert stats.get() == expected diff --git a/changes/changelog.d/82.feature b/changes/changelog.d/82.feature new file mode 100644 index 000000000..e69de29bb diff --git a/front/src/components/About.vue b/front/src/components/About.vue index 01ce6a294..92bafd7af 100644 --- a/front/src/components/About.vue +++ b/front/src/components/About.vue @@ -6,6 +6,7 @@ +
@@ -27,8 +28,12 @@ + + +