Skip to content

Commit

Permalink
Match behavior from TS more closely regarding hard delete status.
Browse files Browse the repository at this point in the history
Previously we diverged by returning the last known version of the data, this reverts it to returning `null` when hard deleting users and channels.
  • Loading branch information
wkal-pubnub committed Oct 25, 2024
1 parent 2765760 commit 9052e46
Show file tree
Hide file tree
Showing 16 changed files with 58 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ interface Channel {
* @param soft Decide if you want to permanently remove channel metadata. The channel metadata gets permanently
* deleted from the App Context storage by default. If you set this parameter to true, the Channel object
* gets the deleted status, and you can still restore/get its data.
* @return For hard delete, the method returns [PNFuture] with the last version of the [Channel] object before it was permanently deleted.
* @return For hard delete, the method returns [PNFuture] without a value (`null`).
* For soft delete, [PNFuture] containing an updated [Channel] instance with the status field set to "deleted".
*/
fun delete(soft: Boolean = false): PNFuture<Channel>
fun delete(soft: Boolean = false): PNFuture<Channel?>

/**
* Forwards message to existing [Channel]
Expand Down
9 changes: 5 additions & 4 deletions pubnub-chat-api/src/commonMain/kotlin/com/pubnub/chat/Chat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,10 @@ interface Chat {
* from the App Context storage by default. If you set this parameter to true, the User object gets the deleted
* status, and you can still restore/get their metadata.
*
* @return [PNFuture] containing [User] object.
* @return For hard delete, the method returns [PNFuture] without a value (`null`).
* For soft delete, [PNFuture] containing an updated [User] instance with the status field set to "deleted".
*/
fun deleteUser(id: String, soft: Boolean = false): PNFuture<User>
fun deleteUser(id: String, soft: Boolean = false): PNFuture<User?>

/**
* Retrieves list of [Channel.id] where a given user is present.
Expand Down Expand Up @@ -228,10 +229,10 @@ interface Chat {
* deleted from the App Context storage by default. If you set this parameter to true, the Channel object
* gets the deleted status, and you can still restore/get its data.
*
* @return For hard delete, the method returns [PNFuture] with the last version of the [Channel] object before it was permanently deleted.
* @return For hard delete, the method returns [PNFuture] without a value (`null`).
* For soft delete, [PNFuture] containing an updated [Channel] instance with the status field set to "deleted".
*/
fun deleteChannel(id: String, soft: Boolean = false): PNFuture<Channel>
fun deleteChannel(id: String, soft: Boolean = false): PNFuture<Channel?>

/**
* Returns a list of [User.id] present on the given [Channel].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ interface Message {
*
* @param soft Decide if you want to permanently remove message data. By default, the message data gets permanently deleted from Message Persistence. If you set this parameter to true, the Message object gets the deleted status and you can still restore/get its data.
* @param preserveFiles Define if you want to keep the files attached to the message or remove them.
* @return For hard delete, the method returns the last version of the Message object before it was permanently deleted. For soft delete, an updated message instance with an added deleted action type.
* @return For hard delete, the method returns `PNFuture` without a value (`null`). For soft delete, a `PNFuture` with an updated message instance with an added deleted action type.
*/
fun delete(soft: Boolean = false, preserveFiles: Boolean = false): PNFuture<Message?>

Expand Down Expand Up @@ -178,7 +178,7 @@ interface Message {
*
* @return A pair of values containing an object with details about the result of the remove message action (indicating whether the message was successfully removed and potentially including additional metadata or information about the removal) and the updated channel object after the removal of the thread.
*/
fun removeThread(): PNFuture<Pair<PNRemoveMessageActionResult, Channel>> // todo add test
fun removeThread(): PNFuture<Pair<PNRemoveMessageActionResult, Channel?>> // todo add test

/**
* Add or remove a reaction to a message.
Expand Down
4 changes: 2 additions & 2 deletions pubnub-chat-api/src/commonMain/kotlin/com/pubnub/chat/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ interface User {
* Deletes the user. If soft deletion is enabled, the user's data is retained but marked as inactive.
*
* @param soft If true, the user is soft deleted, retaining their data but making them inactive.
* @return For hard delete, the method returns [PNFuture] with the last version of the [User] object before it was permanently deleted.
* @return For hard delete, the method returns [PNFuture] without a value (`null`).
* For soft delete, [PNFuture] containing an updated [User] instance with the status field set to "deleted".
*/
fun delete(soft: Boolean = false): PNFuture<User>
fun delete(soft: Boolean = false): PNFuture<User?>

/**
* Retrieves a list of channels where the user is currently present.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ import com.pubnub.chat.internal.error.PubNubErrorMessage.CANNOT_FORWARD_MESSAGE_
import com.pubnub.chat.internal.error.PubNubErrorMessage.CAN_NOT_FIND_CHANNEL_WITH_ID
import com.pubnub.chat.internal.error.PubNubErrorMessage.CHANNEL_ID_ALREADY_EXIST
import com.pubnub.chat.internal.error.PubNubErrorMessage.CHANNEL_ID_IS_REQUIRED
import com.pubnub.chat.internal.error.PubNubErrorMessage.CHANNEL_NOT_EXIST
import com.pubnub.chat.internal.error.PubNubErrorMessage.CHANNEL_NOT_FOUND
import com.pubnub.chat.internal.error.PubNubErrorMessage.COUNT_SHOULD_NOT_EXCEED_100
import com.pubnub.chat.internal.error.PubNubErrorMessage.DEVICE_TOKEN_HAS_TO_BE_DEFINED_IN_CHAT_PUSHNOTIFICATIONS_CONFIG
import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_CREATE_UPDATE_CHANNEL_DATA
import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_CREATE_UPDATE_USER_DATA
import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_FORWARD_MESSAGE
import com.pubnub.chat.internal.error.PubNubErrorMessage.FAILED_TO_RETRIEVE_CHANNEL_DATA
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
Expand Down Expand Up @@ -229,7 +229,7 @@ class ChatImpl(
chat: Chat,
message: Message,
soft: Boolean
): PNFuture<Pair<PNRemoveMessageActionResult, Channel>> {
): PNFuture<Pair<PNRemoveMessageActionResult, Channel?>> {
if (!message.hasThread) {
return PubNubException(THERE_IS_NO_THREAD_TO_BE_DELETED).logErrorAndReturnException(log).asFuture()
}
Expand Down Expand Up @@ -321,19 +321,20 @@ class ChatImpl(
}
}

override fun deleteUser(id: String, soft: Boolean): PNFuture<User> {
override fun deleteUser(id: String, soft: Boolean): PNFuture<User?> {
if (!isValidId(id)) {
return PubNubException(ID_IS_REQUIRED).logErrorAndReturnException(log).asFuture()
}

return getUser(id).thenAsync { user: User? ->
user?.let { notNullUser ->
if (soft) {
performSoftUserDelete(notNullUser)
} else {
performUserDelete(notNullUser)
return if (soft) {
getUser(id).thenAsync { user: User? ->
if (user == null) {
log.pnError(USER_NOT_EXIST)
}
} ?: log.pnError(USER_NOT_EXIST)
performSoftUserDelete(user)
}
} else {
performUserDelete(id).then { null }
}
}

Expand Down Expand Up @@ -454,17 +455,20 @@ class ChatImpl(
}
}

override fun deleteChannel(id: String, soft: Boolean): PNFuture<Channel> {
override fun deleteChannel(id: String, soft: Boolean): PNFuture<Channel?> {
if (!isValidId(id)) {
return log.logErrorAndReturnException(CHANNEL_ID_IS_REQUIRED).asFuture()
}

return getChannelData(id).thenAsync { channel: Channel ->
if (soft) {
return if (soft) {
getChannel(id).thenAsync { channel ->
if (channel == null) {
log.pnError(CHANNEL_NOT_EXIST)
}
performSoftChannelDelete(channel)
} else {
performChannelDelete(channel)
}
} else {
performChannelDelete(id).then { null }
}
}

Expand Down Expand Up @@ -1036,15 +1040,6 @@ class ChatImpl(
return id.isNotEmpty()
}

private fun getChannelData(id: String): PNFuture<Channel> {
return pubNub.getChannelMetadata(channel = id, includeCustom = false)
.then { pnChannelMetadataResult: PNChannelMetadataResult ->
ChannelImpl.fromDTO(this, pnChannelMetadataResult.data)
}.catch { exception ->
Result.failure(PubNubException(FAILED_TO_RETRIEVE_CHANNEL_DATA, exception))
}
}

private fun performSoftUserDelete(user: User): PNFuture<User> {
val updatedUser = (user as UserImpl).copy(status = DELETED)
return pubNub.setUUIDMetadata(
Expand All @@ -1062,8 +1057,8 @@ class ChatImpl(
}
}

private fun performUserDelete(user: User): PNFuture<User> =
pubNub.removeUUIDMetadata(uuid = user.id).then { user }
private fun performUserDelete(userId: String): PNFuture<Unit> =
pubNub.removeUUIDMetadata(uuid = userId).then { }

private fun performSoftChannelDelete(channel: Channel): PNFuture<Channel> {
val updatedChannel = (channel as BaseChannel<*, *>).copyWithStatusDeleted()
Expand All @@ -1082,8 +1077,8 @@ class ChatImpl(
}
}

private fun performChannelDelete(channel: Channel) =
pubNub.removeChannelMetadata(channel = channel.id).then { channel }
private fun performChannelDelete(channelId: String): PNFuture<Unit> =
pubNub.removeChannelMetadata(channel = channelId).then { }

private fun setChannelMetadata(
id: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface ChatInternal : Chat {
chat: Chat,
message: Message,
soft: Boolean = false
): PNFuture<Pair<PNRemoveMessageActionResult, Channel>>
): PNFuture<Pair<PNRemoveMessageActionResult, Channel?>>

fun restoreThreadChannel(message: Message): PNFuture<PNMessageAction?>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ data class UserImpl(
)
}

override fun delete(soft: Boolean): PNFuture<User> {
override fun delete(soft: Boolean): PNFuture<User?> {
return chat.deleteUser(id, soft)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ abstract class BaseChannel<C : Channel, M : Message>(
return chat.updateChannel(id, name, custom, description, status, type)
}

override fun delete(soft: Boolean): PNFuture<Channel> {
override fun delete(soft: Boolean): PNFuture<Channel?> {
return chat.deleteChannel(id, soft)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ data class ThreadChannelImpl(
}
}

override fun delete(soft: Boolean): PNFuture<Channel> {
override fun delete(soft: Boolean): PNFuture<Channel?> {
return chat.removeThreadChannel(chat, parentMessage, soft).then { it.second }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.pubnub.api.models.consumer.PNPublishResult
import com.pubnub.api.models.consumer.history.PNFetchMessageItem
import com.pubnub.api.models.consumer.message_actions.PNAddMessageActionResult
import com.pubnub.api.models.consumer.message_actions.PNMessageAction
import com.pubnub.api.models.consumer.message_actions.PNRemoveMessageActionResult
import com.pubnub.chat.Channel
import com.pubnub.chat.Message
import com.pubnub.chat.ThreadChannel
Expand Down Expand Up @@ -201,7 +202,7 @@ abstract class BaseMessage<T : Message>(

override fun createThread(): PNFuture<ThreadChannel> = ChatImpl.createThreadChannel(chat, this)

override fun removeThread() = chat.removeThreadChannel(chat, this)
override fun removeThread(): PNFuture<Pair<PNRemoveMessageActionResult, Channel?>> = chat.removeThreadChannel(chat, this)

override fun toggleReaction(reaction: String): PNFuture<Message> {
val existingReaction = reactions[reaction]?.find {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.pubnub.chat.Event
import com.pubnub.chat.internal.message.MessageImpl
import com.pubnub.chat.listenForEvents
import com.pubnub.chat.types.EventContent
import com.pubnub.internal.PLATFORM
import com.pubnub.test.await
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
Expand All @@ -25,6 +26,9 @@ class AccessManagerTest : BaseChatIntegrationTest() {

@Test
fun pubNubClient_with_PAM_enabled_should_getChannel_when_token_set() = runTest {
if (PLATFORM == "iOS") {
return@runTest
}
// getToken from server
val channelId = channelPam.id
chatPamServer.createChannel(id = channelId).await()
Expand All @@ -45,6 +49,9 @@ class AccessManagerTest : BaseChatIntegrationTest() {

@Test
fun setLastReadMessageTimetoken_should_send_Receipt_event_when_has_token() = runTest {
if (PLATFORM == "iOS") {
return@runTest
}
var numberOfReceiptEvents = 0
val timetoken = 1000L
val channelId = channelPam.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ abstract class BaseChatIntegrationTest : BaseIntegrationTest() {
fun afterTest() = runTest {
try {
pubnub.removeUUIDMetadata(someUser.id).await()
pubnubPamServer.removeUUIDMetadata(userPamServer.id).await()
pubnubPamServer.removeUUIDMetadata(userPamClient.id).await()
if (PLATFORM != "iOS") {
pubnubPamServer.removeUUIDMetadata(userPamServer.id).await()
pubnubPamServer.removeUUIDMetadata(userPamClient.id).await()
}
pubnub.removeChannelMetadata(channel01.id).await()
pubnub.removeChannelMetadata(channel01Chat02.id).await()
pubnub.removeChannelMetadata(channel02.id).await()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class ChannelTest : BaseTest() {
val channelFutureMock: PNFuture<Channel> = mock(MockMode.strict)
every { chat.deleteChannel(any(), any()) } returns channelFutureMock

val deleteChannelFuture: PNFuture<Channel> = objectUnderTest.delete(soft = softDelete)
val deleteChannelFuture: PNFuture<Channel?> = objectUnderTest.delete(soft = softDelete)

assertEquals(channelFutureMock, deleteChannelFuture)
verify { chat.deleteChannel(id = channelId, soft = softDelete) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ class ChatTest : BaseTest() {
val softDelete = true

// when
objectUnderTest.deleteUser(emptyID, softDelete).async { result: Result<User> ->
objectUnderTest.deleteUser(emptyID, softDelete).async { result: Result<User?> ->
// then
assertTrue(result.isFailure)
assertEquals("Id is required", result.exceptionOrNull()?.message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class UserTest {
val chat = object : FakeChat(chatConfig, pubNub) {
var soft: Boolean? = null

override fun deleteUser(id: String, soft: Boolean): PNFuture<User> {
override fun deleteUser(id: String, soft: Boolean): PNFuture<User?> {
this.soft = soft
return objectUnderTest.asFuture()
}
Expand All @@ -105,7 +105,7 @@ class UserTest {
var softDeleted: Boolean? = null
var deletedUserId: String? = null

override fun deleteUser(id: String, soft: Boolean): PNFuture<User> {
override fun deleteUser(id: String, soft: Boolean): PNFuture<User?> {
this.softDeleted = soft
this.deletedUserId = id
return objectUnderTest.asFuture()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ abstract class FakeChat(override val config: ChatConfiguration, override val pub
chat: Chat,
message: Message,
soft: Boolean
): PNFuture<Pair<PNRemoveMessageActionResult, Channel>> {
): PNFuture<Pair<PNRemoveMessageActionResult, Channel?>> {
TODO("Not yet implemented")
}

Expand Down Expand Up @@ -121,7 +121,7 @@ abstract class FakeChat(override val config: ChatConfiguration, override val pub
TODO("Not yet implemented")
}

override fun deleteUser(id: String, soft: Boolean): PNFuture<User> {
override fun deleteUser(id: String, soft: Boolean): PNFuture<User?> {
TODO("Not yet implemented")
}

Expand Down Expand Up @@ -168,7 +168,7 @@ abstract class FakeChat(override val config: ChatConfiguration, override val pub
TODO("Not yet implemented")
}

override fun deleteChannel(id: String, soft: Boolean): PNFuture<Channel> {
override fun deleteChannel(id: String, soft: Boolean): PNFuture<Channel?> {
TODO("Not yet implemented")
}

Expand Down

0 comments on commit 9052e46

Please sign in to comment.