From 38a77291cb3e0808f3069398e200c3af2bab0cdf Mon Sep 17 00:00:00 2001
From: marcin-cebo <102806110+marcin-cebo@users.noreply.github.com>
Date: Tue, 7 Jan 2025 18:04:34 +0100
Subject: [PATCH] Added status and type to Membership. (#151)
* Refactor. Use non-deprecated Memberships and ChannelMembers methods.
* Increased timeout for JS test to passed.
In new version of PubNub core js sdk verbose logging has been added that slows down test execution.
* Refactor. Use non-deprecated Memberships and ChannelMembers method.
* PubNub kotlin 0.10.0 release.
---------
Co-authored-by: PubNub Release Bot <120067856+pubnub-release-bot@users.noreply.github.com>
---
.pubnub.yml | 11 ++-
Package.swift | 4 +-
README.md | 2 +-
.../gradle/PubNubKotlinMultiplatformPlugin.kt | 2 +-
gradle.properties | 2 +-
gradle/libs.versions.toml | 4 +-
kotlin-js-store/yarn.lock | 8 +-
pubnub-chat-api/api/pubnub-chat-api.api | 2 +
.../kotlin/com/pubnub/chat/Membership.kt | 10 +++
.../com/pubnub/chat/internal/ChatImpl.kt | 58 ++++++++++----
.../pubnub/chat/internal/MembershipImpl.kt | 58 +++++++++++---
.../com/pubnub/chat/internal/UserImpl.kt | 42 +++++-----
.../chat/internal/channel/BaseChannel.kt | 78 +++++++++++++------
.../pubnub/integration/ChatIntegrationTest.kt | 12 +--
.../kotlin/com/pubnub/kmp/ChannelTest.kt | 28 +++----
.../kotlin/com/pubnub/kmp/ChatTest.kt | 50 +++++++++---
.../kotlin/com/pubnub/kmp/MembershipTest.kt | 6 ++
.../kotlin/com/pubnub/kmp/UserTest.kt | 66 ++++++++--------
.../src/jsMain/kotlin/MembershipJs.kt | 4 +
src/jsMain/resources/index.d.ts | 4 +-
20 files changed, 296 insertions(+), 155 deletions(-)
diff --git a/.pubnub.yml b/.pubnub.yml
index 106bc70d..4345b52d 100644
--- a/.pubnub.yml
+++ b/.pubnub.yml
@@ -1,5 +1,5 @@
name: kmp-chat
-version: 0.9.4
+version: 0.10.0
schema: 1
scm: github.com/pubnub/kmp-chat
sdks:
@@ -21,8 +21,8 @@ sdks:
-
distribution-type: library
distribution-repository: maven
- package-name: pubnub-chat-0.9.4
- location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-chat/0.9.4/
+ package-name: pubnub-chat-0.10.0
+ location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-chat/0.10.0/
supported-platforms:
supported-operating-systems:
Android:
@@ -77,6 +77,11 @@ sdks:
license-url: https://github.com/pubnub/kotlin/blob/master/LICENSE
is-required: Required
changelog:
+ - date: 2025-01-07
+ version: 0.10.0
+ changes:
+ - type: feature
+ text: "Added status and type to Membership."
- date: 2024-12-20
version: 0.9.4
changes:
diff --git a/Package.swift b/Package.swift
index 8c8bbebf..01afa6c3 100644
--- a/Package.swift
+++ b/Package.swift
@@ -18,8 +18,8 @@ let package = Package(
targets: [
.binaryTarget(
name: "PubNubChatRemoteBinaryPackage",
- url: "https://github.com/pubnub/kmp-chat/releases/download/kotlin-0.9.4/PubNubChat.xcframework.zip",
- checksum: "b2971bcc09a9e0107c4bcbf3795fd53ab80608f4dc3dbb7c67ee668009e4b1fe"
+ url: "https://github.com/pubnub/kmp-chat/releases/download/kotlin-0.10.0/PubNubChat.xcframework.zip",
+ checksum: "bc2c024e9b83a67d90e078778e140c0858651f96d0909d9a14143d36fa5efdf3"
)
]
)
diff --git a/README.md b/README.md
index 4c2f04eb..fc751079 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ You will need the publish and subscribe keys to authenticate your app. Get your
com.pubnub
pubnub-chat
- 0.9.4
+ 0.10.0
```
diff --git a/build-logic/gradle-plugins/src/main/kotlin/com/pubnub/gradle/PubNubKotlinMultiplatformPlugin.kt b/build-logic/gradle-plugins/src/main/kotlin/com/pubnub/gradle/PubNubKotlinMultiplatformPlugin.kt
index 8b95d4ed..c8ecb29b 100644
--- a/build-logic/gradle-plugins/src/main/kotlin/com/pubnub/gradle/PubNubKotlinMultiplatformPlugin.kt
+++ b/build-logic/gradle-plugins/src/main/kotlin/com/pubnub/gradle/PubNubKotlinMultiplatformPlugin.kt
@@ -78,7 +78,7 @@ class PubNubBaseKotlinMultiplatformPlugin : Plugin {
testTask {
it.environment("MOCHA_OPTIONS", "--exit")
it.useMocha {
- timeout = "20s"
+ timeout = "30s"
}
}
}
diff --git a/gradle.properties b/gradle.properties
index c78d4d29..80c872e2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -10,7 +10,7 @@ SONATYPE_HOST=DEFAULT
SONATYPE_AUTOMATIC_RELEASE=false
GROUP=com.pubnub
POM_PACKAGING=jar
-VERSION_NAME=0.9.6
+VERSION_NAME=0.10.0
POM_NAME=PubNub Chat SDK
POM_DESCRIPTION=This SDK offers a set of handy methods to create your own feature-rich chat or add a chat to your existing application.
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 6b1ee2cc..30e78fb6 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -6,8 +6,8 @@ ktlint = "12.1.0"
dokka = "1.9.20"
kotlinx_serialization = "1.7.3"
kotlinx_coroutines = "1.9.0"
-pubnub = "10.3.2"
-pubnub_swift = "8.2.2"
+pubnub = "10.3.3"
+pubnub_swift = "8.2.3"
[libraries]
pubnub-kotlin-api = { module = "com.pubnub:pubnub-kotlin-api", version.ref = "pubnub" }
diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock
index f36679b5..83c32f93 100644
--- a/kotlin-js-store/yarn.lock
+++ b/kotlin-js-store/yarn.lock
@@ -659,10 +659,10 @@ proxy-from-env@^1.1.0:
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
-pubnub@8.2.8:
- version "8.2.8"
- resolved "https://registry.yarnpkg.com/pubnub/-/pubnub-8.2.8.tgz#68d3b84d07e128b29f74c6c46495f0c5bedd1a3f"
- integrity sha512-OREW+YDWWocOaz16jbrrybD0AyqEFuskCGi+EMgOb9FUJkuYPnInjlMSAUBBrlx7lMTARMQxx3Sk0EIvbB3hig==
+pubnub@8.4.1:
+ version "8.4.1"
+ resolved "https://registry.yarnpkg.com/pubnub/-/pubnub-8.4.1.tgz#5f6f19e84d3187dc8aee0a458bd6b05e90d43e6a"
+ integrity sha512-mPlwVoHJDWPasZx52UfSMiPX5TATm5A+ficSogyqDqTQ4w5EQnwxH+PJdsWc0mPnlT051jM1vIISMeM0fQ30CQ==
dependencies:
agentkeepalive "^3.5.2"
buffer "^6.0.3"
diff --git a/pubnub-chat-api/api/pubnub-chat-api.api b/pubnub-chat-api/api/pubnub-chat-api.api
index 7e3582ec..409db660 100644
--- a/pubnub-chat-api/api/pubnub-chat-api.api
+++ b/pubnub-chat-api/api/pubnub-chat-api.api
@@ -128,6 +128,8 @@ public abstract interface class com/pubnub/chat/Membership {
public abstract fun getCustom ()Ljava/util/Map;
public abstract fun getETag ()Ljava/lang/String;
public abstract fun getLastReadMessageTimetoken ()Ljava/lang/Long;
+ public abstract fun getStatus ()Ljava/lang/String;
+ public abstract fun getType ()Ljava/lang/String;
public abstract fun getUnreadMessagesCount ()Lcom/pubnub/kmp/PNFuture;
public abstract fun getUpdated ()Ljava/lang/String;
public abstract fun getUser ()Lcom/pubnub/chat/User;
diff --git a/pubnub-chat-api/src/commonMain/kotlin/com/pubnub/chat/Membership.kt b/pubnub-chat-api/src/commonMain/kotlin/com/pubnub/chat/Membership.kt
index 8b3b6bd8..9262a99e 100644
--- a/pubnub-chat-api/src/commonMain/kotlin/com/pubnub/chat/Membership.kt
+++ b/pubnub-chat-api/src/commonMain/kotlin/com/pubnub/chat/Membership.kt
@@ -39,6 +39,16 @@ interface Membership {
*/
val eTag: String?
+ /**
+ * Status of a Membership
+ */
+ val status: String?
+
+ /**
+ * Type of a Membership
+ */
+ val type: String?
+
/**
* Timetoken of the last message a user read on a given channel.
*/
diff --git a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt
index 15c3cf38..4cb881a7 100644
--- a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt
+++ b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt
@@ -20,7 +20,7 @@ import com.pubnub.api.models.consumer.objects.PNSortKey
import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadataResult
import com.pubnub.api.models.consumer.objects.member.PNMember
import com.pubnub.api.models.consumer.objects.member.PNMemberArrayResult
-import com.pubnub.api.models.consumer.objects.membership.PNChannelDetailsLevel
+import com.pubnub.api.models.consumer.objects.membership.MembershipInclude
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembershipArrayResult
import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadataArrayResult
@@ -63,6 +63,7 @@ import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_FORWARD_MESSA
import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_RETRIEVE_WHO_IS_PRESENT_DATA
import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_SOFT_DELETE_CHANNEL
import com.pubnub.chat.internal.error.PubNubErrorMessage.ID_IS_REQUIRED
+import com.pubnub.chat.internal.error.PubNubErrorMessage.MODERATION_CAN_BE_SET_ONLY_BY_CLIENT_HAVING_SECRET_KEY
import com.pubnub.chat.internal.error.PubNubErrorMessage.ONLY_ONE_LEVEL_OF_THREAD_NESTING_IS_ALLOWED
import com.pubnub.chat.internal.error.PubNubErrorMessage.STORE_USER_ACTIVITY_INTERVAL_SHOULD_BE_AT_LEAST_1_MIN
import com.pubnub.chat.internal.error.PubNubErrorMessage.THERE_IS_NO_ACTION_TIMETOKEN_CORRESPONDING_TO_THE_THREAD
@@ -556,10 +557,16 @@ class ChatImpl(
val hostMembershipFuture = pubNub.setMemberships(
listOf(PNChannelMembership.Partial(channel.id, membershipCustom)),
filter = "channel.id == '${channel.id}'",
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeCount = true,
- includeType = true,
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = false
+ ),
)
awaitAll(
hostMembershipFuture,
@@ -602,10 +609,16 @@ class ChatImpl(
val hostMembershipFuture = pubNub.setMemberships(
listOf(PNChannelMembership.Partial(channel.id, membershipCustom)),
filter = "channel.id == '${channel.id}'",
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeCount = true,
- includeType = true,
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = false
+ ),
)
awaitAll(
hostMembershipFuture,
@@ -699,6 +712,9 @@ class ChatImpl(
override fun setRestrictions(
restriction: Restriction
): PNFuture {
+ if (this.pubNub.configuration.secretKey.isEmpty()) {
+ return log.logErrorAndReturnException(MODERATION_CAN_BE_SET_ONLY_BY_CLIENT_HAVING_SECRET_KEY).asFuture()
+ }
val channel: String = INTERNAL_MODERATION_PREFIX + restriction.channelId
val userId = restriction.userId
return createChannel(channel).catch { exception ->
@@ -730,7 +746,7 @@ class ChatImpl(
)
)
val uuids = listOf(PNMember.Partial(uuidId = userId, custom = custom, null))
- pubNub.setChannelMembers(channel = channel, uuids = uuids)
+ pubNub.setChannelMembers(channel = channel, users = uuids)
.alsoAsync { _ ->
emitEvent(
channelId = INTERNAL_USER_MODERATION_CHANNEL_PREFIX + userId,
@@ -876,11 +892,17 @@ class ChatImpl(
pubNub.setMemberships(
channels = channelMembershipInputs,
filter = filterExpression,
- uuid = currentUser.id,
- includeCount = true,
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeType = true
+ userId = currentUser.id,
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = false
+ ),
).alsoAsync { _: PNChannelMembershipArrayResult ->
val emitEventFutures: List> =
relevantChannelIds.map { channelId: String ->
@@ -1162,7 +1184,11 @@ class ChatImpl(
customMetadataToSet[PINNED_MESSAGE_TIMETOKEN] = message.timetoken.toString()
customMetadataToSet[PINNED_MESSAGE_CHANNEL_ID] = message.channelId
}
- return pubNub.setChannelMetadata(channel.id, includeCustom = true, custom = createCustomObject(customMetadataToSet))
+ return pubNub.setChannelMetadata(
+ channel = channel.id,
+ includeCustom = true,
+ custom = createCustomObject(customMetadataToSet)
+ )
}
internal fun getThreadId(channelId: String, messageTimetoken: Long): String {
diff --git a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/MembershipImpl.kt b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/MembershipImpl.kt
index aa3be150..813a4ee6 100644
--- a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/MembershipImpl.kt
+++ b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/MembershipImpl.kt
@@ -2,7 +2,7 @@ package com.pubnub.chat.internal
import co.touchlab.kermit.Logger
import com.pubnub.api.models.consumer.objects.member.PNMember
-import com.pubnub.api.models.consumer.objects.membership.PNChannelDetailsLevel
+import com.pubnub.api.models.consumer.objects.membership.MembershipInclude
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership
import com.pubnub.api.models.consumer.pubsub.objects.PNDeleteMembershipEventMessage
import com.pubnub.api.models.consumer.pubsub.objects.PNSetMembershipEvent
@@ -35,6 +35,8 @@ data class MembershipImpl(
override val custom: Map?,
override val updated: String?,
override val eTag: String?,
+ override val status: String?,
+ override val type: String?,
) : Membership {
override val lastReadMessageTimetoken: Long?
get() {
@@ -51,12 +53,18 @@ data class MembershipImpl(
log.pnError(NO_SUCH_MEMBERSHIP_EXISTS)
}
chat.pubNub.setMemberships(
- uuid = user.id,
+ userId = user.id,
channels = listOf(PNChannelMembership.Partial(channel.id, custom)),
- includeCustom = true,
- includeCount = true,
- includeType = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = true,
+ includeType = true,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = true
+ ),
filter = filterThisChannel()
).then { pnChannelMembershipArrayResult ->
fromMembershipDTO(chat, pnChannelMembershipArrayResult.data.first(), user)
@@ -108,14 +116,34 @@ data class MembershipImpl(
chat,
channel,
user,
- update.custom?.value ?: custom,
+ update.custom.let { newCustom ->
+ if (newCustom != null) {
+ newCustom.value
+ } else {
+ custom
+ }
+ },
update.updated,
- update.eTag
+ update.eTag,
+ update.status.let { newStatus ->
+ if (newStatus != null) {
+ newStatus.value
+ } else {
+ status
+ }
+ },
+ update.type.let { newType ->
+ if (newType != null) {
+ newType.value
+ } else {
+ type
+ }
+ }
)
}
private fun exists(): PNFuture =
- chat.pubNub.getMemberships(uuid = user.id, filter = filterThisChannel()).then {
+ chat.pubNub.getMemberships(userId = user.id, filter = filterThisChannel()).then {
it.data.isNotEmpty()
}
@@ -147,11 +175,13 @@ data class MembershipImpl(
previousMembership?.let { it + message.data }
?: MembershipImpl(
chat,
- user = membership.user,
channel = membership.channel,
+ user = membership.user,
custom = message.data.custom?.value,
updated = message.data.updated,
- eTag = message.data.eTag
+ eTag = message.data.eTag,
+ status = message.data.status?.value,
+ type = message.data.type?.value,
)
}
is PNDeleteMembershipEventMessage -> null
@@ -184,7 +214,9 @@ data class MembershipImpl(
user,
channelMembership.custom?.value,
channelMembership.updated,
- channelMembership.eTag
+ channelMembership.eTag,
+ channelMembership.status?.value,
+ channelMembership.type?.value,
)
internal fun fromChannelMemberDTO(chat: ChatInternal, userMembership: PNMember, channel: Channel) =
@@ -195,6 +227,8 @@ data class MembershipImpl(
userMembership.custom?.value,
userMembership.updated,
userMembership.eTag,
+ userMembership.status?.value,
+ userMembership.type?.value,
)
}
}
diff --git a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/UserImpl.kt b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/UserImpl.kt
index 75d5ec8d..bd305b2e 100644
--- a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/UserImpl.kt
+++ b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/UserImpl.kt
@@ -5,7 +5,7 @@ import com.pubnub.api.PubNubException
import com.pubnub.api.models.consumer.objects.PNMembershipKey
import com.pubnub.api.models.consumer.objects.PNPage
import com.pubnub.api.models.consumer.objects.PNSortKey
-import com.pubnub.api.models.consumer.objects.membership.PNChannelDetailsLevel
+import com.pubnub.api.models.consumer.objects.membership.MembershipInclude
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembershipArrayResult
import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadata
@@ -98,15 +98,21 @@ data class UserImpl(
val effectiveFilter: String = filter?.let { "$internalModerationFilter && ($filter)" } ?: internalModerationFilter
return chat.pubNub.getMemberships(
- uuid = id,
+ userId = id,
limit = limit,
page = page,
filter = effectiveFilter,
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeType = true,
- includeChannelDetails = getChannelDetailsType(true)
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = true,
+ includeType = true,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = true
+ )
).then { pnChannelMembershipArrayResult ->
MembershipsResponse(
next = pnChannelMembershipArrayResult.next,
@@ -196,26 +202,24 @@ data class UserImpl(
}
return chat.pubNub.getMemberships(
- uuid = id,
+ userId = id,
limit = limit,
page = page,
filter = filter,
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeType = true
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = true,
+ includeType = true,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = true
+ )
)
}
- private fun getChannelDetailsType(includeChannelWithCustom: Boolean): PNChannelDetailsLevel {
- return if (includeChannelWithCustom) {
- PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM
- } else {
- PNChannelDetailsLevel.CHANNEL
- }
- }
-
private fun getMembershipsFromResult(
pnChannelMembershipArrayResult: PNChannelMembershipArrayResult,
user: User,
diff --git a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt
index bc8aa0bd..848d547c 100644
--- a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt
+++ b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt
@@ -14,10 +14,10 @@ import com.pubnub.api.models.consumer.objects.PNMemberKey
import com.pubnub.api.models.consumer.objects.PNPage
import com.pubnub.api.models.consumer.objects.PNSortKey
import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata
+import com.pubnub.api.models.consumer.objects.member.MemberInclude
import com.pubnub.api.models.consumer.objects.member.PNMember
import com.pubnub.api.models.consumer.objects.member.PNMemberArrayResult
-import com.pubnub.api.models.consumer.objects.member.PNUUIDDetailsLevel
-import com.pubnub.api.models.consumer.objects.membership.PNChannelDetailsLevel
+import com.pubnub.api.models.consumer.objects.membership.MembershipInclude
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembershipArrayResult
import com.pubnub.api.models.consumer.pubsub.objects.PNDeleteChannelMetadataEventMessage
@@ -371,12 +371,18 @@ abstract class BaseChannel(
} else {
chat.pubNub.setMemberships(
channels = listOf(PNChannelMembership.Partial(this.id)),
- uuid = user.id,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeCustom = true,
- includeCount = true,
- includeType = true,
+ userId = user.id,
filter = channelFilterString,
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = false
+ )
).then { setMembershipsResult ->
MembershipImpl.fromMembershipDTO(chat, setMembershipsResult.data.first(), user)
}.thenAsync { membership ->
@@ -397,10 +403,16 @@ abstract class BaseChannel(
return chat.pubNub.setChannelMembers(
this.id,
users.map { PNMember.Partial(it.id) },
- includeCustom = true,
- includeCount = true,
- includeType = true,
- includeUUIDDetails = PNUUIDDetailsLevel.UUID_WITH_CUSTOM,
+ include = MemberInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeUser = true,
+ includeUserCustom = true,
+ includeUserType = true,
+ includeUserStatus = false
+ ),
filter = users.joinToString(" || ") { it.uuidFilterString }
).thenAsync { memberArrayResult: PNMemberArrayResult ->
chat.pubNub.time().thenAsync { time: PNTimeResult ->
@@ -428,10 +440,16 @@ abstract class BaseChannel(
page = page,
filter = filter,
sort = sort,
- includeCustom = true,
- includeCount = true,
- includeType = true,
- includeUUIDDetails = PNUUIDDetailsLevel.UUID_WITH_CUSTOM,
+ include = MemberInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeUser = true,
+ includeUserCustom = true,
+ includeUserType = true,
+ includeUserStatus = false
+ ),
).then { it: PNMemberArrayResult ->
MembersResponse(
it.next,
@@ -484,11 +502,17 @@ abstract class BaseChannel(
custom
)
), // todo should null overwrite? Waiting for optionals?
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeCustom = true,
- includeCount = true,
- includeType = true,
filter = channelFilterString,
+ include = MembershipInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeChannel = true,
+ includeChannelCustom = true,
+ includeChannelType = true,
+ includeChannelStatus = false
+ )
).thenAsync { membershipArray: PNChannelMembershipArrayResult ->
val resultDisconnect = callback?.let { connect(it) }
@@ -505,7 +529,7 @@ abstract class BaseChannel(
}
// there is a discrepancy between KMP and JS. There is no unsubscribe here. This is agreed and will be changed in JS Chat
- override fun leave(): PNFuture = chat.pubNub.removeMemberships(channels = listOf(id), includeType = false).then { Unit }
+ override fun leave(): PNFuture = chat.pubNub.removeMemberships(channels = listOf(id), include = MembershipInclude()).then { Unit }
override fun getPinnedMessage(): PNFuture {
val pinnedMessageTimetoken = this.custom?.get(PINNED_MESSAGE_TIMETOKEN).tryLong() ?: return null.asFuture()
@@ -721,10 +745,16 @@ abstract class BaseChannel(
page = page,
filter = user?.let { "uuid.id == '${user.id}'" },
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeUUIDDetails = PNUUIDDetailsLevel.UUID_WITH_CUSTOM,
- includeType = true
+ include = MemberInclude(
+ includeCustom = true,
+ includeStatus = false,
+ includeType = false,
+ includeTotalCount = true,
+ includeUser = true,
+ includeUserCustom = true,
+ includeUserType = true,
+ includeUserStatus = false
+ ),
)
}
diff --git a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/integration/ChatIntegrationTest.kt b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/integration/ChatIntegrationTest.kt
index 8530bcea..7d9ed19e 100644
--- a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/integration/ChatIntegrationTest.kt
+++ b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/integration/ChatIntegrationTest.kt
@@ -196,7 +196,7 @@ class ChatIntegrationTest : BaseChatIntegrationTest() {
val channelId02 = channel02.id
val membership01: ChannelMembershipInput = PNChannelMembership.Partial(channelId01, custom)
val membership02: ChannelMembershipInput = PNChannelMembership.Partial(channelId02)
- chat.pubNub.setMemberships(channels = listOf(membership01, membership02), uuid = chat.currentUser.id, includeType = false).await()
+ chat.pubNub.setMemberships(channels = listOf(membership01, membership02), userId = chat.currentUser.id).await()
// to each channel add two messages(we want to check if last message will be taken by fetchMessages with limit = 1)
channel01.sendText("message01In$channelId01").await()
@@ -627,10 +627,10 @@ class ChatIntegrationTest : BaseChatIntegrationTest() {
val unbanned = CompletableDeferred()
val restrictionBan = Restriction(userId = userId, channelId = channelId, ban = true, reason = "rude")
val restrictionUnban = Restriction(userId = userId, channelId = channelId, ban = false, mute = false, reason = "ok")
- pubnub.test(backgroundScope, checkAllEvents = false) {
+ pubnubPamServer.test(backgroundScope, checkAllEvents = false) {
var removeListenerAndUnsubscribe: AutoCloseable? = null
- pubnub.awaitSubscribe(channels = listOf(INTERNAL_USER_MODERATION_CHANNEL_PREFIX + userId)) {
- removeListenerAndUnsubscribe = chat.listenForEvents(
+ pubnubPamServer.awaitSubscribe(channels = listOf(INTERNAL_USER_MODERATION_CHANNEL_PREFIX + userId)) {
+ removeListenerAndUnsubscribe = chatPamServer.listenForEvents(
type = EventContent.Moderation::class,
channelId = INTERNAL_USER_MODERATION_CHANNEL_PREFIX + userId
) { event: Event ->
@@ -643,9 +643,9 @@ class ChatIntegrationTest : BaseChatIntegrationTest() {
}
}
- chat.setRestrictions(restrictionBan).await()
+ chatPamServer.setRestrictions(restrictionBan).await()
banned.await()
- chat.setRestrictions(restrictionUnban).await()
+ chatPamServer.setRestrictions(restrictionUnban).await()
unbanned.await()
removeListenerAndUnsubscribe?.close()
diff --git a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChannelTest.kt b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChannelTest.kt
index f843756a..9f3d38ff 100644
--- a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChannelTest.kt
+++ b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChannelTest.kt
@@ -22,7 +22,7 @@ import com.pubnub.api.models.consumer.objects.PNPage
import com.pubnub.api.models.consumer.objects.PNSortKey
import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata
import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadataResult
-import com.pubnub.api.models.consumer.objects.member.PNUUIDDetailsLevel
+import com.pubnub.api.models.consumer.objects.member.MemberInclude
import com.pubnub.api.utils.Clock
import com.pubnub.api.utils.Instant
import com.pubnub.api.utils.PatchValue
@@ -732,10 +732,7 @@ class ChannelTest : BaseTest() {
any(),
any(),
any(),
- any(),
- any(),
- any(),
- any()
+ include = any(),
)
} returns fetChannelMembers
@@ -748,10 +745,10 @@ class ChannelTest : BaseTest() {
page = page,
filter = null,
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeUUIDDetails = PNUUIDDetailsLevel.UUID_WITH_CUSTOM,
- includeType = true
+ include = matching {
+ it.includeCustom && !it.includeStatus && !it.includeType && it.includeTotalCount &&
+ it.includeUser && it.includeUserCustom && it.includeUserType && !it.includeUserStatus
+ },
)
}
}
@@ -771,10 +768,7 @@ class ChannelTest : BaseTest() {
any(),
any(),
any(),
- any(),
- any(),
- any(),
- any()
+ include = any(),
)
} returns getChannelMembers
@@ -787,10 +781,10 @@ class ChannelTest : BaseTest() {
page = page,
filter = "uuid.id == 'userId'",
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeUUIDDetails = PNUUIDDetailsLevel.UUID_WITH_CUSTOM,
- includeType = true
+ include = matching {
+ it.includeCustom && !it.includeStatus && !it.includeType && it.includeTotalCount &&
+ it.includeUser && it.includeUserCustom && it.includeUserType && !it.includeUserStatus
+ },
)
}
}
diff --git a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt
index eb116eb1..cf40a161 100644
--- a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt
+++ b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt
@@ -134,12 +134,22 @@ class ChatTest : BaseTest() {
@BeforeTest
fun setUp() {
- pnConfiguration = createPNConfiguration(UserId(userId), subscribeKey, publishKey, authToken = null)
+ objectUnderTest = ChatImpl(setupConfiguration(withSecretKey = false), pubnub, timerManager = timerManager)
+ }
+
+ private fun setupConfiguration(withSecretKey: Boolean): ChatConfiguration {
+ pnConfiguration = if (withSecretKey) {
+ createPNConfiguration(UserId(userId), subscribeKey, publishKey, "secretKey", authToken = null)
+ } else {
+ createPNConfiguration(UserId(userId), subscribeKey, publishKey, authToken = null)
+ }
+
every { pubnub.configuration } returns pnConfiguration
chatConfig = ChatConfiguration(
typingTimeout = 2000.milliseconds
)
- objectUnderTest = ChatImpl(chatConfig, pubnub, timerManager = timerManager)
+
+ return chatConfig
}
@Test
@@ -986,10 +996,7 @@ class ChatTest : BaseTest() {
any(),
any(),
any(),
- any(),
- any(),
- any(),
- any()
+ include = any(),
)
} returns getMembershipsEndpoint
every { getMembershipsEndpoint.async(any()) } calls { (callback: Consumer>) ->
@@ -1298,10 +1305,7 @@ class ChatTest : BaseTest() {
any(),
any(),
any(),
- any(),
- any(),
- any(),
- any()
+ include = any(),
)
} returns getMembershipsEndpoint
every { getMembershipsEndpoint.async(any()) } calls { (callback: Consumer>) ->
@@ -1325,6 +1329,8 @@ class ChatTest : BaseTest() {
@Test
fun shouldRemoveRestrictionWhenBanAndMuteIsFalse() {
+ objectUnderTest = ChatImpl(setupConfiguration(withSecretKey = true), pubnub, timerManager = timerManager)
+
val restrictedUserId = userId
val restrictedChannelId = channelId
val ban = false
@@ -1386,8 +1392,29 @@ class ChatTest : BaseTest() {
assertEquals(INTERNAL_USER_MODERATION_CHANNEL_PREFIX + restrictedUserId, actualModerationEventChannelId)
}
+ @Test
+ fun shouldThrowExceptionWhenSecretKeyIsNotSet() {
+ val restriction = Restriction(
+ userId = "userId",
+ channelId = "channelId",
+ ban = true,
+ mute = true,
+ reason = "rude"
+ )
+
+ objectUnderTest.setRestrictions(restriction).async { result: Result ->
+ assertTrue(result.isFailure)
+ assertEquals(
+ "Moderation restrictions can only be set by clients initialized with a Secret Key.",
+ result.exceptionOrNull()?.message
+ )
+ }
+ }
+
@Test
fun shouldAddRestrictionWhenBanIsTrue() {
+ objectUnderTest = ChatImpl(setupConfiguration(withSecretKey = true), pubnub, timerManager = timerManager)
+
val restrictedUserId = userId
val restrictedChannelId = channelId
val ban = true
@@ -1420,7 +1447,8 @@ class ChatTest : BaseTest() {
every {
pubnub.setChannelMembers(
channel = capture(channelIdSlot),
- uuids = capture(userIdsSlot)
+ users = capture(userIdsSlot),
+ include = any()
)
} returns manageChannelMembersEndpoint
every { manageChannelMembersEndpoint.async(any()) } calls { (callback: Consumer>) ->
diff --git a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/MembershipTest.kt b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/MembershipTest.kt
index d68ec14a..3f4dfeae 100644
--- a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/MembershipTest.kt
+++ b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/MembershipTest.kt
@@ -40,6 +40,8 @@ class MembershipTest {
user,
mapOf("lastReadMessageTimetoken" to lastMessageTimetoken, "other_stuff" to "some string"),
null,
+ null,
+ null,
null
)
@@ -55,6 +57,8 @@ class MembershipTest {
user,
mapOf(),
null,
+ null,
+ null,
null
)
assertNull(membership.getUnreadMessagesCount().await())
@@ -69,6 +73,8 @@ class MembershipTest {
user,
mapOf("lastReadMessageTimetoken" to lastMessageTimetoken),
null,
+ null,
+ null,
null
)
diff --git a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/UserTest.kt b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/UserTest.kt
index ab111a28..d8106922 100644
--- a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/UserTest.kt
+++ b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/UserTest.kt
@@ -6,7 +6,7 @@ import com.pubnub.api.models.consumer.objects.PNMembershipKey
import com.pubnub.api.models.consumer.objects.PNPage
import com.pubnub.api.models.consumer.objects.PNSortKey
import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata
-import com.pubnub.api.models.consumer.objects.membership.PNChannelDetailsLevel
+import com.pubnub.api.models.consumer.objects.membership.MembershipInclude
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership
import com.pubnub.api.models.consumer.objects.membership.PNChannelMembershipArrayResult
import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadata
@@ -27,6 +27,7 @@ import dev.mokkery.answering.calls
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.matcher.any
+import dev.mokkery.matcher.matching
import dev.mokkery.mock
import dev.mokkery.verify
import kotlin.test.BeforeTest
@@ -190,15 +191,12 @@ class UserTest {
every { chat.pubNub } returns pubNub
every {
pubNub.getMemberships(
- uuid = any(),
+ userId = any(),
limit = any(),
page = any(),
filter = any(),
sort = any(),
- includeCount = any(),
- includeCustom = any(),
- includeChannelDetails = any(),
- includeType = any()
+ include = any()
)
} returns getMembershipsEndpoint
every { getMembershipsEndpoint.async(any()) } calls { (callback1: Consumer>) ->
@@ -225,15 +223,12 @@ class UserTest {
every { chat.pubNub } returns pubNub
every {
pubNub.getMemberships(
- uuid = any(),
+ userId = any(),
limit = any(),
page = any(),
filter = any(),
sort = any(),
- includeCount = any(),
- includeCustom = any(),
- includeChannelDetails = any(),
- includeType = any()
+ include = any(),
)
} returns getMembershipsEndpoint
every { getMembershipsEndpoint.async(any()) } calls { (callback1: Consumer>) ->
@@ -251,15 +246,16 @@ class UserTest {
// then
verify {
pubNub.getMemberships(
- uuid = id,
+ userId = id,
limit = limit,
page = page,
filter = expectedFilter,
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeType = true
+ include = matching {
+ it.includeCustom && it.includeStatus && it.includeType && it.includeTotalCount &&
+ it.includeChannel && it.includeChannelCustom && it.includeChannelType &&
+ it.includeChannelStatus
+ }
)
}
}
@@ -279,10 +275,7 @@ class UserTest {
any(),
any(),
any(),
- any(),
- any(),
- any(),
- any()
+ include = any(),
)
} returns getMemberships
@@ -296,15 +289,16 @@ class UserTest {
val expectedFilter = "channel.id LIKE 'PUBNUB_INTERNAL_MODERATION_*'"
verify {
pubNub.getMemberships(
- uuid = id,
+ userId = id,
limit = limit,
page = page,
filter = expectedFilter,
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeType = true
+ include = matching {
+ it.includeCustom && it.includeStatus && it.includeType && it.includeTotalCount &&
+ it.includeChannel && it.includeChannelCustom && it.includeChannelType &&
+ it.includeChannelStatus
+ }
)
}
}
@@ -325,10 +319,7 @@ class UserTest {
any(),
any(),
any(),
- any(),
- any(),
- any(),
- any()
+ include = any(),
)
} returns getMemberships
@@ -337,15 +328,16 @@ class UserTest {
val expectedFilter = "channel.id == 'PUBNUB_INTERNAL_MODERATION_channelId'"
verify {
pubNub.getMemberships(
- uuid = id,
+ userId = id,
limit = limit,
page = page,
filter = expectedFilter,
sort = sort,
- includeCount = true,
- includeCustom = true,
- includeChannelDetails = PNChannelDetailsLevel.CHANNEL_WITH_CUSTOM,
- includeType = true
+ include = matching {
+ it.includeCustom && it.includeStatus && it.includeType && it.includeTotalCount &&
+ it.includeChannel && it.includeChannelCustom &&
+ it.includeChannelType && it.includeChannelStatus
+ }
)
}
}
@@ -367,7 +359,11 @@ class UserTest {
val user = createUser(chat)
val expectedUser = user.copy(name = randomString(), email = randomString())
- val newUser = user + PNUUIDMetadata(expectedUser.id, name = PatchValue.of(expectedUser.name), email = PatchValue.of(expectedUser.email))
+ val newUser = user + PNUUIDMetadata(
+ expectedUser.id,
+ name = PatchValue.of(expectedUser.name),
+ email = PatchValue.of(expectedUser.email)
+ )
assertEquals(expectedUser, newUser)
}
diff --git a/pubnub-chat-impl/src/jsMain/kotlin/MembershipJs.kt b/pubnub-chat-impl/src/jsMain/kotlin/MembershipJs.kt
index 154c9f3f..363aba89 100644
--- a/pubnub-chat-impl/src/jsMain/kotlin/MembershipJs.kt
+++ b/pubnub-chat-impl/src/jsMain/kotlin/MembershipJs.kt
@@ -16,6 +16,8 @@ class MembershipJs internal constructor(internal val membership: Membership, int
val custom get() = membership.custom?.toJsMap()
val updated by membership::updated
val eTag by membership::eTag
+ val status by membership::status
+ val type by membership::type
val lastReadMessageTimetoken: String? get() = membership.lastReadMessageTimetoken?.toString()
@@ -56,6 +58,8 @@ class MembershipJs internal constructor(internal val membership: Membership, int
"custom" to custom,
"updated" to updated,
"eTag" to eTag,
+ "status" to status,
+ "type" to type,
"lastReadMessageTimetoken" to lastReadMessageTimetoken
)
}
diff --git a/src/jsMain/resources/index.d.ts b/src/jsMain/resources/index.d.ts
index 27ea9eb1..af39f0f9 100644
--- a/src/jsMain/resources/index.d.ts
+++ b/src/jsMain/resources/index.d.ts
@@ -1,7 +1,7 @@
///
import PubNub from "pubnub";
import { GetMembershipsParametersv2, GetChannelMembersParameters, ObjectCustom, SetMembershipsParameters, ChannelMetadataObject, PublishParameters, SendFileParameters } from "pubnub";
-type MembershipFields = Pick;
+type MembershipFields = Pick;
declare class Membership {
private chat;
readonly channel: Channel;
@@ -9,6 +9,8 @@ declare class Membership {
readonly custom: ObjectCustom | null | undefined;
readonly updated: string;
readonly eTag: string;
+ readonly status?: string;
+ readonly type?: string;
update({ custom }: {
custom: ObjectCustom;
}): Promise;