diff --git a/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiErrorsTest.kt b/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiErrorsTest.kt index f91e4557..3b8c66f9 100644 --- a/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiErrorsTest.kt +++ b/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiErrorsTest.kt @@ -113,6 +113,42 @@ class SubsonicApiErrorsTest : SubsonicAPIClientTest() { response.assertError(RequestedDataWasNotFound) } + @Test + fun `Should parse error with reversed tokens order`() { + mockWebServerRule.enqueueResponse("reversed_tokens_generic_error.json") + + val response = client.api.ping().execute() + + response.assertError(Generic("Video streaming not supported")) + } + + @Test + fun `Should parse error if json contains error first before other fields`() { + mockWebServerRule.enqueueResponse("error_first_generic_error.json") + + val response = client.api.ping().execute() + + response.assertError(Generic("Video streaming not supported")) + } + + @Test + fun `Should parse error if json doesn't contain message field`() { + mockWebServerRule.enqueueResponse("without_message_generic_error.json") + + val response = client.api.ping().execute() + + response.assertError(Generic("")) + } + + @Test + fun `Should parse error if error json contains additional object`() { + mockWebServerRule.enqueueResponse("with_additional_json_object_generic_error.json") + + val response = client.api.ping().execute() + + response.assertError(Generic("")) + } + private fun Response.assertError(expectedError: SubsonicError) = with(body()) { error `should not be` null diff --git a/subsonic-api/src/integrationTest/resources/error_first_generic_error.json b/subsonic-api/src/integrationTest/resources/error_first_generic_error.json new file mode 100644 index 00000000..a278910e --- /dev/null +++ b/subsonic-api/src/integrationTest/resources/error_first_generic_error.json @@ -0,0 +1,10 @@ +{ + "subsonic-response": { + "error": { + "message": "Video streaming not supported", + "code": 0 + }, + "version": "1.8.0", + "status": "failed" + } +} diff --git a/subsonic-api/src/integrationTest/resources/reversed_tokens_generic_error.json b/subsonic-api/src/integrationTest/resources/reversed_tokens_generic_error.json new file mode 100644 index 00000000..549214c5 --- /dev/null +++ b/subsonic-api/src/integrationTest/resources/reversed_tokens_generic_error.json @@ -0,0 +1,10 @@ +{ + "subsonic-response": { + "status": "failed", + "version": "1.8.0", + "error": { + "message": "Video streaming not supported", + "code": 0 + } + } +} \ No newline at end of file diff --git a/subsonic-api/src/integrationTest/resources/with_additional_json_object_generic_error.json b/subsonic-api/src/integrationTest/resources/with_additional_json_object_generic_error.json new file mode 100644 index 00000000..5b44bb90 --- /dev/null +++ b/subsonic-api/src/integrationTest/resources/with_additional_json_object_generic_error.json @@ -0,0 +1,13 @@ +{ + "subsonic-response": { + "status": "failed", + "version": "1.8.0", + "error": { + "code": 0, + "unicorn" : { + "code": 41, + "message": "Unicorns doesn't exist!" + } + } + } +} diff --git a/subsonic-api/src/integrationTest/resources/without_message_generic_error.json b/subsonic-api/src/integrationTest/resources/without_message_generic_error.json new file mode 100644 index 00000000..904d1508 --- /dev/null +++ b/subsonic-api/src/integrationTest/resources/without_message_generic_error.json @@ -0,0 +1,9 @@ +{ + "subsonic-response": { + "status": "failed", + "version": "1.8.0", + "error": { + "code": 0 + } + } +} diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicError.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicError.kt index 89559cb2..ad1419e4 100644 --- a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicError.kt +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicError.kt @@ -1,6 +1,8 @@ package org.moire.ultrasonic.api.subsonic import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.JsonToken.END_OBJECT +import com.fasterxml.jackson.core.JsonToken.START_OBJECT import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.annotation.JsonDeserialize @@ -36,13 +38,17 @@ sealed class SubsonicError(val code: Int) { class SubsonicErrorDeserializer : JsonDeserializer() { override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): SubsonicError { - p.nextToken() // { -> "code" - p.nextToken() // "code" -> codeValue - val code = p.valueAsInt - p.nextToken() // codeValue -> "message" - p.nextToken() // "message" -> messageValue - val message = p.text - p.nextToken() // value -> } + var code = -1 + var message = "" + while (p.nextToken() != END_OBJECT) { + when { + p.currentToken == START_OBJECT -> p.skipChildren() + "code".equals(p.currentName, ignoreCase = true) -> + code = p.nextIntValue(-1) + "message".equals(p.currentName, ignoreCase = true) -> + message = p.nextTextValue() + } + } return getError(code, message) } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/RestErrorMapper.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/RestErrorMapper.kt index 385cdb25..5d84442e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/RestErrorMapper.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/RestErrorMapper.kt @@ -20,8 +20,15 @@ import org.moire.ultrasonic.service.SubsonicRESTException */ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String = when (error) { - is Generic -> context - .getString(R.string.api_subsonic_generic, (error as Generic).message) + is Generic -> { + val message = (error as Generic).message + val errorMessage = if (message == "") { + context.getString(R.string.api_subsonic_generic_no_message) + } else { + message + } + context.getString(R.string.api_subsonic_generic, errorMessage) + } RequiredParamMissing -> context.getString(R.string.api_subsonic_param_missing) IncompatibleClientProtocolVersion -> context .getString(R.string.api_subsonic_upgrade_client) diff --git a/ultrasonic/src/main/res/values-es/strings.xml b/ultrasonic/src/main/res/values-es/strings.xml index e43aa0c3..c047418a 100644 --- a/ultrasonic/src/main/res/values-es/strings.xml +++ b/ultrasonic/src/main/res/values-es/strings.xml @@ -424,6 +424,7 @@ Error genérico de api: %1$s + ningún mensaje dado desde el servidor La autenticación por token no es compatible con usuarios LDAP. Nombre de usuario o contraseña incorrectos. No autorizado. Comprueba los permisos de usuario en el servidor de Subsonic. diff --git a/ultrasonic/src/main/res/values-fr/strings.xml b/ultrasonic/src/main/res/values-fr/strings.xml index 936b85f1..0dfb8284 100644 --- a/ultrasonic/src/main/res/values-fr/strings.xml +++ b/ultrasonic/src/main/res/values-fr/strings.xml @@ -424,6 +424,7 @@ Erreur api générique: %1$s + aucun message donné par le serveur L\'authentification par jeton n\'est pas prise en charge pour les utilisateurs LDAP. Mauvais nom d\'usager ou mot de passe. Non autorisé. Vérifiez les permissions de l\'utilisateur dans le serveur Subsonic. diff --git a/ultrasonic/src/main/res/values-hu/strings.xml b/ultrasonic/src/main/res/values-hu/strings.xml index 8ed1f179..d94a0a88 100644 --- a/ultrasonic/src/main/res/values-hu/strings.xml +++ b/ultrasonic/src/main/res/values-hu/strings.xml @@ -424,6 +424,7 @@ Általános api hiba: %1$s + nincs üzenet a szerverről Az LDAP-felhasználók számára nem támogatott a token-hitelesítés. Hibás felhasználónév vagy jelszó! Nem engedélyezett! Ellenőrizze a felhasználó jogosultságait a Subsonic kiszolgálón! diff --git a/ultrasonic/src/main/res/values-pt-rBR/strings.xml b/ultrasonic/src/main/res/values-pt-rBR/strings.xml index 9ef2d86b..ba5042ac 100644 --- a/ultrasonic/src/main/res/values-pt-rBR/strings.xml +++ b/ultrasonic/src/main/res/values-pt-rBR/strings.xml @@ -424,6 +424,7 @@ Erro de api genérico: %1$s + nenhuma mensagem fornecida pelo servidor A autenticação por token não é suportada para usuários LDAP. Login ou senha errada. Não autorizado. Verifique as permissões do usuário no servidor Subsonic. diff --git a/ultrasonic/src/main/res/values-pt/strings.xml b/ultrasonic/src/main/res/values-pt/strings.xml index 4f8da965..b5f1e6c5 100644 --- a/ultrasonic/src/main/res/values-pt/strings.xml +++ b/ultrasonic/src/main/res/values-pt/strings.xml @@ -424,6 +424,7 @@ Erro de api genérico: %1$s + nenhuma mensagem fornecida pelo servidor A autenticação por token não é suportada para usuários LDAP. Login ou senha errada. Não autorizado. Verifique as permissões do usuário no servidor Subsonic. diff --git a/ultrasonic/src/main/res/values/strings.xml b/ultrasonic/src/main/res/values/strings.xml index 9a1d99e9..21ac1e74 100644 --- a/ultrasonic/src/main/res/values/strings.xml +++ b/ultrasonic/src/main/res/values/strings.xml @@ -426,6 +426,7 @@ Generic api error: %1$s + no message given from server Authentication by token is not supported for LDAP users. Wrong username or password. Not authorized. Check user permissions in Subsonic server.