Merge pull request #400 from AppFlowy-IO/leave-workspace
Leave workspace
This commit is contained in:
commit
619f5b3370
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT email FROM af_user WHERE uuid = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "email",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "bde2b88ffb1b59362c7ae82369892c79131c175924f95e5d48d75931fb846f41"
|
||||
}
|
||||
|
|
@ -585,6 +585,19 @@ impl Client {
|
|||
.into_data()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
pub async fn leave_workspace(&self, workspace_id: &str) -> Result<(), AppResponseError> {
|
||||
let url = format!("{}/api/workspace/{}/leave", self.base_url, workspace_id);
|
||||
let resp = self
|
||||
.http_client_with_auth(Method::POST, &url)
|
||||
.await?
|
||||
.json(&())
|
||||
.send()
|
||||
.await?;
|
||||
log_request_id(&resp);
|
||||
AppResponse::<()>::from_response(resp).await?.into_error()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
pub async fn get_workspace_members<W: AsRef<str>>(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -196,3 +196,19 @@ pub async fn is_user_exist<'a, E: Executor<'a, Database = Postgres>>(
|
|||
|
||||
Ok(exists.unwrap_or(false))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn select_email_from_user_uuid(
|
||||
pool: &PgPool,
|
||||
user_uuid: &Uuid,
|
||||
) -> Result<String, AppError> {
|
||||
let email = sqlx::query_scalar!(
|
||||
r#"
|
||||
SELECT email FROM af_user WHERE uuid = $1
|
||||
"#,
|
||||
user_uuid
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
Ok(email)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ pub fn workspace_scope() -> Scope {
|
|||
.route(web::delete().to(delete_workspace_handler))
|
||||
)
|
||||
.service(web::resource("/{workspace_id}/open").route(web::put().to(open_workspace_handler)))
|
||||
.service(web::resource("/{workspace_id}/leave").route(web::post().to(leave_workspace_handler)))
|
||||
.service(
|
||||
web::resource("/{workspace_id}/member")
|
||||
.route(web::get().to(get_workspace_members_handler))
|
||||
|
|
@ -342,6 +343,23 @@ async fn open_workspace_handler(
|
|||
Ok(AppResponse::Ok().with_data(workspace).into())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
async fn leave_workspace_handler(
|
||||
user_uuid: UserUuid,
|
||||
state: Data<AppState>,
|
||||
workspace_id: web::Path<Uuid>,
|
||||
) -> Result<JsonAppResponse<()>> {
|
||||
let workspace_id = workspace_id.into_inner();
|
||||
workspace::ops::leave_workspace(
|
||||
&state.pg_pool,
|
||||
&workspace_id,
|
||||
&user_uuid,
|
||||
&state.workspace_access_control,
|
||||
)
|
||||
.await?;
|
||||
Ok(AppResponse::Ok().into())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
async fn update_workspace_member_handler(
|
||||
payload: Json<WorkspaceMemberChangeset>,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ pub trait CollabAccessControl: Sync + Send + 'static {
|
|||
|
||||
async fn remove_access_level(&self, uid: &i64, oid: &str) -> Result<(), AppError>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CollabMiddlewareAccessControl<AC: CollabAccessControl> {
|
||||
pub access_control: Arc<AC>,
|
||||
|
|
|
|||
|
|
@ -315,6 +315,16 @@ pub async fn add_workspace_members_db_only(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn leave_workspace(
|
||||
pg_pool: &PgPool,
|
||||
workspace_id: &Uuid,
|
||||
user_uuid: &Uuid,
|
||||
workspace_access_control: &impl WorkspaceAccessControl,
|
||||
) -> Result<(), AppResponseError> {
|
||||
let email = database::user::select_email_from_user_uuid(pg_pool, user_uuid).await?;
|
||||
remove_workspace_members(pg_pool, workspace_id, &[email], workspace_access_control).await
|
||||
}
|
||||
|
||||
pub async fn remove_workspace_members(
|
||||
pg_pool: &PgPool,
|
||||
workspace_id: &Uuid,
|
||||
|
|
|
|||
|
|
@ -352,3 +352,35 @@ async fn get_user_workspace_info_after_open_workspace() {
|
|||
workspace_id_c1
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn member_leave_workspace_test() {
|
||||
let c1 = TestClient::new_user().await;
|
||||
let workspace_id_c1 = c1.workspace_id().await;
|
||||
|
||||
let c2 = TestClient::new_user().await;
|
||||
c1.add_workspace_member(&workspace_id_c1, &c2, AFRole::Member)
|
||||
.await;
|
||||
c2.api_client
|
||||
.leave_workspace(&workspace_id_c1)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let members = c1.get_workspace_members(&workspace_id_c1).await;
|
||||
assert_eq!(members.len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn owner_leave_workspace_test() {
|
||||
let c1 = TestClient::new_user().await;
|
||||
let workspace_id_c1 = c1.workspace_id().await;
|
||||
|
||||
let err = c1
|
||||
.api_client
|
||||
.leave_workspace(&workspace_id_c1)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
// owner of workspace cannot leave the workspace
|
||||
assert_eq!(err.code, ErrorCode::NotEnoughPermissions);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue