Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import io.getstream.chat.android.client.parser2.direct.PrivacySettingsAdapter
import io.getstream.chat.android.client.parser2.direct.ReactionAdapter
import io.getstream.chat.android.client.parser2.direct.ReactionGroupAdapter
import io.getstream.chat.android.client.parser2.direct.UserAdapter
import io.getstream.chat.android.client.parser2.direct.UserGroupAdapter
import io.getstream.chat.android.client.parser2.direct.UserGroupMemberAdapter
import io.getstream.chat.android.models.EventType
import io.getstream.chat.android.models.MessageTransformer
import io.getstream.chat.android.models.UserId
Expand Down Expand Up @@ -76,6 +78,8 @@ internal class DirectEventParser(
private val userAdapter by lazy {
UserAdapter(deviceAdapter, privacySettingsAdapter, dateAdapter, userTransformer)
}
private val userGroupMemberAdapter by lazy { UserGroupMemberAdapter(dateAdapter) }
private val userGroupAdapter by lazy { UserGroupAdapter(userGroupMemberAdapter, dateAdapter) }
private val reactionAdapter by lazy { ReactionAdapter(userAdapter, dateAdapter) }
private val pollAdapter by lazy {
PollAdapter(userAdapter, optionAdapter, dateAdapter, currentUserIdProvider)
Expand All @@ -84,7 +88,7 @@ internal class DirectEventParser(
private val messageAdapter by lazy {
MessageAdapter(
attachmentAdapter, channelInfoAdapter, reactionAdapter,
reactionGroupAdapter, userAdapter, moderationDetailsAdapter, moderationAdapter,
reactionGroupAdapter, userAdapter, userGroupAdapter, moderationDetailsAdapter, moderationAdapter,
pollAdapter, reminderAdapter, locationAdapter, dateAdapter, messageTransformer,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import io.getstream.chat.android.models.Poll
import io.getstream.chat.android.models.Reaction
import io.getstream.chat.android.models.ReactionGroup
import io.getstream.chat.android.models.User
import io.getstream.chat.android.models.UserGroup
import java.util.Date

@Suppress("LongParameterList")
Expand All @@ -40,6 +41,7 @@ internal class MessageAdapter(
private val reactionAdapter: JsonAdapter<Reaction>,
private val reactionGroupAdapter: ReactionGroupAdapter,
private val userAdapter: JsonAdapter<User>,
private val userGroupAdapter: JsonAdapter<UserGroup>,
private val moderationDetailsAdapter: JsonAdapter<MessageModerationDetails>,
private val moderationAdapter: JsonAdapter<Moderation>,
private val pollAdapter: JsonAdapter<Poll>,
Expand Down Expand Up @@ -70,6 +72,10 @@ internal class MessageAdapter(
var id: String? = null
var latestReactions: List<Reaction>? = null
var mentionedUsers: List<User>? = null
var mentionedHere: Boolean? = null
var mentionedChannel: Boolean? = null
var mentionedGroups: List<UserGroup>? = null
var mentionedRoles: List<String>? = null
var ownReactions: List<Reaction>? = null
var parentId: String? = null
var pinExpires: Date? = null
Expand Down Expand Up @@ -120,6 +126,16 @@ internal class MessageAdapter(
"id" -> id = reader.nextString()
"latest_reactions" -> latestReactions = JsonParsingUtils.parseList(reader, reactionAdapter)
"mentioned_users" -> mentionedUsers = JsonParsingUtils.parseList(reader, userAdapter)
"mentioned_here" -> mentionedHere = JsonParsingUtils.readNullableBoolean(reader)
"mentioned_channel" -> mentionedChannel = JsonParsingUtils.readNullableBoolean(reader)
"mentioned_groups" -> {
JsonParsingUtils.rejectExplicitNull(reader, "mentioned_groups")
mentionedGroups = JsonParsingUtils.parseList(reader, userGroupAdapter)
}
"mentioned_roles" -> {
JsonParsingUtils.rejectExplicitNull(reader, "mentioned_roles")
mentionedRoles = JsonParsingUtils.parseStringList(reader)
}
"own_reactions" -> ownReactions = JsonParsingUtils.parseList(reader, reactionAdapter)
"parent_id" -> parentId = JsonParsingUtils.readNullableString(reader)
"pin_expires" -> pinExpires = dateAdapter.fromJson(reader)
Expand Down Expand Up @@ -222,6 +238,10 @@ internal class MessageAdapter(
id = id,
latestReactions = filteredLatestReactions,
mentionedUsers = mentionedUsers,
mentionedHere = mentionedHere == true,
mentionedChannel = mentionedChannel == true,
mentionedGroups = mentionedGroups.orEmpty(),
mentionedRoles = mentionedRoles.orEmpty(),
ownReactions = filteredOwnReactions,
parentId = parentId,
pinExpires = pinExpires,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2014-2026 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getstream.chat.android.client.parser2.direct

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import io.getstream.chat.android.models.UserGroup
import io.getstream.chat.android.models.UserGroupMember
import java.util.Date

internal class UserGroupAdapter(
private val memberAdapter: JsonAdapter<UserGroupMember>,
private val dateAdapter: JsonAdapter<Date>,
) : JsonAdapter<UserGroup>() {

override fun fromJson(reader: JsonReader): UserGroup? {
if (reader.peek() == JsonReader.Token.NULL) return reader.nextNull()

reader.beginObject()

var id: String? = null
var name: String? = null
var description: String? = null
var teamId: String? = null
var members: List<UserGroupMember>? = null
var createdBy: String? = null
var createdAt: Date? = null
var updatedAt: Date? = null

while (reader.hasNext()) {
when (reader.nextName()) {
"id" -> id = reader.nextString()
"name" -> name = reader.nextString()
"description" -> description = JsonParsingUtils.readNullableString(reader)
"team_id" -> teamId = JsonParsingUtils.readNullableString(reader)
"members" -> members = JsonParsingUtils.parseList(reader, memberAdapter)
"created_by" -> createdBy = JsonParsingUtils.readNullableString(reader)
"created_at" -> createdAt = dateAdapter.fromJson(reader)
"updated_at" -> updatedAt = dateAdapter.fromJson(reader)
else -> reader.skipValue()
}
}
reader.endObject()

JsonParsingUtils.requireField(id, "id", reader)
JsonParsingUtils.requireField(name, "name", reader)

return UserGroup(
id = id,
name = name,
description = description,
team = teamId.orEmpty(),
members = members ?: emptyList(),
createdBy = createdBy,
createdAt = createdAt,
updatedAt = updatedAt,
)
}

override fun toJson(p0: JsonWriter, p1: UserGroup?) {
error("Serialization not supported for direct-to-domain path")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2014-2026 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getstream.chat.android.client.parser2.direct

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import io.getstream.chat.android.models.UserGroupMember
import java.util.Date

internal class UserGroupMemberAdapter(
private val dateAdapter: JsonAdapter<Date>,
) : JsonAdapter<UserGroupMember>() {

override fun fromJson(reader: JsonReader): UserGroupMember? {
if (reader.peek() == JsonReader.Token.NULL) return reader.nextNull()

reader.beginObject()

var groupId: String? = null
var userId: String? = null
var isAdmin: Boolean? = null
var createdAt: Date? = null

while (reader.hasNext()) {
when (reader.nextName()) {
"group_id" -> groupId = reader.nextString()
"user_id" -> userId = reader.nextString()
"is_admin" -> isAdmin = reader.nextBoolean()
"created_at" -> createdAt = dateAdapter.fromJson(reader)
else -> reader.skipValue()
}
}
reader.endObject()

JsonParsingUtils.requireField(groupId, "group_id", reader)
JsonParsingUtils.requireField(userId, "user_id", reader)

return UserGroupMember(
groupId = groupId,
userId = userId,
isAdmin = isAdmin ?: false,
createdAt = createdAt,
)
}

override fun toJson(p0: JsonWriter, p1: UserGroupMember?) {
error("Serialization not supported for direct-to-domain path")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import io.getstream.chat.android.client.parser2.direct.PrivacySettingsAdapter
import io.getstream.chat.android.client.parser2.direct.ReactionAdapter
import io.getstream.chat.android.client.parser2.direct.ReactionGroupAdapter
import io.getstream.chat.android.client.parser2.direct.UserAdapter
import io.getstream.chat.android.client.parser2.direct.UserGroupAdapter
import io.getstream.chat.android.client.parser2.direct.UserGroupMemberAdapter
import io.getstream.chat.android.client.parser2.testdata.MessageTestData
import io.getstream.chat.android.models.Message
import io.getstream.chat.android.models.MessageTransformer
Expand Down Expand Up @@ -77,6 +79,13 @@ internal class MessageParsingTest {
private val reactionGroupAdapter = ReactionGroupAdapter(
dateAdapter = dateAdapter,
)
private val userGroupMemberAdapter = UserGroupMemberAdapter(
dateAdapter = dateAdapter,
)
private val userGroupAdapter = UserGroupAdapter(
memberAdapter = userGroupMemberAdapter,
dateAdapter = dateAdapter,
)
private val attachmentAdapter = AttachmentAdapter()
private val channelInfoAdapter = ChannelInfoAdapter()
private val moderationDetailsAdapter = MessageModerationDetailsAdapter()
Expand All @@ -101,6 +110,7 @@ internal class MessageParsingTest {
reactionAdapter = reactionAdapter,
reactionGroupAdapter = reactionGroupAdapter,
userAdapter = userAdapter,
userGroupAdapter = userGroupAdapter,
moderationDetailsAdapter = moderationDetailsAdapter,
moderationAdapter = moderationAdapter,
pollAdapter = pollAdapter,
Expand Down Expand Up @@ -268,6 +278,14 @@ internal class MessageParsingTest {
fun `Both paths - throw on explicit null thread_participants`() =
assertBothPathsThrow(MessageTestData.jsonExplicitNullThreadParticipants)

@Test
fun `Both paths - throw on explicit null mentioned_groups`() =
assertBothPathsThrow(MessageTestData.jsonExplicitNullMentionedGroups)

@Test
fun `Both paths - throw on explicit null mentioned_roles`() =
assertBothPathsThrow(MessageTestData.jsonExplicitNullMentionedRoles)

private fun assertBothPathsThrow(json: String) {
assertThrows<JsonDataException> {
parser.fromJson(json, DownstreamMessageDto::class.java)
Expand Down Expand Up @@ -296,6 +314,7 @@ internal class MessageParsingTest {
reactionAdapter = reactionAdapter,
reactionGroupAdapter = reactionGroupAdapter,
userAdapter = userAdapter,
userGroupAdapter = userGroupAdapter,
moderationDetailsAdapter = moderationDetailsAdapter,
moderationAdapter = moderationAdapter,
pollAdapter = pollAdapter,
Expand Down Expand Up @@ -344,6 +363,7 @@ internal class MessageParsingTest {
reactionAdapter = transformedReactionAdapter,
reactionGroupAdapter = reactionGroupAdapter,
userAdapter = transformedUserAdapter,
userGroupAdapter = userGroupAdapter,
moderationDetailsAdapter = moderationDetailsAdapter,
moderationAdapter = moderationAdapter,
pollAdapter = transformedPollAdapter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import io.getstream.chat.android.client.parser2.direct.PrivacySettingsAdapter
import io.getstream.chat.android.client.parser2.direct.ReactionAdapter
import io.getstream.chat.android.client.parser2.direct.ReactionGroupAdapter
import io.getstream.chat.android.client.parser2.direct.UserAdapter
import io.getstream.chat.android.client.parser2.direct.UserGroupAdapter
import io.getstream.chat.android.client.parser2.direct.UserGroupMemberAdapter
import io.getstream.chat.android.client.parser2.testdata.NewMessageEventTestData
import io.getstream.chat.android.models.NoOpChannelTransformer
import io.getstream.chat.android.models.NoOpMessageTransformer
Expand Down Expand Up @@ -77,6 +79,13 @@ internal class NewMessageEventParsingTest {
private val reactionGroupAdapter = ReactionGroupAdapter(
dateAdapter = dateAdapter,
)
private val userGroupMemberAdapter = UserGroupMemberAdapter(
dateAdapter = dateAdapter,
)
private val userGroupAdapter = UserGroupAdapter(
memberAdapter = userGroupMemberAdapter,
dateAdapter = dateAdapter,
)
private val attachmentAdapter = AttachmentAdapter()
private val channelInfoAdapter = ChannelInfoAdapter()
private val moderationDetailsAdapter = MessageModerationDetailsAdapter()
Expand All @@ -100,6 +109,7 @@ internal class NewMessageEventParsingTest {
reactionAdapter = reactionAdapter,
reactionGroupAdapter = reactionGroupAdapter,
userAdapter = userAdapter,
userGroupAdapter = userGroupAdapter,
moderationDetailsAdapter = moderationDetailsAdapter,
moderationAdapter = moderationAdapter,
pollAdapter = pollAdapter,
Expand Down
Loading
Loading