From 9093363b4f21c8ce2f459d154b8be44e7e91f9b2 Mon Sep 17 00:00:00 2001 From: Zack Fu Zi Xiang Date: Thu, 14 Mar 2024 17:32:30 +0800 Subject: [PATCH] feat: document storage size --- admin_frontend/src/ext/api.rs | 51 ++++++++++++++++++++++++------ admin_frontend/src/ext/entities.rs | 7 +++- admin_frontend/src/templates.rs | 4 +-- admin_frontend/src/web_app.rs | 2 +- libs/database-entity/src/dto.rs | 5 +++ src/api/workspace.rs | 14 ++++++++ 6 files changed, 69 insertions(+), 14 deletions(-) diff --git a/admin_frontend/src/ext/api.rs b/admin_frontend/src/ext/api.rs index a8e512a0..af672399 100644 --- a/admin_frontend/src/ext/api.rs +++ b/admin_frontend/src/ext/api.rs @@ -1,8 +1,8 @@ use database_entity::dto::AFWorkspace; use super::entities::{ - JsonResponse, UserUsageLimit, WorkspaceBlobUsage, WorkspaceMember, WorkspaceUsage, - WorkspaceUsageLimit, + JsonResponse, UserUsageLimit, WorkspaceBlobUsage, WorkspaceDocUsage, WorkspaceMember, + WorkspaceUsageLimit, WorkspaceUsageLimits, }; pub async fn get_user_workspace_count(auth_header: &str, appflowy_cloud_base_url: &str) -> u32 { @@ -68,24 +68,35 @@ pub async fn get_user_workspace_usages( auth_header: &str, appflowy_cloud_base_url: &str, appflowy_cloud_gateway_base_url: &str, -) -> Vec { +) -> Vec { let user_workspaces = get_user_workspaces(auth_header, appflowy_cloud_base_url).await; - let mut workspace_usages: Vec = Vec::with_capacity(user_workspaces.len()); + let mut workspace_usages: Vec = Vec::with_capacity(user_workspaces.len()); for user_workspace in user_workspaces { let workspace_id = user_workspace.workspace_id.to_string(); let members = get_user_workspace_members(&workspace_id, auth_header, appflowy_cloud_base_url).await; let workspace_limits = get_user_workspace_limits(&workspace_id, auth_header, appflowy_cloud_gateway_base_url).await; - let blob_usage = + let total_blob_size = get_user_workspace_blob_usage(&workspace_id, auth_header, appflowy_cloud_base_url) .await - .map(|u| u.consumed_capacity) + .map(|u| human_bytes::human_bytes(u.consumed_capacity as f64)) .unwrap_or_else(|err| { tracing::error!("Error getting user workspace blob usage: {:?}", err); - 0 + "0".to_owned() }); + + let total_doc_size = { + get_user_workspace_doc_usage(&workspace_id, auth_header, appflowy_cloud_base_url) + .await + .map(|u| human_bytes::human_bytes(u.total_document_size as f64)) + .unwrap_or_else(|err| { + tracing::error!("Error getting user workspace doc usage: {:?}", err); + "0".to_owned() + }) + }; + let (member_limit, total_blob_limit) = match workspace_limits { Some(limit) => ( limit.member_count.to_string(), @@ -94,12 +105,12 @@ pub async fn get_user_workspace_usages( None => ("N/A".to_string(), "N/A".to_string()), }; - workspace_usages.push(WorkspaceUsage { + workspace_usages.push(WorkspaceUsageLimits { name: user_workspace.workspace_name, member_count: members.len(), member_limit, - total_doc_size: "WIP".to_string(), - total_blob_size: human_bytes::human_bytes(blob_usage as f64), + total_doc_size, + total_blob_size, total_blob_limit, }); } @@ -189,3 +200,23 @@ async fn get_user_workspace_blob_usage( let res = resp.json::>().await?; Ok(res.data) } + +async fn get_user_workspace_doc_usage( + workspace_id: &str, + auth_header: &str, + appflowy_cloud_base_url: &str, +) -> Result { + let http_client = reqwest::Client::new(); + let url = format!( + "{}/api/workspace/{}/usage", + appflowy_cloud_base_url, workspace_id + ); + let resp = http_client + .get(url) + .header("Authorization", format!("Bearer {}", auth_header)) + .send() + .await?; + + let res = resp.json::>().await?; + Ok(res.data) +} diff --git a/admin_frontend/src/ext/entities.rs b/admin_frontend/src/ext/entities.rs index 25a51cdf..9ee1e54e 100644 --- a/admin_frontend/src/ext/entities.rs +++ b/admin_frontend/src/ext/entities.rs @@ -12,7 +12,7 @@ pub struct UserUsageLimit { } #[derive(Serialize)] -pub struct WorkspaceUsage { +pub struct WorkspaceUsageLimits { pub name: String, pub member_count: usize, pub member_limit: String, @@ -39,3 +39,8 @@ pub struct WorkspaceUsageLimit { pub struct WorkspaceBlobUsage { pub consumed_capacity: u64, } + +#[derive(Deserialize)] +pub struct WorkspaceDocUsage { + pub total_document_size: i64, +} diff --git a/admin_frontend/src/templates.rs b/admin_frontend/src/templates.rs index 37ec6592..e047fc30 100644 --- a/admin_frontend/src/templates.rs +++ b/admin_frontend/src/templates.rs @@ -1,7 +1,7 @@ use askama::Template; use gotrue_entity::{dto::User, sso::SSOProvider}; -use crate::ext::entities::WorkspaceUsage; +use crate::ext::entities::WorkspaceUsageLimits; #[derive(Template)] #[template(path = "components/user_usage.html")] @@ -14,7 +14,7 @@ pub struct UserUsage { #[derive(Template)] #[template(path = "components/workspace_usage.html")] pub struct WorkspaceUsageList { - pub workspace_usages: Vec, + pub workspace_usages: Vec, } #[derive(Template)] diff --git a/admin_frontend/src/web_app.rs b/admin_frontend/src/web_app.rs index ab8f07ab..21b43fc3 100644 --- a/admin_frontend/src/web_app.rs +++ b/admin_frontend/src/web_app.rs @@ -2,7 +2,7 @@ use crate::error::WebAppError; use crate::ext::api::{ get_user_workspace_count, get_user_workspace_limit, get_user_workspace_usages, }; -use crate::ext::entities::WorkspaceUsage; +use crate::ext::entities::WorkspaceUsageLimits; use crate::session::UserSession; use askama::Template; use axum::extract::{Path, State}; diff --git a/libs/database-entity/src/dto.rs b/libs/database-entity/src/dto.rs index a8a1ff60..767adba7 100644 --- a/libs/database-entity/src/dto.rs +++ b/libs/database-entity/src/dto.rs @@ -258,6 +258,11 @@ pub enum QueryCollabResult { #[derive(Serialize, Deserialize)] pub struct BatchQueryCollabResult(pub HashMap); +#[derive(Serialize, Deserialize)] +pub struct WorkspaceUsage { + pub total_document_size: i64, +} + #[derive(Debug, Clone, Validate, Serialize, Deserialize)] pub struct InsertCollabMemberParams { pub uid: i64, diff --git a/src/api/workspace.rs b/src/api/workspace.rs index f0b662f1..33171b2c 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -101,6 +101,9 @@ pub fn workspace_scope() -> Scope { .app_data(PayloadConfig::new(10 * 1024 * 1024)) .route(web::post().to(create_collab_list_handler)), ) + .service( + web::resource("/{workspace_id}/usage").route(web::get().to(get_workspace_usage_handler)), + ) .service( web::resource("/{workspace_id}/{object_id}/snapshot") .route(web::get().to(get_collab_snapshot_handler)) @@ -841,6 +844,17 @@ async fn post_realtime_message_stream_handler( Err(AppError::Internal(anyhow!("Failed to send message to websocket server")).into()) } +async fn get_workspace_usage_handler( + user_uuid: UserUuid, + workspace_id: web::Path, + state: Data, +) -> Result>> { + let res = WorkspaceUsage { + total_document_size: 19978, // TODO + }; + Ok(Json(AppResponse::Ok().with_data(res))) +} + #[inline] async fn parser_realtime_msg( payload: Bytes,