Merge pull request #65 from ultrasonic/add-get-chat-messages

Add get chat messages
This commit is contained in:
Yahor Berdnikau 2017-11-16 21:36:55 +01:00 committed by GitHub
commit 52f63cb2b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 158 additions and 153 deletions

View File

@ -0,0 +1,45 @@
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.ChatMessage
/**
* Integration test for [SubsonicAPIDefinition.getChatMessages] call.
*/
class SubsonicApiGetChatMessagesTest : SubsonicAPIClientTest() {
@Test
fun `Should handle error response`() {
val response = checkErrorCallParsed(mockWebServerRule) {
client.api.getChatMessages().execute()
}
response.chatMessages `should equal` emptyList()
}
@Test
fun `Should handle ok response`() {
mockWebServerRule.enqueueResponse("get_chat_messages_ok.json")
val response = client.api.getChatMessages().execute()
assertResponseSuccessful(response)
with(response.body().chatMessages) {
size `should equal to` 2
this[0] `should equal` ChatMessage(username = "sindre", time = 1269771845310,
message = "Sindre was here")
this[1] `should equal` ChatMessage(username = "ben", time = 1269771842504,
message = "Ben too")
}
}
@Test
fun `Should pass since in request param`() {
val since = 21388L
mockWebServerRule.assertRequestParam(expectedParam = "since=$since") {
client.api.getChatMessages(since = since).execute()
}
}
}

View File

@ -0,0 +1,17 @@
{
"subsonic-response" : {
"status" : "ok",
"version" : "1.15.0",
"chatMessages" : {
"chatMessage" : [ {
"username" : "sindre",
"time" : 1269771845310,
"message" : "Sindre was here"
}, {
"username" : "ben",
"time" : 1269771842504,
"message" : "Ben too"
} ]
}
}
}

View File

@ -3,6 +3,7 @@ package org.moire.ultrasonic.api.subsonic
import okhttp3.ResponseBody
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
import org.moire.ultrasonic.api.subsonic.models.JukeboxAction
import org.moire.ultrasonic.api.subsonic.response.ChatMessagesResponse
import org.moire.ultrasonic.api.subsonic.response.GenresResponse
import org.moire.ultrasonic.api.subsonic.response.GetAlbumList2Response
import org.moire.ultrasonic.api.subsonic.response.GetAlbumListResponse
@ -212,6 +213,8 @@ interface SubsonicAPIDefinition {
@Query("musicFolderId") musicFolderId: Long? = null): Call<GetSongsByGenreResponse>
@GET("getUser.view")
fun getUser(
@Query("username") username: String): Call<GetUserResponse>
fun getUser(@Query("username") username: String): Call<GetUserResponse>
@GET("getChatMessages.view")
fun getChatMessages(@Query("since") since: Long? = null): Call<ChatMessagesResponse>
}

View File

@ -0,0 +1,6 @@
package org.moire.ultrasonic.api.subsonic.models
data class ChatMessage(
val username: String = "",
val time: Long = 0,
val message: String = "")

View File

@ -0,0 +1,18 @@
package org.moire.ultrasonic.api.subsonic.response
import com.fasterxml.jackson.annotation.JsonProperty
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
import org.moire.ultrasonic.api.subsonic.SubsonicError
import org.moire.ultrasonic.api.subsonic.models.ChatMessage
class ChatMessagesResponse(
status: Status,
version: SubsonicAPIVersions,
error: SubsonicError?) : SubsonicResponse(status, version, error) {
@JsonProperty("chatMessages") private val wrapper = ChatMessagesWrapper()
val chatMessages: List<ChatMessage> get() = wrapper.messagesList
}
internal class ChatMessagesWrapper(
@JsonProperty("chatMessage") val messagesList: List<ChatMessage> = emptyList())

View File

@ -58,6 +58,7 @@ import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient;
import org.moire.ultrasonic.api.subsonic.models.AlbumListType;
import org.moire.ultrasonic.api.subsonic.models.JukeboxAction;
import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild;
import org.moire.ultrasonic.api.subsonic.response.ChatMessagesResponse;
import org.moire.ultrasonic.api.subsonic.response.GenresResponse;
import org.moire.ultrasonic.api.subsonic.response.GetAlbumList2Response;
import org.moire.ultrasonic.api.subsonic.response.GetAlbumListResponse;
@ -86,6 +87,7 @@ import org.moire.ultrasonic.api.subsonic.response.StreamResponse;
import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse;
import org.moire.ultrasonic.data.APIAlbumConverter;
import org.moire.ultrasonic.data.APIArtistConverter;
import org.moire.ultrasonic.data.APIChatMessageConverter;
import org.moire.ultrasonic.data.APIIndexesConverter;
import org.moire.ultrasonic.data.APIJukeboxConverter;
import org.moire.ultrasonic.data.APILyricsConverter;
@ -113,7 +115,6 @@ import org.moire.ultrasonic.domain.Share;
import org.moire.ultrasonic.domain.UserInfo;
import org.moire.ultrasonic.domain.Version;
import org.moire.ultrasonic.service.parser.BookmarkParser;
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;
@ -1245,31 +1246,17 @@ public class RESTMusicService implements MusicService
return APIUserConverter.toDomainEntity(response.body().getUser());
}
@Override
public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception
{
checkServerVersion(context, "1.2", "Chat not supported.");
@Override
public List<ChatMessage> getChatMessages(Long since,
Context context,
ProgressListener progressListener) throws Exception {
updateProgressListener(progressListener, R.string.parser_reading);
Response<ChatMessagesResponse> response = subsonicAPIClient.getApi()
.getChatMessages(since).execute();
checkResponseSuccessful(response);
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS);
List<String> parameterNames = new ArrayList<String>();
List<Object> parameterValues = new ArrayList<Object>();
parameterNames.add("since");
parameterValues.add(since);
Reader reader = getReader(context, progressListener, "getChatMessages", params, parameterNames, parameterValues);
try
{
return new ChatMessageParser(context).parse(reader, progressListener);
}
finally
{
Util.close(reader);
}
}
return APIChatMessageConverter.toDomainEntitiesList(response.body().getChatMessages());
}
@Override
public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception

View File

@ -1,59 +0,0 @@
package org.moire.ultrasonic.service.parser;
import android.content.Context;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.ChatMessage;
import org.moire.ultrasonic.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Joshua Bahnsen
*/
public class ChatMessageParser extends AbstractParser
{
public ChatMessageParser(Context context)
{
super(context);
}
public List<ChatMessage> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<ChatMessage> result = new ArrayList<ChatMessage>();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("chatMessage".equals(name))
{
ChatMessage chatMessage = new ChatMessage();
chatMessage.setUsername(get("username"));
chatMessage.setTime(getLong("time"));
chatMessage.setMessage(get("message"));
result.add(chatMessage);
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
}

View File

@ -1,67 +0,0 @@
package org.moire.ultrasonic.service.parser;
import android.content.Context;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.UserInfo;
import org.moire.ultrasonic.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
/**
* @author Joshua Bahnsen
*/
public class UserInfoParser extends AbstractParser
{
public UserInfoParser(Context context)
{
super(context);
}
public UserInfo parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
UserInfo result = new UserInfo();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("user".equals(name))
{
result.setAdminRole(getBoolean("adminRole"));
result.setCommentRole(getBoolean("commentRole"));
result.setCoverArtRole(getBoolean("coverArtRole"));
result.setDownloadRole(getBoolean("downloadRole"));
result.setEmail(get("email"));
result.setJukeboxRole(getBoolean("jukeboxRole"));
result.setPlaylistRole(getBoolean("playlistRole"));
result.setPodcastRole(getBoolean("podcastRole"));
result.setScrobblingEnabled(getBoolean("scrobblingEnabled"));
result.setSettingsRole(getBoolean("settingsRole"));
result.setShareRole(getBoolean("shareRole"));
result.setStreamRole(getBoolean("streamRole"));
result.setUploadRole(getBoolean("uploadRole"));
result.setUserName(get("username"));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
}

View File

@ -0,0 +1,15 @@
// Contains helper functions to convert from api ChatMessage entity to domain entity
@file:JvmName("APIChatMessageConverter")
package org.moire.ultrasonic.data
import org.moire.ultrasonic.domain.ChatMessage
import org.moire.ultrasonic.api.subsonic.models.ChatMessage as ApiChatMessage
fun ApiChatMessage.toDomainEntity(): ChatMessage = ChatMessage().apply {
username = this@toDomainEntity.username
time = this@toDomainEntity.time
message = this@toDomainEntity.message
}
fun List<ApiChatMessage>.toDomainEntitiesList(): List<ChatMessage> = this
.map { it.toDomainEntity() }

View File

@ -0,0 +1,40 @@
@file:Suppress("IllegalIdentifier")
package org.moire.ultrasonic.data
import org.amshove.kluent.`should equal to`
import org.amshove.kluent.`should equal`
import org.junit.Test
import org.moire.ultrasonic.api.subsonic.models.ChatMessage
/**
* Unit test for functions converting api [ChatMessage] to domain entity.
*/
class APIChatMessageConverterTest {
@Test
fun `Should convert entity`() {
val entity = ChatMessage("Woohoo", 553434L, "Wow")
val domainEntity = entity.toDomainEntity()
with(domainEntity) {
username `should equal to` entity.username
time `should equal to` entity.time
message `should equal to` entity.message
}
}
@Test
fun `Should convert list of entities`() {
val entitiesList = listOf(ChatMessage("AAA"), ChatMessage("BBB"))
val domainEntitiesList = entitiesList.toDomainEntitiesList()
with(domainEntitiesList) {
size `should equal to` entitiesList.size
forEachIndexed { index, chatMessage ->
chatMessage `should equal` entitiesList[index].toDomainEntity()
}
}
}
}