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

[RKOTLIN-1115] Add support for switching user #1816

Merged
merged 2 commits into from
Aug 7, 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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* None.

### Enhancements
* None.
* [Sync] Add support for switching users with `App.switchUser(User)`. (Issue [#1813](https://github.com/realm/realm-kotlin/issues/1813)/[RKOTLIN-1115](https://jira.mongodb.org/browse/RKOTLIN-1115)).

### Fixed
* None.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ expect object RealmInterop {
fun realm_app_remove_user(app: RealmAppPointer, user: RealmUserPointer, callback: AppCallback<Unit>)
fun realm_app_delete_user(app: RealmAppPointer, user: RealmUserPointer, callback: AppCallback<Unit>)
fun realm_app_link_credentials(app: RealmAppPointer, user: RealmUserPointer, credentials: RealmCredentialsPointer, callback: AppCallback<RealmUserPointer>)
fun realm_app_switch_user(app: RealmAppPointer, user: RealmUserPointer)
fun realm_clear_cached_apps()
fun realm_app_sync_client_get_default_file_path_for_realm(
syncConfig: RealmSyncConfigurationPointer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,10 @@ actual object RealmInterop {
realmc.realm_app_link_user(app.cptr(), user.cptr(), credentials.cptr(), callback)
}

actual fun realm_app_switch_user(app: RealmAppPointer, user: RealmUserPointer) {
realmc.realm_app_switch_user(app.cptr(), user.cptr())
}

actual fun realm_app_get_current_user(app: RealmAppPointer): RealmUserPointer? {
val ptr = realmc.realm_app_get_current_user(app.cptr())
return nativePointerOrNull(ptr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2357,6 +2357,10 @@ actual object RealmInterop {
)
}

actual fun realm_app_switch_user(app: RealmAppPointer, user: RealmUserPointer) {
checkedBooleanResult(realm_wrapper.realm_app_switch_user(app.cptr(), user.cptr()))
}

actual fun realm_clear_cached_apps() {
realm_wrapper.realm_clear_cached_apps()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ public interface App {
*/
public suspend fun login(credentials: Credentials): User

/**
* Switch current user.
*
* @param user the user that should be the new current user. The user must be one of the users
* that are already logged in.
* @throws IllegalStateException If the [user] is not logged in.
*/
public fun switchUser(user: User)

/**
* Create a [Flow] of [AuthenticationChange]-events to receive notifications of updates to all
* app user authentication states: login, logout and removal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ public class AppImpl(
}
}

override fun switchUser(user: User) {
Validation.isType<UserImpl>(user)
RealmInterop.realm_app_switch_user(this.nativePointer, user.nativePointer)
}

internal fun reportAuthenticationChange(user: User, change: User.State) {
val event: AuthenticationChange = when (change) {
User.State.LOGGED_OUT -> LoggedOutImpl(user)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import kotlin.test.assertNotEquals
import kotlin.test.assertNull
import kotlin.test.assertSame
import kotlin.test.assertTrue
import kotlin.test.fail

class AppTests {

Expand Down Expand Up @@ -210,30 +211,30 @@ class AppTests {
assertTrue(app.allUsers().isEmpty())
}

// @Test
// fun switchUser() {
// val user1: User = app.login(Credentials.anonymous())
// assertEquals(user1, app.currentUser())
// val user2: User = app.login(Credentials.anonymous())
// assertEquals(user2, app.currentUser())
//
// assertEquals(user1, app.switchUser(user1))
// assertEquals(user1, app.currentUser())
// }
//
// @Test
// fun switchUser_throwIfUserNotLoggedIn() = runBlocking {
// val user1 = app.login(Credentials.anonymous())
// val user2 = app.login(Credentials.anonymous())
// assertEquals(user2, app.currentUser)
//
// user1.logOut()
// try {
// app.switchUser(user1)
// fail()
// } catch (ignore: IllegalArgumentException) {
// }
// }
@Test
fun switchUser() = runBlocking {
val user1: User = app.login(Credentials.anonymous())
assertEquals(user1, app.currentUser)
val user2: User = app.login(Credentials.anonymous())
assertEquals(user2, app.currentUser)

app.switchUser(user1)
assertEquals(user1, app.currentUser)
}

@Test
fun switchUser_throwIfUserNotLoggedIn() = runBlocking {
val user1 = app.login(Credentials.anonymous())
val user2 = app.login(Credentials.anonymous())
assertEquals(user2, app.currentUser)

user1.logOut()
try {
app.switchUser(user1)
fail()
} catch (ignore: IllegalStateException) {
}
}

@Test
fun currentUser_FallbackToNextValidUser() = runBlocking {
Expand Down Expand Up @@ -262,21 +263,6 @@ class AppTests {
assertNull(app.currentUser)
}

// @Test
// fun switchUser_nullThrows() {
// try {
// app.switchUser(TestHelper.getNull())
// fail()
// } catch (ignore: IllegalArgumentException) {
// }
// }
//
// @Ignore("Add this test once we have support for both EmailPassword and ApiKey Auth Providers")
// @Test
// fun switchUser_authProvidersLockUsers() {
// TODO("FIXME")
// }
//
@Test
fun authenticationChangeAsFlow() = runBlocking<Unit> {
val c = TestChannel<AuthenticationChange>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ class FunctionsTests {
runBlocking {
anonUser.logOut()
}
assertFailsWithMessage<ServiceException>("[Service][Unknown(4351)] unauthorized") {
assertFailsWithMessage<ServiceException>("unauthorized") {
runBlocking {
functions.call(FIRST_ARG_FUNCTION.name, 1, 2, 3)
}
Expand Down
Loading