From 8d55040e9e2dc61ad3fc0d965ea333c8a8cfcc95 Mon Sep 17 00:00:00 2001 From: Eliot Berriot <contact@eliotberriot.com> Date: Thu, 24 May 2018 22:39:32 +0200 Subject: [PATCH] See #230: users with upload permission can now launch import and manage their own imports --- api/funkwhale_api/music/views.py | 24 +++++++++++++++-- api/tests/music/test_views.py | 34 ++++++++++++++++++++---- front/src/components/Sidebar.vue | 9 ++++++- front/src/components/library/Library.vue | 10 ++++--- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index aa07ad52..d8b173b4 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -91,12 +91,21 @@ class ImportBatchViewSet( ) serializer_class = serializers.ImportBatchSerializer permission_classes = (HasUserPermission,) - required_permissions = ['library'] + required_permissions = ['library', 'upload'] + permission_operator = 'or' filter_class = filters.ImportBatchFilter def perform_create(self, serializer): serializer.save(submitted_by=self.request.user) + def get_queryset(self): + qs = super().get_queryset() + # if user do not have library permission, we limit to their + # own jobs + if not self.request.user.has_permissions('library'): + qs = qs.filter(submitted_by=self.request.user) + return qs + class ImportJobViewSet( mixins.CreateModelMixin, @@ -105,11 +114,22 @@ class ImportJobViewSet( queryset = (models.ImportJob.objects.all().select_related()) serializer_class = serializers.ImportJobSerializer permission_classes = (HasUserPermission,) - required_permissions = ['library'] + required_permissions = ['library', 'upload'] + permission_operator = 'or' filter_class = filters.ImportJobFilter + def get_queryset(self): + qs = super().get_queryset() + # if user do not have library permission, we limit to their + # own jobs + if not self.request.user.has_permissions('library'): + qs = qs.filter(batch__submitted_by=self.request.user) + return qs + @list_route(methods=['get']) def stats(self, request, *args, **kwargs): + if not request.user.has_permissions('library'): + return Response(status=403) qs = models.ImportJob.objects.all() filterset = filters.ImportJobFilter(request.GET, queryset=qs) qs = filterset.qs diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py index 9328ba32..1fe11383 100644 --- a/api/tests/music/test_views.py +++ b/api/tests/music/test_views.py @@ -9,12 +9,12 @@ from funkwhale_api.music import views from funkwhale_api.federation import actors -@pytest.mark.parametrize('view,permissions', [ - (views.ImportBatchViewSet, ['library']), - (views.ImportJobViewSet, ['library']), +@pytest.mark.parametrize('view,permissions,operator', [ + (views.ImportBatchViewSet, ['library', 'upload'], 'or'), + (views.ImportJobViewSet, ['library', 'upload'], 'or'), ]) -def test_permissions(assert_user_permission, view, permissions): - assert_user_permission(view, permissions) +def test_permissions(assert_user_permission, view, permissions, operator): + assert_user_permission(view, permissions, operator) def test_artist_list_serializer(api_request, factories, logged_in_api_client): @@ -351,3 +351,27 @@ def test_import_batch_and_job_run_via_api( run.assert_any_call(import_job_id=job1.pk) run.assert_any_call(import_job_id=job2.pk) + + +def test_import_job_viewset_get_queryset_upload_filters_user( + factories, logged_in_api_client): + logged_in_api_client.user.permission_upload = True + logged_in_api_client.user.save() + + job = factories['music.ImportJob']() + url = reverse('api:v1:import-jobs-list') + response = logged_in_api_client.get(url) + + assert response.data['count'] == 0 + + +def test_import_batch_viewset_get_queryset_upload_filters_user( + factories, logged_in_api_client): + logged_in_api_client.user.permission_upload = True + logged_in_api_client.user.save() + + job = factories['music.ImportBatch']() + url = reverse('api:v1:import-batches-list') + response = logged_in_api_client.get(url) + + assert response.data['count'] == 0 diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue index 9f3134c2..e8f330c3 100644 --- a/front/src/components/Sidebar.vue +++ b/front/src/components/Sidebar.vue @@ -68,6 +68,12 @@ :title="$t('Pending import requests')"> {{ notifications.importRequests }}</div> </router-link> + <router-link + class="item" + v-else-if="$store.state.auth.availablePermissions['upload']" + to="/library/import/launch"> + <i class="download icon"></i>{{ $t('Import music') }} + </router-link> <router-link class="item" v-if="$store.state.auth.availablePermissions['federation']" @@ -193,7 +199,8 @@ export default { showAdmin () { let adminPermissions = [ this.$store.state.auth.availablePermissions['federation'], - this.$store.state.auth.availablePermissions['library'] + this.$store.state.auth.availablePermissions['library'], + this.$store.state.auth.availablePermissions['upload'] ] return adminPermissions.filter(e => { return e diff --git a/front/src/components/library/Library.vue b/front/src/components/library/Library.vue index e360ccb1..50337b22 100644 --- a/front/src/components/library/Library.vue +++ b/front/src/components/library/Library.vue @@ -13,10 +13,10 @@ exact> <i18next path="Requests"/> </router-link> - <router-link v-if="$store.state.auth.availablePermissions['library']" class="ui item" to="/library/import/launch" exact> + <router-link v-if="showImports" class="ui item" to="/library/import/launch" exact> <i18next path="Import"/> </router-link> - <router-link v-if="$store.state.auth.availablePermissions['library']" class="ui item" to="/library/import/batches"> + <router-link v-if="showImports" class="ui item" to="/library/import/batches"> <i18next path="Import batches"/> </router-link> </div> @@ -27,7 +27,11 @@ <script> export default { - name: 'library' + computed: { + showImports () { + return this.$store.state.auth.availablePermissions['upload'] || this.$store.state.auth.availablePermissions['library'] + } + } } </script> -- GitLab