Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
jovuit
funkwhale
Commits
b1661827
Commit
b1661827
authored
Mar 04, 2020
by
Eliot Berriot
Browse files
Resolve "Support browsing a specific library content"
parent
ecc3ed3a
Changes
46
Hide whitespace changes
Inline
Side-by-side
api/config/spa_urls.py
View file @
b1661827
...
...
@@ -21,6 +21,11 @@ urlpatterns = [
spa_views
.
library_playlist
,
name
=
"library_playlist"
,
),
urls
.
re_path
(
r
"^library/(?P<uuid>[0-9a-f-]+)/?$"
,
spa_views
.
library_library
,
name
=
"library_library"
,
),
urls
.
re_path
(
r
"^channels/(?P<uuid>[0-9a-f-]+)/?$"
,
audio_spa_views
.
channel_detail_uuid
,
...
...
api/funkwhale_api/federation/api_views.py
View file @
b1661827
...
...
@@ -98,6 +98,26 @@ class LibraryFollowViewSet(
update_follow
(
follow
,
approved
=
False
)
return
response
.
Response
(
status
=
204
)
@
decorators
.
action
(
methods
=
[
"get"
],
detail
=
False
)
def
all
(
self
,
request
,
*
args
,
**
kwargs
):
"""
Return all the subscriptions of the current user, with only limited data
to have a performant endpoint and avoid lots of queries just to display
subscription status in the UI
"""
follows
=
list
(
self
.
get_queryset
().
values_list
(
"uuid"
,
"target__uuid"
,
"approved"
)
)
payload
=
{
"results"
:
[
{
"uuid"
:
str
(
u
[
0
]),
"library"
:
str
(
u
[
1
]),
"approved"
:
u
[
2
]}
for
u
in
follows
],
"count"
:
len
(
follows
),
}
return
response
.
Response
(
payload
,
status
=
200
)
class
LibraryViewSet
(
mixins
.
RetrieveModelMixin
,
viewsets
.
GenericViewSet
):
lookup_field
=
"uuid"
...
...
api/funkwhale_api/federation/utils.py
View file @
b1661827
...
...
@@ -201,3 +201,26 @@ def find_alternate(response_text):
parser
.
feed
(
response_text
)
except
StopParsing
:
return
parser
.
result
def
should_redirect_ap_to_html
(
accept_header
):
if
not
accept_header
:
return
False
redirect_headers
=
[
"text/html"
,
]
no_redirect_headers
=
[
"application/json"
,
"application/activity+json"
,
"application/ld+json"
,
]
parsed_header
=
[
ct
.
lower
().
strip
()
for
ct
in
accept_header
.
split
(
","
)]
for
ct
in
parsed_header
:
if
ct
in
redirect_headers
:
return
True
if
ct
in
no_redirect_headers
:
return
False
return
True
api/funkwhale_api/federation/views.py
View file @
b1661827
from
django
import
forms
from
django.conf
import
settings
from
django.core
import
paginator
from
django.db.models
import
Prefetch
from
django.http
import
HttpResponse
...
...
@@ -7,6 +8,7 @@ from rest_framework import exceptions, mixins, permissions, response, viewsets
from
rest_framework.decorators
import
action
from
funkwhale_api.common
import
preferences
from
funkwhale_api.common
import
utils
as
common_utils
from
funkwhale_api.moderation
import
models
as
moderation_models
from
funkwhale_api.music
import
models
as
music_models
from
funkwhale_api.music
import
utils
as
music_utils
...
...
@@ -14,6 +16,12 @@ from funkwhale_api.music import utils as music_utils
from
.
import
activity
,
authentication
,
models
,
renderers
,
serializers
,
utils
,
webfinger
def
redirect_to_html
(
public_url
):
response
=
HttpResponse
(
status
=
302
)
response
[
"Location"
]
=
common_utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
public_url
)
return
response
class
AuthenticatedIfAllowListEnabled
(
permissions
.
BasePermission
):
def
has_permission
(
self
,
request
,
view
):
allow_list_enabled
=
preferences
.
get
(
"moderation__allow_list_enabled"
)
...
...
@@ -204,13 +212,18 @@ class MusicLibraryViewSet(
renderer_classes
=
renderers
.
get_ap_renderers
()
serializer_class
=
serializers
.
LibrarySerializer
queryset
=
(
music_models
.
Library
.
objects
.
all
().
select_related
(
"actor"
).
filter
(
channel
=
None
)
music_models
.
Library
.
objects
.
all
()
.
local
()
.
select_related
(
"actor"
)
.
filter
(
channel
=
None
)
)
lookup_field
=
"uuid"
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
lb
=
self
.
get_object
()
if
utils
.
should_redirect_ap_to_html
(
request
.
headers
.
get
(
"accept"
)):
# XXX: implement this for actors, albums, tracks, artists
return
redirect_to_html
(
lb
.
get_absolute_url
())
conf
=
{
"id"
:
lb
.
get_federation_id
(),
"actor"
:
lb
.
actor
,
...
...
api/funkwhale_api/music/filters.py
View file @
b1661827
...
...
@@ -41,8 +41,30 @@ class ChannelFilterSet(filters.FilterSet):
return
queryset
.
filter
(
pk__in
=
ids
)
class
LibraryFilterSet
(
filters
.
FilterSet
):
library
=
filters
.
CharFilter
(
field_name
=
"_"
,
method
=
"filter_library"
)
def
filter_library
(
self
,
queryset
,
name
,
value
):
if
not
value
:
return
queryset
actor
=
utils
.
get_actor_from_request
(
self
.
request
)
library
=
models
.
Library
.
objects
.
filter
(
uuid
=
value
).
viewable_by
(
actor
).
first
()
if
not
library
:
return
queryset
.
none
()
uploads
=
models
.
Upload
.
objects
.
filter
(
library
=
library
)
uploads
=
uploads
.
playable_by
(
actor
)
ids
=
uploads
.
values_list
(
self
.
Meta
.
library_filter_field
,
flat
=
True
)
return
queryset
.
filter
(
pk__in
=
ids
)
class
ArtistFilter
(
audio_filters
.
IncludeChannelsFilterSet
,
moderation_filters
.
HiddenContentFilterSet
LibraryFilterSet
,
audio_filters
.
IncludeChannelsFilterSet
,
moderation_filters
.
HiddenContentFilterSet
,
):
q
=
fields
.
SearchFilter
(
search_fields
=
[
"name"
],
fts_search_fields
=
[
"body_text"
])
...
...
@@ -62,6 +84,7 @@ class ArtistFilter(
}
hidden_content_fields_mapping
=
moderation_filters
.
USER_FILTER_CONFIG
[
"ARTIST"
]
include_channels_field
=
"channel"
library_filter_field
=
"track__artist"
def
filter_playable
(
self
,
queryset
,
name
,
value
):
actor
=
utils
.
get_actor_from_request
(
self
.
request
)
...
...
@@ -70,6 +93,7 @@ class ArtistFilter(
class
TrackFilter
(
ChannelFilterSet
,
LibraryFilterSet
,
audio_filters
.
IncludeChannelsFilterSet
,
moderation_filters
.
HiddenContentFilterSet
,
):
...
...
@@ -99,6 +123,7 @@ class TrackFilter(
hidden_content_fields_mapping
=
moderation_filters
.
USER_FILTER_CONFIG
[
"TRACK"
]
include_channels_field
=
"artist__channel"
channel_filter_field
=
"track"
library_filter_field
=
"track"
def
filter_playable
(
self
,
queryset
,
name
,
value
):
actor
=
utils
.
get_actor_from_request
(
self
.
request
)
...
...
@@ -156,6 +181,7 @@ class UploadFilter(audio_filters.IncludeChannelsFilterSet):
class
AlbumFilter
(
ChannelFilterSet
,
LibraryFilterSet
,
audio_filters
.
IncludeChannelsFilterSet
,
moderation_filters
.
HiddenContentFilterSet
,
):
...
...
@@ -175,6 +201,7 @@ class AlbumFilter(
hidden_content_fields_mapping
=
moderation_filters
.
USER_FILTER_CONFIG
[
"ALBUM"
]
include_channels_field
=
"artist__channel"
channel_filter_field
=
"track__album"
library_filter_field
=
"track__album"
def
filter_playable
(
self
,
queryset
,
name
,
value
):
actor
=
utils
.
get_actor_from_request
(
self
.
request
)
...
...
api/funkwhale_api/music/models.py
View file @
b1661827
...
...
@@ -1110,6 +1110,12 @@ LIBRARY_PRIVACY_LEVEL_CHOICES = [
class
LibraryQuerySet
(
models
.
QuerySet
):
def
local
(
self
,
include
=
True
):
query
=
models
.
Q
(
actor__domain_id
=
settings
.
FEDERATION_HOSTNAME
)
if
not
include
:
query
=
~
query
return
self
.
filter
(
query
)
def
with_follows
(
self
,
actor
):
return
self
.
prefetch_related
(
models
.
Prefetch
(
...
...
@@ -1123,14 +1129,14 @@ class LibraryQuerySet(models.QuerySet):
from
funkwhale_api.federation.models
import
LibraryFollow
if
actor
is
None
:
return
Library
.
objects
.
filter
(
privacy_level
=
"everyone"
)
return
self
.
filter
(
privacy_level
=
"everyone"
)
me_query
=
models
.
Q
(
privacy_level
=
"me"
,
actor
=
actor
)
instance_query
=
models
.
Q
(
privacy_level
=
"instance"
,
actor__domain
=
actor
.
domain
)
followed_libraries
=
LibraryFollow
.
objects
.
filter
(
actor
=
actor
,
approved
=
True
).
values_list
(
"target"
,
flat
=
True
)
return
Library
.
objects
.
filter
(
return
self
.
filter
(
me_query
|
instance_query
|
models
.
Q
(
privacy_level
=
"everyone"
)
...
...
@@ -1164,6 +1170,9 @@ class Library(federation_models.FederationMixin):
reverse
(
"federation:music:libraries-detail"
,
kwargs
=
{
"uuid"
:
self
.
uuid
})
)
def
get_absolute_url
(
self
):
return
"/library/{}"
.
format
(
self
.
uuid
)
def
save
(
self
,
**
kwargs
):
if
not
self
.
pk
and
not
self
.
fid
and
self
.
actor
.
get_user
():
self
.
fid
=
self
.
get_federation_id
()
...
...
api/funkwhale_api/music/spa_views.py
View file @
b1661827
...
...
@@ -292,3 +292,33 @@ def library_playlist(request, pk):
# twitter player is also supported in various software
metas
+=
get_twitter_card_metas
(
type
=
"playlist"
,
id
=
obj
.
pk
)
return
metas
def
library_library
(
request
,
uuid
):
queryset
=
models
.
Library
.
objects
.
filter
(
uuid
=
uuid
)
try
:
obj
=
queryset
.
get
()
except
models
.
Library
.
DoesNotExist
:
return
[]
library_url
=
utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
utils
.
spa_reverse
(
"library_library"
,
kwargs
=
{
"uuid"
:
obj
.
uuid
}),
)
metas
=
[
{
"tag"
:
"meta"
,
"property"
:
"og:url"
,
"content"
:
library_url
},
{
"tag"
:
"meta"
,
"property"
:
"og:type"
,
"content"
:
"website"
},
{
"tag"
:
"meta"
,
"property"
:
"og:title"
,
"content"
:
obj
.
name
},
{
"tag"
:
"meta"
,
"property"
:
"og:description"
,
"content"
:
obj
.
description
},
]
if
preferences
.
get
(
"federation__enabled"
):
metas
.
append
(
{
"tag"
:
"link"
,
"rel"
:
"alternate"
,
"type"
:
"application/activity+json"
,
"href"
:
obj
.
fid
,
}
)
return
metas
api/tests/federation/test_api_views.py
View file @
b1661827
...
...
@@ -286,3 +286,25 @@ def test_fetch_duplicate_bypass_with_force(
assert
response
.
status_code
==
201
assert
response
.
data
==
api_serializers
.
FetchSerializer
(
fetch
).
data
fetch_task
.
assert_called_once_with
(
fetch_id
=
fetch
.
pk
)
def
test_library_follow_get_all
(
factories
,
logged_in_api_client
):
actor
=
logged_in_api_client
.
user
.
create_actor
()
library
=
factories
[
"music.Library"
]()
follow
=
factories
[
"federation.LibraryFollow"
](
target
=
library
,
actor
=
actor
)
factories
[
"federation.LibraryFollow"
]()
factories
[
"music.Library"
]()
url
=
reverse
(
"api:v1:federation:library-follows-all"
)
response
=
logged_in_api_client
.
get
(
url
)
assert
response
.
status_code
==
200
assert
response
.
data
==
{
"results"
:
[
{
"uuid"
:
str
(
follow
.
uuid
),
"library"
:
str
(
library
.
uuid
),
"approved"
:
follow
.
approved
,
}
],
"count"
:
1
,
}
api/tests/federation/test_views.py
View file @
b1661827
...
...
@@ -2,7 +2,14 @@ import pytest
from
django.core.paginator
import
Paginator
from
django.urls
import
reverse
from
funkwhale_api.federation
import
actors
,
serializers
,
webfinger
from
funkwhale_api.common
import
utils
from
funkwhale_api.federation
import
(
actors
,
serializers
,
webfinger
,
utils
as
federation_utils
,
)
def
test_authenticate_skips_anonymous_fetch_when_allow_list_enabled
(
...
...
@@ -159,7 +166,7 @@ def test_wellknown_webfinger_local(factories, api_client, settings, mocker):
@
pytest
.
mark
.
parametrize
(
"privacy_level"
,
[
"me"
,
"instance"
,
"everyone"
])
def
test_music_library_retrieve
(
factories
,
api_client
,
privacy_level
):
library
=
factories
[
"music.Library"
](
privacy_level
=
privacy_level
)
library
=
factories
[
"music.Library"
](
privacy_level
=
privacy_level
,
actor__local
=
True
)
expected
=
serializers
.
LibrarySerializer
(
library
).
data
url
=
reverse
(
"federation:music:libraries-detail"
,
kwargs
=
{
"uuid"
:
library
.
uuid
})
...
...
@@ -170,7 +177,7 @@ def test_music_library_retrieve(factories, api_client, privacy_level):
def
test_music_library_retrieve_excludes_channel_libraries
(
factories
,
api_client
):
channel
=
factories
[
"audio.Channel"
]()
channel
=
factories
[
"audio.Channel"
](
local
=
True
)
library
=
channel
.
library
url
=
reverse
(
"federation:music:libraries-detail"
,
kwargs
=
{
"uuid"
:
library
.
uuid
})
...
...
@@ -180,7 +187,7 @@ def test_music_library_retrieve_excludes_channel_libraries(factories, api_client
def
test_music_library_retrieve_page_public
(
factories
,
api_client
):
library
=
factories
[
"music.Library"
](
privacy_level
=
"everyone"
)
library
=
factories
[
"music.Library"
](
privacy_level
=
"everyone"
,
actor__local
=
True
)
upload
=
factories
[
"music.Upload"
](
library
=
library
,
import_status
=
"finished"
)
id
=
library
.
get_federation_id
()
expected
=
serializers
.
CollectionPageSerializer
(
...
...
@@ -253,7 +260,7 @@ def test_channel_upload_retrieve(factories, api_client):
@
pytest
.
mark
.
parametrize
(
"privacy_level"
,
[
"me"
,
"instance"
])
def
test_music_library_retrieve_page_private
(
factories
,
api_client
,
privacy_level
):
library
=
factories
[
"music.Library"
](
privacy_level
=
privacy_level
)
library
=
factories
[
"music.Library"
](
privacy_level
=
privacy_level
,
actor__local
=
True
)
url
=
reverse
(
"federation:music:libraries-detail"
,
kwargs
=
{
"uuid"
:
library
.
uuid
})
response
=
api_client
.
get
(
url
,
{
"page"
:
1
})
...
...
@@ -264,7 +271,7 @@ def test_music_library_retrieve_page_private(factories, api_client, privacy_leve
def
test_music_library_retrieve_page_follow
(
factories
,
api_client
,
authenticated_actor
,
approved
,
expected
):
library
=
factories
[
"music.Library"
](
privacy_level
=
"me"
)
library
=
factories
[
"music.Library"
](
privacy_level
=
"me"
,
actor__local
=
True
)
factories
[
"federation.LibraryFollow"
](
actor
=
authenticated_actor
,
target
=
library
,
approved
=
approved
)
...
...
@@ -344,3 +351,35 @@ def test_music_upload_detail_private_approved_follow(
response
=
api_client
.
get
(
url
)
assert
response
.
status_code
==
200
@
pytest
.
mark
.
parametrize
(
"accept_header,expected"
,
[
(
"text/html,application/xhtml+xml"
,
True
),
(
"text/html,application/json"
,
True
),
(
""
,
False
),
(
None
,
False
),
(
"application/json"
,
False
),
(
"application/activity+json"
,
False
),
(
"application/json,text/html"
,
False
),
(
"application/activity+json,text/html"
,
False
),
],
)
def
test_should_redirect_ap_to_html
(
accept_header
,
expected
):
assert
federation_utils
.
should_redirect_ap_to_html
(
accept_header
)
is
expected
def
test_music_library_retrieve_redirects_to_html_if_header_set
(
factories
,
api_client
,
settings
):
library
=
factories
[
"music.Library"
](
actor__local
=
True
)
url
=
reverse
(
"federation:music:libraries-detail"
,
kwargs
=
{
"uuid"
:
library
.
uuid
})
response
=
api_client
.
get
(
url
,
HTTP_ACCEPT
=
"text/html"
)
expected_url
=
utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
utils
.
spa_reverse
(
"library_library"
,
kwargs
=
{
"uuid"
:
library
.
uuid
}),
)
assert
response
.
status_code
==
302
assert
response
[
"Location"
]
==
expected_url
api/tests/music/test_filters.py
View file @
b1661827
...
...
@@ -142,3 +142,45 @@ def test_channel_filter_album(factories, queryset_equal_list, mocker, anonymous_
)
assert
filterset
.
qs
==
[
upload
.
track
.
album
]
def
test_library_filter_track
(
factories
,
queryset_equal_list
,
mocker
,
anonymous_user
):
library
=
factories
[
"music.Library"
](
privacy_level
=
"everyone"
)
upload
=
factories
[
"music.Upload"
](
library
=
library
,
playable
=
True
)
factories
[
"music.Track"
]()
qs
=
upload
.
track
.
__class__
.
objects
.
all
()
filterset
=
filters
.
TrackFilter
(
{
"library"
:
library
.
uuid
},
request
=
mocker
.
Mock
(
user
=
anonymous_user
,
actor
=
None
),
queryset
=
qs
,
)
assert
filterset
.
qs
==
[
upload
.
track
]
def
test_library_filter_album
(
factories
,
queryset_equal_list
,
mocker
,
anonymous_user
):
library
=
factories
[
"music.Library"
](
privacy_level
=
"everyone"
)
upload
=
factories
[
"music.Upload"
](
library
=
library
,
playable
=
True
)
factories
[
"music.Album"
]()
qs
=
upload
.
track
.
album
.
__class__
.
objects
.
all
()
filterset
=
filters
.
AlbumFilter
(
{
"library"
:
library
.
uuid
},
request
=
mocker
.
Mock
(
user
=
anonymous_user
,
actor
=
None
),
queryset
=
qs
,
)
assert
filterset
.
qs
==
[
upload
.
track
.
album
]
def
test_library_filter_artist
(
factories
,
queryset_equal_list
,
mocker
,
anonymous_user
):
library
=
factories
[
"music.Library"
](
privacy_level
=
"everyone"
)
upload
=
factories
[
"music.Upload"
](
library
=
library
,
playable
=
True
)
factories
[
"music.Artist"
]()
qs
=
upload
.
track
.
artist
.
__class__
.
objects
.
all
()
filterset
=
filters
.
ArtistFilter
(
{
"library"
:
library
.
uuid
},
request
=
mocker
.
Mock
(
user
=
anonymous_user
,
actor
=
None
),
queryset
=
qs
,
)
assert
filterset
.
qs
==
[
upload
.
track
.
artist
]
api/tests/music/test_spa_views.py
View file @
b1661827
...
...
@@ -282,3 +282,32 @@ def test_library_playlist_empty(spa_html, no_api_auth, client, factories, settin
# we only test our custom metas, not the default ones
assert
metas
[:
len
(
expected_metas
)]
==
expected_metas
def
test_library_library
(
spa_html
,
no_api_auth
,
client
,
factories
,
settings
):
library
=
factories
[
"music.Library"
]()
url
=
"/library/{}"
.
format
(
library
.
uuid
)
response
=
client
.
get
(
url
)
expected_metas
=
[
{
"tag"
:
"meta"
,
"property"
:
"og:url"
,
"content"
:
utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
url
),
},
{
"tag"
:
"meta"
,
"property"
:
"og:type"
,
"content"
:
"website"
},
{
"tag"
:
"meta"
,
"property"
:
"og:title"
,
"content"
:
library
.
name
},
{
"tag"
:
"meta"
,
"property"
:
"og:description"
,
"content"
:
library
.
description
},
{
"tag"
:
"link"
,
"rel"
:
"alternate"
,
"type"
:
"application/activity+json"
,
"href"
:
library
.
fid
,
},
]
metas
=
utils
.
parse_meta
(
response
.
content
.
decode
())
# we only test our custom metas, not the default ones
assert
metas
[:
len
(
expected_metas
)]
==
expected_metas
changes/changelog.d/926.feature
0 → 100644
View file @
b1661827
C
an
now browse a library content through the UI (#926)
front/src/components/audio/LibraryFollowButton.vue
0 → 100644
View file @
b1661827
<
template
>
<button
@
click.stop=
"toggle"
:class=
"['ui', 'pink',
{'inverted': isApproved || isPending}, {'favorited': isApproved}, 'icon', 'labeled', 'button']">
<i
class=
"heart icon"
></i>
<translate
v-if=
"isApproved"
translate-context=
"Content/Library/Card.Button.Label/Verb"
>
Unfollow
</translate>
<translate
v-else-if=
"isPending"
translate-context=
"Content/Library/Card.Button.Label/Verb"
>
Cancel follow request
</translate>
<translate
v-else
translate-context=
"Content/Library/Card.Button.Label/Verb"
>
Follow
</translate>
</button>
</
template
>
<
script
>
export
default
{
props
:
{
library
:
{
type
:
Object
},
},
computed
:
{
isPending
()
{
return
this
.
follow
&&
this
.
follow
.
approved
===
null
},
isApproved
()
{
return
this
.
follow
&&
(
this
.
follow
.
approved
===
true
||
(
this
.
follow
.
approved
===
null
&&
this
.
library
.
privacy_level
===
'
everyone
'
))
},
follow
()
{
return
this
.
$store
.
getters
[
'
libraries/follow
'
](
this
.
library
.
uuid
)
}
},
methods
:
{
toggle
()
{
if
(
this
.
isApproved
||
this
.
isPending
)
{
this
.
$emit
(
'
unfollowed
'
)
}
else
{
this
.
$emit
(
'
followed
'
)
}
this
.
$store
.
dispatch
(
'
libraries/toggle
'
,
this
.
library
.
uuid
)
}
}
}
</
script
>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<
style
scoped
>
</
style
>
front/src/components/audio/PlayButton.vue
View file @
b1661827
...
...
@@ -68,6 +68,7 @@ export default {
iconOnly
:
{
type
:
Boolean
,
default
:
false
},
artist
:
{
type
:
Object
,
required
:
false
},
album
:
{
type
:
Object
,
required
:
false
},
library
:
{
type
:
Object
,
required
:
false
},
isPlayable
:
{
type
:
Boolean
,
required
:
false
,
default
:
null
}
},
data
()
{
...
...
@@ -196,6 +197,9 @@ export default {
}
else
if
(
self
.
album
)
{
let
params
=
{
'
album
'
:
self
.
album
.
id
,
include_channels
:
'
true
'
,
'
ordering
'
:
'
disc_number,position
'
}
self
.
getTracksPage
(
1
,
params
,
resolve
)
}
else
if
(
self
.
library
)
{
let
params
=
{
'
library
'
:
self
.
library
.
uuid
,
'
ordering
'
:
'
-creation_date
'
}
self
.
getTracksPage
(
1
,
params
,
resolve
)
}
})
return
getTracks
.
then
((
tracks
)
=>
{
...
...
front/src/components/audio/album/Widget.vue
View file @
b1661827
...
...
@@ -5,6 +5,7 @@
<span
v-if=
"showCount"
class=
"ui tiny circular label"
>
{{
count
}}
</span>
</h3>
<slot></slot>
<inline-search-bar
v-model=
"query"
v-if=
"search"
@
search=
"albums = []; fetchData()"
></inline-search-bar>
<div
class=
"ui hidden divider"
></div>
<div
class=
"ui app-cards cards"
>
<div
v-if=
"isLoading"
class=
"ui inverted active dimmer"
>
...
...
@@ -12,14 +13,9 @@
</div>
<album-card
v-for=
"album in albums"
:album=
"album"
:key=
"album.id"
/>
</div>
<template
v-if=
"!isLoading && albums.length === 0"
>
<div
class=
"ui placeholder segment"
>
<div
class=
"ui icon header"
>
<i
class=
"compact disc icon"
></i>
No results matching your query
</div>
</div>
</
template
>
<slot
v-if=
"!isLoading && albums.length === 0"
name=
"empty-state"
>
<empty-state
@
refresh=
"fetchData"
:refresh=
"true"
></empty-state>
</slot>
<template
v-if=
"nextPage"
>
<div
class=
"ui hidden divider"
></div>
<button
v-if=
"nextPage"
@
click=
"fetchData(nextPage)"
:class=
"['ui', 'basic', 'button']"
>
...
...
@@ -30,7 +26,6 @@
</template>
<
script
>
import
_
from
'
@/lodash
'
import
axios
from
'
axios
'
import
AlbumCard
from
'
@/components/audio/album/Card
'
...
...
@@ -39,6 +34,7 @@ export default {
filters
:
{
type
:
Object
,
required
:
true
},
controls
:
{
type
:
Boolean
,
default
:
true
},
showCount
:
{
type
:
Boolean
,
default
:
false
},
search
:
{
type
:
Boolean
,
default
:
false
},
limit
:
{
type
:
Number
,
default
:
12
},
},
components
:
{
...
...
@@ -51,20 +47,19 @@ export default {
isLoading
:
false
,
errors
:
null
,
previousPage
:
null
,
nextPage
:
null
nextPage
:
null
,
query
:
''
,
}
},
created
()
{
this
.
fetchData
(
'
albums/
'
)
this
.
fetchData
()
},
methods
:
{
fetchData
(
url
)
{
if
(
!
url
)
{
return
}
url
=
url
||
'
albums/
'
this
.
isLoading
=
true
let
self
=
this
let
params
=
_
.
clone
(
this
.
filters
)
let
params
=
{
q
:
this
.
query
,
...
this
.
filters
}
params
.
page_size
=
this
.
limit
params
.
offset
=
this
.
offset
axios
.
get
(
url
,
{
params
:
params
}).
then
((
response
)
=>
{
...
...
@@ -91,7 +86,7 @@ export default {
this
.
fetchData
()