Skip to content

Commit bb868f7

Browse files
author
Leandro Ferreira
committed
Showing users of workspace
1 parent 46084cd commit bb868f7

File tree

11 files changed

+219
-74
lines changed

11 files changed

+219
-74
lines changed

application/common_flows/wide_screen_common/src/commonMain/kotlin/io/writeopia/notes/desktop/components/App.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ fun DesktopApp(
222222
userOnlineState = globalShellViewModel.userState,
223223
showDeleteConfirmation = globalShellViewModel.showDeleteConfirmation,
224224
syncWorkspaceState = globalShellViewModel.lastWorkspaceSync,
225+
workspaceToEdit = globalShellViewModel.workspaceToEdit,
225226
onDismissRequest = globalShellViewModel::hideSettings,
226227
selectColorTheme = selectColorTheme,
227228
workspaces = globalShellViewModel.availableWorkspaces,
@@ -246,7 +247,8 @@ fun DesktopApp(
246247
)
247248
},
248249
syncWorkspace = globalShellViewModel::syncWorkspace,
249-
addUserToTeam = globalShellViewModel::addUserToTeam
250+
addUserToTeam = globalShellViewModel::addUserToTeam,
251+
selectWorkspaceToManage = globalShellViewModel::selectWorkspaceToManage,
250252
)
251253
}
252254

application/core/auth_core/src/commonMain/kotlin/io/writeopia/auth/core/data/AuthApi.kt

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,4 @@ class AuthApi(private val client: HttpClient, private val baseUrl: String) {
8787
ResultData.Error(e)
8888
}
8989
}
90-
91-
suspend fun getAvailableWorkspaces(token: String): ResultData<List<Workspace>> {
92-
return try {
93-
val response = client.get("$baseUrl/api/workspace/user") {
94-
header(HttpHeaders.Authorization, "Bearer $token")
95-
}.body<List<WorkspaceApi>>()
96-
97-
ResultData.Complete(response.map { workspaceApi -> workspaceApi.toModel() })
98-
} catch (e: Exception) {
99-
ResultData.Error(e)
100-
}
101-
}
10290
}

application/core/documents/src/commonMain/kotlin/io/writeopia/core/folders/api/WorkspaceApi.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.writeopia.core.folders.api
22

33
import io.ktor.client.HttpClient
4+
import io.ktor.client.call.body
5+
import io.ktor.client.request.get
46
import io.ktor.client.request.header
57
import io.ktor.client.request.post
68
import io.ktor.client.request.setBody
@@ -11,6 +13,9 @@ import io.ktor.http.isSuccess
1113
import io.writeopia.app.requests.AddUserToWorkspaceRequest
1214
import io.writeopia.sdk.models.utils.ResultData
1315
import io.writeopia.sdk.models.workspace.Role
16+
import io.writeopia.sdk.models.workspace.Workspace
17+
import io.writeopia.sdk.serialization.data.WorkspaceApi
18+
import io.writeopia.sdk.serialization.data.toModel
1419

1520
class WorkspaceApi(private val client: HttpClient, private val baseUrl: String) {
1621

@@ -32,4 +37,32 @@ class WorkspaceApi(private val client: HttpClient, private val baseUrl: String)
3237
ResultData.Error()
3338
}
3439
}
40+
41+
suspend fun getAvailableWorkspaces(token: String): ResultData<List<Workspace>> {
42+
return try {
43+
val response = client.get("$baseUrl/api/workspace/user") {
44+
header(HttpHeaders.Authorization, "Bearer $token")
45+
}.body<List<WorkspaceApi>>()
46+
47+
ResultData.Complete(response.map { workspaceApi -> workspaceApi.toModel() })
48+
} catch (e: Exception) {
49+
ResultData.Error(e)
50+
}
51+
}
52+
53+
suspend fun usersOfWorkspace(
54+
workspaceId: String,
55+
token: String
56+
): ResultData<List<String>> {
57+
return try {
58+
val response = client.get("$baseUrl/api/user/workspace/${workspaceId}") {
59+
header(HttpHeaders.Authorization, "Bearer $token")
60+
}
61+
62+
ResultData.Complete(response.body())
63+
} catch (e: Exception) {
64+
ResultData.Error(e)
65+
}
66+
}
67+
3568
}

application/features/account/src/commonMain/kotlin/io/writeopia/account/ui/SettingsDialog.kt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ fun SettingsDialog(
8888
showDeleteConfirmation: StateFlow<Boolean>,
8989
syncWorkspaceState: StateFlow<String>,
9090
workspaces: StateFlow<ResultData<List<Workspace>>>,
91+
workspaceToEdit: StateFlow<Workspace?>,
9192
onDismissRequest: () -> Unit,
9293
selectColorTheme: (ColorThemeOption) -> Unit,
9394
selectWorkplacePath: (String) -> Unit,
@@ -103,7 +104,8 @@ fun SettingsDialog(
103104
dismissDeleteConfirm: () -> Unit,
104105
deleteAccount: () -> Unit,
105106
syncWorkspace: () -> Unit,
106-
addUserToTeam: (String, String) -> Unit
107+
addUserToTeam: (String) -> Unit,
108+
selectWorkspaceToManage: (String) -> Unit,
107109
) {
108110
val ollamaUrl by ollamaUrlState.collectAsState()
109111

@@ -162,7 +164,7 @@ fun SettingsDialog(
162164
)
163165
},
164166
teamsScreen = {
165-
TeamsSection(workspaces, addUserToTeam)
167+
TeamsSection(workspaces, workspaceToEdit, selectWorkspaceToManage, addUserToTeam)
166168
}
167169
)
168170
}
@@ -816,7 +818,9 @@ fun DownloadModels(
816818
@Composable
817819
private fun TeamsSection(
818820
workspacesState: StateFlow<ResultData<List<Workspace>>>,
819-
addUserToTeam: (String, String) -> Unit
821+
selectedWorkspaceState: StateFlow<Workspace?>,
822+
selectWorkspace: (String) -> Unit,
823+
addUserToTeam: (String) -> Unit
820824
) {
821825
Column {
822826
val titleStyle = MaterialTheme.typography.titleLarge
@@ -831,21 +835,19 @@ private fun TeamsSection(
831835
when (workspaces) {
832836
is ResultData.Complete -> {
833837
val workspaces = (workspaces as ResultData.Complete<List<Workspace>>).data
834-
var selectedWorkspace = remember {
835-
mutableStateOf<Workspace?>(null)
836-
}
838+
837839

838840
LazyRow(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
839841
items(workspaces) { workspace ->
840842
CommonButton(text = workspace.name) {
841-
selectedWorkspace.value = workspace
843+
selectWorkspace(workspace.id)
842844
}
843845
}
844846
}
845847

846848
Spacer(modifier = Modifier.height(12.dp))
847849

848-
val selected = selectedWorkspace.value
850+
val selected = selectedWorkspaceState.collectAsState().value
849851

850852
if (selected != null) {
851853
BasicText(
@@ -886,7 +888,7 @@ private fun TeamsSection(
886888
Spacer(modifier = Modifier.width(8.dp))
887889

888890
CommonButton(text = "Add") {
889-
addUserToTeam(selected.id, userEmail)
891+
addUserToTeam(userEmail)
890892
}
891893
}
892894
}

application/features/global_shell/src/commonMain/kotlin/io/writeopia/global/shell/viewmodel/GlobalShellKmpViewModel.kt

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,28 @@ class GlobalShellKmpViewModel(
271271
MutableStateFlow(ResultData.Idle())
272272
override val availableWorkspaces: StateFlow<ResultData<List<Workspace>>> = _availableWorkspaces
273273

274+
private val _workspaceToEdit = MutableStateFlow<String?>(null)
275+
override val workspaceToEdit: StateFlow<Workspace?> =
276+
combine(_availableWorkspaces, _workspaceToEdit) { workspacesResult, selectedId ->
277+
if (workspacesResult is ResultData.Complete) {
278+
workspacesResult.data.firstOrNull { it.id == selectedId }
279+
} else {
280+
null
281+
}
282+
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
283+
284+
override val usersOfWorkspaceToEdit: StateFlow<ResultData<List<String>>> =
285+
workspaceToEdit.map { workspace ->
286+
val token = authRepository.getAuthToken()
287+
val workspaceId = workspace?.id
288+
289+
if (token != null && workspaceId != null) {
290+
workspaceApi.usersOfWorkspace(workspaceId, token)
291+
} else {
292+
ResultData.Error()
293+
}
294+
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), ResultData.Idle())
295+
274296
init {
275297
folderStateController.initCoroutine(viewModelScope)
276298

@@ -302,7 +324,7 @@ class GlobalShellKmpViewModel(
302324

303325
viewModelScope.launch {
304326
val result = authRepository.getAuthToken()?.let { token ->
305-
authApi.getAvailableWorkspaces(token)
327+
workspaceApi.getAvailableWorkspaces(token)
306328
}
307329

308330
if (result != null) {
@@ -529,12 +551,26 @@ class GlobalShellKmpViewModel(
529551
}
530552
}
531553

532-
override fun addUserToTeam(workspaceId: String, userEmail: String) {
554+
override fun addUserToTeam(userEmail: String) {
533555
viewModelScope.launch {
556+
val workspace = workspaceToEdit.value
557+
558+
if (workspace != null) {
559+
authRepository.getAuthToken()?.let { token ->
560+
val result = workspaceApi.addUserToWorkspace(workspace.id, userEmail, token)
534561

562+
if (result is ResultData.Complete) {
563+
//Todo: Renew the users of selected workspace
564+
}
565+
}
566+
}
535567
}
536568
}
537569

570+
override fun selectWorkspaceToManage(workspaceId: String) {
571+
_workspaceToEdit.value = workspaceId
572+
}
573+
538574
private suspend fun getUserId(): String =
539575
localUserId ?: authRepository.getUser().id.also { id ->
540576
localUserId = id

application/features/global_shell/src/commonMain/kotlin/io/writeopia/global/shell/viewmodel/GlobalShellViewModel.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ interface GlobalShellViewModel : FolderController, OllamaConfigController {
3838

3939
val availableWorkspaces: StateFlow<ResultData<List<Workspace>>>
4040

41+
val workspaceToEdit: StateFlow<Workspace?>
42+
43+
val usersOfWorkspaceToEdit: StateFlow<ResultData<List<String>>>
44+
4145
override val ollamaSelectedModelState: StateFlow<String>
4246

4347
override val ollamaUrl: StateFlow<String>
@@ -76,7 +80,9 @@ interface GlobalShellViewModel : FolderController, OllamaConfigController {
7680

7781
fun deleteAccount(sideEffect: () -> Unit)
7882

79-
fun addUserToTeam(workspaceId: String, userEmail: String)
83+
fun addUserToTeam(userEmail: String)
84+
85+
fun selectWorkspaceToManage(workspaceId: String)
8086

8187
override fun changeOllamaUrl(url: String)
8288

backend/core/auth/src/main/java/io/writeopia/api/core/auth/repository/WorkspaceRepository.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ internal fun WriteopiaDbBackend.isUserInWorkspace(userId: String, workspaceId: S
7777
.executeAsList()
7878
.any { entity -> entity.workspace_id == workspaceId }
7979

80+
81+
internal fun WriteopiaDbBackend.isUserAdminInWorkspace(userId: String, workspaceId: String): Boolean =
82+
this.workspaceEntityQueries
83+
.getWorkspacesByUserIdIfAdmin(userId)
84+
.executeAsList()
85+
.any { entity -> entity.workspace_id == workspaceId }
86+
87+
internal fun WriteopiaDbBackend.getUsersInWorkspace(workspaceId: String): List<String> =
88+
this.workspaceToUserQueries
89+
.getUsersInWorkspace(workspaceId)
90+
.executeAsList()
91+
8092
internal suspend fun WriteopiaDbBackend.removeUserFromWorkspace(workspaceId: String, userId: String) {
8193
this.workspaceToUserQueries.removeUserFromWorkspace(workspaceId, userId)
8294
}

0 commit comments

Comments
 (0)