mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-25 07:07:32 -04:00
324 lines
10 KiB
Rust
324 lines
10 KiB
Rust
#![allow(unused_variables)]
|
|
|
|
use crate::af_cloud::define::LoggedUser;
|
|
use crate::local_server::uid::UserIDGenerator;
|
|
use client_api::entity::GotrueTokenResponse;
|
|
use collab::core::origin::CollabOrigin;
|
|
use collab::preclude::Collab;
|
|
use collab_entity::CollabObject;
|
|
use collab_user::core::UserAwareness;
|
|
use flowy_ai_pub::cloud::billing_dto::WorkspaceUsageAndLimit;
|
|
use flowy_ai_pub::cloud::{AFWorkspaceSettings, AFWorkspaceSettingsChange};
|
|
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,
|
|
};
|
|
use flowy_user_pub::DEFAULT_USER_NAME;
|
|
use lazy_static::lazy_static;
|
|
use lib_infra::async_trait::async_trait;
|
|
use lib_infra::box_any::BoxAny;
|
|
use lib_infra::util::timestamp;
|
|
use std::sync::Arc;
|
|
use tokio::sync::Mutex;
|
|
use uuid::Uuid;
|
|
|
|
lazy_static! {
|
|
static ref ID_GEN: Mutex<UserIDGenerator> = Mutex::new(UserIDGenerator::new(1));
|
|
}
|
|
|
|
pub(crate) struct LocalServerUserServiceImpl {
|
|
pub logged_user: Arc<dyn LoggedUser>,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl UserCloudService for LocalServerUserServiceImpl {
|
|
async fn sign_up(&self, params: BoxAny) -> Result<AuthResponse, FlowyError> {
|
|
let params = params.unbox_or_error::<SignUpParams>()?;
|
|
let uid = ID_GEN.lock().await.next_id();
|
|
let workspace_id = Uuid::new_v4().to_string();
|
|
let user_workspace = UserWorkspace::new_local(workspace_id, "");
|
|
let user_name = if params.name.is_empty() {
|
|
DEFAULT_USER_NAME()
|
|
} else {
|
|
params.name.clone()
|
|
};
|
|
Ok(AuthResponse {
|
|
user_id: uid,
|
|
user_uuid: Uuid::new_v4(),
|
|
name: user_name,
|
|
latest_workspace: user_workspace.clone(),
|
|
user_workspaces: vec![user_workspace],
|
|
is_new_user: true,
|
|
// Anon user doesn't have email
|
|
email: None,
|
|
token: None,
|
|
encryption_type: EncryptionType::NoEncryption,
|
|
updated_at: timestamp(),
|
|
metadata: None,
|
|
})
|
|
}
|
|
|
|
async fn sign_in(&self, params: BoxAny) -> Result<AuthResponse, FlowyError> {
|
|
let params: SignInParams = params.unbox_or_error::<SignInParams>()?;
|
|
let uid = ID_GEN.lock().await.next_id();
|
|
|
|
let workspace_id = Uuid::new_v4();
|
|
let user_workspace = UserWorkspace::new_local(workspace_id.to_string(), "My Workspace");
|
|
Ok(AuthResponse {
|
|
user_id: uid,
|
|
user_uuid: Uuid::new_v4(),
|
|
name: params.name,
|
|
latest_workspace: user_workspace.clone(),
|
|
user_workspaces: vec![user_workspace],
|
|
is_new_user: false,
|
|
email: Some(params.email),
|
|
token: None,
|
|
encryption_type: EncryptionType::NoEncryption,
|
|
updated_at: timestamp(),
|
|
metadata: None,
|
|
})
|
|
}
|
|
|
|
async fn sign_out(&self, _token: Option<String>) -> Result<(), FlowyError> {
|
|
Ok(())
|
|
}
|
|
|
|
async fn generate_sign_in_url_with_email(&self, _email: &str) -> Result<String, FlowyError> {
|
|
Err(
|
|
FlowyError::local_version_not_support()
|
|
.with_context("Not support generate sign in url with email"),
|
|
)
|
|
}
|
|
|
|
async fn create_user(&self, _email: &str, _password: &str) -> Result<(), FlowyError> {
|
|
Err(FlowyError::local_version_not_support().with_context("Not support create user"))
|
|
}
|
|
|
|
async fn sign_in_with_password(
|
|
&self,
|
|
_email: &str,
|
|
_password: &str,
|
|
) -> Result<GotrueTokenResponse, FlowyError> {
|
|
Err(FlowyError::local_version_not_support().with_context("Not support"))
|
|
}
|
|
|
|
async fn sign_in_with_magic_link(
|
|
&self,
|
|
_email: &str,
|
|
_redirect_to: &str,
|
|
) -> Result<(), FlowyError> {
|
|
Err(FlowyError::local_version_not_support().with_context("Not support"))
|
|
}
|
|
|
|
async fn sign_in_with_passcode(
|
|
&self,
|
|
_email: &str,
|
|
_passcode: &str,
|
|
) -> Result<GotrueTokenResponse, FlowyError> {
|
|
Err(FlowyError::local_version_not_support().with_context("Not support"))
|
|
}
|
|
|
|
async fn generate_oauth_url_with_provider(&self, _provider: &str) -> Result<String, FlowyError> {
|
|
Err(FlowyError::internal().with_context("Can't oauth url when using offline mode"))
|
|
}
|
|
|
|
async fn update_user(&self, params: UpdateUserProfileParams) -> Result<(), FlowyError> {
|
|
let uid = self.logged_user.user_id()?;
|
|
let mut conn = self.logged_user.get_sqlite_db(uid)?;
|
|
let changeset = UserTableChangeset::new(params);
|
|
update_user_profile(&mut conn, changeset)?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError> {
|
|
let mut conn = self.logged_user.get_sqlite_db(uid)?;
|
|
let profile = select_user_profile(uid, &mut conn)?;
|
|
Ok(profile)
|
|
}
|
|
|
|
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<UserWorkspace, FlowyError> {
|
|
let uid = self.logged_user.user_id()?;
|
|
let mut conn = self.logged_user.get_sqlite_db(uid)?;
|
|
|
|
let workspace = select_user_workspace(&workspace_id.to_string(), &mut conn)?;
|
|
Ok(UserWorkspace::from(workspace))
|
|
}
|
|
|
|
async fn get_all_workspace(&self, uid: i64) -> Result<Vec<UserWorkspace>, FlowyError> {
|
|
let conn = self.logged_user.get_sqlite_db(uid)?;
|
|
let workspaces = select_all_user_workspace(uid, conn)?;
|
|
Ok(workspaces)
|
|
}
|
|
|
|
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,
|
|
))
|
|
}
|
|
|
|
async fn patch_workspace(
|
|
&self,
|
|
workspace_id: &Uuid,
|
|
new_workspace_name: Option<String>,
|
|
new_workspace_icon: Option<String>,
|
|
) -> Result<(), FlowyError> {
|
|
Ok(())
|
|
}
|
|
|
|
async fn delete_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
|
Ok(())
|
|
}
|
|
|
|
async fn get_user_awareness_doc_state(
|
|
&self,
|
|
uid: i64,
|
|
workspace_id: &Uuid,
|
|
object_id: &Uuid,
|
|
) -> Result<Vec<u8>, FlowyError> {
|
|
let collab = Collab::new_with_origin(
|
|
CollabOrigin::Empty,
|
|
object_id.to_string().as_str(),
|
|
vec![],
|
|
false,
|
|
);
|
|
let awareness = UserAwareness::create(collab, None)?;
|
|
let encode_collab = awareness.encode_collab_v1(|_collab| Ok::<_, FlowyError>(()))?;
|
|
Ok(encode_collab.doc_state.to_vec())
|
|
}
|
|
|
|
async fn create_collab_object(
|
|
&self,
|
|
_collab_object: &CollabObject,
|
|
_data: Vec<u8>,
|
|
) -> Result<(), FlowyError> {
|
|
Ok(())
|
|
}
|
|
|
|
async fn batch_create_collab_object(
|
|
&self,
|
|
workspace_id: &Uuid,
|
|
objects: Vec<UserCollabParams>,
|
|
) -> Result<(), FlowyError> {
|
|
Ok(())
|
|
}
|
|
|
|
async fn get_workspace_member(
|
|
&self,
|
|
workspace_id: &Uuid,
|
|
uid: i64,
|
|
) -> Result<WorkspaceMember, FlowyError> {
|
|
// For local server, only current user is the member
|
|
let conn = self.logged_user.get_sqlite_db(uid)?;
|
|
let result = select_workspace_member(conn, &workspace_id.to_string(), uid);
|
|
|
|
match result {
|
|
Ok(row) => Ok(WorkspaceMember::from(row)),
|
|
Err(err) => {
|
|
if err.is_record_not_found() {
|
|
let mut conn = self.logged_user.get_sqlite_db(uid)?;
|
|
let profile = select_user_profile(uid, &mut conn)?;
|
|
let row = WorkspaceMemberTable {
|
|
email: profile.email.to_string(),
|
|
role: 0,
|
|
name: profile.name.to_string(),
|
|
avatar_url: Some(profile.icon_url),
|
|
uid,
|
|
workspace_id: workspace_id.to_string(),
|
|
updated_at: Default::default(),
|
|
};
|
|
|
|
let member = WorkspaceMember::from(row.clone());
|
|
upsert_workspace_member(&mut conn, row)?;
|
|
Ok(member)
|
|
} else {
|
|
Err(err)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
async fn get_workspace_usage(
|
|
&self,
|
|
workspace_id: &Uuid,
|
|
) -> Result<WorkspaceUsageAndLimit, FlowyError> {
|
|
Ok(WorkspaceUsageAndLimit {
|
|
member_count: 1,
|
|
member_count_limit: 1,
|
|
storage_bytes: i64::MAX,
|
|
storage_bytes_limit: i64::MAX,
|
|
storage_bytes_unlimited: true,
|
|
single_upload_limit: i64::MAX,
|
|
single_upload_unlimited: true,
|
|
ai_responses_count: i64::MAX,
|
|
ai_responses_count_limit: i64::MAX,
|
|
ai_image_responses_count: i64::MAX,
|
|
ai_image_responses_count_limit: 0,
|
|
local_ai: true,
|
|
ai_responses_unlimited: true,
|
|
})
|
|
}
|
|
|
|
async fn get_workspace_setting(
|
|
&self,
|
|
workspace_id: &Uuid,
|
|
) -> Result<AFWorkspaceSettings, FlowyError> {
|
|
let uid = self.logged_user.user_id()?;
|
|
let mut conn = self.logged_user.get_sqlite_db(uid)?;
|
|
|
|
// By default, workspace setting is existed in local server
|
|
let result = select_workspace_setting(&mut conn, &workspace_id.to_string());
|
|
match result {
|
|
Ok(row) => Ok(AFWorkspaceSettings {
|
|
disable_search_indexing: row.disable_search_indexing,
|
|
ai_model: row.ai_model,
|
|
}),
|
|
Err(err) => {
|
|
if err.is_record_not_found() {
|
|
let row = WorkspaceSettingsTable {
|
|
id: workspace_id.to_string(),
|
|
disable_search_indexing: false,
|
|
ai_model: "".to_string(),
|
|
};
|
|
let setting = AFWorkspaceSettings {
|
|
disable_search_indexing: row.disable_search_indexing,
|
|
ai_model: row.ai_model.clone(),
|
|
};
|
|
upsert_workspace_setting(&mut conn, row)?;
|
|
Ok(setting)
|
|
} else {
|
|
Err(err)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
async fn update_workspace_setting(
|
|
&self,
|
|
workspace_id: &Uuid,
|
|
workspace_settings: AFWorkspaceSettingsChange,
|
|
) -> Result<AFWorkspaceSettings, FlowyError> {
|
|
let uid = self.logged_user.user_id()?;
|
|
let mut conn = self.logged_user.get_sqlite_db(uid)?;
|
|
|
|
let changeset = WorkspaceSettingsChangeset {
|
|
id: workspace_id.to_string(),
|
|
disable_search_indexing: workspace_settings.disable_search_indexing,
|
|
ai_model: workspace_settings.ai_model,
|
|
};
|
|
|
|
update_workspace_setting(&mut conn, changeset)?;
|
|
let row = select_workspace_setting(&mut conn, &workspace_id.to_string())?;
|
|
|
|
Ok(AFWorkspaceSettings {
|
|
disable_search_indexing: row.disable_search_indexing,
|
|
ai_model: row.ai_model,
|
|
})
|
|
}
|
|
}
|