Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
interfect
funkwhale
Commits
472cc7e2
Verified
Commit
472cc7e2
authored
Apr 11, 2018
by
Eliot Berriot
Browse files
Detail library view with settings update
parent
f4f75dcb
Changes
7
Hide whitespace changes
Inline
Side-by-side
api/funkwhale_api/federation/serializers.py
View file @
472cc7e2
...
...
@@ -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'
,
...
...
api/funkwhale_api/federation/views.py
View file @
472cc7e2
...
...
@@ -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
=
(
...
...
api/tests/federation/test_views.py
View file @
472cc7e2
...
...
@@ -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
front/src/router/index.js
View file @
472cc7e2
...
...
@@ -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
'
,
...
...
front/src/views/federation/Base.vue
0 → 100644
View file @
472cc7e2
<
template
>
<div
class=
"main pusher"
v-title=
"'Federation'"
>
<div
class=
"ui secondary pointing menu"
>
</div>
<router-view
:key=
"$route.fullPath"
></router-view>
</div>
</
template
>
front/src/views/federation/Home.vue
View file @
472cc7e2
<
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>
...
...
front/src/views/federation/LibraryDetail.vue
0 → 100644
View file @
472cc7e2
<
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
>
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment