See #230: users with upload permission can now launch import and manage their own imports
This commit is contained in:
parent
dfb4f5f62a
commit
8d55040e9e
|
@ -91,12 +91,21 @@ class ImportBatchViewSet(
|
||||||
)
|
)
|
||||||
serializer_class = serializers.ImportBatchSerializer
|
serializer_class = serializers.ImportBatchSerializer
|
||||||
permission_classes = (HasUserPermission,)
|
permission_classes = (HasUserPermission,)
|
||||||
required_permissions = ['library']
|
required_permissions = ['library', 'upload']
|
||||||
|
permission_operator = 'or'
|
||||||
filter_class = filters.ImportBatchFilter
|
filter_class = filters.ImportBatchFilter
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
serializer.save(submitted_by=self.request.user)
|
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(
|
class ImportJobViewSet(
|
||||||
mixins.CreateModelMixin,
|
mixins.CreateModelMixin,
|
||||||
|
@ -105,11 +114,22 @@ class ImportJobViewSet(
|
||||||
queryset = (models.ImportJob.objects.all().select_related())
|
queryset = (models.ImportJob.objects.all().select_related())
|
||||||
serializer_class = serializers.ImportJobSerializer
|
serializer_class = serializers.ImportJobSerializer
|
||||||
permission_classes = (HasUserPermission,)
|
permission_classes = (HasUserPermission,)
|
||||||
required_permissions = ['library']
|
required_permissions = ['library', 'upload']
|
||||||
|
permission_operator = 'or'
|
||||||
filter_class = filters.ImportJobFilter
|
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'])
|
@list_route(methods=['get'])
|
||||||
def stats(self, request, *args, **kwargs):
|
def stats(self, request, *args, **kwargs):
|
||||||
|
if not request.user.has_permissions('library'):
|
||||||
|
return Response(status=403)
|
||||||
qs = models.ImportJob.objects.all()
|
qs = models.ImportJob.objects.all()
|
||||||
filterset = filters.ImportJobFilter(request.GET, queryset=qs)
|
filterset = filters.ImportJobFilter(request.GET, queryset=qs)
|
||||||
qs = filterset.qs
|
qs = filterset.qs
|
||||||
|
|
|
@ -9,12 +9,12 @@ from funkwhale_api.music import views
|
||||||
from funkwhale_api.federation import actors
|
from funkwhale_api.federation import actors
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('view,permissions', [
|
@pytest.mark.parametrize('view,permissions,operator', [
|
||||||
(views.ImportBatchViewSet, ['library']),
|
(views.ImportBatchViewSet, ['library', 'upload'], 'or'),
|
||||||
(views.ImportJobViewSet, ['library']),
|
(views.ImportJobViewSet, ['library', 'upload'], 'or'),
|
||||||
])
|
])
|
||||||
def test_permissions(assert_user_permission, view, permissions):
|
def test_permissions(assert_user_permission, view, permissions, operator):
|
||||||
assert_user_permission(view, permissions)
|
assert_user_permission(view, permissions, operator)
|
||||||
|
|
||||||
|
|
||||||
def test_artist_list_serializer(api_request, factories, logged_in_api_client):
|
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=job1.pk)
|
||||||
run.assert_any_call(import_job_id=job2.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
|
||||||
|
|
|
@ -68,6 +68,12 @@
|
||||||
:title="$t('Pending import requests')">
|
:title="$t('Pending import requests')">
|
||||||
{{ notifications.importRequests }}</div>
|
{{ notifications.importRequests }}</div>
|
||||||
</router-link>
|
</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
|
<router-link
|
||||||
class="item"
|
class="item"
|
||||||
v-if="$store.state.auth.availablePermissions['federation']"
|
v-if="$store.state.auth.availablePermissions['federation']"
|
||||||
|
@ -193,7 +199,8 @@ export default {
|
||||||
showAdmin () {
|
showAdmin () {
|
||||||
let adminPermissions = [
|
let adminPermissions = [
|
||||||
this.$store.state.auth.availablePermissions['federation'],
|
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 adminPermissions.filter(e => {
|
||||||
return e
|
return e
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
exact>
|
exact>
|
||||||
<i18next path="Requests"/>
|
<i18next path="Requests"/>
|
||||||
</router-link>
|
</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"/>
|
<i18next path="Import"/>
|
||||||
</router-link>
|
</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"/>
|
<i18next path="Import batches"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +27,11 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'library'
|
computed: {
|
||||||
|
showImports () {
|
||||||
|
return this.$store.state.auth.availablePermissions['upload'] || this.$store.state.auth.availablePermissions['library']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue