diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/AuthDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/AuthDI.kt index 097dd86ca0..4138e40932 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/AuthDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/AuthDI.kt @@ -229,12 +229,12 @@ object SetupNewAccountModule { @Provides @PerScreen fun provideCreateAccountUseCase( - repository: AuthRepository - ): CreateAccount { - return CreateAccount( - repository = repository - ) - } + repository: AuthRepository, + configStorage: ConfigStorage + ): CreateAccount = CreateAccount( + repository = repository, + configStorage = configStorage + ) } @Module diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt index eaeeacb365..d163812165 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt @@ -17,7 +17,9 @@ class AuthCacheDataStore(private val cache: AuthCache) : AuthDataStore { throw UnsupportedOperationException() } - override suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): AccountEntity { + + + override suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): AccountSetup { throw UnsupportedOperationException() } diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt index 71b4d21642..738ffd52ef 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt @@ -23,7 +23,11 @@ class AuthDataRepository( name: String, avatarPath: String?, invitationCode: String - ): Account = factory.remote.createAccount(name, avatarPath, invitationCode).toDomain() + ): AccountSetup = factory.remote.createAccount( + name = name, + avatarPath = avatarPath, + invitationCode = invitationCode + ) override suspend fun deleteAccount(): AccountStatus = factory.remote.deleteAccount() override suspend fun restoreAccount(): AccountStatus = factory.remote.restoreAccount() diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt index 0ef3a216d8..8a91fd84a8 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt @@ -12,7 +12,7 @@ interface AuthDataStore { suspend fun startAccount(id: String, path: String): AccountSetup - suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): AccountEntity + suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): AccountSetup suspend fun deleteAccount() : AccountStatus suspend fun restoreAccount() : AccountStatus diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt index 78c70f1c17..a521555ed3 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow interface AuthRemote { suspend fun startAccount(id: String, path: String): AccountSetup - suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): AccountEntity + suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): AccountSetup suspend fun deleteAccount() : AccountStatus suspend fun restoreAccount() : AccountStatus suspend fun recoverAccount() diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt index bd530e9e71..1b81d875b8 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt @@ -1,5 +1,6 @@ package com.anytypeio.anytype.data.auth.repo +import com.anytypeio.anytype.core_models.AccountSetup import com.anytypeio.anytype.core_models.AccountStatus import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.data.auth.model.AccountEntity @@ -17,7 +18,11 @@ class AuthRemoteDataStore( name: String, avatarPath: String?, invitationCode: String - ) = authRemote.createAccount(name, avatarPath, invitationCode) + ) : AccountSetup = authRemote.createAccount( + name = name, + avatarPath = avatarPath, + invitationCode = invitationCode + ) override suspend fun deleteAccount(): AccountStatus = authRemote.deleteAccount() diff --git a/data/src/test/java/com/anytypeio/anytype/data/AuthDataRepositoryTest.kt b/data/src/test/java/com/anytypeio/anytype/data/AuthDataRepositoryTest.kt index 64cf96ff0b..ab1c5c7352 100644 --- a/data/src/test/java/com/anytypeio/anytype/data/AuthDataRepositoryTest.kt +++ b/data/src/test/java/com/anytypeio/anytype/data/AuthDataRepositoryTest.kt @@ -1,23 +1,30 @@ package com.anytypeio.anytype.data -import com.anytypeio.anytype.core_models.Account -import com.anytypeio.anytype.core_models.AccountSetup -import com.anytypeio.anytype.core_models.AccountStatus -import com.anytypeio.anytype.core_models.FeaturesConfig import com.anytypeio.anytype.core_models.StubAccount import com.anytypeio.anytype.core_models.StubAccountSetup -import com.anytypeio.anytype.core_models.StubConfig import com.anytypeio.anytype.core_models.StubFeatureConfig import com.anytypeio.anytype.data.auth.model.AccountEntity import com.anytypeio.anytype.data.auth.model.WalletEntity -import com.anytypeio.anytype.data.auth.repo.* +import com.anytypeio.anytype.data.auth.repo.AuthCache +import com.anytypeio.anytype.data.auth.repo.AuthCacheDataStore +import com.anytypeio.anytype.data.auth.repo.AuthDataRepository +import com.anytypeio.anytype.data.auth.repo.AuthDataStoreFactory +import com.anytypeio.anytype.data.auth.repo.AuthRemote +import com.anytypeio.anytype.data.auth.repo.AuthRemoteDataStore import com.anytypeio.anytype.test_utils.MockDataFactory import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test import org.mockito.Mock import org.mockito.MockitoAnnotations -import org.mockito.kotlin.* +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.stub +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoMoreInteractions +import org.mockito.kotlin.verifyZeroInteractions class AuthDataRepositoryTest { @@ -29,8 +36,6 @@ class AuthDataRepositoryTest { lateinit var repo: AuthDataRepository - val config = StubConfig() - @Before fun setup() { MockitoAnnotations.openMocks(this) @@ -86,14 +91,16 @@ class AuthDataRepositoryTest { val name = MockDataFactory.randomString() - val account = AccountEntity( - id = name, - name = MockDataFactory.randomString(), - color = null - ) + val setup = StubAccountSetup() authRemote.stub { - onBlocking { createAccount(name = name, avatarPath = path, invitationCode = "code") } doReturn account + onBlocking { + createAccount( + name = name, + avatarPath = path, + invitationCode = "code" + ) + } doReturn setup } repo.createAccount( diff --git a/domain/build.gradle b/domain/build.gradle index 57a2e61ff5..cfd21dc1fb 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -18,4 +18,6 @@ dependencies { testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" testImplementation unitTestDependencies.coroutineTesting + + testImplementation project(":test:core-models-stub") } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt index efeb844d6e..f5afef6b48 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt @@ -4,30 +4,28 @@ import com.anytypeio.anytype.core_models.Account import com.anytypeio.anytype.domain.auth.repo.AuthRepository import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.base.Either +import com.anytypeio.anytype.domain.config.ConfigStorage /** * Creates an account, then stores it and sets as current user account. */ open class CreateAccount( - private val repository: AuthRepository -) : BaseUseCase() { + private val repository: AuthRepository, + private val configStorage: ConfigStorage, + ) : BaseUseCase() { - override suspend fun run(params: Params) = try { - repository.createAccount( + override suspend fun run(params: Params) = safe { + val setup = repository.createAccount( name = params.name, avatarPath = params.avatarPath, invitationCode = params.invitationCode - ).let { account -> - with(repository) { - saveAccount(account) - setCurrentAccount(account.id) - account - } - }.let { - Either.Right(it) + ) + with(repository) { + saveAccount(setup.account) + setCurrentAccount(setup.account.id) } - } catch (e: Throwable) { - Either.Left(e) + configStorage.set(setup.config) + setup.account } /** diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt index 6607dc870c..85f1101a9e 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt @@ -17,7 +17,11 @@ interface AuthRepository { */ suspend fun startAccount(id: String, path: String): AccountSetup - suspend fun createAccount(name: String, avatarPath: String?, invitationCode: String): Account + suspend fun createAccount( + name: String, + avatarPath: String?, + invitationCode: String + ): AccountSetup suspend fun deleteAccount() : AccountStatus suspend fun restoreAccount() : AccountStatus diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt index fe178980c1..2c1c27b7b4 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt @@ -2,8 +2,10 @@ package com.anytypeio.anytype.domain.auth import com.anytypeio.anytype.core_models.Account import com.anytypeio.anytype.core_models.CoroutineTestRule +import com.anytypeio.anytype.core_models.StubAccountSetup import com.anytypeio.anytype.domain.auth.interactor.CreateAccount import com.anytypeio.anytype.domain.auth.repo.AuthRepository +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.test_utils.MockDataFactory import com.nhaarman.mockitokotlin2.doReturn import com.nhaarman.mockitokotlin2.stub @@ -27,45 +29,48 @@ class CreateAccountTest { @Mock lateinit var repo: AuthRepository + @Mock + lateinit var configStorage: ConfigStorage + lateinit var createAccount: CreateAccount @Before fun setup() { MockitoAnnotations.initMocks(this) - createAccount = CreateAccount(repository = repo) + createAccount = CreateAccount( + repository = repo, + configStorage = configStorage + ) } @Test - fun `should create account and save it and set as current user account`() = runBlocking { + fun `should create account and save it and set as current user account and save config in storage`() = + runBlocking { - val name = MockDataFactory.randomString() + val name = MockDataFactory.randomString() - val path = null + val path = null - val code = "code" + val code = "code" - val account = Account( - id = MockDataFactory.randomUuid(), - name = MockDataFactory.randomString(), - avatar = null, - color = null - ) + val setup = StubAccountSetup() - val param = CreateAccount.Params( - name = name, - avatarPath = path, - invitationCode = code - ) + val param = CreateAccount.Params( + name = name, + avatarPath = path, + invitationCode = code + ) - repo.stub { - onBlocking { createAccount(name, path, code) } doReturn account + repo.stub { + onBlocking { createAccount(name, path, code) } doReturn setup + } + + createAccount.run(param) + + verify(repo, times(1)).createAccount(name, path, code) + verify(repo, times(1)).saveAccount(setup.account) + verify(repo, times(1)).setCurrentAccount(setup.account.id) + verifyNoMoreInteractions(repo) + verify(configStorage, times(1)).set(setup.config) } - - createAccount.run(param) - - verify(repo, times(1)).createAccount(name, path, code) - verify(repo, times(1)).saveAccount(account) - verify(repo, times(1)).setCurrentAccount(account.id) - verifyNoMoreInteractions(repo) - } } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMappers.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMappers.kt index 631755532c..8c1fd8da55 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMappers.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMappers.kt @@ -7,7 +7,39 @@ import com.anytypeio.anytype.core_models.Config import com.anytypeio.anytype.core_models.FeaturesConfig import com.anytypeio.anytype.middleware.mappers.core -fun Rpc.Account.Select.Response.core(): AccountSetup { +fun Rpc.Account.Create.Response.toAccountSetup() : AccountSetup { + val acc = account + checkNotNull(acc) { "Account can't be empty" } + val configuration = acc.config + checkNotNull(configuration) { "Config can't be empty" } + val info = acc.info + checkNotNull(info) { "Info can't be empty" } + val status = acc.status + checkNotNull(status) { "Status can't be empty" } + + return AccountSetup( + account = Account( + id = acc.id, + name = acc.name, + color = acc.avatar?.color, + avatar = null + ), + features = FeaturesConfig( + enableDataView = configuration.enableDataview, + enableDebug = configuration.enableDebug, + enableChannelSwitch = configuration.enableReleaseChannelSwitch, + enableSpaces = configuration.enableSpaces + ), + config = Config( + home = info.homeObjectId, + profile = info.profileObjectId, + gateway = info.gatewayUrl + ), + status = status.core() + ) +} + +fun Rpc.Account.Select.Response.toAccountSetup(): AccountSetup { val acc = account checkNotNull(acc) { "Account can't be empty" } val configuration = acc.config diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt index f755e8e275..52adb5f70c 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt @@ -29,15 +29,11 @@ class AuthMiddleware( name: String, avatarPath: String?, invitationCode: String - ) = withContext(Dispatchers.IO) { - middleware.accountCreate(name, avatarPath, invitationCode).let { response -> - AccountEntity( - id = response.id, - name = response.name, - color = response.avatar?.color - ) - } - } + ) : AccountSetup = middleware.accountCreate( + name = name, + path = avatarPath, + invitationCode = invitationCode + ) override suspend fun deleteAccount(): AccountStatus = middleware.accountDelete() override suspend fun restoreAccount(): AccountStatus = middleware.accountRestore() diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index 1aea2a2114..0e2b232813 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -25,7 +25,7 @@ import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.Response import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.middleware.BuildConfig -import com.anytypeio.anytype.middleware.auth.core +import com.anytypeio.anytype.middleware.auth.toAccountSetup import com.anytypeio.anytype.middleware.const.Constants import com.anytypeio.anytype.middleware.mappers.MObjectType import com.anytypeio.anytype.middleware.mappers.MRelation @@ -49,29 +49,16 @@ class Middleware( name: String, path: String?, invitationCode: String - ): CreateAccountResponse { - + ): AccountSetup { val request = Rpc.Account.Create.Request( name = name, alphaInviteCode = invitationCode, avatarLocalPath = path ) - if (BuildConfig.DEBUG) logRequest(request) - val response = service.accountCreate(request) - if (BuildConfig.DEBUG) logResponse(response) - - val acc = response.account - - checkNotNull(acc) - - return CreateAccountResponse( - acc.id, - acc.name, - acc.avatar - ) + return response.toAccountSetup() } @Throws(Exception::class) @@ -117,7 +104,7 @@ class Middleware( if (BuildConfig.DEBUG) logRequest(request) val response = service.accountSelect(request) if (BuildConfig.DEBUG) logResponse(response) - return response.core() + return response.toAccountSetup() } @Throws(Exception::class)