Skip to content
Snippets Groups Projects
Commit 53ade207 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'more-performant-favorites' into 'develop'

More performant favorites

See merge request funkwhale/funkwhale!522
parents 38e047e4 3916986f
No related branches found
No related tags found
No related merge requests found
...@@ -12,3 +12,6 @@ MUSIC_DIRECTORY_PATH=/music ...@@ -12,3 +12,6 @@ MUSIC_DIRECTORY_PATH=/music
BROWSABLE_API_ENABLED=True BROWSABLE_API_ENABLED=True
FORWARDED_PROTO=http FORWARDED_PROTO=http
LDAP_ENABLED=False LDAP_ENABLED=False
# Uncomment this if you're using traefik/https
# FORCE_HTTPS_URLS=True
...@@ -14,6 +14,7 @@ from .common import * # noqa ...@@ -14,6 +14,7 @@ from .common import * # noqa
# DEBUG # DEBUG
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
DEBUG = env.bool("DJANGO_DEBUG", default=True) DEBUG = env.bool("DJANGO_DEBUG", default=True)
FORCE_HTTPS_URLS = env.bool("FORCE_HTTPS_URLS", default=False)
TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG
# SECRET CONFIGURATION # SECRET CONFIGURATION
...@@ -80,3 +81,5 @@ CSRF_TRUSTED_ORIGINS = [o for o in ALLOWED_HOSTS] ...@@ -80,3 +81,5 @@ CSRF_TRUSTED_ORIGINS = [o for o in ALLOWED_HOSTS]
if env.bool("WEAK_PASSWORDS", default=False): if env.bool("WEAK_PASSWORDS", default=False):
# Faster during tests # Faster during tests
PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",) PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",)
MIDDLEWARE = ("funkwhale_api.common.middleware.DevHttpsMiddleware",) + MIDDLEWARE
...@@ -135,3 +135,25 @@ class SPAFallbackMiddleware: ...@@ -135,3 +135,25 @@ class SPAFallbackMiddleware:
return serve_spa(request) return serve_spa(request)
return response return response
class DevHttpsMiddleware:
"""
In development, it's sometimes difficult to have django use HTTPS
when we have django behind nginx behind traefix.
We thus use a simple setting (in dev ONLY) to control that.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if settings.FORCE_HTTPS_URLS:
setattr(request.__class__, "scheme", "https")
setattr(
request,
"get_host",
lambda: request.__class__.get_host(request).replace(":80", ":443"),
)
return self.get_response(request)
...@@ -71,3 +71,19 @@ class TrackFavoriteViewSet( ...@@ -71,3 +71,19 @@ class TrackFavoriteViewSet(
return Response({}, status=400) return Response({}, status=400)
favorite.delete() favorite.delete()
return Response([], status=status.HTTP_204_NO_CONTENT) return Response([], status=status.HTTP_204_NO_CONTENT)
@list_route(methods=["get"])
def all(self, request, *args, **kwargs):
"""
Return all the favorites of the current user, with only limited data
to have a performant endpoint and avoid lots of queries just to display
favorites status in the UI
"""
if not request.user.is_authenticated:
return Response({"results": [], "count": 0}, status=200)
favorites = list(
request.user.track_favorites.values("id", "track").order_by("id")
)
payload = {"results": favorites, "count": len(favorites)}
return Response(payload, status=200)
...@@ -39,6 +39,18 @@ def test_user_can_get_his_favorites(api_request, factories, logged_in_client, cl ...@@ -39,6 +39,18 @@ def test_user_can_get_his_favorites(api_request, factories, logged_in_client, cl
assert response.data["results"] == expected assert response.data["results"] == expected
def test_user_can_retrieve_all_favorites_at_once(
api_request, factories, logged_in_client, client
):
favorite = factories["favorites.TrackFavorite"](user=logged_in_client.user)
factories["favorites.TrackFavorite"]()
url = reverse("api:v1:favorites:tracks-all")
response = logged_in_client.get(url, {"user": logged_in_client.user.pk})
expected = [{"track": favorite.track.id, "id": favorite.id}]
assert response.status_code == 200
assert response.data["results"] == expected
def test_user_can_add_favorite_via_api(factories, logged_in_client, activity_muted): def test_user_can_add_favorite_via_api(factories, logged_in_client, activity_muted):
track = factories["music.Track"]() track = factories["music.Track"]()
url = reverse("api:v1:favorites:tracks-list") url = reverse("api:v1:favorites:tracks-list")
......
Performance improvement when fetching favorites, down to a single, small http request
...@@ -60,20 +60,12 @@ export default { ...@@ -60,20 +60,12 @@ export default {
page_size: 50, page_size: 50,
ordering: '-creation_date' ordering: '-creation_date'
} }
let promise let promise = axios.get('favorites/tracks/all/', {params: params})
if (url) {
promise = axios.get(url)
} else {
promise = axios.get('favorites/tracks/', {params: params})
}
return promise.then((response) => { return promise.then((response) => {
logger.default.info('Fetched a batch of ' + response.data.results.length + ' favorites') logger.default.info('Fetched a batch of ' + response.data.results.length + ' favorites')
response.data.results.forEach(result => { response.data.results.forEach(result => {
commit('track', {id: result.track.id, value: true}) commit('track', {id: result.track, value: true})
}) })
if (response.data.next) {
dispatch('fetch', response.data.next)
}
}) })
} }
} }
......
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