chore: create workspace member

This commit is contained in:
Nathan 2025-04-21 21:07:38 +08:00
parent 4634b51edf
commit 9cd49c2447
13 changed files with 88 additions and 68 deletions

View file

@ -27,6 +27,7 @@ class ChatMemberBloc extends Bloc<ChatMemberEvent, ChatMemberState> {
final payload = WorkspaceMemberIdPB(
uid: Int64.parseInt(userId),
);
await UserEventGetMemberInfo(payload).send().then((result) {
result.fold(
(member) {

View file

@ -244,13 +244,6 @@ class UserBackendService implements IUserBackendService {
return UserEventGetWorkspaceSubscriptionInfo(params).send();
}
Future<FlowyResult<WorkspaceMemberPB, FlowyError>>
getWorkspaceMember() async {
final data = WorkspaceMemberIdPB.create()..uid = userId;
return UserEventGetMemberInfo(data).send();
}
@override
Future<FlowyResult<PaymentLinkPB, FlowyError>> createSubscription(
String workspaceId,

View file

@ -5,6 +5,7 @@ use collab_entity::CollabType;
use collab_folder::Folder;
use event_integration_test::user_event::use_localhost_af_cloud;
use event_integration_test::EventIntegrationTest;
use flowy_user::entities::AFRolePB;
use flowy_user_pub::entities::AuthType;
use std::time::Duration;
use tokio::task::LocalSet;
@ -327,4 +328,10 @@ async fn af_cloud_create_local_workspace_test() {
for view in views {
test.get_view(&view.id).await;
}
let members = test
.get_workspace_members(&created_workspace.workspace_id)
.await;
assert_eq!(members.len(), 1);
assert_eq!(members[0].role, AFRolePB::Owner);
}

View file

@ -2,12 +2,14 @@ use collab_folder::{View, ViewIcon, ViewLayout};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode;
use flowy_folder_pub::cloud::gen_view_id;
use lib_infra::validator_fn::required_not_empty_str;
use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;
use uuid::Uuid;
use validator::Validate;
use crate::entities::icon::ViewIconPB;
use crate::entities::parser::view::{ViewIdentify, ViewName, ViewThumbnail};
@ -394,9 +396,10 @@ impl TryInto<CreateViewParams> for CreateOrphanViewPayloadPB {
}
}
#[derive(Default, ProtoBuf, Clone, Debug)]
#[derive(Default, ProtoBuf, Validate, Clone, Debug)]
pub struct ViewIdPB {
#[pb(index = 1)]
#[validate(custom(function = "required_not_empty_str"))]
pub value: String,
}

View file

@ -111,7 +111,7 @@ pub(crate) async fn get_view_handler(
folder: AFPluginState<Weak<FolderManager>>,
) -> DataResult<ViewPB, FlowyError> {
let folder = upgrade_folder(folder)?;
let view_id: ViewIdPB = data.into_inner();
let view_id = data.try_into_inner()?;
let view_pb = folder.get_view_pb(&view_id.value).await?;
data_result_ok(view_pb)
}

View file

@ -9,7 +9,7 @@ use collab_integrate::CollabKVDB;
use flowy_error::{FlowyError, FlowyResult};
use std::sync::{Arc, Weak};
use tokio::task::spawn_blocking;
use tracing::{event, info, Level};
use tracing::{error, event, info, Level};
use uuid::Uuid;
impl FolderManager {
@ -139,9 +139,12 @@ impl FolderManager {
);
let weak_folder_indexer = Arc::downgrade(&self.folder_indexer);
let workspace_id = *workspace_id;
tokio::spawn(async move {
if let Some(folder_indexer) = weak_folder_indexer.upgrade() {
folder_indexer.initialize().await;
if let Err(err) = folder_indexer.initialize(&workspace_id).await {
error!("Failed to initialize folder indexer: {:?}", err);
}
}
});

View file

@ -38,7 +38,7 @@ pub trait IndexManager: Send + Sync {
#[async_trait]
pub trait FolderIndexManager: IndexManager {
async fn initialize(&self);
async fn initialize(&self, workspace_id: &Uuid) -> Result<(), FlowyError>;
fn index_all_views(&self, views: Vec<Arc<View>>, workspace_id: Uuid);

View file

@ -35,8 +35,6 @@ impl Drop for TantivyState {
}
}
const FOLDER_INDEX_DIR: &str = "folder_index";
#[derive(Clone)]
pub struct FolderIndexManagerImpl {
auth_user: Weak<AuthenticateUser>,
@ -64,7 +62,7 @@ impl FolderIndexManagerImpl {
}
/// Initializes the state using the workspace directory.
async fn initialize(&self) -> FlowyResult<()> {
async fn initialize(&self, workspace_id: &Uuid) -> FlowyResult<()> {
if let Some(state) = self.state.write().await.take() {
info!("Re-initializing folder indexer");
drop(state);
@ -82,7 +80,7 @@ impl FolderIndexManagerImpl {
.upgrade()
.ok_or_else(|| FlowyError::internal().with_context("AuthenticateUser is not available"))?;
let index_path = auth_user.get_index_path()?.join(FOLDER_INDEX_DIR);
let index_path = auth_user.get_index_path()?.join(workspace_id.to_string());
if !index_path.exists() {
fs::create_dir_all(&index_path).map_err(|e| {
error!("Failed to create folder index directory: {:?}", e);
@ -327,10 +325,9 @@ impl IndexManager for FolderIndexManagerImpl {
#[async_trait]
impl FolderIndexManager for FolderIndexManagerImpl {
async fn initialize(&self) {
if let Err(e) = self.initialize().await {
error!("Failed to initialize FolderIndexManager: {:?}", e);
}
async fn initialize(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
self.initialize(workspace_id).await?;
Ok(())
}
fn index_all_views(&self, views: Vec<Arc<View>>, workspace_id: Uuid) {

View file

@ -2,6 +2,7 @@
use crate::af_cloud::define::LoggedUser;
use crate::local_server::uid::UserIDGenerator;
use anyhow::Context;
use client_api::entity::GotrueTokenResponse;
use collab::core::origin::CollabOrigin;
use collab::preclude::Collab;
@ -13,10 +14,10 @@ use flowy_error::FlowyError;
use flowy_user_pub::cloud::{UserCloudService, UserCollabParams};
use flowy_user_pub::entities::*;
use flowy_user_pub::sql::{
select_all_user_workspace, select_user_profile, select_user_workspace, select_workspace_member,
select_workspace_setting, update_user_profile, update_workspace_setting, upsert_workspace_member,
upsert_workspace_setting, UserTableChangeset, WorkspaceMemberTable, WorkspaceSettingsChangeset,
WorkspaceSettingsTable,
insert_local_workspace, select_all_user_workspace, select_user_profile, select_user_workspace,
select_workspace_member, select_workspace_setting, update_user_profile, update_workspace_setting,
upsert_workspace_member, upsert_workspace_setting, UserTableChangeset, WorkspaceMemberTable,
WorkspaceSettingsChangeset, WorkspaceSettingsTable,
};
use flowy_user_pub::DEFAULT_USER_NAME;
use lazy_static::lazy_static;
@ -161,10 +162,11 @@ impl UserCloudService for LocalServerUserServiceImpl {
async fn create_workspace(&self, workspace_name: &str) -> Result<UserWorkspace, FlowyError> {
let workspace_id = Uuid::new_v4();
Ok(UserWorkspace::new_local(
workspace_id.to_string(),
workspace_name,
))
let uid = self.logged_user.user_id()?;
let mut conn = self.logged_user.get_sqlite_db(uid)?;
let user_workspace =
insert_local_workspace(uid, &workspace_id.to_string(), workspace_name, &mut conn)?;
Ok(user_workspace)
}
async fn patch_workspace(
@ -180,6 +182,15 @@ impl UserCloudService for LocalServerUserServiceImpl {
Ok(())
}
async fn get_workspace_members(
&self,
workspace_id: Uuid,
) -> Result<Vec<WorkspaceMember>, FlowyError> {
let uid = self.logged_user.user_id()?;
let member = self.get_workspace_member(&workspace_id, uid).await?;
Ok(vec![member])
}
async fn get_user_awareness_doc_state(
&self,
uid: i64,
@ -227,15 +238,16 @@ impl UserCloudService for LocalServerUserServiceImpl {
Err(err) => {
if err.is_record_not_found() {
let mut conn = self.logged_user.get_sqlite_db(uid)?;
let profile = select_user_profile(uid, &workspace_id.to_string(), &mut conn)?;
let profile = select_user_profile(uid, &workspace_id.to_string(), &mut conn)
.context("Can't find user profile when create workspace member")?;
let row = WorkspaceMemberTable {
email: profile.email.to_string(),
role: 0,
role: Role::Owner as i32,
name: profile.name.to_string(),
avatar_url: Some(profile.icon_url),
uid,
workspace_id: workspace_id.to_string(),
updated_at: Default::default(),
updated_at: chrono::Utc::now().naive_utc(),
};
let member = WorkspaceMember::from(row.clone());

View file

@ -231,9 +231,7 @@ pub trait UserCloudService: Send + Sync + 'static {
async fn get_workspace_members(
&self,
workspace_id: Uuid,
) -> Result<Vec<WorkspaceMember>, FlowyError> {
Ok(vec![])
}
) -> Result<Vec<WorkspaceMember>, FlowyError>;
async fn get_user_awareness_doc_state(
&self,

View file

@ -1,6 +1,8 @@
use crate::cloud::UserUpdate;
use crate::entities::{AuthType, UpdateUserProfileParams, UserProfile};
use crate::sql::select_user_workspace;
use crate::entities::{AuthType, Role, UpdateUserProfileParams, UserProfile, UserWorkspace};
use crate::sql::{
select_user_workspace, upsert_user_workspace, upsert_workspace_member, WorkspaceMemberTable,
};
use flowy_error::{FlowyError, FlowyResult};
use flowy_sqlite::schema::user_table;
use flowy_sqlite::{prelude::*, DBConnection, ExpressionMethods, RunQueryDsl};
@ -92,6 +94,33 @@ pub fn update_user_profile(
Ok(())
}
pub fn insert_local_workspace(
uid: i64,
workspace_id: &str,
workspace_name: &str,
conn: &mut SqliteConnection,
) -> FlowyResult<UserWorkspace> {
let user_workspace = UserWorkspace::new_local(workspace_id.to_string(), workspace_name);
conn.immediate_transaction(|conn| {
let row = select_user_table_row(uid, conn)?;
let row = WorkspaceMemberTable {
email: row.email,
role: Role::Owner as i32,
name: row.name,
avatar_url: Some(row.icon_url),
uid,
workspace_id: workspace_id.to_string(),
updated_at: chrono::Utc::now().naive_utc(),
};
upsert_user_workspace(uid, AuthType::Local, user_workspace.clone(), conn)?;
upsert_workspace_member(conn, row)?;
Ok::<_, FlowyError>(())
})?;
Ok(user_workspace)
}
fn select_user_table_row(uid: i64, conn: &mut SqliteConnection) -> Result<UserTable, FlowyError> {
let row = user_table::dsl::user_table
.filter(user_table::id.eq(&uid.to_string()))

View file

@ -147,7 +147,7 @@ pub struct UpdateWorkspaceMemberPB {
}
// Workspace Role
#[derive(Debug, ProtoBuf_Enum, Clone, Default)]
#[derive(Debug, ProtoBuf_Enum, Clone, Default, Eq, PartialEq)]
pub enum AFRolePB {
Owner = 0,
Member = 1,

View file

@ -7,7 +7,6 @@ use arc_swap::ArcSwapOption;
use collab::lock::RwLock;
use collab_user::core::UserAwareness;
use dashmap::DashMap;
use flowy_server_pub::AuthenticatorType;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_sqlite::schema::user_table;
use flowy_sqlite::ConnectionPool;
@ -131,30 +130,15 @@ impl UserManager {
let user = self
.get_user_profile_from_disk(session.user_id, &session.user_workspace.id)
.await?;
self.cloud_service.set_server_auth_type(&user.auth_type);
// Get the current authenticator from the environment variable
let env_auth_type = current_authenticator();
// If the current authenticator is different from the authenticator in the session and it's
// not a local authenticator, we need to sign out the user.
if user.auth_type != AuthType::Local && user.auth_type != env_auth_type {
event!(
tracing::Level::INFO,
"Auth type changed from {:?} to {:?}",
user.auth_type,
env_auth_type
);
self.sign_out().await?;
return Ok(());
}
let auth_type = user.workspace_auth_type;
self.cloud_service.set_server_auth_type(&auth_type);
event!(
tracing::Level::INFO,
"init user session: {}:{}, auth type: {:?}",
user.uid,
user.email,
user.auth_type,
auth_type,
);
self.prepare_user(&session).await;
@ -253,7 +237,7 @@ impl UserManager {
(Ok(collab_db), Ok(sqlite_pool)) => {
run_collab_data_migration(
&session,
&user.auth_type,
&auth_type,
collab_db,
sqlite_pool,
self.store_preferences.clone(),
@ -267,7 +251,7 @@ impl UserManager {
self.set_first_time_installed_version();
let cloud_config = get_cloud_config(session.user_id, &self.store_preferences);
// Init the user awareness. here we ignore the error
let _ = self.initial_user_awareness(&session, &user.auth_type).await;
let _ = self.initial_user_awareness(&session, &auth_type).await;
user_status_callback
.on_launch_if_authenticated(
@ -275,7 +259,7 @@ impl UserManager {
&cloud_config,
&session.user_workspace,
&self.authenticate_user.user_config.device_id,
&user.auth_type,
&auth_type,
)
.await?;
} else {
@ -357,7 +341,7 @@ impl UserManager {
self.save_auth_data(&response, auth_type, &session).await?;
let _ = self
.initial_user_awareness(&session, &user_profile.auth_type)
.initial_user_awareness(&session, &user_profile.workspace_auth_type)
.await;
self
.user_status_callback
@ -556,7 +540,7 @@ impl UserManager {
workspace_id: &str,
) -> FlowyResult<()> {
// If the user is a local user, no need to refresh the user profile
if old_user_profile.auth_type.is_local() {
if old_user_profile.workspace_auth_type.is_local() {
return Ok(());
}
@ -800,13 +784,6 @@ impl UserManager {
}
}
fn current_authenticator() -> AuthType {
match AuthenticatorType::from_env() {
AuthenticatorType::Local => AuthType::Local,
AuthenticatorType::AppFlowyCloud => AuthType::AppFlowyCloud,
}
}
pub fn upsert_user_profile_change(
uid: i64,
workspace_id: &str,