diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 41028d6aba..28f2680642 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "bytes", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "again", "anyhow", @@ -685,6 +685,7 @@ dependencies = [ "getrandom 0.2.10", "gotrue", "infra", + "lazy_static", "mime", "parking_lot 0.12.1", "percent-encoding", @@ -713,7 +714,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "collab-entity", "collab-rt-entity", @@ -725,7 +726,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "futures-channel", "futures-util", @@ -934,7 +935,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "bincode", @@ -959,7 +960,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "async-trait", @@ -1276,7 +1277,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "app-error", @@ -2240,6 +2241,7 @@ dependencies = [ "base64 0.21.5", "bytes", "chrono", + "client-api", "collab", "collab-database", "collab-document", @@ -2596,7 +2598,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "futures-util", @@ -2613,7 +2615,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "app-error", @@ -2978,7 +2980,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "bytes", @@ -5079,7 +5081,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cba2248132de961f5dbab2a87c86b485dc701a56#cba2248132de961f5dbab2a87c86b485dc701a56" dependencies = [ "anyhow", "app-error", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 95402906de..acaf2dd929 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -99,8 +99,8 @@ validator = { version = "0.16.1", features = ["derive"] } # Run the script.add_workspace_members: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } -client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cba2248132de961f5dbab2a87c86b485dc701a56" } +client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cba2248132de961f5dbab2a87c86b485dc701a56" } [profile.dev] opt-level = 1 diff --git a/frontend/rust-lib/flowy-error/src/errors.rs b/frontend/rust-lib/flowy-error/src/errors.rs index 2cd5ef7dd0..c6a4290440 100644 --- a/frontend/rust-lib/flowy-error/src/errors.rs +++ b/frontend/rust-lib/flowy-error/src/errors.rs @@ -187,3 +187,9 @@ impl From for FlowyError { FlowyError::internal().with_context(e) } } + +impl From for FlowyError { + fn from(e: String) -> Self { + FlowyError::internal().with_context(e) + } +} diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs index 616fddb7b9..7970443ccc 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use anyhow::anyhow; use client_api::entity::billing_dto::{ - SubscriptionPlan, SubscriptionStatus, WorkspaceSubscriptionPlan, WorkspaceSubscriptionStatus, + RecurringInterval, SubscriptionPlan, WorkspaceSubscriptionStatus, WorkspaceUsageAndLimit, }; use client_api::entity::workspace_dto::{ CreateWorkspaceParam, PatchWorkspaceParam, WorkspaceMemberChangeset, WorkspaceMemberInvitation, @@ -23,7 +23,6 @@ use flowy_user_pub::cloud::{UserCloudService, UserCollabParams, UserUpdate, User use flowy_user_pub::entities::{ AFCloudOAuthParams, AuthResponse, Role, UpdateUserProfileParams, UserCredentials, UserProfile, UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember, - WorkspaceSubscription, WorkspaceUsage, }; use lib_infra::box_any::BoxAny; use lib_infra::future::FutureResult; @@ -476,19 +475,18 @@ where fn subscribe_workspace( &self, workspace_id: String, - recurring_interval: flowy_user_pub::entities::RecurringInterval, - workspace_subscription_plan: flowy_user_pub::entities::SubscriptionPlan, + recurring_interval: RecurringInterval, + subscription_plan: SubscriptionPlan, success_url: String, ) -> FutureResult { let try_get_client = self.server.try_get_client(); let workspace_id = workspace_id.to_string(); FutureResult::new(async move { - let subscription_plan = to_workspace_subscription_plan(workspace_subscription_plan)?; let client = try_get_client?; let payment_link = client .create_subscription( &workspace_id, - to_recurring_interval(recurring_interval), + recurring_interval, subscription_plan, &success_url, ) @@ -525,40 +523,39 @@ where }) } - fn get_workspace_subscriptions(&self) -> FutureResult, FlowyError> { + fn get_workspace_subscriptions( + &self, + ) -> FutureResult, FlowyError> { let try_get_client = self.server.try_get_client(); FutureResult::new(async move { let client = try_get_client?; - let workspace_subscriptions = client - .list_subscription() - .await? - .into_iter() - .map(to_workspace_subscription) - .collect(); + let workspace_subscriptions = client.list_subscription().await?; Ok(workspace_subscriptions) }) } - fn cancel_workspace_subscription(&self, workspace_id: String) -> FutureResult<(), FlowyError> { + fn cancel_workspace_subscription( + &self, + workspace_id: String, + plan: SubscriptionPlan, + ) -> FutureResult<(), FlowyError> { let try_get_client = self.server.try_get_client(); FutureResult::new(async move { let client = try_get_client?; - client.cancel_subscription(&workspace_id).await?; + client.cancel_subscription(&workspace_id, &plan).await?; Ok(()) }) } - fn get_workspace_usage(&self, workspace_id: String) -> FutureResult { + fn get_workspace_usage( + &self, + workspace_id: String, + ) -> FutureResult { let try_get_client = self.server.try_get_client(); FutureResult::new(async move { let client = try_get_client?; - let usage = client.get_billing_workspace_usage(&workspace_id).await?; - Ok(WorkspaceUsage { - member_count: usage.member_count, - member_count_limit: usage.member_count_limit, - total_blob_bytes: usage.total_blob_bytes, - total_blob_bytes_limit: usage.total_blob_bytes_limit, - }) + let usage = client.get_workspace_usage_and_limit(&workspace_id).await?; + Ok(usage) }) } @@ -695,51 +692,3 @@ fn oauth_params_from_box_any(any: BoxAny) -> Result client_api::entity::billing_dto::RecurringInterval { - match r { - flowy_user_pub::entities::RecurringInterval::Month => { - client_api::entity::billing_dto::RecurringInterval::Month - }, - flowy_user_pub::entities::RecurringInterval::Year => { - client_api::entity::billing_dto::RecurringInterval::Year - }, - } -} - -fn to_workspace_subscription_plan( - s: flowy_user_pub::entities::SubscriptionPlan, -) -> Result { - match s { - flowy_user_pub::entities::SubscriptionPlan::Pro => Ok(SubscriptionPlan::Pro), - flowy_user_pub::entities::SubscriptionPlan::Team => Ok(SubscriptionPlan::Team), - flowy_user_pub::entities::SubscriptionPlan::None => Err(FlowyError::new( - ErrorCode::InvalidParams, - "Invalid subscription plan", - )), - } -} - -fn to_workspace_subscription(s: WorkspaceSubscriptionStatus) -> WorkspaceSubscription { - WorkspaceSubscription { - workspace_id: s.workspace_id, - subscription_plan: match s.workspace_plan { - WorkspaceSubscriptionPlan::Pro => flowy_user_pub::entities::SubscriptionPlan::Pro, - WorkspaceSubscriptionPlan::Team => flowy_user_pub::entities::SubscriptionPlan::Team, - _ => flowy_user_pub::entities::SubscriptionPlan::None, - }, - recurring_interval: match s.recurring_interval { - client_api::entity::billing_dto::RecurringInterval::Month => { - flowy_user_pub::entities::RecurringInterval::Month - }, - client_api::entity::billing_dto::RecurringInterval::Year => { - flowy_user_pub::entities::RecurringInterval::Year - }, - }, - is_active: matches!(s.subscription_status, SubscriptionStatus::Active), - has_canceled: s.canceled_at.is_some(), - canceled_at: s.canceled_at, - } -} diff --git a/frontend/rust-lib/flowy-user-pub/src/cloud.rs b/frontend/rust-lib/flowy-user-pub/src/cloud.rs index 44f215906b..e75f79f507 100644 --- a/frontend/rust-lib/flowy-user-pub/src/cloud.rs +++ b/frontend/rust-lib/flowy-user-pub/src/cloud.rs @@ -1,3 +1,7 @@ +use client_api::entity::billing_dto::RecurringInterval; +use client_api::entity::billing_dto::SubscriptionPlan; +use client_api::entity::billing_dto::WorkspaceSubscriptionStatus; +use client_api::entity::billing_dto::WorkspaceUsageAndLimit; pub use client_api::entity::{AFWorkspaceSettings, AFWorkspaceSettingsChange}; use collab_entity::{CollabObject, CollabType}; use flowy_error::{internal_error, ErrorCode, FlowyError}; @@ -13,9 +17,8 @@ use tokio_stream::wrappers::WatchStream; use uuid::Uuid; use crate::entities::{ - AuthResponse, Authenticator, RecurringInterval, Role, SubscriptionPlan, UpdateUserProfileParams, - UserCredentials, UserProfile, UserTokenState, UserWorkspace, WorkspaceInvitation, - WorkspaceInvitationStatus, WorkspaceMember, WorkspaceSubscription, WorkspaceUsage, + AuthResponse, Authenticator, Role, UpdateUserProfileParams, UserCredentials, UserProfile, + UserTokenState, UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -281,15 +284,24 @@ pub trait UserCloudService: Send + Sync + 'static { FutureResult::new(async { Err(FlowyError::not_support()) }) } - fn get_workspace_subscriptions(&self) -> FutureResult, FlowyError> { + fn get_workspace_subscriptions( + &self, + ) -> FutureResult, FlowyError> { FutureResult::new(async { Err(FlowyError::not_support()) }) } - fn cancel_workspace_subscription(&self, workspace_id: String) -> FutureResult<(), FlowyError> { + fn cancel_workspace_subscription( + &self, + workspace_id: String, + plan: SubscriptionPlan, + ) -> FutureResult<(), FlowyError> { FutureResult::new(async { Err(FlowyError::not_support()) }) } - fn get_workspace_usage(&self, workspace_id: String) -> FutureResult { + fn get_workspace_usage( + &self, + workspace_id: String, + ) -> FutureResult { FutureResult::new(async { Err(FlowyError::not_support()) }) } diff --git a/frontend/rust-lib/flowy-user-pub/src/entities.rs b/frontend/rust-lib/flowy-user-pub/src/entities.rs index d76a4afd31..579207d99e 100644 --- a/frontend/rust-lib/flowy-user-pub/src/entities.rs +++ b/frontend/rust-lib/flowy-user-pub/src/entities.rs @@ -1,6 +1,9 @@ use std::str::FromStr; use chrono::{DateTime, Utc}; +use client_api::entity::billing_dto::{ + RecurringInterval, SubscriptionPlan, SubscriptionStatus, WorkspaceSubscriptionStatus, +}; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::*; @@ -453,59 +456,6 @@ pub struct WorkspaceInvitation { pub updated_at: DateTime, } -#[derive(Clone, Debug)] -pub enum RecurringInterval { - Month, - Year, -} - -impl Into for RecurringInterval { - fn into(self) -> i64 { - match self { - RecurringInterval::Month => 0, - RecurringInterval::Year => 1, - } - } -} - -impl From for RecurringInterval { - fn from(value: i64) -> Self { - match value { - 0 => RecurringInterval::Month, - 1 => RecurringInterval::Year, - _ => RecurringInterval::Month, - } - } -} - -#[derive(Clone, Debug)] -pub enum SubscriptionPlan { - None, - Pro, - Team, -} - -impl Into for SubscriptionPlan { - fn into(self) -> i64 { - match self { - SubscriptionPlan::None => 0, - SubscriptionPlan::Pro => 1, - SubscriptionPlan::Team => 2, - } - } -} - -impl From for SubscriptionPlan { - fn from(value: i64) -> Self { - match value { - 0 => SubscriptionPlan::None, - 1 => SubscriptionPlan::Pro, - 2 => SubscriptionPlan::Team, - _ => SubscriptionPlan::None, - } - } -} - pub struct WorkspaceSubscription { pub workspace_id: String, pub subscription_plan: SubscriptionPlan, @@ -515,9 +465,15 @@ pub struct WorkspaceSubscription { pub canceled_at: Option, } -pub struct WorkspaceUsage { - pub member_count: usize, - pub member_count_limit: usize, - pub total_blob_bytes: usize, - pub total_blob_bytes_limit: usize, +impl From for WorkspaceSubscription { + fn from(sub_status: WorkspaceSubscriptionStatus) -> Self { + WorkspaceSubscription { + workspace_id: sub_status.workspace_id, + subscription_plan: sub_status.workspace_plan, + recurring_interval: sub_status.recurring_interval, + is_active: sub_status.subscription_status == SubscriptionStatus::Active, + has_canceled: sub_status.canceled_at.is_some(), + canceled_at: sub_status.canceled_at, + } + } } diff --git a/frontend/rust-lib/flowy-user/Cargo.toml b/frontend/rust-lib/flowy-user/Cargo.toml index 0d53b9f6b7..f2eb89dc4c 100644 --- a/frontend/rust-lib/flowy-user/Cargo.toml +++ b/frontend/rust-lib/flowy-user/Cargo.toml @@ -24,6 +24,7 @@ collab-user = { workspace = true } collab-entity = { workspace = true } collab-plugins = { workspace = true } flowy-user-pub = { workspace = true } +client-api = { workspace = true } anyhow.workspace = true tracing.workspace = true bytes.workspace = true diff --git a/frontend/rust-lib/flowy-user/src/entities/workspace.rs b/frontend/rust-lib/flowy-user/src/entities/workspace.rs index 392fced085..6ca46abe90 100644 --- a/frontend/rust-lib/flowy-user/src/entities/workspace.rs +++ b/frontend/rust-lib/flowy-user/src/entities/workspace.rs @@ -1,12 +1,10 @@ +use client_api::entity::billing_dto::{RecurringInterval, SubscriptionPlan}; use std::str::FromStr; use validator::Validate; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_user_pub::cloud::{AFWorkspaceSettings, AFWorkspaceSettingsChange}; -use flowy_user_pub::entities::{ - RecurringInterval, Role, SubscriptionPlan, WorkspaceInvitation, WorkspaceMember, - WorkspaceSubscription, -}; +use flowy_user_pub::entities::{Role, WorkspaceInvitation, WorkspaceMember, WorkspaceSubscription}; use lib_infra::validator_fn::required_not_empty_str; #[derive(ProtoBuf, Default, Clone)] @@ -180,6 +178,16 @@ pub struct UserWorkspaceIdPB { pub workspace_id: String, } +#[derive(ProtoBuf, Default, Clone, Validate)] +pub struct CancelWorkspaceSubscriptionPB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub workspace_id: String, + + #[pb(index = 2)] + pub plan: SubscriptionPlanPB, +} + #[derive(ProtoBuf, Default, Clone)] pub struct WorkspaceMemberIdPB { #[pb(index = 1)] @@ -261,6 +269,9 @@ pub enum SubscriptionPlanPB { None = 0, Pro = 1, Team = 2, + + AiMax = 3, + AiLocal = 4, } impl From for SubscriptionPlan { @@ -268,7 +279,9 @@ impl From for SubscriptionPlan { match value { SubscriptionPlanPB::Pro => SubscriptionPlan::Pro, SubscriptionPlanPB::Team => SubscriptionPlan::Team, - SubscriptionPlanPB::None => SubscriptionPlan::None, + SubscriptionPlanPB::None => SubscriptionPlan::Free, + SubscriptionPlanPB::AiMax => SubscriptionPlan::AiMax, + SubscriptionPlanPB::AiLocal => SubscriptionPlan::AiLocal, } } } @@ -278,7 +291,9 @@ impl From for SubscriptionPlanPB { match value { SubscriptionPlan::Pro => SubscriptionPlanPB::Pro, SubscriptionPlan::Team => SubscriptionPlanPB::Team, - SubscriptionPlan::None => SubscriptionPlanPB::None, + SubscriptionPlan::Free => SubscriptionPlanPB::None, + SubscriptionPlan::AiMax => SubscriptionPlanPB::AiMax, + SubscriptionPlan::AiLocal => SubscriptionPlanPB::AiLocal, } } } @@ -336,9 +351,19 @@ pub struct WorkspaceUsagePB { #[pb(index = 2)] pub member_count_limit: u64, #[pb(index = 3)] - pub total_blob_bytes: u64, + pub storage_bytes: u64, #[pb(index = 4)] - pub total_blob_bytes_limit: u64, + pub storage_bytes_limit: u64, + #[pb(index = 5)] + pub storage_bytes_unlimited: bool, + #[pb(index = 6)] + pub ai_responses_count: u64, + #[pb(index = 7)] + pub ai_responses_count_limit: u64, + #[pb(index = 8)] + pub ai_responses_unlimited: bool, + #[pb(index = 9)] + pub local_ai: bool, } #[derive(Debug, ProtoBuf, Default, Clone)] diff --git a/frontend/rust-lib/flowy-user/src/event_handler.rs b/frontend/rust-lib/flowy-user/src/event_handler.rs index c10bd4484f..b4836117a2 100644 --- a/frontend/rust-lib/flowy-user/src/event_handler.rs +++ b/frontend/rust-lib/flowy-user/src/event_handler.rs @@ -789,12 +789,14 @@ pub async fn get_workspace_subscriptions_handler( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn cancel_workspace_subscription_handler( - param: AFPluginData, + param: AFPluginData, manager: AFPluginState>, ) -> Result<(), FlowyError> { - let workspace_id = param.into_inner().workspace_id; + let params = param.into_inner(); let manager = upgrade_manager(manager)?; - manager.cancel_workspace_subscription(workspace_id).await?; + manager + .cancel_workspace_subscription(params.workspace_id, params.plan.into()) + .await?; Ok(()) } @@ -809,8 +811,13 @@ pub async fn get_workspace_usage_handler( data_result_ok(WorkspaceUsagePB { member_count: workspace_usage.member_count as u64, member_count_limit: workspace_usage.member_count_limit as u64, - total_blob_bytes: workspace_usage.total_blob_bytes as u64, - total_blob_bytes_limit: workspace_usage.total_blob_bytes_limit as u64, + storage_bytes: workspace_usage.storage_bytes as u64, + storage_bytes_limit: workspace_usage.storage_bytes_limit as u64, + storage_bytes_unlimited: workspace_usage.storage_bytes_unlimited, + ai_responses_count: workspace_usage.ai_responses_count as u64, + ai_responses_count_limit: workspace_usage.ai_responses_count_limit as u64, + ai_responses_unlimited: workspace_usage.ai_responses_unlimited, + local_ai: workspace_usage.local_ai, }) } diff --git a/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs b/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs index 829b406c00..78c2fd8913 100644 --- a/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs +++ b/frontend/rust-lib/flowy-user/src/services/sqlite_sql/workspace_sql.rs @@ -1,4 +1,5 @@ use chrono::{TimeZone, Utc}; +use client_api::entity::billing_dto::{RecurringInterval, SubscriptionPlan}; use diesel::insert_into; use diesel::{RunQueryDsl, SqliteConnection}; use flowy_error::{FlowyError, FlowyResult}; @@ -7,8 +8,7 @@ use flowy_sqlite::schema::workspace_subscriptions_table; use flowy_sqlite::schema::workspace_subscriptions_table::dsl; use flowy_sqlite::DBConnection; use flowy_sqlite::{query_dsl::*, ExpressionMethods}; -use flowy_user_pub::entities::UserWorkspace; -use flowy_user_pub::entities::WorkspaceSubscription; +use flowy_user_pub::entities::{UserWorkspace, WorkspaceSubscription}; use std::convert::TryFrom; #[derive(Clone, Default, Queryable, Identifiable, Insertable)] @@ -118,16 +118,17 @@ pub fn upsert_workspace_subscription>( Ok(()) } -impl From for WorkspaceSubscription { - fn from(value: WorkspaceSubscriptionsTable) -> Self { - Self { +impl TryFrom for WorkspaceSubscription { + type Error = FlowyError; + fn try_from(value: WorkspaceSubscriptionsTable) -> Result { + Ok(Self { workspace_id: value.workspace_id, - subscription_plan: value.subscription_plan.into(), - recurring_interval: value.recurring_interval.into(), + subscription_plan: SubscriptionPlan::try_from(value.subscription_plan as i16)?, + recurring_interval: RecurringInterval::try_from(value.recurring_interval as i16)?, is_active: value.is_active, has_canceled: value.has_canceled, canceled_at: value.canceled_at, - } + }) } } diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs index 575a92fe2e..7b9c0483a5 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs @@ -1,4 +1,7 @@ use chrono::{Duration, NaiveDateTime, Utc}; +use client_api::entity::billing_dto::{ + RecurringInterval, SubscriptionPlan, WorkspaceUsageAndLimit, +}; use std::convert::TryFrom; use std::sync::Arc; @@ -11,9 +14,8 @@ use flowy_folder_pub::entities::{AppFlowyData, ImportData}; use flowy_sqlite::schema::user_workspace_table; use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods}; use flowy_user_pub::entities::{ - RecurringInterval, Role, SubscriptionPlan, UpdateUserProfileParams, UserWorkspace, - WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember, WorkspaceSubscription, - WorkspaceUsage, + Role, UpdateUserProfileParams, UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus, + WorkspaceMember, WorkspaceSubscription, }; use lib_dispatch::prelude::af_spawn; @@ -462,9 +464,9 @@ impl UserManager { } return Ok(vec![WorkspaceSubscription { - workspace_id: subscription.workspace_id, - subscription_plan: subscription.subscription_plan.into(), - recurring_interval: subscription.recurring_interval.into(), + workspace_id, + subscription_plan: SubscriptionPlan::try_from(subscription.subscription_plan as i16)?, + recurring_interval: RecurringInterval::try_from(subscription.recurring_interval as i16)?, is_active: subscription.is_active, has_canceled: subscription.has_canceled, canceled_at: subscription.canceled_at, @@ -480,25 +482,24 @@ impl UserManager { &self, uid: i64, ) -> FlowyResult> { - let subscriptions = self + let subscriptions: Vec = self .cloud_services .get_user_service()? .get_workspace_subscriptions() - .await?; + .await? + .into_iter() + .map(WorkspaceSubscription::from) + .collect(); for subscription in &subscriptions { let db = self.authenticate_user.get_sqlite_connection(uid)?; let record = WorkspaceSubscriptionsTable { - workspace_id: subscription.workspace_id.clone(), - subscription_plan: >::into( - subscription.subscription_plan.clone(), - ), - recurring_interval: >::into( - subscription.recurring_interval.clone(), - ), - is_active: subscription.is_active, - has_canceled: subscription.has_canceled, - canceled_at: subscription.canceled_at.clone().into(), + workspace_id: subscription.workspace_id.clone().into(), + subscription_plan: subscription.subscription_plan.clone() as i64, + recurring_interval: subscription.recurring_interval.clone() as i64, + is_active: subscription.canceled_at.is_none(), + has_canceled: subscription.canceled_at.is_some(), + canceled_at: subscription.canceled_at.into(), updated_at: Utc::now().naive_utc(), }; @@ -509,17 +510,24 @@ impl UserManager { } #[instrument(level = "info", skip(self), err)] - pub async fn cancel_workspace_subscription(&self, workspace_id: String) -> FlowyResult<()> { + pub async fn cancel_workspace_subscription( + &self, + workspace_id: String, + plan: SubscriptionPlan, + ) -> FlowyResult<()> { self .cloud_services .get_user_service()? - .cancel_workspace_subscription(workspace_id) + .cancel_workspace_subscription(workspace_id, plan) .await?; Ok(()) } #[instrument(level = "info", skip(self), err)] - pub async fn get_workspace_usage(&self, workspace_id: String) -> FlowyResult { + pub async fn get_workspace_usage( + &self, + workspace_id: String, + ) -> FlowyResult { let workspace_usage = self .cloud_services .get_user_service()?