Fix #616: Fixed inconsistencies in subsonic error responses

environments/review-front-funk-vgsw69/deployments/41
Eliot Berriot 2018-11-18 23:17:31 +01:00
rodzic dabe1afd5d
commit 22de4a98c5
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: DD6965E2476E5C27
5 zmienionych plików z 84 dodań i 23 usunięć

Wyświetl plik

@ -5,23 +5,27 @@ from rest_framework import renderers
import funkwhale_api import funkwhale_api
class SubsonicJSONRenderer(renderers.JSONRenderer): def structure_payload(data):
def render(self, data, accepted_media_type=None, renderer_context=None): payload = {
if not data:
# when stream view is called, we don't have any data
return super().render(data, accepted_media_type, renderer_context)
final = {
"subsonic-response": {
"status": "ok", "status": "ok",
"version": "1.16.0", "version": "1.16.0",
"type": "funkwhale", "type": "funkwhale",
"funkwhaleVersion": funkwhale_api.__version__, "funkwhaleVersion": funkwhale_api.__version__,
} }
} payload.update(data)
final["subsonic-response"].update(data) if "detail" in payload:
if "error" in final: payload["error"] = {"code": 0, "message": payload.pop("detail")}
# an error was returned if "error" in payload:
final["subsonic-response"]["status"] = "failed" payload["status"] = "failed"
return payload
class SubsonicJSONRenderer(renderers.JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
if not data:
# when stream view is called, we don't have any data
return super().render(data, accepted_media_type, renderer_context)
final = {"subsonic-response": structure_payload(data)}
return super().render(final, accepted_media_type, renderer_context) return super().render(final, accepted_media_type, renderer_context)
@ -32,15 +36,8 @@ class SubsonicXMLRenderer(renderers.JSONRenderer):
if not data: if not data:
# when stream view is called, we don't have any data # when stream view is called, we don't have any data
return super().render(data, accepted_media_type, renderer_context) return super().render(data, accepted_media_type, renderer_context)
final = { final = structure_payload(data)
"xmlns": "http://subsonic.org/restapi", final["xmlns"] = "http://subsonic.org/restapi"
"status": "ok",
"version": "1.16.0",
}
final.update(data)
if "error" in final:
# an error was returned
final["status"] = "failed"
tree = dict_to_xml_tree("subsonic-response", final) tree = dict_to_xml_tree("subsonic-response", final)
return b'<?xml version="1.0" encoding="UTF-8"?>\n' + ET.tostring( return b'<?xml version="1.0" encoding="UTF-8"?>\n' + ET.tostring(
tree, encoding="utf-8" tree, encoding="utf-8"

Wyświetl plik

@ -97,7 +97,10 @@ class SubsonicViewSet(viewsets.GenericViewSet):
def handle_exception(self, exc): def handle_exception(self, exc):
# subsonic API sends 200 status code with custom error # subsonic API sends 200 status code with custom error
# codes in the payload # codes in the payload
mapping = {exceptions.AuthenticationFailed: (40, "Wrong username or password.")} mapping = {
exceptions.AuthenticationFailed: (40, "Wrong username or password."),
exceptions.NotAuthenticated: (10, "Required parameter is missing."),
}
payload = {"status": "failed"} payload = {"status": "failed"}
if exc.__class__ in mapping: if exc.__class__ in mapping:
code, message = mapping[exc.__class__] code, message = mapping[exc.__class__]

Wyświetl plik

@ -1,4 +1,5 @@
import json import json
import pytest
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import funkwhale_api import funkwhale_api
@ -6,6 +7,50 @@ import funkwhale_api
from funkwhale_api.subsonic import renderers from funkwhale_api.subsonic import renderers
@pytest.mark.parametrize(
"data,expected",
[
(
{"hello": "world"},
{
"status": "ok",
"version": "1.16.0",
"type": "funkwhale",
"funkwhaleVersion": funkwhale_api.__version__,
"hello": "world",
},
),
(
{
"hello": "world",
"error": {"code": 10, "message": "something went wrong"},
},
{
"status": "failed",
"version": "1.16.0",
"type": "funkwhale",
"funkwhaleVersion": funkwhale_api.__version__,
"hello": "world",
"error": {"code": 10, "message": "something went wrong"},
},
),
(
{"hello": "world", "detail": "something went wrong"},
{
"status": "failed",
"version": "1.16.0",
"type": "funkwhale",
"funkwhaleVersion": funkwhale_api.__version__,
"hello": "world",
"error": {"code": 0, "message": "something went wrong"},
},
),
],
)
def test_structure_payload(data, expected):
assert renderers.structure_payload(data) == expected
def test_json_renderer(): def test_json_renderer():
data = {"hello": "world"} data = {"hello": "world"}
expected = { expected = {
@ -32,7 +77,8 @@ def test_xml_renderer_dict_to_xml():
def test_xml_renderer(): def test_xml_renderer():
payload = {"hello": "world"} payload = {"hello": "world"}
expected = b'<?xml version="1.0" encoding="UTF-8"?>\n<subsonic-response hello="world" status="ok" version="1.16.0" xmlns="http://subsonic.org/restapi" />' # noqa expected = '<?xml version="1.0" encoding="UTF-8"?>\n<subsonic-response funkwhaleVersion="{}" hello="world" status="ok" type="funkwhale" version="1.16.0" xmlns="http://subsonic.org/restapi" />' # noqa
expected = expected.format(funkwhale_api.__version__).encode()
renderer = renderers.SubsonicXMLRenderer() renderer = renderers.SubsonicXMLRenderer()
rendered = renderer.render(payload) rendered = renderer.render(payload)

Wyświetl plik

@ -43,6 +43,20 @@ def test_exception_wrong_credentials(f, db, api_client):
assert response.data == expected assert response.data == expected
@pytest.mark.parametrize("f", ["json"])
def test_exception_missing_credentials(f, db, api_client):
url = reverse("api:subsonic-get-artists")
response = api_client.get(url)
expected = {
"status": "failed",
"error": {"code": 10, "message": "Required parameter is missing."},
}
assert response.status_code == 200
assert response.data == expected
def test_disabled_subsonic(preferences, api_client): def test_disabled_subsonic(preferences, api_client):
preferences["subsonic__enabled"] = False preferences["subsonic__enabled"] = False
url = reverse("api:subsonic-ping") url = reverse("api:subsonic-ping")

Wyświetl plik

@ -0,0 +1 @@
Fixed inconsistencies in subsonic error responses (#616)