Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PBE-1345] support user privacy settings #5249

Merged
merged 6 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Added `reason` and `custom` fields to flag user endpoint.[#5242](https://github.com/GetStream/stream-chat-android/pull/5242)
- Added `reactionGroups` field to `Message` entity. [#5247](https://github.com/GetStream/stream-chat-android/pull/5247)
- Added `ReactionSorting` interface to allow custom sorting of reactions. [#5248](https://github.com/GetStream/stream-chat-android/pull/5248)
- Added `privacySettings` field to `User` entity. [#5249](https://github.com/GetStream/stream-chat-android/pull/5249)

### ⚠️ Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2892,6 +2892,14 @@ internal constructor(
*/
@CheckResult
public fun keystroke(channelType: String, channelId: String, parentId: String? = null): Call<ChatEvent> {
val currentUser = clientState.user.value
if (currentUser?.privacySettings?.typingIndicators?.enabled == false) {
logger.v { "[keystroke] rejected (typing indicators are disabled)" }
return ErrorCall(
userScope,
Error.GenericError("Typing indicators are disabled for the current user."),
)
}
val extraData: Map<Any, Any> = parentId?.let {
mapOf(ARG_TYPING_PARENT_ID to parentId)
} ?: emptyMap()
Expand Down Expand Up @@ -2933,6 +2941,14 @@ internal constructor(
*/
@CheckResult
public fun stopTyping(channelType: String, channelId: String, parentId: String? = null): Call<ChatEvent> {
val currentUser = clientState.user.value
if (currentUser?.privacySettings?.typingIndicators?.enabled == false) {
logger.v { "[stopTyping] rejected (typing indicators are disabled)" }
return ErrorCall(
userScope,
Error.GenericError("Typing indicators are disabled for the current user."),
)
}
val extraData: Map<Any, Any> = parentId?.let {
mapOf(ARG_TYPING_PARENT_ID to parentId)
} ?: emptyMap()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2014-2024 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getstream.chat.android.client.api2.mapping

import io.getstream.chat.android.PrivacySettings
import io.getstream.chat.android.ReadReceipts
import io.getstream.chat.android.TypingIndicators
import io.getstream.chat.android.client.api2.model.dto.PrivacySettingsDto
import io.getstream.chat.android.client.api2.model.dto.ReadReceiptsDto
import io.getstream.chat.android.client.api2.model.dto.TypingIndicatorsDto

internal fun PrivacySettings.toDto(): PrivacySettingsDto = PrivacySettingsDto(
typing_indicators = typingIndicators?.toDto(),
read_receipts = readReceipts?.toDto(),
)

internal fun TypingIndicators.toDto(): TypingIndicatorsDto = TypingIndicatorsDto(
enabled = enabled,
)

internal fun ReadReceipts.toDto(): ReadReceiptsDto = ReadReceiptsDto(
enabled = enabled,
)

internal fun PrivacySettingsDto.toDomain(): PrivacySettings = PrivacySettings(
typingIndicators = typing_indicators?.toDomain(),
readReceipts = read_receipts?.toDomain(),
)

internal fun TypingIndicatorsDto.toDomain(): TypingIndicators = TypingIndicators(
enabled = enabled,
)

internal fun ReadReceiptsDto.toDomain(): ReadReceipts = ReadReceipts(
enabled = enabled,
)
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ internal fun User.toDto(): UpstreamUserDto =
name = name,
image = image,
invisible = isInvisible,
privacy_settings = privacySettings?.toDto(),
language = language,
role = role,
devices = devices.map(Device::toDto),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2014-2024 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getstream.chat.android.client.api2.model.dto

import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
internal data class PrivacySettingsDto(
val typing_indicators: TypingIndicatorsDto? = null,
val read_receipts: ReadReceiptsDto? = null,
)

@JsonClass(generateAdapter = true)
internal data class TypingIndicatorsDto(
val enabled: Boolean,
)

@JsonClass(generateAdapter = true)
internal data class ReadReceiptsDto(
val enabled: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal data class UpstreamUserDto(
val name: String,
val image: String,
val invisible: Boolean,
val privacy_settings: PrivacySettingsDto?,
val language: String,
val role: String,
val devices: List<DeviceDto>,
Expand All @@ -58,6 +59,7 @@ internal data class DownstreamUserDto(
val image: String?,
val role: String,
val invisible: Boolean = false,
val privacy_settings: PrivacySettingsDto?,
val language: String?,
val banned: Boolean,
val devices: List<DeviceDto>?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import io.getstream.chat.android.client.socket.ChatSocketStateService.State
import io.getstream.chat.android.client.token.TokenManager
import io.getstream.chat.android.core.internal.coroutines.DispatcherProvider
import io.getstream.chat.android.models.User
import io.getstream.log.StreamLog
import io.getstream.log.taggedLogger
import io.getstream.result.Error
import kotlinx.coroutines.Job
Expand Down Expand Up @@ -191,7 +190,6 @@ internal open class ChatSocket(
}

private suspend fun handleEvent(chatEvent: ChatEvent) {
StreamLog.v("Chat:Events") { "[handleEvent] Received $chatEvent" }
when (chatEvent) {
is ConnectedEvent -> chatSocketStateService.onConnectionEstablished(chatEvent)
is HealthEvent -> healthMonitor.ack()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.getstream.chat.android.client.socket

import io.getstream.chat.android.PrivacySettings
import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.client.parser.ChatParser
import io.getstream.chat.android.client.token.TokenManager
Expand Down Expand Up @@ -90,6 +91,7 @@ internal class SocketFactory(
if (user.role.isNotBlank()) put("role", user.role)
user.banned?.also { put("banned", it) }
user.invisible?.also { put("invisible", it) }
user.privacySettings?.also { put("privacy_settings", it.reducePrivacySettings()) }
if (user.teams.isNotEmpty()) put("teams", user.teams)
if (user.language.isNotBlank()) put("language", user.language)
if (user.image.isNotBlank()) put("image", user.image)
Expand All @@ -98,6 +100,26 @@ internal class SocketFactory(
}
}

private fun PrivacySettings.reducePrivacySettings(): Map<String, Any> = mutableMapOf<String, Any>()
.apply {
typingIndicators?.also {
put(
"typing_indicators",
mapOf<String, Any>(
"enabled" to it.enabled,
),
)
}
readReceipts?.also {
put(
"read_receipts",
mapOf<String, Any>(
"enabled" to it.enabled,
),
)
}
}

internal sealed class ConnectionConf {
var isReconnection: Boolean = false
private set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.getstream.chat.android.client.errors.extractCause
import io.getstream.chat.android.client.errors.fromChatErrorCode
import io.getstream.chat.android.client.events.ChatEvent
import io.getstream.chat.android.client.parser.ChatParser
import io.getstream.log.StreamLog
import io.getstream.result.Error
import io.getstream.result.Result
import io.getstream.result.recover
Expand All @@ -43,6 +44,7 @@ internal class StreamWebSocket(

private val webSocket = socketCreator(object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
StreamLog.v("Chat:Events") { "[handleEvent] event: `$text`" }
eventFlow.tryEmit(parseMessage(text))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ public fun User.mergePartially(that: User): User = this.copy(
banned = that.banned,
name = that.name,
image = that.image,
privacySettings = that.privacySettings,
extraData = that.extraData,
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package io.getstream.chat.android.client.parser2.testdata
import io.getstream.chat.android.client.api2.model.dto.DeviceDto
import io.getstream.chat.android.client.api2.model.dto.DownstreamMuteDto
import io.getstream.chat.android.client.api2.model.dto.DownstreamUserDto
import io.getstream.chat.android.client.api2.model.dto.PrivacySettingsDto
import io.getstream.chat.android.client.api2.model.dto.ReadReceiptsDto
import io.getstream.chat.android.client.api2.model.dto.TypingIndicatorsDto
import io.getstream.chat.android.client.api2.model.dto.UpstreamUserDto
import org.intellij.lang.annotations.Language
import java.util.Date
Expand Down Expand Up @@ -56,6 +59,7 @@ internal object UserDtoTestData {
name = "username",
image = "image",
invisible = false,
privacy_settings = null,
language = "language",
role = "",
devices = emptyList(),
Expand Down Expand Up @@ -103,6 +107,7 @@ internal object UserDtoTestData {
name = null,
image = null,
invisible = false,
privacy_settings = null,
language = null,
role = "",
devices = emptyList(),
Expand All @@ -126,6 +131,14 @@ internal object UserDtoTestData {
"id": "userId",
"role": "owner",
"invisible": false,
"privacy_settings": {
"typing_indicators": {
"enabled": false
},
"read_receipts": {
"enabled": false
}
},
"language": "language",
"banned": false,
"devices": [
Expand Down Expand Up @@ -163,6 +176,14 @@ internal object UserDtoTestData {
name = "username",
image = "image",
invisible = false,
privacy_settings = PrivacySettingsDto(
typing_indicators = TypingIndicatorsDto(
enabled = false,
),
read_receipts = ReadReceiptsDto(
enabled = false,
),
),
language = "language",
role = "owner",
devices = listOf(DeviceDto(id = "deviceId", push_provider = "provider", provider_name = "provider_name")),
Expand Down Expand Up @@ -209,6 +230,7 @@ internal object UserDtoTestData {
image = "image",
language = "language",
invisible = false,
privacy_settings = null,
banned = true,
devices = emptyList(),
teams = emptyList(),
Expand All @@ -223,6 +245,14 @@ internal object UserDtoTestData {
"name": "username",
"image": "image",
"invisible": false,
"privacy_settings": {
"typing_indicators": {
"enabled": false
},
"read_receipts": {
"enabled": false
}
},
"language": "language",
"role": "owner",
"devices": [
Expand All @@ -239,6 +269,14 @@ internal object UserDtoTestData {
id = "userId",
role = "owner",
invisible = false,
privacy_settings = PrivacySettingsDto(
typing_indicators = TypingIndicatorsDto(
enabled = false,
),
read_receipts = ReadReceiptsDto(
enabled = false,
),
),
banned = false,
devices = listOf(DeviceDto(id = "deviceId", push_provider = "provider", provider_name = "provider_name")),
teams = listOf("team1", "team2"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public fun ChannelCapabilities.toSet(): Set<String> = setOf(
SEND_REPLY,
SET_CHANNEL_COOLDOWN,
SEND_TYPING_EVENTS,
TYPING_EVENTS,
UPDATE_ANY_MESSAGE,
UPDATE_CHANNEL,
UPDATE_CHANNEL_MEMBERS,
Expand Down
Loading
Loading