Implemented plain fields for UserBridgeMapper.kt
Affected: none MAILAND-722
This commit is contained in:
parent
fc1dc71928
commit
1920352afc
|
@ -20,6 +20,7 @@ config/detekt/reports/
|
|||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
scripts/extract_dependencies/raw_dependencies.txt
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
|
|
@ -75,6 +75,7 @@ import static ch.protonmail.android.core.Constants.Prefs.PREF_USED_SPACE;
|
|||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_CREDIT;
|
||||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_CURRENCY;
|
||||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_ID;
|
||||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_NAME;
|
||||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_ORG_PRIVATE_KEY;
|
||||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_PRIVATE;
|
||||
import static ch.protonmail.android.core.Constants.Prefs.PREF_USER_SERVICES;
|
||||
|
@ -162,6 +163,7 @@ public class User {
|
|||
public static User load(String username) {
|
||||
final SharedPreferences securePrefs = ProtonMailApplication.getApplication().getSecureSharedPreferences(username);
|
||||
final User user = new User();
|
||||
user.name = securePrefs.getString(PREF_USER_NAME, "");
|
||||
if (!TextUtils.isEmpty(username)) {
|
||||
user.username = username;
|
||||
}
|
||||
|
@ -476,14 +478,46 @@ public class User {
|
|||
return allowMobileSignatureEdit || role > 0;
|
||||
}
|
||||
|
||||
public int getPrivate() {
|
||||
return isPrivate;
|
||||
}
|
||||
|
||||
public int getSubscribed() {
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
public int getServices() {
|
||||
return services;
|
||||
}
|
||||
|
||||
public boolean isPaidUser() {
|
||||
return subscribed > 0;
|
||||
}
|
||||
|
||||
public int getCredit() {
|
||||
return credit;
|
||||
}
|
||||
|
||||
public String getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public String getOrganizationPrivateKey() {
|
||||
return organizationPrivateKey;
|
||||
}
|
||||
|
||||
public int getDelinquentValue() {
|
||||
return delinquent;
|
||||
}
|
||||
|
||||
public boolean getDelinquent() {
|
||||
return delinquent >= 3;
|
||||
}
|
||||
|
||||
public int getMaxUpload() {
|
||||
return maxUpload;
|
||||
}
|
||||
|
||||
public void setAndSaveUsedSpace(long usedSpace) {
|
||||
if (this.usedSpace != usedSpace) {
|
||||
this.usedSpace = usedSpace;
|
||||
|
@ -728,6 +762,10 @@ public class User {
|
|||
return AddressId;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -18,16 +18,19 @@
|
|||
*/
|
||||
package ch.protonmail.android.mapper.bridge
|
||||
|
||||
import ch.protonmail.android.domain.entity.Bytes
|
||||
import ch.protonmail.android.domain.entity.Id
|
||||
import ch.protonmail.android.domain.entity.Name
|
||||
import ch.protonmail.android.domain.entity.NotBlankString
|
||||
import ch.protonmail.android.domain.entity.bytes
|
||||
import ch.protonmail.android.domain.entity.user.Addresses
|
||||
import ch.protonmail.android.domain.entity.user.Delinquent
|
||||
import ch.protonmail.android.domain.entity.user.Plan
|
||||
import ch.protonmail.android.domain.entity.user.Role
|
||||
import ch.protonmail.android.domain.entity.user.User
|
||||
import ch.protonmail.android.domain.entity.user.UserKeys
|
||||
import ch.protonmail.android.domain.entity.user.UserSpace
|
||||
import me.proton.core.util.kotlin.takeIfNotBlank
|
||||
import me.proton.core.util.kotlin.toBoolean
|
||||
import ch.protonmail.android.api.models.User as OldUser
|
||||
|
||||
/**
|
||||
|
@ -39,19 +42,49 @@ class UserBridgeMapper : BridgeMapper<OldUser, User> {
|
|||
override fun OldUser.toNewModel(): User {
|
||||
|
||||
return User(
|
||||
id = Id("id"), // TODO
|
||||
id = Id(id),
|
||||
name = Name(name),
|
||||
addresses = Addresses(emptyMap()), // TODO
|
||||
keys = UserKeys(null, emptyList()), // TODO
|
||||
plans = emptySet(), // TODO
|
||||
private = false, // TODO
|
||||
role = Role.values().first { it.i == role },
|
||||
organizationPrivateKey = null, // TODO
|
||||
currency = NotBlankString("eur"), // TODO
|
||||
credits = 0, // TODO
|
||||
delinquent = Delinquent.None, //TODO
|
||||
totalUploadLimit = Bytes(0u), //TODO
|
||||
dedicatedSpace = UserSpace(Bytes(0u), Bytes(0u)) // TODO
|
||||
plans = getPlans(services, subscribed),
|
||||
private = private.toBoolean(),
|
||||
role = getRole(role),
|
||||
organizationPrivateKey = getOrganizationKey(organizationPrivateKey),
|
||||
currency = NotBlankString(currency),
|
||||
credits = credit,
|
||||
delinquent = getDelinquent(delinquentValue),
|
||||
totalUploadLimit = maxUpload.bytes,
|
||||
dedicatedSpace = UserSpace(usedSpace.bytes, maxSpace.bytes)
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun getPlans(services: Int, subscribed: Int) = buildSet {
|
||||
fun Int.hasMail() = MAIL_PLAN_VALUE and this == MAIL_PLAN_VALUE
|
||||
fun Int.hasVpn() = VPN_PLAN_VALUE and this == VPN_PLAN_VALUE
|
||||
|
||||
if (subscribed.hasMail()) add(Plan.Mail.Paid)
|
||||
else if (services.hasMail()) add(Plan.Mail.Free)
|
||||
|
||||
if (subscribed.hasVpn()) add(Plan.Vpn.Paid)
|
||||
else if (services.hasVpn()) add(Plan.Vpn.Free)
|
||||
}
|
||||
|
||||
private fun getRole(value: Int) = Role.values().first { it.i == value }
|
||||
|
||||
private fun getOrganizationKey(key: String?) = key?.takeIfNotBlank()?.let(::NotBlankString)
|
||||
|
||||
private fun getDelinquent(value: Int) = when (value.toUInt()) {
|
||||
Delinquent.None.i -> Delinquent.None
|
||||
Delinquent.InvoiceAvailable.i -> Delinquent.InvoiceAvailable
|
||||
Delinquent.InvoiceOverdue.i -> Delinquent.InvoiceOverdue
|
||||
Delinquent.InvoiceDelinquent.i -> Delinquent.InvoiceDelinquent
|
||||
Delinquent.IncomingMailDisabled.i -> Delinquent.IncomingMailDisabled
|
||||
else -> throw IllegalArgumentException("Cannot get Delinquent for value $value")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAIL_PLAN_VALUE = 1 // 001
|
||||
const val VPN_PLAN_VALUE = 4 // 100
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,29 @@
|
|||
*/
|
||||
package ch.protonmail.android.mapper.bridge
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.text.TextUtils
|
||||
import assert4k.*
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_DELINQUENT
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_MAX_SPACE
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_MAX_UPLOAD_FILE_SIZE
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_ROLE
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_SUBSCRIBED
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USED_SPACE
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USER_CREDIT
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USER_CURRENCY
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USER_ID
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USER_NAME
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USER_ORG_PRIVATE_KEY
|
||||
import ch.protonmail.android.core.Constants.Prefs.PREF_USER_PRIVATE
|
||||
import ch.protonmail.android.core.ProtonMailApplication
|
||||
import ch.protonmail.android.domain.entity.user.Delinquent
|
||||
import ch.protonmail.android.domain.entity.user.Plan
|
||||
import ch.protonmail.android.domain.entity.user.Role
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import me.proton.core.util.kotlin.invoke
|
||||
import kotlin.test.Test
|
||||
import ch.protonmail.android.api.models.User as OldUser
|
||||
|
@ -34,12 +53,23 @@ internal class UserBridgeMapperTest {
|
|||
private val mapper = UserBridgeMapper()
|
||||
|
||||
@Test
|
||||
fun `verify it transform correctly`() {
|
||||
fun `transform from api`() {
|
||||
|
||||
// GIVEN
|
||||
val oldUser = mockk<OldUser>(relaxed = true) {
|
||||
every { id } returns "id"
|
||||
every { name } returns "name"
|
||||
every { role } returns 1
|
||||
every { services } returns 4 // TODO: use 5 when addresses are handled
|
||||
every { subscribed } returns 4
|
||||
every { private } returns 1
|
||||
every { role } returns 2
|
||||
every { organizationPrivateKey } returns "orgKey"
|
||||
every { currency } returns "eur"
|
||||
every { credit } returns 10
|
||||
every { delinquentValue } returns 3
|
||||
every { maxUpload } returns 12_345
|
||||
every { usedSpace } returns 15_000
|
||||
every { maxSpace } returns 30_000
|
||||
}
|
||||
|
||||
// WHEN
|
||||
|
@ -47,8 +77,90 @@ internal class UserBridgeMapperTest {
|
|||
|
||||
// THEN
|
||||
assert that newUser * {
|
||||
+id.s equals "id"
|
||||
+name.s equals "name"
|
||||
+role equals Role.ORGANIZATION_MEMBER
|
||||
+(plans * {
|
||||
+size() equals 1 // TODO use 2 when addresses are handled
|
||||
// it contains Plan.Mail.Free // TODO uncomment when addresses are handled
|
||||
it contains Plan.Vpn.Paid
|
||||
})
|
||||
+private equals true
|
||||
+role equals Role.ORGANIZATION_ADMIN
|
||||
+organizationPrivateKey?.s equals "orgKey"
|
||||
+currency.s equals "eur"
|
||||
+credits() equals 10
|
||||
+delinquent equals Delinquent.InvoiceDelinquent
|
||||
+totalUploadLimit.l equals 12_345uL
|
||||
+(dedicatedSpace * {
|
||||
+used.l() equals 15_000uL
|
||||
+total.l() equals 30_000uL
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `transform from preferences`() {
|
||||
mockkStatic(ProtonMailApplication::class, TextUtils::class, SystemClock::class)
|
||||
every { ProtonMailApplication.getApplication() } returns mockk {
|
||||
every { getString(any()) } returns ""
|
||||
every { resources } returns mockk(relaxed = true)
|
||||
every { getSecureSharedPreferences("username") } returns mockk() {
|
||||
|
||||
// Defaults
|
||||
every { getBoolean(any(), any()) } returns false
|
||||
every { getInt(any(), any()) } returns 0
|
||||
every { getLong(any(), any()) } returns 0
|
||||
every { getString(any(), any()) } returns ""
|
||||
|
||||
// Meaningful User data
|
||||
every { getString(PREF_USER_ID, any()) } returns "id"
|
||||
every { getString(PREF_USER_NAME, any()) } returns "username"
|
||||
every { getInt(PREF_SUBSCRIBED, any()) } returns 4 // TODO: use 5 when addresses are handled
|
||||
every { getInt(PREF_USER_PRIVATE, any()) } returns 1
|
||||
every { getInt(PREF_ROLE, any()) } returns 2
|
||||
every { getString(PREF_USER_ORG_PRIVATE_KEY, any()) } returns "orgKey"
|
||||
every { getString(PREF_USER_CURRENCY, any()) } returns "eur"
|
||||
every { getInt(PREF_USER_CREDIT, any()) } returns 10
|
||||
every { getInt(PREF_DELINQUENT, any()) } returns 3
|
||||
every { getInt(PREF_MAX_UPLOAD_FILE_SIZE, any()) } returns 12_345
|
||||
every { getLong(PREF_USED_SPACE, any()) } returns 15_000
|
||||
every { getLong(PREF_MAX_SPACE, any()) } returns 30_000
|
||||
|
||||
every { edit() } returns mockk(relaxed = true)
|
||||
}
|
||||
every { getSharedPreferences(any(), any()) } returns mockk(relaxed = true)
|
||||
}
|
||||
every { TextUtils.isEmpty(any()) } answers { firstArg<String?>().isNullOrEmpty() }
|
||||
every { SystemClock.elapsedRealtime() } returns 0
|
||||
|
||||
// GIVEN
|
||||
val oldUser = OldUser.load("username")
|
||||
|
||||
// WHEN
|
||||
val newUser = mapper { oldUser.toNewModel() }
|
||||
|
||||
// THEN
|
||||
assert that newUser * {
|
||||
+id.s equals "id"
|
||||
+name.s equals "username"
|
||||
+(plans * {
|
||||
+size() equals 1 // TODO use 2 when addresses are handled
|
||||
// it contains Plan.Mail.Free // TODO uncomment when addresses are handled
|
||||
it contains Plan.Vpn.Paid
|
||||
})
|
||||
+private equals true
|
||||
+role equals Role.ORGANIZATION_ADMIN
|
||||
+organizationPrivateKey?.s equals "orgKey"
|
||||
+currency.s equals "eur"
|
||||
+credits() equals 10
|
||||
+delinquent equals Delinquent.InvoiceDelinquent
|
||||
+totalUploadLimit.l equals 12_345uL
|
||||
+(dedicatedSpace * {
|
||||
+used.l() equals 15_000uL
|
||||
+total.l() equals 30_000uL
|
||||
})
|
||||
}
|
||||
|
||||
unmockkStatic(ProtonMailApplication::class, TextUtils::class, SystemClock::class)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,5 +29,6 @@ val repos: RepositoryHandler.() -> Unit get() = {
|
|||
jcenter()
|
||||
// Proton Core libraries
|
||||
maven("https://dl.bintray.com/proton/Core-publishing")
|
||||
// Assert4k
|
||||
maven("https://dl.bintray.com/4face/4face")
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ private fun <V : Validable> Validator<V>.wrap() = invoke()
|
|||
* [Validator] that accepts only strings that are not blank
|
||||
*/
|
||||
fun NotBlankStringValidator(field: String) = { _: Any ->
|
||||
require(field.isNotBlank())
|
||||
require(field.isNotBlank()) { "String is blank" }
|
||||
}.wrap()
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,6 +38,7 @@ package ch.protonmail.android.domain.entity
|
|||
* Represent a given number of bytes
|
||||
*/
|
||||
inline class Bytes(val l: ULong)
|
||||
val Number.bytes get() = Bytes(toLong().toULong())
|
||||
|
||||
/**
|
||||
* Entity representing an email address
|
||||
|
|
|
@ -71,15 +71,23 @@ data class User( // TODO: consider naming UserInfo or simialar
|
|||
val dedicatedSpace: UserSpace
|
||||
|
||||
) : Validable by Validator<User>({
|
||||
|
||||
// Addresses
|
||||
require(addresses.hasAddresses || plans.none { it is Plan.Mail }) { "Mail plan but no addresses" }
|
||||
|
||||
require(keys.hasKeys || !addresses.hasAddresses) { "Has addresses but not key" }
|
||||
// Keys
|
||||
require(keys.hasKeys || !addresses.hasAddresses) { "Has addresses but no keys" }
|
||||
|
||||
require(role == Role.ORGANIZATION_ADMIN && organizationPrivateKey != null ||
|
||||
role != Role.ORGANIZATION_ADMIN && organizationPrivateKey == null) {
|
||||
"Has organization but not organization key"
|
||||
// Organization
|
||||
val isAdmin = role == Role.ORGANIZATION_ADMIN
|
||||
require(!isAdmin || isAdmin && organizationPrivateKey != null) {
|
||||
"Is organization admin but doesn't have organization key"
|
||||
}
|
||||
require(isAdmin || !isAdmin && organizationPrivateKey == null) {
|
||||
"Is not organization admin, but has organization key"
|
||||
}
|
||||
|
||||
// Plans
|
||||
require(plans.count { it is Plan.Mail } <= 1 &&
|
||||
plans.count { it is Plan.Vpn } <= 1) {
|
||||
"Has 2 or more plans of the same type"
|
||||
|
@ -104,4 +112,4 @@ enum class Role(val i: Int) {
|
|||
}
|
||||
|
||||
// TODO can this entity be used on other spaces under a different name?
|
||||
data class UserSpace(val total: Bytes, val used: Bytes)
|
||||
data class UserSpace(val used: Bytes, val total: Bytes)
|
||||
|
|
|
@ -147,7 +147,7 @@ internal class UserTest {
|
|||
0,
|
||||
Delinquent.None,
|
||||
Bytes(5_000u),
|
||||
UserSpace(Bytes(5_000_000u), Bytes(25_000u))
|
||||
UserSpace(Bytes(25_000u), Bytes(5_000_000u))
|
||||
)
|
||||
|
||||
private val notEmptyAddresses = Addresses(
|
||||
|
|
Loading…
Reference in New Issue