Skip to content

Commit

Permalink
feat: api for delete items from trash permanently (#1068)
Browse files Browse the repository at this point in the history
  • Loading branch information
khorshuheng authored Dec 17, 2024
1 parent 91c2a92 commit 68881a9
Show file tree
Hide file tree
Showing 6 changed files with 428 additions and 27 deletions.
34 changes: 34 additions & 0 deletions libs/client-api/src/http_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,40 @@ impl Client {
AppResponse::<()>::from_response(resp).await?.into_error()
}

pub async fn delete_workspace_page_view_from_trash(
&self,
workspace_id: Uuid,
view_id: &str,
) -> Result<(), AppResponseError> {
let url = format!(
"{}/api/workspace/{}/trash/{}",
self.base_url, workspace_id, view_id
);
let resp = self
.http_client_with_auth(Method::DELETE, &url)
.await?
.send()
.await?;
AppResponse::<()>::from_response(resp).await?.into_error()
}

pub async fn delete_all_workspace_page_views_from_trash(
&self,
workspace_id: Uuid,
) -> Result<(), AppResponseError> {
let url = format!(
"{}/api/workspace/{}/delete-all-pages-from-trash",
self.base_url, workspace_id
);
let resp = self
.http_client_with_auth(Method::POST, &url)
.await?
.json(&json!({}))
.send()
.await?;
AppResponse::<()>::from_response(resp).await?.into_error()
}

pub async fn update_workspace_page_view(
&self,
workspace_id: Uuid,
Expand Down
11 changes: 11 additions & 0 deletions src/api/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ pub struct AppFlowyWebMetrics {
pub update_size_bytes: Histogram,
pub decoding_failure_count: Gauge,
pub apply_update_failure_count: Gauge,
pub apply_update_timeout_count: Gauge,
}

impl AppFlowyWebMetrics {
Expand All @@ -243,6 +244,7 @@ impl AppFlowyWebMetrics {
update_size_bytes: Histogram::new(update_size_buckets),
decoding_failure_count: Default::default(),
apply_update_failure_count: Default::default(),
apply_update_timeout_count: Default::default(),
}
}

Expand All @@ -264,6 +266,11 @@ impl AppFlowyWebMetrics {
"Number of updates that failed to apply",
metrics.apply_update_failure_count.clone(),
);
web_update_registry.register(
"apply_update_timeout_count",
"Number of updates that failed to apply within timeout",
metrics.apply_update_timeout_count.clone(),
);
metrics
}

Expand All @@ -278,4 +285,8 @@ impl AppFlowyWebMetrics {
pub fn incr_apply_update_failure_count(&self, count: i64) {
self.apply_update_failure_count.inc_by(count);
}

pub fn incr_apply_update_timeout_count(&self, count: i64) {
self.apply_update_timeout_count.inc_by(count);
}
}
25 changes: 25 additions & 0 deletions src/api/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use actix_web::HttpRequest;
use appflowy_ai_client::dto::AIModel;
use async_trait::async_trait;
use byteorder::{ByteOrder, LittleEndian};
use chrono::Utc;
use collab_rt_entity::user::RealtimeUser;
use collab_rt_protocol::spawn_blocking_validate_encode_collab;
use database_entity::dto::CollabParams;
use std::str::FromStr;
use tokio_stream::StreamExt;
use uuid::Uuid;

#[inline]
pub fn compress_type_from_header_value(headers: &HeaderMap) -> Result<CompressionType, AppError> {
Expand Down Expand Up @@ -86,6 +89,28 @@ pub fn device_id_from_headers(headers: &HeaderMap) -> Result<&str, AppError> {
)
}

/// Create new realtime user for requests from appflowy web
pub fn realtime_user_for_web_request(
headers: &HeaderMap,
uid: i64,
) -> Result<RealtimeUser, AppError> {
let app_version = client_version_from_headers(headers)
.map(|s| s.to_string())
.unwrap_or_else(|_| "web".to_string());
let device_id = device_id_from_headers(headers)
.map(|s| s.to_string())
.unwrap_or_else(|_| Uuid::new_v4().to_string());
let session_id = device_id.clone();
let user = RealtimeUser {
uid,
device_id,
connect_at: Utc::now().timestamp(),
session_id,
app_version,
};
Ok(user)
}

#[async_trait]
pub trait CollabValidator {
async fn check_encode_collab(&self) -> Result<(), AppError>;
Expand Down
108 changes: 85 additions & 23 deletions src/api/workspace.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::api::util::{client_version_from_headers, PayloadReader};
use crate::api::util::{client_version_from_headers, realtime_user_for_web_request, PayloadReader};
use crate::api::util::{compress_type_from_header_value, device_id_from_headers, CollabValidator};
use crate::api::ws::RealtimeServerAddr;
use crate::biz;
Expand All @@ -12,9 +12,9 @@ use crate::biz::workspace::ops::{
get_reactions_on_published_view, remove_comment_on_published_view, remove_reaction_on_comment,
};
use crate::biz::workspace::page_view::{
create_page, create_space, get_page_view_collab, move_page, move_page_to_trash,
restore_all_pages_from_trash, restore_page_from_trash, update_page, update_page_collab_data,
update_space,
create_page, create_space, delete_all_pages_from_trash, delete_trash, get_page_view_collab,
move_page, move_page_to_trash, restore_all_pages_from_trash, restore_page_from_trash,
update_page, update_page_collab_data, update_space,
};
use crate::biz::workspace::publish::get_workspace_default_publish_view_info_meta;
use crate::domain::compression::{
Expand Down Expand Up @@ -172,6 +172,10 @@ pub fn workspace_scope() -> Scope {
web::resource("/{workspace_id}/restore-all-pages-from-trash")
.route(web::post().to(restore_all_pages_from_trash_handler)),
)
.service(
web::resource("/{workspace_id}/delete-all-pages-from-trash")
.route(web::post().to(delete_all_pages_from_trash_handler)),
)
.service(
web::resource("/{workspace_id}/batch/collab")
.route(web::post().to(batch_create_collab_handler)),
Expand Down Expand Up @@ -254,6 +258,10 @@ pub fn workspace_scope() -> Scope {
web::resource("/{workspace_id}/favorite").route(web::get().to(get_favorite_views_handler)),
)
.service(web::resource("/{workspace_id}/trash").route(web::get().to(get_trash_views_handler)))
.service(
web::resource("/{workspace_id}/trash/{view_id}")
.route(web::delete().to(delete_page_from_trash_handler)),
)
.service(
web::resource("/published-outline/{publish_namespace}")
.route(web::get().to(get_workspace_publish_outline_handler)),
Expand Down Expand Up @@ -910,32 +918,27 @@ async fn post_web_update_handler(
server: Data<RealtimeServerAddr>,
req: HttpRequest,
) -> Result<Json<AppResponse<()>>> {
let payload = payload.into_inner();
let app_version = client_version_from_headers(req.headers())
.map(|s| s.to_string())
.unwrap_or_else(|_| "web".to_string());
let device_id = device_id_from_headers(req.headers())
.map(|s| s.to_string())
.unwrap_or_else(|_| Uuid::new_v4().to_string());
let session_id = device_id.clone();

let (workspace_id, object_id) = path.into_inner();
let collab_type = payload.collab_type.clone();
let uid = state
.user_cache
.get_user_uid(&user_uuid)
.await
.map_err(AppResponseError::from)?;

let user = RealtimeUser {
uid,
device_id,
connect_at: timestamp(),
session_id,
app_version,
};
let (workspace_id, object_id) = path.into_inner();
state
.collab_access_control
.enforce_action(
&workspace_id.to_string(),
&uid,
&object_id.to_string(),
Action::Write,
)
.await?;
let user = realtime_user_for_web_request(req.headers(), uid)?;
trace!("create onetime web realtime user: {}", user);

let payload = payload.into_inner();
let collab_type = payload.collab_type.clone();

update_page_collab_data(
&state.metrics.appflowy_web_metrics,
server,
Expand Down Expand Up @@ -1089,6 +1092,65 @@ async fn restore_all_pages_from_trash_handler(
Ok(Json(AppResponse::Ok()))
}

async fn delete_page_from_trash_handler(
user_uuid: UserUuid,
path: web::Path<(Uuid, String)>,
state: Data<AppState>,
server: Data<RealtimeServerAddr>,
req: HttpRequest,
) -> Result<Json<AppResponse<()>>> {
let uid = state
.user_cache
.get_user_uid(&user_uuid)
.await
.map_err(AppResponseError::from)?;
let (workspace_id, view_id) = path.into_inner();
state
.workspace_access_control
.enforce_action(&uid, &workspace_id.to_string(), Action::Write)
.await?;
let user = realtime_user_for_web_request(req.headers(), uid)?;
delete_trash(
&state.metrics.appflowy_web_metrics,
server,
user,
&state.collab_access_control_storage,
workspace_id,
&view_id,
)
.await?;
Ok(Json(AppResponse::Ok()))
}

async fn delete_all_pages_from_trash_handler(
user_uuid: UserUuid,
path: web::Path<Uuid>,
state: Data<AppState>,
server: Data<RealtimeServerAddr>,
req: HttpRequest,
) -> Result<Json<AppResponse<()>>> {
let uid = state
.user_cache
.get_user_uid(&user_uuid)
.await
.map_err(AppResponseError::from)?;
let workspace_id = path.into_inner();
state
.workspace_access_control
.enforce_action(&uid, &workspace_id.to_string(), Action::Write)
.await?;
let user = realtime_user_for_web_request(req.headers(), uid)?;
delete_all_pages_from_trash(
&state.metrics.appflowy_web_metrics,
server,
user,
&state.collab_access_control_storage,
workspace_id,
)
.await?;
Ok(Json(AppResponse::Ok()))
}

async fn update_page_view_handler(
user_uuid: UserUuid,
path: web::Path<(Uuid, String)>,
Expand Down
Loading

0 comments on commit 68881a9

Please sign in to comment.