Răsfoiți Sursa

Merge pull request #4277 from nextcloud/bugfix/4272/fixToHandleOldServerVersions

Bugfix/4272/fix to handle old server versions
Marcel Hibbe 7 luni în urmă
părinte
comite
21bb71fba4

+ 2 - 3
app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt

@@ -1745,9 +1745,8 @@ class CallActivity : CallBaseActivity() {
         ApplicationWideCurrentRoomHolder.getInstance().callStartTime = conversation.callStartTime
     }
 
-    private fun startCallTimeCounter(callStartTime: Long?) {
-        if (callStartTime != null &&
-            callStartTime != 0L &&
+    private fun startCallTimeCounter(callStartTime: Long) {
+        if (callStartTime != 0L &&
             hasSpreedFeatureCapability(
                 conversationUser!!.capabilities!!.spreedCapability!!, SpreedFeatures.RECORDING_V1
             )

+ 4 - 4
app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt

@@ -356,8 +356,8 @@ class ConversationInfoActivity :
             binding.webinarInfoView.startTimeButton.setOnClickListener {
                 MaterialDialog(this, BottomSheet(WRAP_CONTENT)).show {
                     val currentTimeCalendar = Calendar.getInstance()
-                    if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != 0L) {
-                        currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer!! * DateConstants.SECOND_DIVIDER
+                    if (conversation!!.lobbyTimer != 0L) {
+                        currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer * DateConstants.SECOND_DIVIDER
                     }
 
                     dateTimePicker(
@@ -746,13 +746,13 @@ class ConversationInfoActivity :
 
             setupWebinaryView()
 
-            if (!ConversationUtils.canLeave(conversation!!)) {
+            if (!conversation!!.canLeaveConversation) {
                 binding.leaveConversationAction.visibility = GONE
             } else {
                 binding.leaveConversationAction.visibility = VISIBLE
             }
 
-            if (!ConversationUtils.canDelete(conversation!!, spreedCapabilities)) {
+            if (!conversation!!.canDeleteConversation) {
                 binding.deleteConversationAction.visibility = GONE
             } else {
                 binding.deleteConversationAction.visibility = VISIBLE

+ 21 - 21
app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt

@@ -116,36 +116,36 @@ fun Conversation.asEntity(accountId: Long) =
     ConversationEntity(
         internalId = "$accountId@$token",
         accountId = accountId,
-        token = token!!,
-        name = name!!,
-        displayName = displayName!!,
-        description = description!!,
-        type = type!!,
+        token = token,
+        name = name,
+        displayName = displayName,
+        description = description,
+        type = type,
         lastPing = lastPing,
-        participantType = participantType!!,
+        participantType = participantType,
         hasPassword = hasPassword,
-        sessionId = sessionId!!,
-        actorId = actorId!!,
-        actorType = actorType!!,
+        sessionId = sessionId,
+        actorId = actorId,
+        actorType = actorType,
         favorite = favorite,
         lastActivity = lastActivity,
         unreadMessages = unreadMessages,
         unreadMention = unreadMention,
         lastMessage = lastMessage?.let { LoganSquare.serialize(lastMessage) },
-        objectType = objectType!!,
-        notificationLevel = notificationLevel!!,
-        conversationReadOnlyState = conversationReadOnlyState!!,
-        lobbyState = lobbyState!!,
-        lobbyTimer = lobbyTimer!!,
+        objectType = objectType,
+        notificationLevel = notificationLevel,
+        conversationReadOnlyState = conversationReadOnlyState,
+        lobbyState = lobbyState,
+        lobbyTimer = lobbyTimer,
         lastReadMessage = lastReadMessage,
         lastCommonReadMessage = lastCommonReadMessage,
         hasCall = hasCall,
         callFlag = callFlag,
         canStartCall = canStartCall,
-        canLeaveConversation = canLeaveConversation!!,
-        canDeleteConversation = canDeleteConversation!!,
-        unreadMentionDirect = unreadMentionDirect!!,
-        notificationCalls = notificationCalls!!,
+        canLeaveConversation = canLeaveConversation,
+        canDeleteConversation = canDeleteConversation,
+        unreadMentionDirect = unreadMentionDirect,
+        notificationCalls = notificationCalls,
         permissions = permissions,
         messageExpiration = messageExpiration,
         status = status,
@@ -153,9 +153,9 @@ fun Conversation.asEntity(accountId: Long) =
         statusMessage = statusMessage,
         statusClearAt = statusClearAt,
         callRecording = callRecording,
-        avatarVersion = avatarVersion!!,
-        hasCustomAvatar = hasCustomAvatar!!,
-        callStartTime = callStartTime!!,
+        avatarVersion = avatarVersion,
+        hasCustomAvatar = hasCustomAvatar,
+        callStartTime = callStartTime,
         recordingConsentRequired = recordingConsentRequired,
         remoteServer = remoteServer,
         remoteToken = remoteToken

+ 21 - 67
app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt

@@ -16,7 +16,6 @@ import com.nextcloud.talk.models.json.participants.Participant
 class ConversationModel(
     var internalId: String,
     var accountId: Long,
-    // var roomId: String? = null,
     var token: String,
     var name: String,
     var displayName: String,
@@ -70,46 +69,45 @@ class ConversationModel(
             return ConversationModel(
                 internalId = user.id!!.toString() + "@" + conversation.token,
                 accountId = user.id!!,
-                // roomId = conversation.roomId,
-                token = conversation.token!!,
-                name = conversation.name!!,
-                displayName = conversation.displayName!!,
-                description = conversation.description!!,
-                type = conversation.type.let { ConversationEnums.ConversationType.valueOf(it!!.name) },
+                token = conversation.token,
+                name = conversation.name,
+                displayName = conversation.displayName,
+                description = conversation.description,
+                type = conversation.type.let { ConversationEnums.ConversationType.valueOf(it.name) },
                 lastPing = conversation.lastPing,
-                participantType = conversation.participantType.let { Participant.ParticipantType.valueOf(it!!.name) },
+                participantType = conversation.participantType.let { Participant.ParticipantType.valueOf(it.name) },
                 hasPassword = conversation.hasPassword,
-                sessionId = conversation.sessionId!!,
-                actorId = conversation.actorId!!,
-                actorType = conversation.actorType!!,
+                sessionId = conversation.sessionId,
+                actorId = conversation.actorId,
+                actorType = conversation.actorType,
                 password = conversation.password,
                 favorite = conversation.favorite,
                 lastActivity = conversation.lastActivity,
                 unreadMessages = conversation.unreadMessages,
                 unreadMention = conversation.unreadMention,
                 lastMessage = conversation.lastMessage,
-                objectType = conversation.objectType.let { ConversationEnums.ObjectType.valueOf(it!!.name) },
+                objectType = conversation.objectType.let { ConversationEnums.ObjectType.valueOf(it.name) },
                 notificationLevel = conversation.notificationLevel.let {
                     ConversationEnums.NotificationLevel.valueOf(
-                        it!!.name
+                        it.name
                     )
                 },
                 conversationReadOnlyState = conversation.conversationReadOnlyState.let {
                     ConversationEnums.ConversationReadOnlyState.valueOf(
-                        it!!.name
+                        it.name
                     )
                 },
-                lobbyState = conversation.lobbyState.let { ConversationEnums.LobbyState.valueOf(it!!.name) },
-                lobbyTimer = conversation.lobbyTimer!!,
+                lobbyState = conversation.lobbyState.let { ConversationEnums.LobbyState.valueOf(it.name) },
+                lobbyTimer = conversation.lobbyTimer,
                 lastReadMessage = conversation.lastReadMessage,
                 lastCommonReadMessage = conversation.lastCommonReadMessage,
                 hasCall = conversation.hasCall,
                 callFlag = conversation.callFlag,
                 canStartCall = conversation.canStartCall,
-                canLeaveConversation = conversation.canLeaveConversation!!,
-                canDeleteConversation = conversation.canDeleteConversation!!,
-                unreadMentionDirect = conversation.unreadMentionDirect!!,
-                notificationCalls = conversation.notificationCalls!!,
+                canLeaveConversation = conversation.canLeaveConversation,
+                canDeleteConversation = conversation.canDeleteConversation,
+                unreadMentionDirect = conversation.unreadMentionDirect,
+                notificationCalls = conversation.notificationCalls,
                 permissions = conversation.permissions,
                 messageExpiration = conversation.messageExpiration,
                 status = conversation.status,
@@ -117,9 +115,9 @@ class ConversationModel(
                 statusMessage = conversation.statusMessage,
                 statusClearAt = conversation.statusClearAt,
                 callRecording = conversation.callRecording,
-                avatarVersion = conversation.avatarVersion!!,
-                hasCustomAvatar = conversation.hasCustomAvatar!!,
-                callStartTime = conversation.callStartTime!!,
+                avatarVersion = conversation.avatarVersion,
+                hasCustomAvatar = conversation.hasCustomAvatar,
+                callStartTime = conversation.callStartTime,
                 recordingConsentRequired = conversation.recordingConsentRequired,
                 remoteServer = conversation.remoteServer,
                 remoteToken = conversation.remoteToken
@@ -127,47 +125,3 @@ class ConversationModel(
         }
     }
 }
-
-// enum class ConversationType {
-//     DUMMY,
-//     ROOM_TYPE_ONE_TO_ONE_CALL,
-//     ROOM_GROUP_CALL,
-//     ROOM_PUBLIC_CALL,
-//     ROOM_SYSTEM,
-//     FORMER_ONE_TO_ONE,
-//     NOTE_TO_SELF
-// }
-//
-// enum class ParticipantType {
-//     DUMMY,
-//     OWNER,
-//     MODERATOR,
-//     USER,
-//     GUEST,
-//     USER_FOLLOWING_LINK,
-//     GUEST_MODERATOR
-// }
-//
-// enum class ObjectType {
-//     DEFAULT,
-//     SHARE_PASSWORD,
-//     FILE,
-//     ROOM
-// }
-//
-// enum class NotificationLevel {
-//     DEFAULT,
-//     ALWAYS,
-//     MENTION,
-//     NEVER
-// }
-//
-// enum class ConversationReadOnlyState {
-//     CONVERSATION_READ_WRITE,
-//     CONVERSATION_READ_ONLY
-// }
-//
-// enum class LobbyState {
-//     LOBBY_STATE_ALL_PARTICIPANTS,
-//     LOBBY_STATE_MODERATORS_ONLY
-// }

+ 30 - 103
app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt

@@ -12,8 +12,6 @@ package com.nextcloud.talk.models.json.conversations
 import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
-import com.nextcloud.talk.data.user.model.User
-import com.nextcloud.talk.models.domain.ConversationModel
 import com.nextcloud.talk.models.json.chat.ChatMessageJson
 import com.nextcloud.talk.models.json.converters.ConversationObjectTypeConverter
 import com.nextcloud.talk.models.json.converters.EnumLobbyStateConverter
@@ -22,48 +20,45 @@ import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter
 import com.nextcloud.talk.models.json.converters.EnumReadOnlyConversationConverter
 import com.nextcloud.talk.models.json.converters.EnumRoomTypeConverter
 import com.nextcloud.talk.models.json.participants.Participant.ParticipantType
-import com.nextcloud.talk.utils.ConversationUtils
 import kotlinx.parcelize.Parcelize
 
 @Parcelize
 @JsonObject
 data class Conversation(
-    // @JsonField(name = ["id"])
-    // var roomId: String? = null,
     @JsonField(name = ["token"])
-    var token: String? = null,
+    var token: String = "",
 
     @JsonField(name = ["name"])
-    var name: String? = null,
+    var name: String = "",
 
     @JsonField(name = ["displayName"])
-    var displayName: String? = null,
+    var displayName: String = "",
 
     @JsonField(name = ["description"])
-    var description: String? = null,
+    var description: String = "",
 
     @JsonField(name = ["type"], typeConverter = EnumRoomTypeConverter::class)
-    var type: ConversationEnums.ConversationType? = null,
+    var type: ConversationEnums.ConversationType = ConversationEnums.ConversationType.DUMMY,
 
     @JsonField(name = ["lastPing"])
     var lastPing: Long = 0,
 
     @JsonField(name = ["participantType"], typeConverter = EnumParticipantTypeConverter::class)
-    var participantType: ParticipantType? = null,
+    var participantType: ParticipantType = ParticipantType.DUMMY,
 
     @JsonField(name = ["hasPassword"])
     var hasPassword: Boolean = false,
 
     @JsonField(name = ["sessionId"])
-    var sessionId: String? = null,
+    var sessionId: String = "0",
 
     @JsonField(name = ["actorId"])
-    var actorId: String? = null,
+    var actorId: String = "",
 
     @JsonField(name = ["actorType"])
-    var actorType: String? = null,
+    var actorType: String = "",
 
-    var password: String? = null,
+    var password: String? = null, //check if this can be removed.Does not belong to api response but is used internally?
 
     @JsonField(name = ["isFavorite"])
     var favorite: Boolean = false,
@@ -81,19 +76,20 @@ data class Conversation(
     var lastMessage: ChatMessageJson? = null,
 
     @JsonField(name = ["objectType"], typeConverter = ConversationObjectTypeConverter::class)
-    var objectType: ConversationEnums.ObjectType? = null,
+    var objectType: ConversationEnums.ObjectType = ConversationEnums.ObjectType.DEFAULT,
 
     @JsonField(name = ["notificationLevel"], typeConverter = EnumNotificationLevelConverter::class)
-    var notificationLevel: ConversationEnums.NotificationLevel? = null,
+    var notificationLevel: ConversationEnums.NotificationLevel = ConversationEnums.NotificationLevel.DEFAULT,
 
     @JsonField(name = ["readOnly"], typeConverter = EnumReadOnlyConversationConverter::class)
-    var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState? = null,
+    var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState =
+        ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE,
 
     @JsonField(name = ["lobbyState"], typeConverter = EnumLobbyStateConverter::class)
-    var lobbyState: ConversationEnums.LobbyState? = null,
+    var lobbyState: ConversationEnums.LobbyState = ConversationEnums.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS,
 
     @JsonField(name = ["lobbyTimer"])
-    var lobbyTimer: Long? = null,
+    var lobbyTimer: Long = 0,
 
     @JsonField(name = ["lastReadMessage"])
     var lastReadMessage: Int = 0,
@@ -111,16 +107,16 @@ data class Conversation(
     var canStartCall: Boolean = false,
 
     @JsonField(name = ["canLeaveConversation"])
-    var canLeaveConversation: Boolean? = null,
+    var canLeaveConversation: Boolean = true,
 
     @JsonField(name = ["canDeleteConversation"])
-    var canDeleteConversation: Boolean? = null,
+    var canDeleteConversation: Boolean = false,
 
     @JsonField(name = ["unreadMentionDirect"])
-    var unreadMentionDirect: Boolean? = null,
+    var unreadMentionDirect: Boolean = false,
 
     @JsonField(name = ["notificationCalls"])
-    var notificationCalls: Int? = null,
+    var notificationCalls: Int = 0,
 
     @JsonField(name = ["permissions"])
     var permissions: Int = 0,
@@ -129,107 +125,38 @@ data class Conversation(
     var messageExpiration: Int = 0,
 
     @JsonField(name = ["status"])
-    var status: String? = null,
+    var status: String? = "",
 
     @JsonField(name = ["statusIcon"])
-    var statusIcon: String? = null,
+    var statusIcon: String? = "",
 
     @JsonField(name = ["statusMessage"])
-    var statusMessage: String? = null,
+    var statusMessage: String? = "",
 
     @JsonField(name = ["statusClearAt"])
-    var statusClearAt: Long? = 0,
+    var statusClearAt: Long? = null,
 
     @JsonField(name = ["callRecording"])
     var callRecording: Int = 0,
 
     @JsonField(name = ["avatarVersion"])
-    var avatarVersion: String? = "",
+    var avatarVersion: String = "",
 
     // Be aware that variables with "is" at the beginning will lead to the error:
     // "@JsonField annotation can only be used on private fields if both getter and setter are present."
     // Instead, name it with "has" at the beginning: isCustomAvatar -> hasCustomAvatar
     @JsonField(name = ["isCustomAvatar"])
-    var hasCustomAvatar: Boolean? = false,
+    var hasCustomAvatar: Boolean = false,
 
     @JsonField(name = ["callStartTime"])
-    var callStartTime: Long? = 0L,
+    var callStartTime: Long = 0L,
 
     @JsonField(name = ["recordingConsent"])
     var recordingConsentRequired: Int = 0,
 
     @JsonField(name = ["remoteServer"])
-    var remoteServer: String? = null,
+    var remoteServer: String? = "",
 
     @JsonField(name = ["remoteToken"])
-    var remoteToken: String? = null
-) : Parcelable {
-    @Deprecated("Use ConversationUtil")
-    val isPublic: Boolean
-        get() = ConversationEnums.ConversationType.ROOM_PUBLIC_CALL == type
-
-    @Deprecated("Use ConversationUtil")
-    val isGuest: Boolean
-        get() = ParticipantType.GUEST == participantType ||
-            ParticipantType.GUEST_MODERATOR == participantType ||
-            ParticipantType.USER_FOLLOWING_LINK == participantType
-
-    @Deprecated("Use ConversationUtil")
-    val isParticipantOwnerOrModerator: Boolean
-        get() = ParticipantType.OWNER == participantType ||
-            ParticipantType.GUEST_MODERATOR == participantType ||
-            ParticipantType.MODERATOR == participantType
-
-    @Deprecated("Use ConversationUtil")
-    fun canModerate(conversationUser: User): Boolean {
-        return isParticipantOwnerOrModerator &&
-            !ConversationUtils.isLockedOneToOne(
-                ConversationModel.mapToConversationModel(this, conversationUser),
-                conversationUser.capabilities?.spreedCapability!!
-            ) &&
-            type != ConversationEnums.ConversationType.FORMER_ONE_TO_ONE &&
-            !ConversationUtils.isNoteToSelfConversation(
-                ConversationModel.mapToConversationModel(this, conversationUser)
-            )
-    }
-
-    @Deprecated("Use ConversationUtil")
-    fun isLobbyViewApplicable(conversationUser: User): Boolean {
-        return !canModerate(conversationUser) &&
-            (
-                type == ConversationEnums.ConversationType.ROOM_GROUP_CALL ||
-                    type == ConversationEnums.ConversationType.ROOM_PUBLIC_CALL
-                )
-    }
-
-    @Deprecated("Use ConversationUtil")
-    fun isNameEditable(conversationUser: User): Boolean {
-        return canModerate(conversationUser) && ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL != type
-    }
-
-    @Deprecated("Use ConversationUtil")
-    fun canLeave(): Boolean {
-        return if (canLeaveConversation != null) {
-            // Available since APIv2
-            canLeaveConversation!!
-        } else {
-            true
-        }
-    }
-
-    @Deprecated("Use ConversationUtil")
-    fun canDelete(conversationUser: User): Boolean {
-        return if (canDeleteConversation != null) {
-            // Available since APIv2
-            canDeleteConversation!!
-        } else {
-            canModerate(conversationUser)
-            // Fallback for APIv1
-        }
-    }
-
-    @Deprecated("Use ConversationUtil")
-    fun isNoteToSelfConversation(): Boolean {
-        return type == ConversationEnums.ConversationType.NOTE_TO_SELF
-    }
-}
+    var remoteToken: String? = ""
+) : Parcelable

+ 1 - 1
app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt

@@ -134,7 +134,7 @@ class ConversationsListBottomDialog(
         )
 
         binding.conversationOperationLeave.visibility = setVisibleIf(
-            ConversationUtils.canLeave(conversation) &&
+            conversation.canLeaveConversation &&
                 // leaving is by api not possible for the last user with moderator permissions.
                 // for now, hide this option for all moderators.
                 !ConversationUtils.canModerate(conversation, currentUser.capabilities!!.spreedCapability!!)

+ 2 - 2
app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt

@@ -295,6 +295,6 @@ object CapabilitiesUtil {
     const val RECORDING_CONSENT_NOT_REQUIRED = 0
     const val RECORDING_CONSENT_REQUIRED = 1
     const val RECORDING_CONSENT_DEPEND_ON_CONVERSATION = 2
-    private const val SERVER_VERSION_MIN_SUPPORTED = 14
-    private const val SERVER_VERSION_SUPPORT_WARNING = 18
+    private const val SERVER_VERSION_MIN_SUPPORTED = 17
+    private const val SERVER_VERSION_SUPPORT_WARNING = 26
 }

+ 0 - 19
app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt

@@ -55,25 +55,6 @@ object ConversationUtils {
             ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL != conversation.type
     }
 
-    fun canLeave(conversation: ConversationModel): Boolean {
-        return if (conversation.canLeaveConversation != null) {
-            // Available since APIv2
-            conversation.canLeaveConversation!!
-        } else {
-            true
-        }
-    }
-
-    fun canDelete(conversation: ConversationModel, spreedCapability: SpreedCapability): Boolean {
-        return if (conversation.canDeleteConversation != null) {
-            // Available since APIv2
-            conversation.canDeleteConversation!!
-        } else {
-            canModerate(conversation, spreedCapability)
-            // Fallback for APIv1
-        }
-    }
-
     fun isNoteToSelfConversation(currentConversation: ConversationModel?): Boolean {
         return currentConversation != null &&
             currentConversation.type == ConversationEnums.ConversationType.NOTE_TO_SELF

+ 157 - 0
app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt

@@ -0,0 +1,157 @@
+import com.bluelinelabs.logansquare.LoganSquare
+import com.nextcloud.talk.data.database.mappers.asEntity
+import com.nextcloud.talk.data.database.mappers.asModel
+import com.nextcloud.talk.data.database.model.ConversationEntity
+import com.nextcloud.talk.models.json.conversations.ConversationEnums
+import com.nextcloud.talk.models.json.conversations.RoomOverall
+import com.nextcloud.talk.models.json.participants.Participant
+import org.junit.Assert.*
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.io.File
+
+@RunWith(Parameterized::class)
+class ConversationConversionTest(
+    private val jsonFileName: String
+) {
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "{index}: testDeserialization({0})")
+        fun data(): List<String> {
+            return listOf(
+                "RoomOverallExample_APIv1.json",
+                "RoomOverallExample_APIv2.json",
+                "RoomOverallExample_APIv4.json"
+            )
+        }
+    }
+
+    @Test
+    fun testDeserialization() {
+        val jsonFile = File("src/test/resources/$jsonFileName")
+        val jsonString = jsonFile.readText()
+
+        val roomOverall: RoomOverall = LoganSquare.parse(jsonString, RoomOverall::class.java)
+        assertNotNull(roomOverall)
+
+        val conversationJson = roomOverall.ocs!!.data!!
+        assertNotNull(conversationJson)
+
+        val conversationEntity = conversationJson.asEntity(1)
+        assertNotNull(conversationEntity)
+
+        val apiVersion : Int = jsonFileName.substringAfterLast("APIv").first().digitToInt()
+
+        checkConversationEntity(conversationEntity, apiVersion)
+
+        val conversationModel = conversationEntity.asModel()
+        val conversationEntityConvertedBack = conversationModel.asEntity()
+
+        checkConversationEntity(conversationEntityConvertedBack, apiVersion)
+    }
+
+    private fun checkConversationEntity(
+        conversationEntity: ConversationEntity,
+        apiVersion: Int
+    ) {
+        assertEquals("1@juwd77g6", conversationEntity.internalId)
+        assertEquals(1, conversationEntity.accountId)
+
+        // check if default values are set for the fields when API_V1 is used
+        if (apiVersion == 1) {
+            // default values for API_V2 fields
+            assertEquals(false, conversationEntity.canDeleteConversation)
+            assertEquals(true, conversationEntity.canLeaveConversation)
+
+            // default values for API_V3 fields
+            assertEquals("", conversationEntity.description)
+            assertEquals("", conversationEntity.actorType)
+            assertEquals("", conversationEntity.actorId)
+            assertEquals(0, conversationEntity.callFlag)
+            assertEquals(0, conversationEntity.lastCommonReadMessage)
+
+            // default values for API_V4 fields
+            assertEquals("", conversationEntity.avatarVersion)
+            assertEquals(0, conversationEntity.callStartTime)
+            assertEquals(0, conversationEntity.callRecording)
+            assertEquals(false, conversationEntity.unreadMentionDirect)
+            assertEquals("", conversationEntity.status)
+            assertEquals("", conversationEntity.statusIcon)
+            assertEquals("", conversationEntity.statusMessage)
+            assertEquals(null, conversationEntity.statusClearAt)
+            assertEquals("", conversationEntity.avatarVersion)
+            assertEquals(0, conversationEntity.callStartTime)
+            assertEquals(0, conversationEntity.callRecording)
+        }
+
+        if (apiVersion >= 1) {
+            assertEquals("juwd77g6", conversationEntity.token)
+            assertEquals(ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL, conversationEntity.type)
+            assertEquals("marcel", conversationEntity.name)
+            assertEquals("Marcel", conversationEntity.displayName)
+            assertEquals(Participant.ParticipantType.OWNER, conversationEntity.participantType)
+            assertEquals(
+                ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE,
+                conversationEntity.conversationReadOnlyState
+            )
+            assertEquals(1727185155, conversationEntity.lastPing)
+            assertEquals("0", conversationEntity.sessionId)
+            assertEquals(false, conversationEntity.hasPassword)
+            assertEquals(false, conversationEntity.hasCall)
+            assertEquals(true, conversationEntity.canStartCall)
+            assertEquals(1727098966, conversationEntity.lastActivity)
+            assertEquals(false, conversationEntity.favorite)
+            assertEquals(ConversationEnums.NotificationLevel.ALWAYS, conversationEntity.notificationLevel)
+            assertEquals(ConversationEnums.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS, conversationEntity.lobbyState)
+            assertEquals(0, conversationEntity.lobbyTimer)
+            assertEquals(0, conversationEntity.unreadMessages)
+            assertEquals(false, conversationEntity.unreadMention)
+            assertEquals(92320, conversationEntity.lastReadMessage)
+            assertNotNull(conversationEntity.lastMessage)
+            assertTrue(conversationEntity.lastMessage is String)
+            assertTrue(conversationEntity.lastMessage!!.contains("token"))
+            assertEquals(ConversationEnums.ObjectType.DEFAULT, conversationEntity.objectType)
+        }
+
+        if (apiVersion >= 2) {
+            assertEquals(false, conversationEntity.canDeleteConversation)
+            assertEquals(true, conversationEntity.canLeaveConversation)
+        }
+
+        if (apiVersion >= 3) {
+            assertEquals("test", conversationEntity.description)
+            // assertEquals("", conversationEntity.attendeeId)      // Not implemented
+            // assertEquals("", conversationEntity.attendeePin)     // Not implemented
+            assertEquals("users", conversationEntity.actorType)
+            assertEquals("marcel2", conversationEntity.actorId)
+
+            // assertEquals("", conversationEntity.listable)     // Not implemented
+            assertEquals(0, conversationEntity.callFlag)
+            // assertEquals("", conversationEntity.sipEnabled)     // Not implemented
+            // assertEquals("", conversationEntity.canEnableSIP)     // Not implemented
+            assertEquals(92320, conversationEntity.lastCommonReadMessage)
+        }
+
+        if (apiVersion >= 4) {
+            assertEquals("143a9df3", conversationEntity.avatarVersion)
+            assertEquals(0, conversationEntity.callStartTime)
+            assertEquals(0, conversationEntity.callRecording)
+            assertEquals(false, conversationEntity.unreadMentionDirect)
+            // assertEquals(, conversationEntity.breakoutRoomMode)     // Not implemented
+            // assertEquals(, conversationEntity.breakoutRoomStatus)     // Not implemented
+            assertEquals("away", conversationEntity.status)
+            assertEquals("👻", conversationEntity.statusIcon)
+            assertEquals("buuuuh", conversationEntity.statusMessage)
+            assertEquals(null, conversationEntity.statusClearAt)
+            assertEquals("143a9df3", conversationEntity.avatarVersion)
+            // assertEquals("", conversationEntity.isCustomAvatar)     // Not implemented
+            assertEquals(0, conversationEntity.callStartTime)
+            assertEquals(0, conversationEntity.callRecording)
+            // assertEquals("", conversationEntity.recordingConsent)     // Not implemented
+            // assertEquals("", conversationEntity.mentionPermissions)     // Not implemented
+            // assertEquals("", conversationEntity.isArchived)     // Not implemented
+        }
+    }
+}

+ 66 - 0
app/src/test/resources/RoomOverallExample_APIv1.json

@@ -0,0 +1,66 @@
+{
+    "ocs": {
+        "meta": {
+            "status": "ok",
+            "statuscode": 200,
+            "message": "OK"
+        },
+        "data": {
+            "id": 6410,
+            "token": "juwd77g6",
+            "type": 1,
+            "name": "marcel",
+            "displayName": "Marcel",
+            "objectType": "",
+            "objectId": "",
+            "participantType": 1,
+            "participantInCall": false,
+            "participantFlags": 0,
+            "readOnly": 0,
+            "count": 0,
+            "hasPassword": false,
+            "hasCall": false,
+            "canStartCall": true,
+            "lastActivity": 1727098966,
+            "lastReadMessage": 92320,
+            "unreadMessages": 0,
+            "unreadMention": false,
+            "isFavorite": false,
+            "notificationLevel": 1,
+            "lobbyState": 0,
+            "lobbyTimer": 0,
+            "lastPing": 1727185155,
+            "sessionId": "0",
+            "participants": {
+                "marcel": {
+                    "name": "marcel",
+                    "type": 1,
+                    "call": 0,
+                    "sessionId": "tonIuryMpwk5mR2h6lFqPC6M8m6hxdT4YN9X9I1v4i2LOJb9r3FzANx\/7HT0j6r8fzBFPJqnOrT\/mdvHzFlfqQsr6Gxo0\/aLkDfIRL32XlGIzficfLaBNCsyctPxwgHv0fwmJUOS2i0ONdC+QWyTJ4bpYw1Ch9hiybxCgEtss3xy9fbjPwWj3gLvpMpcH0OuNkfEwHqByhpiAb3xuu60\/6j671uwYiGe2Ba7PzLFJ3LVuVRXXTbeaZlVwTAioOu"
+                },
+                "Testuser.Lastname": {
+                    "name": "Testuser",
+                    "type": 1,
+                    "call": 0,
+                    "sessionId": "0"
+                }
+            },
+            "numGuests": 0,
+            "guestList": "",
+            "lastMessage": {
+                "id": 175430,
+                "token": "juwd77g6",
+                "actorType": "users",
+                "actorId": "marcel",
+                "actorDisplayName": "Marcel",
+                "timestamp": 1727182442,
+                "message": "test",
+                "messageParameters": [],
+                "systemMessage": "",
+                "messageType": "comment",
+                "isReplyable": true,
+                "referenceId": ""
+            }
+        }
+    }
+}

+ 51 - 0
app/src/test/resources/RoomOverallExample_APIv2.json

@@ -0,0 +1,51 @@
+{
+    "ocs": {
+        "meta": {
+            "status": "ok",
+            "statuscode": 200,
+            "message": "OK"
+        },
+        "data": {
+            "id": 6410,
+            "token": "juwd77g6",
+            "type": 1,
+            "name": "marcel",
+            "displayName": "Marcel",
+            "objectType": "",
+            "objectId": "",
+            "participantType": 1,
+            "participantFlags": 0,
+            "readOnly": 0,
+            "hasPassword": false,
+            "hasCall": false,
+            "canStartCall": true,
+            "lastActivity": 1727098966,
+            "lastReadMessage": 92320,
+            "unreadMessages": 0,
+            "unreadMention": false,
+            "isFavorite": false,
+            "canLeaveConversation": true,
+            "canDeleteConversation": false,
+            "notificationLevel": 1,
+            "lobbyState": 0,
+            "lobbyTimer": 0,
+            "lastPing": 1727185155,
+            "sessionId": "0",
+            "guestList": "",
+            "lastMessage": {
+                "id": 175430,
+                "token": "juwd77g6",
+                "actorType": "users",
+                "actorId": "marcel",
+                "actorDisplayName": "Marcel",
+                "timestamp": 1727182442,
+                "message": "test",
+                "messageParameters": [],
+                "systemMessage": "",
+                "messageType": "comment",
+                "isReplyable": true,
+                "referenceId": ""
+            }
+        }
+    }
+}

+ 83 - 0
app/src/test/resources/RoomOverallExample_APIv4.json

@@ -0,0 +1,83 @@
+{
+    "ocs": {
+        "meta": {
+            "status": "ok",
+            "statuscode": 200,
+            "message": "OK"
+        },
+        "data": {
+            "id": 181,
+            "token": "juwd77g6",
+            "type": 1,
+            "name": "marcel",
+            "displayName": "Marcel",
+            "objectType": "",
+            "objectId": "",
+            "participantType": 1,
+            "participantFlags": 0,
+            "readOnly": 0,
+            "hasPassword": false,
+            "hasCall": false,
+            "callStartTime": 0,
+            "callRecording": 0,
+            "canStartCall": true,
+            "lastActivity": 1727098966,
+            "lastReadMessage": 92320,
+            "unreadMessages": 0,
+            "unreadMention": false,
+            "unreadMentionDirect": false,
+            "isFavorite": false,
+            "canLeaveConversation": true,
+            "canDeleteConversation": false,
+            "notificationLevel": 1,
+            "notificationCalls": 1,
+            "lobbyState": 0,
+            "lobbyTimer": 0,
+            "lastPing": 1727185155,
+            "sessionId": "0",
+            "lastMessage": {
+                "id": 92320,
+                "token": "3853979093",
+                "actorType": "users",
+                "actorId": "marcel",
+                "actorDisplayName": "Marcel",
+                "timestamp": 1726673204,
+                "message": "Test",
+                "messageParameters": [],
+                "systemMessage": "",
+                "messageType": "comment",
+                "isReplyable": true,
+                "referenceId": "",
+                "reactions": {},
+                "expirationTimestamp": 0,
+                "markdown": true
+            },
+            "sipEnabled": 0,
+            "actorType": "users",
+            "actorId": "marcel2",
+            "attendeeId": 5810,
+            "permissions": 254,
+            "attendeePermissions": 0,
+            "callPermissions": 0,
+            "defaultPermissions": 0,
+            "canEnableSIP": false,
+            "attendeePin": "",
+            "description": "test",
+            "lastCommonReadMessage": 92320,
+            "listable": 0,
+            "callFlag": 0,
+            "messageExpiration": 0,
+            "avatarVersion": "143a9df3",
+            "isCustomAvatar": false,
+            "breakoutRoomMode": 0,
+            "breakoutRoomStatus": 0,
+            "recordingConsent": 0,
+            "mentionPermissions": 0,
+            "isArchived": false,
+            "status": "away",
+            "statusIcon": "👻",
+            "statusMessage": "buuuuh",
+            "statusClearAt": null
+        }
+    }
+}