From ee96a44fef5d24c3f3cc0ca100baea427ad09c75 Mon Sep 17 00:00:00 2001 From: Zack Date: Thu, 19 Dec 2024 15:19:24 +0800 Subject: [PATCH] feat: use new api to get the workspace member role (#6783) * chore: update to latest client api * chore: merge with main * chore: remove unneeded code * fix: sqlite migration * fix: cargo fmt * feat: use new api to get the member role --------- Co-authored-by: Lucas.Xu --- .../ai/local_ai_on_boarding_bloc.dart | 9 ++-- .../settings/ai/settings_ai_bloc.dart | 15 ++++--- .../settings/settings_dialog_bloc.dart | 15 ++++--- .../application/user/user_workspace_bloc.dart | 17 -------- .../menu/sidebar/footer/sidebar_toast.dart | 6 +-- .../menu/sidebar/space/space_more_popup.dart | 2 +- .../setting_ai_view/settings_ai_view.dart | 42 ++++++++++--------- .../pages/settings_workspace_view.dart | 32 ++++++++------ .../pages/sites/domain/domain_item.dart | 4 +- .../sites/domain/domain_more_action.dart | 2 +- .../settings/settings_dialog.dart | 15 +++---- .../settings/widgets/settings_menu.dart | 2 - frontend/rust-lib/flowy-ai-pub/Cargo.toml | 2 +- .../af_cloud/impls/user/cloud_service_impl.rs | 1 + .../src/local_server/impls/user.rs | 5 ++- .../2024-12-12-102351_workspace_role/down.sql | 1 + .../2024-12-12-102351_workspace_role/up.sql | 1 + frontend/rust-lib/flowy-sqlite/src/schema.rs | 1 + .../rust-lib/flowy-user-pub/src/entities.rs | 16 ++++++- .../rust-lib/flowy-user-pub/src/session.rs | 3 +- .../flowy-user/src/entities/user_profile.rs | 5 +++ .../flowy-user/src/entities/workspace.rs | 2 +- .../src/services/sqlite_sql/workspace_sql.rs | 3 ++ .../user_manager/manager_user_workspace.rs | 1 + 24 files changed, 114 insertions(+), 88 deletions(-) create mode 100644 frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/down.sql create mode 100644 frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/up.sql diff --git a/frontend/appflowy_flutter/lib/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart index 39a02b0964..2c1bf34a87 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart @@ -15,8 +15,11 @@ part 'local_ai_on_boarding_bloc.freezed.dart'; class LocalAIOnBoardingBloc extends Bloc { - LocalAIOnBoardingBloc(this.userProfile, this.member, this.workspaceId) - : super(const LocalAIOnBoardingState()) { + LocalAIOnBoardingBloc( + this.userProfile, + this.currentWorkspaceMemberRole, + this.workspaceId, + ) : super(const LocalAIOnBoardingState()) { _userService = UserBackendService(userId: userProfile.id); _successListenable = getIt(); _successListenable.addListener(_onPaymentSuccessful); @@ -36,7 +39,7 @@ class LocalAIOnBoardingBloc } final UserProfilePB userProfile; - final WorkspaceMemberPB member; + final AFRolePB? currentWorkspaceMemberRole; final String workspaceId; late final IUserBackendService _userService; late final SubscriptionSuccessListenable _successListenable; diff --git a/frontend/appflowy_flutter/lib/workspace/application/settings/ai/settings_ai_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/settings/ai/settings_ai_bloc.dart index af0b390ebd..91ac63944c 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/settings/ai/settings_ai_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/settings/ai/settings_ai_bloc.dart @@ -14,13 +14,18 @@ class SettingsAIBloc extends Bloc { SettingsAIBloc( this.userProfile, this.workspaceId, - WorkspaceMemberPB? member, + AFRolePB? currentWorkspaceMemberRole, ) : _userListener = UserListener(userProfile: userProfile), _userService = UserBackendService(userId: userProfile.id), - super(SettingsAIState(userProfile: userProfile, member: member)) { + super( + SettingsAIState( + userProfile: userProfile, + currentWorkspaceMemberRole: currentWorkspaceMemberRole, + ), + ) { _dispatch(); - if (member == null) { + if (currentWorkspaceMemberRole == null) { _userService.getWorkspaceMember().then((result) { result.fold( (member) { @@ -85,7 +90,7 @@ class SettingsAIBloc extends Bloc { ); }, refreshMember: (member) { - emit(state.copyWith(member: member)); + emit(state.copyWith(currentWorkspaceMemberRole: member.role)); }, ); }); @@ -152,7 +157,7 @@ class SettingsAIState with _$SettingsAIState { const factory SettingsAIState({ required UserProfilePB userProfile, UseAISettingPB? aiSettings, - WorkspaceMemberPB? member, + AFRolePB? currentWorkspaceMemberRole, @Default(true) bool enableSearchIndexing, }) = _SettingsAIState; } diff --git a/frontend/appflowy_flutter/lib/workspace/application/settings/settings_dialog_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/settings/settings_dialog_bloc.dart index 7edb1483d4..0578d9808b 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/settings/settings_dialog_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/settings/settings_dialog_bloc.dart @@ -33,7 +33,7 @@ class SettingsDialogBloc extends Bloc { SettingsDialogBloc( this.userProfile, - this.workspaceMember, { + this.currentWorkspaceMemberRole, { SettingsPage? initPage, }) : _userListener = UserListener(userProfile: userProfile), super(SettingsDialogState.initial(userProfile, initPage)) { @@ -41,7 +41,7 @@ class SettingsDialogBloc } final UserProfilePB userProfile; - final WorkspaceMemberPB? workspaceMember; + final AFRolePB? currentWorkspaceMemberRole; final UserListener _userListener; @override @@ -57,8 +57,10 @@ class SettingsDialogBloc initial: () async { _userListener.start(onProfileUpdated: _profileUpdated); - final isBillingEnabled = - await _isBillingEnabled(userProfile, workspaceMember); + final isBillingEnabled = await _isBillingEnabled( + userProfile, + currentWorkspaceMemberRole, + ); if (isBillingEnabled) { emit(state.copyWith(isBillingEnabled: true)); } @@ -86,7 +88,7 @@ class SettingsDialogBloc Future _isBillingEnabled( UserProfilePB userProfile, [ - WorkspaceMemberPB? member, + AFRolePB? currentWorkspaceMemberRole, ]) async { if ([ AuthenticatorPB.Local, @@ -94,7 +96,8 @@ class SettingsDialogBloc return false; } - if (member == null || member.role != AFRolePB.Owner) { + if (currentWorkspaceMemberRole == null || + currentWorkspaceMemberRole != AFRolePB.Owner) { return false; } diff --git a/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart index b48e87b8d1..7f32a86d1c 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart @@ -63,13 +63,6 @@ class UserWorkspaceBloc extends Bloc { actionResult: null, ), ); - - /// We wait with fetching the workspace member as it may take some time, - /// to avoid blocking the UI from rendering (the sidebar). - final workspaceMemberResult = - await _userService.getWorkspaceMember(); - final workspaceMember = workspaceMemberResult.toNullable(); - emit(state.copyWith(currentWorkspaceMember: workspaceMember)); }, fetchWorkspaces: () async { final result = await _fetchWorkspaces(); @@ -238,14 +231,6 @@ class UserWorkspaceBloc extends Bloc { ), ), ); - - /// We wait with fetching the workspace member as it may take some time, - /// to avoid blocking the UI from rendering (the sidebar). - final workspaceMemberResult = - await _userService.getWorkspaceMember(); - final workspaceMember = workspaceMemberResult.toNullable(); - - emit(state.copyWith(currentWorkspaceMember: workspaceMember)); }, renameWorkspace: (workspaceId, name) async { final result = @@ -515,7 +500,6 @@ class UserWorkspaceState with _$UserWorkspaceState { const factory UserWorkspaceState({ @Default(null) UserWorkspacePB? currentWorkspace, @Default([]) List workspaces, - @Default(null) WorkspaceMemberPB? currentWorkspaceMember, @Default(null) UserWorkspaceActionResult? actionResult, @Default(false) bool isCollabWorkspaceOn, }) = _UserWorkspaceState; @@ -533,7 +517,6 @@ class UserWorkspaceState with _$UserWorkspaceState { if (identical(this, other)) return true; return other is UserWorkspaceState && - other.currentWorkspaceMember == currentWorkspaceMember && other.currentWorkspace == currentWorkspace && _deepCollectionEquality.equals(other.workspaces, workspaces) && identical(other.actionResult, actionResult); diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/footer/sidebar_toast.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/footer/sidebar_toast.dart index 37c1e068d3..6d2b93be45 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/footer/sidebar_toast.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/footer/sidebar_toast.dart @@ -94,15 +94,15 @@ class SidebarToast extends StatelessWidget { } final userWorkspaceBloc = context.read(); - final member = userWorkspaceBloc.state.currentWorkspaceMember; - if (member == null) { + final role = userWorkspaceBloc.state.currentWorkspace?.role; + if (role == null) { return Log.error( "Member is null. It should not happen. If you see this error, it's a bug", ); } // Only if the user is the workspace owner will we navigate to the plan page. - if (member.role.isOwner) { + if (role.isOwner) { showSettingsDialog( context, userProfile, diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart index e4c3a97a66..4b13062c3e 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart @@ -150,7 +150,7 @@ class SpaceMoreActionTypeWrapper extends CustomActionCell { final isOwner = context .read() ?.state - .currentWorkspaceMember + .currentWorkspace ?.role .isOwner ?? false; diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/setting_ai_view/settings_ai_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/setting_ai_view/settings_ai_view.dart index 0c3965c731..a6181ba016 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/setting_ai_view/settings_ai_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/setting_ai_view/settings_ai_view.dart @@ -1,21 +1,20 @@ +import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/shared/af_role_pb_extension.dart'; import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart'; +import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart'; import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/local_ai_setting.dart'; import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/model_selection.dart'; -import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart'; -import 'package:flowy_infra/theme_extension.dart'; -import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart'; import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class AIFeatureOnlySupportedWhenUsingAppFlowyCloud extends StatelessWidget { @@ -39,19 +38,20 @@ class SettingsAIView extends StatelessWidget { const SettingsAIView({ super.key, required this.userProfile, - required this.member, + required this.currentWorkspaceMemberRole, required this.workspaceId, }); final UserProfilePB userProfile; - final WorkspaceMemberPB? member; + final AFRolePB? currentWorkspaceMemberRole; final String workspaceId; @override Widget build(BuildContext context) { return BlocProvider( - create: (_) => SettingsAIBloc(userProfile, workspaceId, member) - ..add(const SettingsAIEvent.started()), + create: (_) => + SettingsAIBloc(userProfile, workspaceId, currentWorkspaceMemberRole) + ..add(const SettingsAIEvent.started()), child: BlocBuilder( builder: (context, state) { final children = [ @@ -60,11 +60,11 @@ class SettingsAIView extends StatelessWidget { children.add(const _AISearchToggle(value: false)); - if (state.member != null) { + if (state.currentWorkspaceMemberRole != null) { children.add( _LocalAIOnBoarding( userProfile: userProfile, - member: state.member!, + currentWorkspaceMemberRole: state.currentWorkspaceMemberRole!, workspaceId: workspaceId, ), ); @@ -129,11 +129,11 @@ class _AISearchToggle extends StatelessWidget { class _LocalAIOnBoarding extends StatelessWidget { const _LocalAIOnBoarding({ required this.userProfile, - required this.member, + required this.currentWorkspaceMemberRole, required this.workspaceId, }); final UserProfilePB userProfile; - final WorkspaceMemberPB member; + final AFRolePB? currentWorkspaceMemberRole; final String workspaceId; @override @@ -142,16 +142,18 @@ class _LocalAIOnBoarding extends StatelessWidget { return BillingGateGuard( builder: (context) { return BlocProvider( - create: (context) => - LocalAIOnBoardingBloc(userProfile, member, workspaceId) - ..add(const LocalAIOnBoardingEvent.started()), + create: (context) => LocalAIOnBoardingBloc( + userProfile, + currentWorkspaceMemberRole, + workspaceId, + )..add(const LocalAIOnBoardingEvent.started()), child: BlocBuilder( builder: (context, state) { // Show the local AI settings if the user has purchased the AI Local plan if (kDebugMode || state.isPurchaseAILocal) { return const LocalAISetting(); } else { - if (member.role.isOwner) { + if (currentWorkspaceMemberRole?.isOwner ?? false) { // Show the upgrade to AI Local plan button if the user has not purchased the AI Local plan return _UpgradeToAILocalPlan( onTap: () { diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart index 159171e55e..94b8923db5 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart @@ -1,7 +1,5 @@ import 'dart:async'; -import 'package:flutter/material.dart'; - import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart'; @@ -45,6 +43,7 @@ import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -52,11 +51,11 @@ class SettingsWorkspaceView extends StatelessWidget { const SettingsWorkspaceView({ super.key, required this.userProfile, - this.workspaceMember, + this.currentWorkspaceMemberRole, }); final UserProfilePB userProfile; - final WorkspaceMemberPB? workspaceMember; + final AFRolePB? currentWorkspaceMemberRole; @override Widget build(BuildContext context) { @@ -93,7 +92,11 @@ class SettingsWorkspaceView extends StatelessWidget { SettingsCategory( title: LocaleKeys.settings_workspacePage_workspaceName_title .tr(), - children: [_WorkspaceNameSetting(member: workspaceMember)], + children: [ + _WorkspaceNameSetting( + currentWorkspaceMemberRole: currentWorkspaceMemberRole, + ), + ], ), const SettingsCategorySpacer(), SettingsCategory( @@ -104,7 +107,7 @@ class SettingsWorkspaceView extends StatelessWidget { .tr(), children: [ _WorkspaceIconSetting( - enableEdit: workspaceMember?.role.isOwner ?? false, + enableEdit: currentWorkspaceMemberRole?.isOwner ?? false, workspace: state.workspace, ), ], @@ -185,14 +188,14 @@ class SettingsWorkspaceView extends StatelessWidget { fontWeight: FontWeight.w600, onPressed: () => showConfirmDialog( context: context, - title: workspaceMember?.role.isOwner ?? false + title: currentWorkspaceMemberRole?.isOwner ?? false ? LocaleKeys .settings_workspacePage_deleteWorkspacePrompt_title .tr() : LocaleKeys .settings_workspacePage_leaveWorkspacePrompt_title .tr(), - description: workspaceMember?.role.isOwner ?? false + description: currentWorkspaceMemberRole?.isOwner ?? false ? LocaleKeys .settings_workspacePage_deleteWorkspacePrompt_content .tr() @@ -201,13 +204,13 @@ class SettingsWorkspaceView extends StatelessWidget { .tr(), style: ConfirmPopupStyle.cancelAndOk, onConfirm: () => context.read().add( - workspaceMember?.role.isOwner ?? false + currentWorkspaceMemberRole?.isOwner ?? false ? const WorkspaceSettingsEvent.deleteWorkspace() : const WorkspaceSettingsEvent.leaveWorkspace(), ), ), buttonType: SingleSettingsButtonType.danger, - buttonLabel: workspaceMember?.role.isOwner ?? false + buttonLabel: currentWorkspaceMemberRole?.isOwner ?? false ? LocaleKeys .settings_workspacePage_manageWorkspace_deleteWorkspace .tr() @@ -225,9 +228,11 @@ class SettingsWorkspaceView extends StatelessWidget { } class _WorkspaceNameSetting extends StatefulWidget { - const _WorkspaceNameSetting({this.member}); + const _WorkspaceNameSetting({ + this.currentWorkspaceMemberRole, + }); - final WorkspaceMemberPB? member; + final AFRolePB? currentWorkspaceMemberRole; @override State<_WorkspaceNameSetting> createState() => _WorkspaceNameSettingState(); @@ -255,7 +260,8 @@ class _WorkspaceNameSettingState extends State<_WorkspaceNameSetting> { } }, builder: (_, state) { - if (widget.member == null || !widget.member!.role.isOwner) { + if (widget.currentWorkspaceMemberRole == null || + !widget.currentWorkspaceMemberRole!.isOwner) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2.5), child: FlowyText.regular( diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_item.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_item.dart index f7a96db510..d075deabb0 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_item.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_item.dart @@ -109,7 +109,7 @@ class _HomePageButton extends StatelessWidget { final isOwner = context .watch() .state - .currentWorkspaceMember + .currentWorkspace ?.role .isOwner ?? false; @@ -227,7 +227,7 @@ class _FreePlanUpgradeButton extends StatelessWidget { final isOwner = context .watch() .state - .currentWorkspaceMember + .currentWorkspace ?.role .isOwner ?? false; diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_more_action.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_more_action.dart index 82215c9f42..9c506b22ff 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_more_action.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/sites/domain/domain_more_action.dart @@ -82,7 +82,7 @@ class _DomainMoreActionState extends State { final isOwner = context .watch() .state - .currentWorkspaceMember + .currentWorkspace ?.role .isOwner ?? false; diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart index d09704093b..24e1e52deb 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart @@ -57,7 +57,7 @@ class SettingsDialog extends StatelessWidget { return BlocProvider( create: (context) => SettingsDialogBloc( user, - context.read().state.currentWorkspaceMember, + context.read().state.currentWorkspace?.role, initPage: initPage, )..add(const SettingsDialogEvent.initial()), child: BlocBuilder( @@ -80,10 +80,6 @@ class SettingsDialog extends StatelessWidget { currentPage: context.read().state.page, isBillingEnabled: state.isBillingEnabled, - member: context - .read() - .state - .currentWorkspaceMember, ), ), Expanded( @@ -98,7 +94,8 @@ class SettingsDialog extends StatelessWidget { context .read() .state - .currentWorkspaceMember, + .currentWorkspace + ?.role, ), ), ], @@ -114,7 +111,7 @@ class SettingsDialog extends StatelessWidget { String workspaceId, SettingsPage page, UserProfilePB user, - WorkspaceMemberPB? member, + AFRolePB? currentWorkspaceMemberRole, ) { switch (page) { case SettingsPage.account: @@ -126,7 +123,7 @@ class SettingsDialog extends StatelessWidget { case SettingsPage.workspace: return SettingsWorkspaceView( userProfile: user, - workspaceMember: member, + currentWorkspaceMemberRole: currentWorkspaceMemberRole, ); case SettingsPage.manageData: return SettingsManageDataView(userProfile: user); @@ -140,7 +137,7 @@ class SettingsDialog extends StatelessWidget { if (user.authenticator == AuthenticatorPB.AppFlowyCloud) { return SettingsAIView( userProfile: user, - member: member, + currentWorkspaceMemberRole: currentWorkspaceMemberRole, workspaceId: workspaceId, ); } else { diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart index 58f60919a6..c9069b8be3 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart @@ -16,14 +16,12 @@ class SettingsMenu extends StatelessWidget { required this.currentPage, required this.userProfile, required this.isBillingEnabled, - this.member, }); final Function changeSelectedPage; final SettingsPage currentPage; final UserProfilePB userProfile; final bool isBillingEnabled; - final WorkspaceMemberPB? member; @override Widget build(BuildContext context) { diff --git a/frontend/rust-lib/flowy-ai-pub/Cargo.toml b/frontend/rust-lib/flowy-ai-pub/Cargo.toml index f7ebbdf1bb..3afd04d530 100644 --- a/frontend/rust-lib/flowy-ai-pub/Cargo.toml +++ b/frontend/rust-lib/flowy-ai-pub/Cargo.toml @@ -11,4 +11,4 @@ flowy-error = { workspace = true } client-api = { workspace = true } bytes.workspace = true futures.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs index f36777934d..4f7ce7a3e9 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs @@ -667,6 +667,7 @@ fn to_user_workspace(af_workspace: AFWorkspace) -> UserWorkspace { workspace_database_id: af_workspace.database_storage_id.to_string(), icon: af_workspace.icon, member_count: af_workspace.member_count.unwrap_or(0), + role: af_workspace.role.map(|r| r.into()), } } diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs index de940c7a02..c800cc7ced 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs @@ -34,7 +34,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { let params = params.unbox_or_error::()?; let uid = ID_GEN.lock().await.next_id(); let workspace_id = uuid::Uuid::new_v4().to_string(); - let user_workspace = UserWorkspace::new(&workspace_id, uid); + let user_workspace = UserWorkspace::new_local(&workspace_id, uid); let user_name = if params.name.is_empty() { DEFAULT_USER_NAME() } else { @@ -214,6 +214,7 @@ fn make_user_workspace() -> UserWorkspace { created_at: Default::default(), workspace_database_id: uuid::Uuid::new_v4().to_string(), icon: "".to_string(), - member_count: 0, + member_count: 1, + role: None, } } diff --git a/frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/down.sql b/frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/down.sql new file mode 100644 index 0000000000..da7c4c54cc --- /dev/null +++ b/frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/down.sql @@ -0,0 +1 @@ +ALTER TABLE user_workspace_table DROP COLUMN role; diff --git a/frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/up.sql b/frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/up.sql new file mode 100644 index 0000000000..38842fde4b --- /dev/null +++ b/frontend/rust-lib/flowy-sqlite/migrations/2024-12-12-102351_workspace_role/up.sql @@ -0,0 +1 @@ +ALTER TABLE user_workspace_table ADD COLUMN role INT; diff --git a/frontend/rust-lib/flowy-sqlite/src/schema.rs b/frontend/rust-lib/flowy-sqlite/src/schema.rs index fc885497dd..efd0089757 100644 --- a/frontend/rust-lib/flowy-sqlite/src/schema.rs +++ b/frontend/rust-lib/flowy-sqlite/src/schema.rs @@ -102,6 +102,7 @@ diesel::table! { database_storage_id -> Text, icon -> Text, member_count -> BigInt, + role -> Nullable, } } diff --git a/frontend/rust-lib/flowy-user-pub/src/entities.rs b/frontend/rust-lib/flowy-user-pub/src/entities.rs index aab167e9f6..8f31edf740 100644 --- a/frontend/rust-lib/flowy-user-pub/src/entities.rs +++ b/frontend/rust-lib/flowy-user-pub/src/entities.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use chrono::{DateTime, Utc}; pub use client_api::entity::billing_dto::RecurringInterval; +use client_api::entity::AFRole; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::*; @@ -145,10 +146,12 @@ pub struct UserWorkspace { pub icon: String, #[serde(default)] pub member_count: i64, + #[serde(default)] + pub role: Option, } impl UserWorkspace { - pub fn new(workspace_id: &str, _uid: i64) -> Self { + pub fn new_local(workspace_id: &str, _uid: i64) -> Self { Self { id: workspace_id.to_string(), name: "".to_string(), @@ -156,6 +159,7 @@ impl UserWorkspace { workspace_database_id: Uuid::new_v4().to_string(), icon: "".to_string(), member_count: 1, + role: None, } } } @@ -420,6 +424,16 @@ impl From for i32 { } } +impl From for Role { + fn from(value: AFRole) -> Self { + match value { + AFRole::Owner => Role::Owner, + AFRole::Member => Role::Member, + AFRole::Guest => Role::Guest, + } + } +} + pub struct WorkspaceMember { pub email: String, pub role: Role, diff --git a/frontend/rust-lib/flowy-user-pub/src/session.rs b/frontend/rust-lib/flowy-user-pub/src/session.rs index 94d4c6718a..4c2668477a 100644 --- a/frontend/rust-lib/flowy-user-pub/src/session.rs +++ b/frontend/rust-lib/flowy-user-pub/src/session.rs @@ -75,7 +75,8 @@ impl<'de> Visitor<'de> for SessionVisitor { // For historical reasons, the database_storage_id is constructed by the user_id. workspace_database_id: STANDARD.encode(format!("{}:user:database", user_id)), icon: "".to_owned(), - member_count: 0, + member_count: 1, + role: None, }) } } diff --git a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs index ba2e945044..facc9d8b41 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs @@ -11,6 +11,7 @@ use crate::entities::{AIModelPB, AuthenticatorPB}; use crate::errors::ErrorCode; use super::parser::UserStabilityAIKey; +use super::AFRolePB; #[derive(Default, ProtoBuf)] pub struct UserTokenPB { @@ -237,6 +238,9 @@ pub struct UserWorkspacePB { #[pb(index = 5)] pub member_count: i64, + + #[pb(index = 6, one_of)] + pub role: Option, } impl From for UserWorkspacePB { @@ -247,6 +251,7 @@ impl From for UserWorkspacePB { created_at_timestamp: value.created_at.timestamp(), icon: value.icon, member_count: value.member_count, + role: value.role.map(AFRolePB::from), } } } diff --git a/frontend/rust-lib/flowy-user/src/entities/workspace.rs b/frontend/rust-lib/flowy-user/src/entities/workspace.rs index 211f75ef4c..736979f11a 100644 --- a/frontend/rust-lib/flowy-user/src/entities/workspace.rs +++ b/frontend/rust-lib/flowy-user/src/entities/workspace.rs @@ -147,7 +147,7 @@ pub struct UpdateWorkspaceMemberPB { } // Workspace Role -#[derive(ProtoBuf_Enum, Clone, Default)] +#[derive(Debug, ProtoBuf_Enum, Clone, Default)] pub enum AFRolePB { Owner = 0, Member = 1, diff --git a/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs b/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs index 312b8beca1..f057f9eefb 100644 --- a/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs +++ b/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs @@ -17,6 +17,7 @@ pub struct UserWorkspaceTable { pub database_storage_id: String, pub icon: String, pub member_count: i64, + pub role: Option, } pub fn get_user_workspace_op(workspace_id: &str, mut conn: DBConnection) -> Option { @@ -94,6 +95,7 @@ impl TryFrom<(i64, &UserWorkspace)> for UserWorkspaceTable { database_storage_id: value.1.workspace_database_id.clone(), icon: value.1.icon.clone(), member_count: value.1.member_count, + role: value.1.role.clone().map(|v| v as i32), }) } } @@ -110,6 +112,7 @@ impl From for UserWorkspace { workspace_database_id: value.database_storage_id, icon: value.icon, member_count: value.member_count, + role: value.role.map(|v| v.into()), } } } diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs index 98a8cf5657..34a34bad55 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs @@ -730,6 +730,7 @@ pub fn save_all_user_workspaces( user_workspace_table::database_storage_id.eq(&user_workspace.database_storage_id), user_workspace_table::icon.eq(&user_workspace.icon), user_workspace_table::member_count.eq(&user_workspace.member_count), + user_workspace_table::role.eq(&user_workspace.role), )) .execute(conn)?;