Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ data class ResolvedUserFlags(
val requireCoinbaseEmailVerification: ResolvedFlag<Boolean>,
val tipPresets: ResolvedFlag<List<TipPresets>>,
val usernameMinBalance: ResolvedFlag<Fiat>,
val messageEditWindow: ResolvedFlag<Duration?>,
val messageDeleteWindow: ResolvedFlag<Duration?>,
)

internal fun UserFlags.resolve(overrides: Overrides): ResolvedUserFlags = ResolvedUserFlags(
Expand All @@ -56,4 +58,7 @@ internal fun UserFlags.resolve(overrides: Overrides): ResolvedUserFlags = Resolv
requireCoinbaseEmailVerification = ResolvedFlag(requireCoinbaseEmailVerification, overrides.requireCoinbaseEmailVerification),
tipPresets = ResolvedFlag(tipPresets, FieldOverride.None),
usernameMinBalance = ResolvedFlag(usernameMinBalance, FieldOverride.None),
// Read-only for now — no debug override support until the edit/delete UI lands.
messageEditWindow = ResolvedFlag(messageEditWindow, FieldOverride.None),
messageDeleteWindow = ResolvedFlag(messageDeleteWindow, FieldOverride.None),
)
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ private data class CachedFlags(
val requireCoinbaseEmailVerification: Boolean,
val tipPresets: List<CachedTipPresets> = emptyList(),
val usernameMinBalance: CachedFiat = CachedFiat(quarks = 0),
val messageEditWindowMillis: Long? = null,
val messageDeleteWindowMillis: Long? = null,
) {
fun toDomain(): UserFlags = UserFlags(
isStaff = isStaff,
Expand All @@ -202,6 +204,8 @@ private data class CachedFlags(
requireCoinbaseEmailVerification = requireCoinbaseEmailVerification,
tipPresets = tipPresets.map { it.toDomain() },
usernameMinBalance = usernameMinBalance.toDomain(),
messageEditWindow = messageEditWindowMillis?.milliseconds,
messageDeleteWindow = messageDeleteWindowMillis?.milliseconds,
)

companion object {
Expand All @@ -226,6 +230,8 @@ private data class CachedFlags(
requireCoinbaseEmailVerification = flags.requireCoinbaseEmailVerification,
tipPresets = flags.tipPresets.map { CachedTipPresets.fromDomain(it) },
usernameMinBalance = CachedFiat.fromDomain(flags.usernameMinBalance),
messageEditWindowMillis = flags.messageEditWindow?.inWholeMilliseconds,
messageDeleteWindowMillis = flags.messageDeleteWindow?.inWholeMilliseconds,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class ResolvedUserFlagsTest {
assertEquals(true, resolved.requireCoinbaseEmailVerification.effectiveValue)
assertEquals(ServerFlags.tipPresets, resolved.tipPresets.effectiveValue)
assertEquals(Fiat(quarks = 5_000_000L), resolved.usernameMinBalance.effectiveValue)
assertEquals(15.seconds, resolved.messageEditWindow.effectiveValue)
assertEquals(60.seconds, resolved.messageDeleteWindow.effectiveValue)
}

@Test
Expand Down Expand Up @@ -142,6 +144,8 @@ private val ServerFlags = UserFlags(
TipPresets(region = "US", minimum = 1.0, low = 2.0, medium = 3.0, high = 4.0),
),
usernameMinBalance = Fiat(quarks = 5_000_000L),
messageEditWindow = 15.seconds,
messageDeleteWindow = 60.seconds,
)

// Every value here differs from the matching server value above, so a flag that reads the
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protovalidate-kt = "0.1.1"
# 0.3.0 is the first release of either package to ship R8 keep rules for its generated
# messages, which is what lets proguard-rules.pro drop its own.
ocp-client-protocol = "0.3.0"
flipcash2-client-protocol = "0.3.0"
flipcash2-client-protocol = "0.4.0"

# The Android port is the ONLY libphonenumber this app depends on, deliberately. Google's
# `com.googlecode` artifact used to sit alongside it; the two ship separate copies of the metadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ internal class UserFlagsMapper @Inject constructor():
requireCoinbaseEmailVerification = from.requireCoinbaseEmailVerification,
tipPresets = from.tipPresetsList.map { it.toDomain() },
usernameMinBalance = Fiat(quarks = from.usernameMinBalance),
messageEditWindow = if (from.hasMessageEditWindow()) {
from.messageEditWindow.seconds.toDuration(DurationUnit.SECONDS)
} else null,
messageDeleteWindow = if (from.hasMessageDeleteWindow()) {
from.messageDeleteWindow.seconds.toDuration(DurationUnit.SECONDS)
} else null,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ data class UserFlags(
val tipPresets: List<TipPresets>,
// USDF that must be held across all currencies before a username can be set.
val usernameMinBalance: Fiat,
// Duration after message creation when a message can be edited. Absent when
// the server hasn't set a window (not the same as a zero-length window).
val messageEditWindow: Duration?,
// Duration after message creation when a message can be deleted. Absent when
// the server hasn't set a window (not the same as a zero-length window).
val messageDeleteWindow: Duration?,
) {
companion object {
val Default = UserFlags(
Expand All @@ -42,6 +48,8 @@ data class UserFlags(
requireCoinbaseEmailVerification = false,
tipPresets = emptyList(),
usernameMinBalance = Fiat.Zero,
messageEditWindow = null,
messageDeleteWindow = null,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,27 @@ class UserFlagsMapperTest {

assertTrue(result.tipPresets.isEmpty())
}

@Test
fun `maps message edit and delete windows when set`() {
val proto = FlipcashAccountService.UserFlags.newBuilder()
.setMessageEditWindow(com.google.protobuf.Duration.newBuilder().setSeconds(15).build())
.setMessageDeleteWindow(com.google.protobuf.Duration.newBuilder().setSeconds(60).build())
.build()

val result = mapper.map(proto)

assertEquals(15.seconds, result.messageEditWindow)
assertEquals(60.seconds, result.messageDeleteWindow)
}

@Test
fun `message edit and delete windows are null when unset, not zero`() {
val proto = userFlags { }

val result = mapper.map(proto)

assertNull(result.messageEditWindow)
assertNull(result.messageDeleteWindow)
}
}
Loading