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()
|
.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)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
pub async fn get_workspace_members<W: AsRef<str>>(
|
pub async fn get_workspace_members<W: AsRef<str>>(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -196,3 +196,19 @@ pub async fn is_user_exist<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
|
|
||||||
Ok(exists.unwrap_or(false))
|
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))
|
.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}/open").route(web::put().to(open_workspace_handler)))
|
||||||
|
.service(web::resource("/{workspace_id}/leave").route(web::post().to(leave_workspace_handler)))
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{workspace_id}/member")
|
web::resource("/{workspace_id}/member")
|
||||||
.route(web::get().to(get_workspace_members_handler))
|
.route(web::get().to(get_workspace_members_handler))
|
||||||
|
|
@ -342,6 +343,23 @@ async fn open_workspace_handler(
|
||||||
Ok(AppResponse::Ok().with_data(workspace).into())
|
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)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
async fn update_workspace_member_handler(
|
async fn update_workspace_member_handler(
|
||||||
payload: Json<WorkspaceMemberChangeset>,
|
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>;
|
async fn remove_access_level(&self, uid: &i64, oid: &str) -> Result<(), AppError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CollabMiddlewareAccessControl<AC: CollabAccessControl> {
|
pub struct CollabMiddlewareAccessControl<AC: CollabAccessControl> {
|
||||||
pub access_control: Arc<AC>,
|
pub access_control: Arc<AC>,
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,16 @@ pub async fn add_workspace_members_db_only(
|
||||||
Ok(())
|
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(
|
pub async fn remove_workspace_members(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
|
|
|
||||||
|
|
@ -352,3 +352,35 @@ async fn get_user_workspace_info_after_open_workspace() {
|
||||||
workspace_id_c1
|
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