See #890: expose number of reports linked to tracks, albums, libraries, accounts and artists via the /stats route
This commit is contained in:
parent
d4deb830c0
commit
9552b49a46
|
@ -73,7 +73,7 @@ class LocalFromFidQuerySet:
|
||||||
return self.filter(~query)
|
return self.filter(~query)
|
||||||
|
|
||||||
|
|
||||||
class MutationQuerySet(models.QuerySet):
|
class GenericTargetQuerySet(models.QuerySet):
|
||||||
def get_for_target(self, target):
|
def get_for_target(self, target):
|
||||||
content_type = ContentType.objects.get_for_model(target)
|
content_type = ContentType.objects.get_for_model(target)
|
||||||
return self.filter(target_content_type=content_type, target_id=target.pk)
|
return self.filter(target_content_type=content_type, target_id=target.pk)
|
||||||
|
@ -119,7 +119,7 @@ class Mutation(models.Model):
|
||||||
)
|
)
|
||||||
target = GenericForeignKey("target_content_type", "target_id")
|
target = GenericForeignKey("target_content_type", "target_id")
|
||||||
|
|
||||||
objects = MutationQuerySet.as_manager()
|
objects = GenericTargetQuerySet.as_manager()
|
||||||
|
|
||||||
def get_federation_id(self):
|
def get_federation_id(self):
|
||||||
if self.fid:
|
if self.fid:
|
||||||
|
|
|
@ -248,6 +248,7 @@ class Actor(models.Model):
|
||||||
|
|
||||||
def get_stats(self):
|
def get_stats(self):
|
||||||
from funkwhale_api.music import models as music_models
|
from funkwhale_api.music import models as music_models
|
||||||
|
from funkwhale_api.moderation import models as moderation_models
|
||||||
|
|
||||||
data = Actor.objects.filter(pk=self.pk).aggregate(
|
data = Actor.objects.filter(pk=self.pk).aggregate(
|
||||||
outbox_activities=models.Count("outbox_activities", distinct=True),
|
outbox_activities=models.Count("outbox_activities", distinct=True),
|
||||||
|
@ -260,6 +261,7 @@ class Actor(models.Model):
|
||||||
data["artists"] = music_models.Artist.objects.filter(
|
data["artists"] = music_models.Artist.objects.filter(
|
||||||
from_activity__actor=self.pk
|
from_activity__actor=self.pk
|
||||||
).count()
|
).count()
|
||||||
|
data["reports"] = moderation_models.Report.objects.get_for_target(self).count()
|
||||||
data["albums"] = music_models.Album.objects.filter(
|
data["albums"] = music_models.Album.objects.filter(
|
||||||
from_activity__actor=self.pk
|
from_activity__actor=self.pk
|
||||||
).count()
|
).count()
|
||||||
|
|
|
@ -41,6 +41,7 @@ def get_stats(tracks, target):
|
||||||
).count()
|
).count()
|
||||||
data["libraries"] = uploads.values_list("library", flat=True).distinct().count()
|
data["libraries"] = uploads.values_list("library", flat=True).distinct().count()
|
||||||
data["uploads"] = uploads.count()
|
data["uploads"] = uploads.count()
|
||||||
|
data["reports"] = moderation_models.Report.objects.get_for_target(target).count()
|
||||||
data.update(get_media_stats(uploads))
|
data.update(get_media_stats(uploads))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -248,6 +249,7 @@ class ManageLibraryViewSet(
|
||||||
"tracks": tracks.count(),
|
"tracks": tracks.count(),
|
||||||
"albums": albums.count(),
|
"albums": albums.count(),
|
||||||
"artists": len(artists),
|
"artists": len(artists),
|
||||||
|
"reports": moderation_models.Report.objects.get_for_target(library).count(),
|
||||||
}
|
}
|
||||||
data.update(get_media_stats(uploads.all()))
|
data.update(get_media_stats(uploads.all()))
|
||||||
return response.Response(data, status=200)
|
return response.Response(data, status=200)
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.dispatch import receiver
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from funkwhale_api.common import models as common_models
|
||||||
from funkwhale_api.federation import models as federation_models
|
from funkwhale_api.federation import models as federation_models
|
||||||
from funkwhale_api.federation import utils as federation_utils
|
from funkwhale_api.federation import utils as federation_utils
|
||||||
|
|
||||||
|
@ -152,6 +153,8 @@ class Report(federation_models.FederationMixin):
|
||||||
"Note", content_type_field="target_content_type", object_id_field="target_id"
|
"Note", content_type_field="target_content_type", object_id_field="target_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = common_models.GenericTargetQuerySet.as_manager()
|
||||||
|
|
||||||
def get_federation_id(self):
|
def get_federation_id(self):
|
||||||
if self.fid:
|
if self.fid:
|
||||||
return self.fid
|
return self.fid
|
||||||
|
|
|
@ -124,6 +124,7 @@ def test_actor_stats(factories):
|
||||||
"albums": 0,
|
"albums": 0,
|
||||||
"uploads": 0,
|
"uploads": 0,
|
||||||
"artists": 0,
|
"artists": 0,
|
||||||
|
"reports": 0,
|
||||||
"outbox_activities": 0,
|
"outbox_activities": 0,
|
||||||
"received_library_follows": 0,
|
"received_library_follows": 0,
|
||||||
"emitted_library_follows": 0,
|
"emitted_library_follows": 0,
|
||||||
|
|
|
@ -189,6 +189,7 @@ def test_artist_detail_stats(factories, superuser_api_client):
|
||||||
"listenings": 0,
|
"listenings": 0,
|
||||||
"playlists": 0,
|
"playlists": 0,
|
||||||
"mutations": 0,
|
"mutations": 0,
|
||||||
|
"reports": 0,
|
||||||
"track_favorites": 0,
|
"track_favorites": 0,
|
||||||
"media_total_size": 0,
|
"media_total_size": 0,
|
||||||
"media_downloaded_size": 0,
|
"media_downloaded_size": 0,
|
||||||
|
@ -238,6 +239,7 @@ def test_album_detail_stats(factories, superuser_api_client):
|
||||||
"listenings": 0,
|
"listenings": 0,
|
||||||
"playlists": 0,
|
"playlists": 0,
|
||||||
"mutations": 0,
|
"mutations": 0,
|
||||||
|
"reports": 0,
|
||||||
"track_favorites": 0,
|
"track_favorites": 0,
|
||||||
"media_total_size": 0,
|
"media_total_size": 0,
|
||||||
"media_downloaded_size": 0,
|
"media_downloaded_size": 0,
|
||||||
|
@ -284,6 +286,7 @@ def test_track_detail_stats(factories, superuser_api_client):
|
||||||
"listenings": 0,
|
"listenings": 0,
|
||||||
"playlists": 0,
|
"playlists": 0,
|
||||||
"mutations": 0,
|
"mutations": 0,
|
||||||
|
"reports": 0,
|
||||||
"track_favorites": 0,
|
"track_favorites": 0,
|
||||||
"media_total_size": 0,
|
"media_total_size": 0,
|
||||||
"media_downloaded_size": 0,
|
"media_downloaded_size": 0,
|
||||||
|
@ -346,6 +349,7 @@ def test_library_detail_stats(factories, superuser_api_client):
|
||||||
"tracks": 0,
|
"tracks": 0,
|
||||||
"albums": 0,
|
"albums": 0,
|
||||||
"artists": 0,
|
"artists": 0,
|
||||||
|
"reports": 0,
|
||||||
"media_total_size": 0,
|
"media_total_size": 0,
|
||||||
"media_downloaded_size": 0,
|
"media_downloaded_size": 0,
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,16 @@
|
||||||
{{ stats.playlists }}
|
{{ stats.playlists }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<router-link :to="{name: 'manage.moderation.reports.list', query: {q: getQuery('target', `album:${object.id}`) }}">
|
||||||
|
<translate translate-context="Content/Moderation/Table.Label/Noun">Linked reports</translate>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ stats.reports }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="{name: 'manage.library.edits', query: {q: getQuery('target', 'album ' + object.id)}}">
|
<router-link :to="{name: 'manage.library.edits', query: {q: getQuery('target', 'album ' + object.id)}}">
|
||||||
|
|
|
@ -171,6 +171,16 @@
|
||||||
{{ stats.playlists }}
|
{{ stats.playlists }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<router-link :to="{name: 'manage.moderation.reports.list', query: {q: getQuery('target', `artist:${object.id}`) }}">
|
||||||
|
<translate translate-context="Content/Moderation/Table.Label/Noun">Linked reports</translate>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ stats.reports }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="{name: 'manage.library.edits', query: {q: getQuery('target', 'artist ' + object.id)}}">
|
<router-link :to="{name: 'manage.library.edits', query: {q: getQuery('target', 'artist ' + object.id)}}">
|
||||||
|
|
|
@ -174,6 +174,16 @@
|
||||||
{{ stats.followers }}
|
{{ stats.followers }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<router-link :to="{name: 'manage.moderation.reports.list', query: {q: getQuery('target', `library:${object.uuid}`) }}">
|
||||||
|
<translate translate-context="Content/Moderation/Table.Label/Noun">Linked reports</translate>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ stats.reports }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -235,6 +235,16 @@
|
||||||
{{ stats.playlists }}
|
{{ stats.playlists }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<router-link :to="{name: 'manage.moderation.reports.list', query: {q: getQuery('target', `track:${object.id}`) }}">
|
||||||
|
<translate translate-context="Content/Moderation/Table.Label/Noun">Linked reports</translate>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ stats.reports }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="{name: 'manage.library.edits', query: {q: getQuery('target', 'track ' + object.id)}}">
|
<router-link :to="{name: 'manage.library.edits', query: {q: getQuery('target', 'track ' + object.id)}}">
|
||||||
|
|
|
@ -264,6 +264,16 @@
|
||||||
{{ stats.emitted_library_follows}}
|
{{ stats.emitted_library_follows}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<router-link :to="{name: 'manage.moderation.reports.list', query: {q: getQuery('target', `account:${object.full_username}`) }}">
|
||||||
|
<translate translate-context="Content/Moderation/Table.Label/Noun">Linked reports</translate>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ stats.reports }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -57,6 +57,15 @@
|
||||||
<div v-else-if="mode === 'card'">
|
<div v-else-if="mode === 'card'">
|
||||||
<report-card @handled="fetchData" :obj="obj" v-for="obj in result.results" :key="obj.uuid" />
|
<report-card @handled="fetchData" :obj="obj" v-for="obj in result.results" :key="obj.uuid" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ui center aligned basic segment">
|
||||||
|
<pagination
|
||||||
|
v-if="result && result.count > paginateBy"
|
||||||
|
@page-changed="selectPage"
|
||||||
|
:current="page"
|
||||||
|
:paginate-by="paginateBy"
|
||||||
|
:total="result.count"
|
||||||
|
></pagination>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue