diff --git a/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiGetUserTest.kt b/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiGetUserTest.kt new file mode 100644 index 00000000..648cbeae --- /dev/null +++ b/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiGetUserTest.kt @@ -0,0 +1,57 @@ +package org.moire.ultrasonic.api.subsonic + +import org.amshove.kluent.`should equal to` +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.api.subsonic.models.User + +/** + * Integration test for [SubsonicAPIDefinition.getUser] call. + */ +class SubsonicApiGetUserTest : SubsonicAPIClientTest() { + @Test + fun `Should handle error response`() { + val response = checkErrorCallParsed(mockWebServerRule) { + client.api.getUser("some").execute() + } + + response.user `should equal` User() + } + + @Test + fun `Should handle ok response`() { + mockWebServerRule.enqueueResponse("get_user_ok.json") + + val response = client.api.getUser("some").execute() + + assertResponseSuccessful(response) + with(response.body().user) { + username `should equal to` "GodOfUniverse" + email `should equal to` "some.mail@example.com" + scrobblingEnabled `should equal to` false + adminRole `should equal to` true + settingsRole `should equal to` true + downloadRole `should equal to` true + uploadRole `should equal to` true + playlistRole `should equal to` true + coverArtRole `should equal to` true + commentRole `should equal to` true + podcastRole `should equal to` true + streamRole `should equal to` true + jukeboxRole `should equal to` true + shareRole `should equal to` true + videoConverstionRole `should equal to` false + folderList.size `should equal to` 1 + folderList[0] `should equal to` 0 + } + } + + @Test + fun `Should pass username in request param`() { + val username = "Mighty" + + mockWebServerRule.assertRequestParam(expectedParam = "username=$username") { + client.api.getUser(username).execute() + } + } +} diff --git a/subsonic-api/src/integrationTest/resources/get_user_ok.json b/subsonic-api/src/integrationTest/resources/get_user_ok.json new file mode 100644 index 00000000..26e509df --- /dev/null +++ b/subsonic-api/src/integrationTest/resources/get_user_ok.json @@ -0,0 +1,24 @@ +{ + "subsonic-response" : { + "status" : "ok", + "version" : "1.15.0", + "user" : { + "username" : "GodOfUniverse", + "email" : "some.mail@example.com", + "scrobblingEnabled" : false, + "adminRole" : true, + "settingsRole" : true, + "downloadRole" : true, + "uploadRole" : true, + "playlistRole" : true, + "coverArtRole" : true, + "commentRole" : true, + "podcastRole" : true, + "streamRole" : true, + "jukeboxRole" : true, + "shareRole" : true, + "videoConversionRole" : false, + "folder" : [ 0 ] + } + } +} \ No newline at end of file diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt index ca63cb3f..276fcda0 100644 --- a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt @@ -19,6 +19,7 @@ import org.moire.ultrasonic.api.subsonic.response.GetRandomSongsResponse import org.moire.ultrasonic.api.subsonic.response.GetSongsByGenreResponse import org.moire.ultrasonic.api.subsonic.response.GetStarredResponse import org.moire.ultrasonic.api.subsonic.response.GetStarredTwoResponse +import org.moire.ultrasonic.api.subsonic.response.GetUserResponse import org.moire.ultrasonic.api.subsonic.response.JukeboxResponse import org.moire.ultrasonic.api.subsonic.response.LicenseResponse import org.moire.ultrasonic.api.subsonic.response.MusicFoldersResponse @@ -209,4 +210,8 @@ interface SubsonicAPIDefinition { @Query("count") count: Int = 10, @Query("offset") offset: Int = 0, @Query("musicFolderId") musicFolderId: Long? = null): Call + + @GET("getUser.view") + fun getUser( + @Query("username") username: String): Call } diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/models/User.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/models/User.kt new file mode 100644 index 00000000..792f2556 --- /dev/null +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/models/User.kt @@ -0,0 +1,21 @@ +package org.moire.ultrasonic.api.subsonic.models + +import com.fasterxml.jackson.annotation.JsonProperty + +data class User( + val username: String = "", + val email: String = "", + val scrobblingEnabled: Boolean = false, + val adminRole: Boolean = false, + val settingsRole: Boolean = false, + val downloadRole: Boolean = false, + val uploadRole: Boolean = false, + val playlistRole: Boolean = false, + val coverArtRole: Boolean = false, + val commentRole: Boolean = false, + val podcastRole: Boolean = false, + val streamRole: Boolean = false, + val jukeboxRole: Boolean = false, + val shareRole: Boolean = false, + val videoConverstionRole: Boolean = false, + @JsonProperty("folder") val folderList: List = emptyList()) diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/response/GetUserResponse.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/response/GetUserResponse.kt new file mode 100644 index 00000000..31934af4 --- /dev/null +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/response/GetUserResponse.kt @@ -0,0 +1,11 @@ +package org.moire.ultrasonic.api.subsonic.response + +import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions +import org.moire.ultrasonic.api.subsonic.SubsonicError +import org.moire.ultrasonic.api.subsonic.models.User + +class GetUserResponse( + status: Status, + version: SubsonicAPIVersions, + error: SubsonicError?, + val user: User = User()) : SubsonicResponse(status, version, error) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java index 33147a0c..7e456b1d 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java @@ -74,6 +74,7 @@ import org.moire.ultrasonic.api.subsonic.response.GetRandomSongsResponse; import org.moire.ultrasonic.api.subsonic.response.GetSongsByGenreResponse; import org.moire.ultrasonic.api.subsonic.response.GetStarredResponse; import org.moire.ultrasonic.api.subsonic.response.GetStarredTwoResponse; +import org.moire.ultrasonic.api.subsonic.response.GetUserResponse; import org.moire.ultrasonic.api.subsonic.response.JukeboxResponse; import org.moire.ultrasonic.api.subsonic.response.LicenseResponse; import org.moire.ultrasonic.api.subsonic.response.MusicFoldersResponse; @@ -94,6 +95,7 @@ import org.moire.ultrasonic.data.APIPlaylistConverter; import org.moire.ultrasonic.data.APIPodcastConverter; import org.moire.ultrasonic.data.APISearchConverter; import org.moire.ultrasonic.data.APIShareConverter; +import org.moire.ultrasonic.data.APIUserConverter; import org.moire.ultrasonic.data.ApiGenreConverter; import org.moire.ultrasonic.domain.Bookmark; import org.moire.ultrasonic.domain.ChatMessage; @@ -115,7 +117,6 @@ import org.moire.ultrasonic.service.parser.ChatMessageParser; import org.moire.ultrasonic.service.parser.ErrorParser; import org.moire.ultrasonic.service.parser.MusicDirectoryParser; import org.moire.ultrasonic.service.parser.SubsonicRESTException; -import org.moire.ultrasonic.service.parser.UserInfoParser; import org.moire.ultrasonic.service.ssl.SSLSocketFactory; import org.moire.ultrasonic.service.ssl.TrustSelfSignedStrategy; import org.moire.ultrasonic.util.CancellableTask; @@ -1228,31 +1229,21 @@ public class RESTMusicService implements MusicService return result; } - @Override - public UserInfo getUser(String username, Context context, ProgressListener progressListener) throws Exception - { - checkServerVersion(context, "1.3", "getUser not supported."); + @Override + public UserInfo getUser(String username, + Context context, + ProgressListener progressListener) throws Exception { + if (username == null) { + throw new IllegalArgumentException("Username is null"); + } - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); + updateProgressListener(progressListener, R.string.parser_reading); + Response response = subsonicAPIClient.getApi() + .getUser(username).execute(); + checkResponseSuccessful(response); - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("username"); - parameterValues.add(username); - - Reader reader = getReader(context, progressListener, "getUser", params, parameterNames, parameterValues); - - try - { - return new UserInfoParser(context).parse(reader, progressListener); - } - finally - { - Util.close(reader); - } - } + return APIUserConverter.toDomainEntity(response.body().getUser()); + } @Override public List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIUserConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIUserConverter.kt new file mode 100644 index 00000000..30fd036f --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIUserConverter.kt @@ -0,0 +1,23 @@ +// Helper functions to convert User entity to domain entity +@file:JvmName("APIUserConverter") +package org.moire.ultrasonic.data + +import org.moire.ultrasonic.domain.UserInfo +import org.moire.ultrasonic.api.subsonic.models.User + +fun User.toDomainEntity(): UserInfo = UserInfo().apply { + adminRole = this@toDomainEntity.adminRole + commentRole = this@toDomainEntity.commentRole + coverArtRole = this@toDomainEntity.coverArtRole + downloadRole = this@toDomainEntity.downloadRole + email = this@toDomainEntity.email + jukeboxRole = this@toDomainEntity.jukeboxRole + playlistRole = this@toDomainEntity.playlistRole + podcastRole = this@toDomainEntity.podcastRole + scrobblingEnabled = this@toDomainEntity.scrobblingEnabled + settingsRole = this@toDomainEntity.settingsRole + shareRole = this@toDomainEntity.shareRole + streamRole = this@toDomainEntity.streamRole + uploadRole = this@toDomainEntity.uploadRole + userName = this@toDomainEntity.username +} diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIUserConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIUserConverterTest.kt new file mode 100644 index 00000000..4b5f2eb7 --- /dev/null +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIUserConverterTest.kt @@ -0,0 +1,37 @@ +@file:Suppress("IllegalIdentifier") + +package org.moire.ultrasonic.data + +import org.amshove.kluent.`should equal to` +import org.junit.Test +import org.moire.ultrasonic.api.subsonic.models.User + +/** + * Test conversion from api [User] to domain [UserInfo]. + */ +class APIUserConverterTest { + @Test + fun `Should convert to domain entity`() { + val entity = User(username = "Awsemo", email = "none@none.net", scrobblingEnabled = false, + shareRole = true, streamRole = true) + + val domainEntity = entity.toDomainEntity() + + with(domainEntity) { + adminRole `should equal to` entity.adminRole + commentRole `should equal to` entity.commentRole + coverArtRole `should equal to` entity.coverArtRole + downloadRole `should equal to` entity.downloadRole + email `should equal to` entity.email + jukeboxRole `should equal to` entity.jukeboxRole + playlistRole `should equal to` entity.playlistRole + podcastRole `should equal to` entity.podcastRole + scrobblingEnabled `should equal to` entity.scrobblingEnabled + settingsRole `should equal to` entity.settingsRole + shareRole `should equal to` entity.shareRole + streamRole `should equal to` entity.streamRole + uploadRole `should equal to` entity.uploadRole + userName `should equal to` entity.username + } + } +}