diff --git a/src/api/workspace.rs b/src/api/workspace.rs index c0088970..36a119b6 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -294,6 +294,7 @@ async fn post_workspace_invite_handler( &user_uuid, &workspace_id, invited_members, + state.config.appflowy_web_url.as_deref(), ) .await?; Ok(AppResponse::Ok().into()) diff --git a/src/biz/workspace/ops.rs b/src/biz/workspace/ops.rs index e4d01ea6..2e1f9ae6 100644 --- a/src/biz/workspace/ops.rs +++ b/src/biz/workspace/ops.rs @@ -327,6 +327,7 @@ pub async fn invite_workspace_members( inviter: &Uuid, workspace_id: &Uuid, invitations: Vec, + appflowy_web_url: Option<&str>, ) -> Result<(), AppError> { let mut txn = pg_pool .begin() @@ -352,12 +353,17 @@ pub async fn invite_workspace_members( let pending_invitations = database::workspace::select_workspace_pending_invitations(pg_pool, workspace_id).await?; - for invitation in invitations { + // check if any of the invited users are already members of the workspace + for invitation in &invitations { if workspace_members_by_email.contains_key(&invitation.email) { - tracing::warn!("User already in workspace: {}", invitation.email); - continue; + return Err(AppError::InvalidRequest(format!( + "User with email {} is already a member of the workspace", + invitation.email + ))); } + } + for invitation in invitations { let inviter_name = inviter_name.clone(); let workspace_name = workspace_name.clone(); let workspace_member_count = workspace_member_count.to_string(); @@ -384,32 +390,39 @@ pub async fn invite_workspace_members( .await?; invite_id }, - Some(inv) => { + Some(invite_id) => { tracing::warn!("User already invited: {}", invitation.email); - *inv + *invite_id }, }; // Generate a link such that when clicked, the user is added to the workspace. - let accept_url = gotrue_client - .admin_generate_link( - &admin_token, - &GenerateLinkParams { - type_: GenerateLinkType::MagicLink, - email: invitation.email.clone(), - redirect_to: format!( - "/web/login-callback?action=accept_workspace_invite&workspace_invitation_id={}&workspace_name={}&workspace_icon={}&user_name={}&user_icon={}&workspace_member_count={}", - invite_id, workspace_name, - workspace_icon_url, - inviter_name, - user_icon_url, - workspace_member_count, - ), - ..Default::default() + let accept_url = { + match appflowy_web_url { + Some(appflowy_web_url) => format!("{}/accept-invitation?invitated_id={}", appflowy_web_url, invite_id), + None => { + gotrue_client + .admin_generate_link( + &admin_token, + &GenerateLinkParams { + type_: GenerateLinkType::MagicLink, + email: invitation.email.clone(), + redirect_to: format!( + "/web/login-callback?action=accept_workspace_invite&workspace_invitation_id={}&workspace_name={}&workspace_icon={}&user_name={}&user_icon={}&workspace_member_count={}", + invite_id, workspace_name, + workspace_icon_url, + inviter_name, + user_icon_url, + workspace_member_count, + ), + ..Default::default() + }, + ) + .await? + .action_link }, - ) - .await? - .action_link; + } + }; // send email can be slow, so send email in background let cloned_mailer = mailer.clone(); diff --git a/src/config/config.rs b/src/config/config.rs index 2e1ccb8a..4fdc639d 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -24,6 +24,7 @@ pub struct Config { pub published_collab: PublishedCollabSetting, pub mailer: MailerSetting, pub apple_oauth: AppleOAuthSetting, + pub appflowy_web_url: Option, } #[derive(serde::Deserialize, Clone, Debug)] @@ -244,6 +245,7 @@ pub fn get_configuration() -> Result { client_id: get_env_var("APPFLOWY_APPLE_OAUTH_CLIENT_ID", ""), client_secret: get_env_var("APPFLOWY_APPLE_OAUTH_CLIENT_SECRET", "").into(), }, + appflowy_web_url: std::env::var("APPFLOWY_WEB_URL").ok(), }; Ok(config) } diff --git a/tests/workspace/invitation_crud.rs b/tests/workspace/invitation_crud.rs index 7c2cbfc7..e84cc655 100644 --- a/tests/workspace/invitation_crud.rs +++ b/tests/workspace/invitation_crud.rs @@ -58,7 +58,7 @@ async fn invite_workspace_crud() { .unwrap(); assert_eq!(invitation.inviter_email, Some(alice.email)); - assert_eq!(invitation.status , AFWorkspaceInvitationStatus::Pending); + assert_eq!(invitation.status, AFWorkspaceInvitationStatus::Pending); bob_client .accept_workspace_invitation(&invite_id)