feat: added tests for inviting member which has not signed up yet
This commit is contained in:
parent
dca443affc
commit
c293929b11
|
|
@ -76,6 +76,30 @@ pub async fn generate_sign_in_action_link(email: &str) -> String {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as generate_unique_registered_user_client
|
||||||
|
// but with specific email
|
||||||
|
pub async fn api_client_with_email(user_email: &str) -> client_api::Client {
|
||||||
|
let new_user_sign_in_link = {
|
||||||
|
let admin_client = admin_user_client().await;
|
||||||
|
admin_client
|
||||||
|
.generate_sign_in_action_link(user_email)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let client = localhost_client();
|
||||||
|
let appflowy_sign_in_url = client
|
||||||
|
.extract_sign_in_url(&new_user_sign_in_link)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
client
|
||||||
|
.sign_in_with_url(&appflowy_sign_in_url)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
client
|
||||||
|
}
|
||||||
|
|
||||||
pub fn localhost_gotrue_client() -> gotrue::api::Client {
|
pub fn localhost_gotrue_client() -> gotrue::api::Client {
|
||||||
let reqwest_client = reqwest::Client::new();
|
let reqwest_client = reqwest::Client::new();
|
||||||
gotrue::api::Client::new(reqwest_client, &LOCALHOST_GOTRUE)
|
gotrue::api::Client::new(reqwest_client, &LOCALHOST_GOTRUE)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ pub struct CreateWorkspaceMember {
|
||||||
pub role: AFRole,
|
pub role: AFRole,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct WorkspaceMemberInvitation {
|
pub struct WorkspaceMemberInvitation {
|
||||||
pub email: String,
|
pub email: String,
|
||||||
pub role: AFRole,
|
pub role: AFRole,
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,8 @@ async fn post_workspace_invite_handler(
|
||||||
let invited_members = payload.into_inner();
|
let invited_members = payload.into_inner();
|
||||||
workspace::ops::invite_workspace_members(
|
workspace::ops::invite_workspace_members(
|
||||||
&state.pg_pool,
|
&state.pg_pool,
|
||||||
|
&state.gotrue_admin,
|
||||||
|
&state.gotrue_client,
|
||||||
&user_uuid,
|
&user_uuid,
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
invited_members,
|
invited_members,
|
||||||
|
|
|
||||||
|
|
@ -255,10 +255,7 @@ async fn setup_admin_account(
|
||||||
) -> Result<GoTrueAdmin, Error> {
|
) -> Result<GoTrueAdmin, Error> {
|
||||||
let admin_email = gotrue_setting.admin_email.as_str();
|
let admin_email = gotrue_setting.admin_email.as_str();
|
||||||
let password = gotrue_setting.admin_password.as_str();
|
let password = gotrue_setting.admin_password.as_str();
|
||||||
let gotrue_admin = GoTrueAdmin {
|
let gotrue_admin = GoTrueAdmin::new(admin_email.to_owned(), password.to_owned());
|
||||||
admin_email: admin_email.to_owned(),
|
|
||||||
password: admin_email.to_owned().into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let res_resp = gotrue_client.sign_up(admin_email, password, None).await;
|
let res_resp = gotrue_client.sign_up(admin_email, password, None).await;
|
||||||
match res_resp {
|
match res_resp {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::biz::workspace::access_control::WorkspaceAccessControl;
|
use crate::biz::workspace::access_control::WorkspaceAccessControl;
|
||||||
|
use crate::state::GoTrueAdmin;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use database::collab::upsert_collab_member_with_txn;
|
use database::collab::upsert_collab_member_with_txn;
|
||||||
|
|
@ -17,6 +18,8 @@ use database::workspace::{
|
||||||
use database_entity::dto::{
|
use database_entity::dto::{
|
||||||
AFAccessLevel, AFRole, AFWorkspace, AFWorkspaceInvitation, AFWorkspaceInvitationStatus,
|
AFAccessLevel, AFRole, AFWorkspace, AFWorkspaceInvitation, AFWorkspaceInvitationStatus,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use gotrue::params::InviteUserParams;
|
||||||
use shared_entity::dto::workspace_dto::{
|
use shared_entity::dto::workspace_dto::{
|
||||||
CreateWorkspaceMember, WorkspaceMemberChangeset, WorkspaceMemberInvitation,
|
CreateWorkspaceMember, WorkspaceMemberChangeset, WorkspaceMemberInvitation,
|
||||||
};
|
};
|
||||||
|
|
@ -26,7 +29,7 @@ use sqlx::{types::uuid, PgPool};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::instrument;
|
use tracing::{info, instrument};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use workspace_template::document::get_started::GetStartedDocumentTemplate;
|
use workspace_template::document::get_started::GetStartedDocumentTemplate;
|
||||||
|
|
||||||
|
|
@ -159,6 +162,8 @@ pub async fn accept_workspace_invite(
|
||||||
#[instrument(level = "debug", skip_all, err)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
pub async fn invite_workspace_members(
|
pub async fn invite_workspace_members(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
|
gotrue_admin: &GoTrueAdmin,
|
||||||
|
gotrue_client: &gotrue::api::Client,
|
||||||
inviter: &Uuid,
|
inviter: &Uuid,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
invitations: Vec<WorkspaceMemberInvitation>,
|
invitations: Vec<WorkspaceMemberInvitation>,
|
||||||
|
|
@ -168,7 +173,37 @@ pub async fn invite_workspace_members(
|
||||||
.await
|
.await
|
||||||
.context("Begin transaction to invite workspace members")?;
|
.context("Begin transaction to invite workspace members")?;
|
||||||
|
|
||||||
|
let admin_token = gotrue_admin.token(gotrue_client).await?;
|
||||||
for invitation in invitations {
|
for invitation in invitations {
|
||||||
|
match gotrue_client
|
||||||
|
.admin_invite_user(
|
||||||
|
&admin_token,
|
||||||
|
&InviteUserParams {
|
||||||
|
email: invitation.email.clone(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(new_user) => {
|
||||||
|
info!(
|
||||||
|
"Invited new user: {:?} to workspace: {:?}",
|
||||||
|
new_user, workspace_id
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Err(err) => match err {
|
||||||
|
app_error::gotrue::GoTrueError::Internal(ref err_serde) => {
|
||||||
|
match (err_serde.code, err_serde.msg.as_str()) {
|
||||||
|
(422, "A user with this email address has already been registered") => {
|
||||||
|
info!("User already exists, skipping invite");
|
||||||
|
},
|
||||||
|
_ => return Err(AppError::Internal(err.into())),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => return Err(err.into()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
insert_workspace_invitation(
|
insert_workspace_invitation(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
filters.push(format!("gotrue={}", level));
|
filters.push(format!("gotrue={}", level));
|
||||||
let conf =
|
let conf =
|
||||||
get_configuration().map_err(|e| anyhow::anyhow!("Failed to read configuration: {}", e))?;
|
get_configuration().map_err(|e| anyhow::anyhow!("Failed to read configuration: {}", e))?;
|
||||||
init_subscriber(&conf.app_env, filters);
|
// init_subscriber(&conf.app_env, filters);
|
||||||
|
|
||||||
// If current build is debug and the feature "custom_env" is not enabled, load from .env
|
// If current build is debug and the feature "custom_env" is not enabled, load from .env
|
||||||
// otherwise, load from .env.without_nginx.
|
// otherwise, load from .env.without_nginx.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use app_error::ErrorCode;
|
use app_error::ErrorCode;
|
||||||
use client_api_test_util::TestClient;
|
use client_api_test_util::{api_client_with_email, TestClient};
|
||||||
use database_entity::dto::{AFAccessLevel, AFRole, QueryCollabMembers};
|
use database_entity::dto::{AFAccessLevel, AFRole, QueryCollabMembers};
|
||||||
use shared_entity::dto::workspace_dto::CreateWorkspaceMember;
|
use shared_entity::dto::workspace_dto::WorkspaceMemberInvitation;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_workspace_owner_after_sign_up_test() {
|
async fn get_workspace_owner_after_sign_up_test() {
|
||||||
|
|
@ -73,20 +73,34 @@ async fn add_not_exist_workspace_members() {
|
||||||
let c1 = TestClient::new_user_without_ws_conn().await;
|
let c1 = TestClient::new_user_without_ws_conn().await;
|
||||||
let workspace_id = c1.workspace_id().await;
|
let workspace_id = c1.workspace_id().await;
|
||||||
let email = format!("{}@appflowy.io", uuid::Uuid::new_v4());
|
let email = format!("{}@appflowy.io", uuid::Uuid::new_v4());
|
||||||
let err = c1
|
c1.api_client
|
||||||
.api_client
|
.invite_workspace_members(
|
||||||
.add_workspace_members(
|
&workspace_id,
|
||||||
workspace_id,
|
vec![WorkspaceMemberInvitation {
|
||||||
vec![CreateWorkspaceMember {
|
email: email.clone(),
|
||||||
email,
|
|
||||||
role: AFRole::Member,
|
role: AFRole::Member,
|
||||||
}],
|
}],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(err.code, ErrorCode::RecordNotFound);
|
let invited_client = api_client_with_email(&email).await;
|
||||||
|
let invite_id = invited_client
|
||||||
|
.list_workspace_invitations(None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.invite_id;
|
||||||
|
invited_client
|
||||||
|
.accept_workspace_invitation(invite_id.to_string().as_str())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let workspaces = invited_client.get_workspaces().await.unwrap();
|
||||||
|
assert_eq!(workspaces.0.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn update_workspace_member_role_not_enough_permission() {
|
async fn update_workspace_member_role_not_enough_permission() {
|
||||||
let c1 = TestClient::new_user_without_ws_conn().await;
|
let c1 = TestClient::new_user_without_ws_conn().await;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue