Skip to content
Snippets Groups Projects
Verified Commit 472cc7e2 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Detail library view with settings update

parent f4f75dcb
No related branches found
No related tags found
No related merge requests found
......@@ -112,6 +112,8 @@ class APIActorSerializer(serializers.ModelSerializer):
'manually_approves_followers',
]
class LibraryActorSerializer(ActorSerializer):
url = serializers.ListField(
child=serializers.JSONField())
......@@ -137,33 +139,52 @@ class LibraryActorSerializer(ActorSerializer):
return validated_data
class APIFollowSerializer(serializers.ModelSerializer):
class Meta:
model = models.Follow
fields = [
'uuid',
'actor',
'target',
'approved',
'creation_date',
'modification_date',
]
class APILibrarySerializer(serializers.ModelSerializer):
actor = APIActorSerializer
actor = APIActorSerializer()
follow = APIFollowSerializer()
class Meta:
model = models.Library
fields = [
read_only_fields = [
'actor',
'autoimport',
'federation_enabled',
'download_files',
'tracks_count',
'url',
'uuid',
'creation_date',
'url',
'tracks_count',
'follow',
'fetched_date',
'modification_date',
'creation_date',
]
fields = [
'autoimport',
'federation_enabled',
'download_files',
] + read_only_fields
class APILibraryCreateSerializer(serializers.ModelSerializer):
actor = serializers.URLField()
federation_enabled = serializers.BooleanField()
uuid = serializers.UUIDField(read_only=True)
class Meta:
model = models.Library
fields = [
'uuid',
'actor',
'autoimport',
'federation_enabled',
......
......@@ -166,6 +166,8 @@ class MusicFilesViewSet(FederationMixin, viewsets.GenericViewSet):
class LibraryViewSet(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
permission_classes = [rest_permissions.DjangoModelPermissions]
......@@ -173,6 +175,7 @@ class LibraryViewSet(
'actor',
'follow',
)
lookup_field = 'uuid'
filter_class = filters.LibraryFilter
serializer_class = serializers.APILibrarySerializer
ordering_fields = (
......
......@@ -275,3 +275,34 @@ def test_can_list_libraries(factories, superuser_api_client):
serializers.APILibrarySerializer(library1).data,
serializers.APILibrarySerializer(library2).data,
]
def test_can_detail_library(factories, superuser_api_client):
library = factories['federation.Library']()
url = reverse(
'api:v1:federation:libraries-detail',
kwargs={'uuid': str(library.uuid)})
response = superuser_api_client.get(url)
assert response.status_code == 200
assert response.data == serializers.APILibrarySerializer(library).data
def test_can_patch_library(factories, superuser_api_client):
library = factories['federation.Library']()
data = {
'federation_enabled': not library.federation_enabled,
'download_files': not library.download_files,
'autoimport': not library.autoimport,
}
url = reverse(
'api:v1:federation:libraries-detail',
kwargs={'uuid': str(library.uuid)})
response = superuser_api_client.patch(url, data)
assert response.status_code == 200
library.refresh_from_db()
for k, v in data.items():
assert getattr(library, k) == v
......@@ -25,7 +25,9 @@ import RequestsList from '@/components/requests/RequestsList'
import PlaylistDetail from '@/views/playlists/Detail'
import PlaylistList from '@/views/playlists/List'
import Favorites from '@/components/favorites/List'
import Federation from '@/views/federation/Home'
import FederationBase from '@/views/federation/Base'
import FederationHome from '@/views/federation/Home'
import FederationLibraryDetail from '@/views/federation/LibraryDetail'
Vue.use(Router)
......@@ -86,7 +88,11 @@ export default new Router({
},
{
path: '/manage/federation',
component: Federation
component: FederationBase,
children: [
{ path: '', component: FederationHome },
{ path: 'library/:id', name: 'federation.libraries.detail', component: FederationLibraryDetail, props: true }
]
},
{
path: '/library',
......
<template>
<div class="main pusher" v-title="'Federation'">
<div class="ui secondary pointing menu">
</div>
<router-view :key="$route.fullPath"></router-view>
</div>
</template>
<template>
<div class="main pusher" v-title="'Federation'">
<div>
<div class="ui vertical stripe segment">
<h1 class="ui header">Manage federation</h1>
<library-form @scanned="updateLibraryData"></library-form>
......
<template>
<div>
<div v-if="isLoading" class="ui vertical segment" v-title="'Library'">
<div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div>
</div>
<template v-if="object">
<div :class="['ui', 'head', 'vertical', 'center', 'aligned', 'stripe', 'segment']" v-title="libraryUsername">
<div class="segment-content">
<h2 class="ui center aligned icon header">
<i class="circular inverted cloud olive icon"></i>
<div class="content">
{{ libraryUsername }}
</div>
</h2>
</div>
<div class="ui hidden divider"></div>
<div class="ui one column centered grid">
<table class="ui collapsing very basic table">
<tbody>
<tr>
<td>Follow status</td>
<td>
<template v-if="object.follow.approved === null">
<i class="loading icon"></i> Pending approval
</template>
<template v-else-if="object.follow.approved === true">
<i class="check icon"></i> Following
</template>
<template v-else-if="object.follow.approved === false">
<i class="x icon"></i> Not following
</template>
</td>
<td>
</td>
</tr>
<tr>
<td>Federation</td>
<td>
<div class="ui toggle checkbox">
<input
@change="update('federation_enabled')"
v-model="object.federation_enabled" type="checkbox">
<label></label>
</div>
</td>
<td>
</td>
</tr>
<tr>
<td>Auto importing</td>
<td>
<div class="ui toggle checkbox">
<input
@change="update('autoimport')"
v-model="object.autoimport" type="checkbox">
<label></label>
</div>
</td>
<td></td>
</tr>
<tr>
<td>File mirroring</td>
<td>
<div class="ui toggle checkbox">
<input
@change="update('download_files')"
v-model="object.download_files" type="checkbox">
<label></label>
</div>
</td>
<td></td>
</tr>
<tr>
<td>Library size</td>
<td>
{{ object.tracks_count }} tracks
</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="ui vertical stripe segment">
<h2>Tracks available in this library</h2>
<div class="ui stackable doubling three column grid">
</div>
</div>
</template>
</div>
</template>
<script>
import axios from 'axios'
import logger from '@/logging'
export default {
props: ['id'],
components: {},
data () {
return {
isLoading: true,
object: null
}
},
created () {
this.fetchData()
},
methods: {
fetchData () {
var self = this
this.isLoading = true
let url = 'federation/libraries/' + this.id + '/'
logger.default.debug('Fetching library "' + this.id + '"')
axios.get(url).then((response) => {
self.object = response.data
self.isLoading = false
})
},
update (attr) {
let newValue = this.object[attr]
let params = {}
let self = this
params[attr] = newValue
axios.patch('federation/libraries/' + this.id + '/', params).then((response) => {
console.log(`${attr} was updated succcessfully to ${newValue}`)
}, (error) => {
console.log(`Error while setting ${attr} to ${newValue}`, error)
self.object[attr] = !newValue
})
}
},
computed: {
libraryUsername () {
let actor = this.object.actor
return `${actor.preferred_username}@${actor.domain}`
}
},
watch: {
id () {
this.fetchData()
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment