See #542: Removed import requests code
This commit is contained in:
parent
42933fa138
commit
62c98b2386
|
@ -65,10 +65,6 @@ v1_patterns += [
|
|||
r"^users/",
|
||||
include(("funkwhale_api.users.api_urls", "users"), namespace="users"),
|
||||
),
|
||||
url(
|
||||
r"^requests/",
|
||||
include(("funkwhale_api.requests.api_urls", "requests"), namespace="requests"),
|
||||
),
|
||||
url(r"^token/$", jwt_views.obtain_jwt_token, name="token"),
|
||||
url(r"^token/refresh/$", jwt_views.refresh_jwt_token, name="token_refresh"),
|
||||
]
|
||||
|
|
|
@ -2,7 +2,6 @@ from django_filters import rest_framework as filters
|
|||
|
||||
from funkwhale_api.common import fields
|
||||
from funkwhale_api.music import models as music_models
|
||||
from funkwhale_api.requests import models as requests_models
|
||||
from funkwhale_api.users import models as users_models
|
||||
|
||||
|
||||
|
@ -51,13 +50,3 @@ class ManageInvitationFilterSet(filters.FilterSet):
|
|||
if value is None:
|
||||
return queryset
|
||||
return queryset.open(value)
|
||||
|
||||
|
||||
class ManageImportRequestFilterSet(filters.FilterSet):
|
||||
q = fields.SearchFilter(
|
||||
search_fields=["user__username", "albums", "artist_name", "comment"]
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = requests_models.ImportRequest
|
||||
fields = ["q", "status"]
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from funkwhale_api.common import serializers as common_serializers
|
||||
from funkwhale_api.music import models as music_models
|
||||
from funkwhale_api.requests import models as requests_models
|
||||
from funkwhale_api.users import models as users_models
|
||||
|
||||
from . import filters
|
||||
|
@ -169,69 +168,3 @@ class ManageInvitationActionSerializer(common_serializers.ActionSerializer):
|
|||
@transaction.atomic
|
||||
def handle_delete(self, objects):
|
||||
return objects.delete()
|
||||
|
||||
|
||||
class ManageImportRequestSerializer(serializers.ModelSerializer):
|
||||
user = ManageUserSimpleSerializer(required=False)
|
||||
|
||||
class Meta:
|
||||
model = requests_models.ImportRequest
|
||||
fields = [
|
||||
"id",
|
||||
"status",
|
||||
"creation_date",
|
||||
"imported_date",
|
||||
"user",
|
||||
"albums",
|
||||
"artist_name",
|
||||
"comment",
|
||||
]
|
||||
read_only_fields = [
|
||||
"id",
|
||||
"status",
|
||||
"creation_date",
|
||||
"imported_date",
|
||||
"user",
|
||||
"albums",
|
||||
"artist_name",
|
||||
"comment",
|
||||
]
|
||||
|
||||
def validate_code(self, value):
|
||||
if not value:
|
||||
return value
|
||||
if users_models.Invitation.objects.filter(code__iexact=value).exists():
|
||||
raise serializers.ValidationError(
|
||||
"An invitation with this code already exists"
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
class ManageImportRequestActionSerializer(common_serializers.ActionSerializer):
|
||||
actions = [
|
||||
common_serializers.Action(
|
||||
"mark_closed",
|
||||
allow_all=True,
|
||||
qs_filter=lambda qs: qs.filter(status__in=["pending", "accepted"]),
|
||||
),
|
||||
common_serializers.Action(
|
||||
"mark_imported",
|
||||
allow_all=True,
|
||||
qs_filter=lambda qs: qs.filter(status__in=["pending", "accepted"]),
|
||||
),
|
||||
common_serializers.Action("delete", allow_all=False),
|
||||
]
|
||||
filterset_class = filters.ManageImportRequestFilterSet
|
||||
|
||||
@transaction.atomic
|
||||
def handle_delete(self, objects):
|
||||
return objects.delete()
|
||||
|
||||
@transaction.atomic
|
||||
def handle_mark_closed(self, objects):
|
||||
return objects.update(status="closed")
|
||||
|
||||
@transaction.atomic
|
||||
def handle_mark_imported(self, objects):
|
||||
now = timezone.now()
|
||||
return objects.update(status="imported", imported_date=now)
|
||||
|
|
|
@ -5,10 +5,6 @@ from . import views
|
|||
|
||||
library_router = routers.SimpleRouter()
|
||||
library_router.register(r"uploads", views.ManageUploadViewSet, "uploads")
|
||||
requests_router = routers.SimpleRouter()
|
||||
requests_router.register(
|
||||
r"import-requests", views.ManageImportRequestViewSet, "import-requests"
|
||||
)
|
||||
users_router = routers.SimpleRouter()
|
||||
users_router.register(r"users", views.ManageUserViewSet, "users")
|
||||
users_router.register(r"invitations", views.ManageInvitationViewSet, "invitations")
|
||||
|
@ -16,7 +12,4 @@ users_router.register(r"invitations", views.ManageInvitationViewSet, "invitation
|
|||
urlpatterns = [
|
||||
url(r"^library/", include((library_router.urls, "instance"), namespace="library")),
|
||||
url(r"^users/", include((users_router.urls, "instance"), namespace="users")),
|
||||
url(
|
||||
r"^requests/", include((requests_router.urls, "instance"), namespace="requests")
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,6 @@ from rest_framework.decorators import list_route
|
|||
|
||||
from funkwhale_api.common import preferences
|
||||
from funkwhale_api.music import models as music_models
|
||||
from funkwhale_api.requests import models as requests_models
|
||||
from funkwhale_api.users import models as users_models
|
||||
from funkwhale_api.users.permissions import HasUserPermission
|
||||
|
||||
|
@ -93,31 +92,3 @@ class ManageInvitationViewSet(
|
|||
serializer.is_valid(raise_exception=True)
|
||||
result = serializer.save()
|
||||
return response.Response(result, status=200)
|
||||
|
||||
|
||||
class ManageImportRequestViewSet(
|
||||
mixins.ListModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
viewsets.GenericViewSet,
|
||||
):
|
||||
queryset = (
|
||||
requests_models.ImportRequest.objects.all()
|
||||
.order_by("-id")
|
||||
.select_related("user")
|
||||
)
|
||||
serializer_class = serializers.ManageImportRequestSerializer
|
||||
filter_class = filters.ManageImportRequestFilterSet
|
||||
permission_classes = (HasUserPermission,)
|
||||
required_permissions = ["library"]
|
||||
ordering_fields = ["creation_date", "imported_date"]
|
||||
|
||||
@list_route(methods=["post"])
|
||||
def action(self, request, *args, **kwargs):
|
||||
queryset = self.get_queryset()
|
||||
serializer = serializers.ManageImportRequestActionSerializer(
|
||||
request.data, queryset=queryset
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
result = serializer.save()
|
||||
return response.Response(result, status=200)
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
@admin.register(models.ImportRequest)
|
||||
class ImportRequestAdmin(admin.ModelAdmin):
|
||||
list_display = ["artist_name", "user", "status", "creation_date"]
|
||||
list_select_related = ["user"]
|
||||
list_filter = ["status"]
|
||||
search_fields = ["artist_name", "comment", "albums"]
|
|
@ -1,8 +0,0 @@
|
|||
from rest_framework import routers
|
||||
|
||||
from . import views
|
||||
|
||||
router = routers.SimpleRouter()
|
||||
router.register(r"import-requests", views.ImportRequestViewSet, "import-requests")
|
||||
|
||||
urlpatterns = router.urls
|
|
@ -1,15 +0,0 @@
|
|||
import factory
|
||||
|
||||
from funkwhale_api.factories import registry
|
||||
from funkwhale_api.users.factories import UserFactory
|
||||
|
||||
|
||||
@registry.register
|
||||
class ImportRequestFactory(factory.django.DjangoModelFactory):
|
||||
artist_name = factory.Faker("name")
|
||||
albums = factory.Faker("sentence")
|
||||
user = factory.SubFactory(UserFactory)
|
||||
comment = factory.Faker("paragraph")
|
||||
|
||||
class Meta:
|
||||
model = "requests.ImportRequest"
|
|
@ -1,20 +0,0 @@
|
|||
import django_filters
|
||||
|
||||
from funkwhale_api.common import fields
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
class ImportRequestFilter(django_filters.FilterSet):
|
||||
|
||||
q = fields.SearchFilter(
|
||||
search_fields=["artist_name", "user__username", "albums", "comment"]
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.ImportRequest
|
||||
fields = {
|
||||
"artist_name": ["exact", "iexact", "startswith", "icontains"],
|
||||
"status": ["exact"],
|
||||
"user__username": ["exact"],
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from funkwhale_api.users.serializers import UserBasicSerializer
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
class ImportRequestSerializer(serializers.ModelSerializer):
|
||||
user = UserBasicSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.ImportRequest
|
||||
fields = (
|
||||
"id",
|
||||
"status",
|
||||
"albums",
|
||||
"artist_name",
|
||||
"user",
|
||||
"creation_date",
|
||||
"imported_date",
|
||||
"comment",
|
||||
)
|
||||
read_only_fields = ("creation_date", "imported_date", "user", "status")
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data["user"] = self.context["user"]
|
||||
return super().create(validated_data)
|
|
@ -1,27 +0,0 @@
|
|||
from rest_framework import mixins, viewsets
|
||||
|
||||
from . import filters, models, serializers
|
||||
|
||||
|
||||
class ImportRequestViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
viewsets.GenericViewSet,
|
||||
):
|
||||
|
||||
serializer_class = serializers.ImportRequestSerializer
|
||||
queryset = (
|
||||
models.ImportRequest.objects.all().select_related().order_by("-creation_date")
|
||||
)
|
||||
filter_class = filters.ImportRequestFilter
|
||||
ordering_fields = ("id", "artist_name", "creation_date", "status")
|
||||
|
||||
def perform_create(self, serializer):
|
||||
return serializer.save(user=self.request.user)
|
||||
|
||||
def get_serializer_context(self):
|
||||
context = super().get_serializer_context()
|
||||
if self.request.user.is_authenticated:
|
||||
context["user"] = self.request.user
|
||||
return context
|
|
@ -36,44 +36,3 @@ def test_user_update_permission(factories):
|
|||
assert user.permission_upload is True
|
||||
assert user.permission_library is False
|
||||
assert user.permission_settings is True
|
||||
|
||||
|
||||
def test_manage_import_request_mark_closed(factories):
|
||||
affected = factories["requests.ImportRequest"].create_batch(
|
||||
size=5, status="pending"
|
||||
)
|
||||
# we do not update imported requests
|
||||
factories["requests.ImportRequest"].create_batch(size=5, status="imported")
|
||||
s = serializers.ManageImportRequestActionSerializer(
|
||||
queryset=affected[0].__class__.objects.all(),
|
||||
data={"objects": "all", "action": "mark_closed"},
|
||||
)
|
||||
|
||||
assert s.is_valid(raise_exception=True) is True
|
||||
s.save()
|
||||
|
||||
assert affected[0].__class__.objects.filter(status="imported").count() == 5
|
||||
for ir in affected:
|
||||
ir.refresh_from_db()
|
||||
assert ir.status == "closed"
|
||||
|
||||
|
||||
def test_manage_import_request_mark_imported(factories, now):
|
||||
affected = factories["requests.ImportRequest"].create_batch(
|
||||
size=5, status="pending"
|
||||
)
|
||||
# we do not update closed requests
|
||||
factories["requests.ImportRequest"].create_batch(size=5, status="closed")
|
||||
s = serializers.ManageImportRequestActionSerializer(
|
||||
queryset=affected[0].__class__.objects.all(),
|
||||
data={"objects": "all", "action": "mark_imported"},
|
||||
)
|
||||
|
||||
assert s.is_valid(raise_exception=True) is True
|
||||
s.save()
|
||||
|
||||
assert affected[0].__class__.objects.filter(status="closed").count() == 5
|
||||
for ir in affected:
|
||||
ir.refresh_from_db()
|
||||
assert ir.status == "imported"
|
||||
assert ir.imported_date == now
|
||||
|
|
|
@ -10,7 +10,6 @@ from funkwhale_api.manage import serializers, views
|
|||
(views.ManageUploadViewSet, ["library"], "and"),
|
||||
(views.ManageUserViewSet, ["settings"], "and"),
|
||||
(views.ManageInvitationViewSet, ["settings"], "and"),
|
||||
(views.ManageImportRequestViewSet, ["library"], "and"),
|
||||
],
|
||||
)
|
||||
def test_permissions(assert_user_permission, view, permissions, operator):
|
||||
|
@ -65,15 +64,3 @@ def test_invitation_view_create(factories, superuser_api_client, mocker):
|
|||
|
||||
assert response.status_code == 201
|
||||
assert superuser_api_client.user.invitations.latest("id") is not None
|
||||
|
||||
|
||||
def test_music_requests_view(factories, superuser_api_client, mocker):
|
||||
invitations = factories["requests.ImportRequest"].create_batch(size=5)
|
||||
qs = invitations[0].__class__.objects.order_by("-id")
|
||||
url = reverse("api:v1:manage:requests:import-requests-list")
|
||||
|
||||
response = superuser_api_client.get(url, {"sort": "-id"})
|
||||
expected = serializers.ManageImportRequestSerializer(qs, many=True).data
|
||||
|
||||
assert response.data["count"] == len(invitations)
|
||||
assert response.data["results"] == expected
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
from django.urls import reverse
|
||||
|
||||
|
||||
def test_request_viewset_requires_auth(db, api_client):
|
||||
url = reverse("api:v1:requests:import-requests-list")
|
||||
response = api_client.get(url)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_user_can_create_request(logged_in_api_client):
|
||||
url = reverse("api:v1:requests:import-requests-list")
|
||||
user = logged_in_api_client.user
|
||||
data = {
|
||||
"artist_name": "System of a Down",
|
||||
"albums": "All please!",
|
||||
"comment": "Please, they rock!",
|
||||
}
|
||||
response = logged_in_api_client.post(url, data)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
ir = user.import_requests.latest("id")
|
||||
assert ir.status == "pending"
|
||||
assert ir.creation_date is not None
|
||||
for field, value in data.items():
|
||||
assert getattr(ir, field) == value
|
|
@ -34,9 +34,6 @@
|
|||
<router-link class="item" to="/about">
|
||||
<translate>About this instance</translate>
|
||||
</router-link>
|
||||
<router-link class="item" :to="{name: 'library.request'}">
|
||||
<translate>Request music</translate>
|
||||
</router-link>
|
||||
<a href="https://funkwhale.audio" class="item" target="_blank"><translate>Official website</translate></a>
|
||||
<a href="https://docs.funkwhale.audio" class="item" target="_blank"><translate>Documentation</translate></a>
|
||||
<a href="https://code.eliotberriot.com/funkwhale/funkwhale" class="item" target="_blank">
|
||||
|
|
|
@ -27,12 +27,10 @@ import Favorites from '@/components/favorites/List'
|
|||
import AdminSettings from '@/views/admin/Settings'
|
||||
import AdminLibraryBase from '@/views/admin/library/Base'
|
||||
import AdminLibraryFilesList from '@/views/admin/library/FilesList'
|
||||
import AdminLibraryRequestsList from '@/views/admin/library/RequestsList'
|
||||
import AdminUsersBase from '@/views/admin/users/Base'
|
||||
import AdminUsersDetail from '@/views/admin/users/UsersDetail'
|
||||
import AdminUsersList from '@/views/admin/users/UsersList'
|
||||
import AdminInvitationsList from '@/views/admin/users/InvitationsList'
|
||||
import MusicRequest from '@/views/library/MusicRequest'
|
||||
import FederationBase from '@/views/federation/Base'
|
||||
import FederationScan from '@/views/federation/Scan'
|
||||
import FederationLibraryDetail from '@/views/federation/LibraryDetail'
|
||||
|
@ -257,11 +255,6 @@ export default new Router({
|
|||
path: 'files',
|
||||
name: 'manage.library.files',
|
||||
component: AdminLibraryFilesList
|
||||
},
|
||||
{
|
||||
path: 'requests',
|
||||
name: 'manage.library.requests',
|
||||
component: AdminLibraryRequestsList
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -292,11 +285,6 @@ export default new Router({
|
|||
component: Library,
|
||||
children: [
|
||||
{ path: '', component: LibraryHome, name: 'library.index' },
|
||||
{
|
||||
path: 'requests/',
|
||||
name: 'library.request',
|
||||
component: MusicRequest
|
||||
},
|
||||
{
|
||||
path: 'artists/',
|
||||
name: 'library.artists.browse',
|
||||
|
|
|
@ -4,15 +4,6 @@
|
|||
<router-link
|
||||
class="ui item"
|
||||
:to="{name: 'manage.library.files'}"><translate>Files</translate></router-link>
|
||||
<router-link
|
||||
class="ui item"
|
||||
:to="{name: 'manage.library.requests'}">
|
||||
<translate>Import requests</translate>
|
||||
<div
|
||||
:class="['ui', {'teal': $store.state.ui.notifications.importRequests > 0}, 'label']"
|
||||
:title="labels.pendingRequests">
|
||||
{{ $store.state.ui.notifications.importRequests }}</div>
|
||||
</router-link>
|
||||
</div>
|
||||
<router-view :key="$route.fullPath"></router-view>
|
||||
</div>
|
||||
|
@ -23,10 +14,8 @@ export default {
|
|||
computed: {
|
||||
labels () {
|
||||
let title = this.$gettext('Manage library')
|
||||
let pendingRequests = this.$gettext('Pending import requests')
|
||||
return {
|
||||
title,
|
||||
pendingRequests
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<template>
|
||||
<div v-title="labels.importRequests">
|
||||
<div class="ui vertical stripe segment">
|
||||
<h2 class="ui header"><translate>Import requests</translate></h2>
|
||||
<div class="ui hidden divider"></div>
|
||||
<library-requests-table></library-requests-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LibraryRequestsTable from '@/components/manage/library/RequestsTable'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LibraryRequestsTable
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
return {
|
||||
importRequests: this.$gettext('Import requests')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -1,32 +0,0 @@
|
|||
<template>
|
||||
<div class="ui vertical stripe segment" v-title="labels.title">
|
||||
<div class="ui small text container">
|
||||
<h2 class="ui header">
|
||||
<translate>Request some music</translate>
|
||||
</h2>
|
||||
<request-form v-if="$store.state.auth.authenticated"></request-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RequestForm from '@/components/requests/Form'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
RequestForm
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
let title = this.$gettext('Request some music')
|
||||
return {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
Loading…
Reference in New Issue