mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: update api from billing
This commit is contained in:
parent
0802651546
commit
89f31b98d6
26
frontend/rust-lib/Cargo.lock
generated
26
frontend/rust-lib/Cargo.lock
generated
@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "app-error"
|
name = "app-error"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -183,7 +183,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "appflowy-ai-client"
|
name = "appflowy-ai-client"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -664,7 +664,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-api"
|
name = "client-api"
|
||||||
version = "0.2.0"
|
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 = [
|
dependencies = [
|
||||||
"again",
|
"again",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -685,6 +685,7 @@ dependencies = [
|
|||||||
"getrandom 0.2.10",
|
"getrandom 0.2.10",
|
||||||
"gotrue",
|
"gotrue",
|
||||||
"infra",
|
"infra",
|
||||||
|
"lazy_static",
|
||||||
"mime",
|
"mime",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
@ -713,7 +714,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-api-entity"
|
name = "client-api-entity"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"collab-entity",
|
"collab-entity",
|
||||||
"collab-rt-entity",
|
"collab-rt-entity",
|
||||||
@ -725,7 +726,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-websocket"
|
name = "client-websocket"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -934,7 +935,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-rt-entity"
|
name = "collab-rt-entity"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -959,7 +960,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-rt-protocol"
|
name = "collab-rt-protocol"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1276,7 +1277,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "database-entity"
|
name = "database-entity"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2240,6 +2241,7 @@ dependencies = [
|
|||||||
"base64 0.21.5",
|
"base64 0.21.5",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"client-api",
|
||||||
"collab",
|
"collab",
|
||||||
"collab-database",
|
"collab-database",
|
||||||
"collab-document",
|
"collab-document",
|
||||||
@ -2596,7 +2598,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gotrue"
|
name = "gotrue"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -2613,7 +2615,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gotrue-entity"
|
name = "gotrue-entity"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2978,7 +2980,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "infra"
|
name = "infra"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -5079,7 +5081,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "shared-entity"
|
name = "shared-entity"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
|
@ -99,8 +99,8 @@ validator = { version = "0.16.1", features = ["derive"] }
|
|||||||
# Run the script.add_workspace_members:
|
# Run the script.add_workspace_members:
|
||||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
client-api = { 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 = "9884d93aa2805013f36a79c1757174a0b5063065" }
|
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cba2248132de961f5dbab2a87c86b485dc701a56" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
@ -187,3 +187,9 @@ impl From<tokio::sync::oneshot::error::RecvError> for FlowyError {
|
|||||||
FlowyError::internal().with_context(e)
|
FlowyError::internal().with_context(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for FlowyError {
|
||||||
|
fn from(e: String) -> Self {
|
||||||
|
FlowyError::internal().with_context(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use client_api::entity::billing_dto::{
|
use client_api::entity::billing_dto::{
|
||||||
SubscriptionPlan, SubscriptionStatus, WorkspaceSubscriptionPlan, WorkspaceSubscriptionStatus,
|
RecurringInterval, SubscriptionPlan, WorkspaceSubscriptionStatus, WorkspaceUsageAndLimit,
|
||||||
};
|
};
|
||||||
use client_api::entity::workspace_dto::{
|
use client_api::entity::workspace_dto::{
|
||||||
CreateWorkspaceParam, PatchWorkspaceParam, WorkspaceMemberChangeset, WorkspaceMemberInvitation,
|
CreateWorkspaceParam, PatchWorkspaceParam, WorkspaceMemberChangeset, WorkspaceMemberInvitation,
|
||||||
@ -23,7 +23,6 @@ use flowy_user_pub::cloud::{UserCloudService, UserCollabParams, UserUpdate, User
|
|||||||
use flowy_user_pub::entities::{
|
use flowy_user_pub::entities::{
|
||||||
AFCloudOAuthParams, AuthResponse, Role, UpdateUserProfileParams, UserCredentials, UserProfile,
|
AFCloudOAuthParams, AuthResponse, Role, UpdateUserProfileParams, UserCredentials, UserProfile,
|
||||||
UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember,
|
UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember,
|
||||||
WorkspaceSubscription, WorkspaceUsage,
|
|
||||||
};
|
};
|
||||||
use lib_infra::box_any::BoxAny;
|
use lib_infra::box_any::BoxAny;
|
||||||
use lib_infra::future::FutureResult;
|
use lib_infra::future::FutureResult;
|
||||||
@ -476,19 +475,18 @@ where
|
|||||||
fn subscribe_workspace(
|
fn subscribe_workspace(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: String,
|
workspace_id: String,
|
||||||
recurring_interval: flowy_user_pub::entities::RecurringInterval,
|
recurring_interval: RecurringInterval,
|
||||||
workspace_subscription_plan: flowy_user_pub::entities::SubscriptionPlan,
|
subscription_plan: SubscriptionPlan,
|
||||||
success_url: String,
|
success_url: String,
|
||||||
) -> FutureResult<String, FlowyError> {
|
) -> FutureResult<String, FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
let workspace_id = workspace_id.to_string();
|
let workspace_id = workspace_id.to_string();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let subscription_plan = to_workspace_subscription_plan(workspace_subscription_plan)?;
|
|
||||||
let client = try_get_client?;
|
let client = try_get_client?;
|
||||||
let payment_link = client
|
let payment_link = client
|
||||||
.create_subscription(
|
.create_subscription(
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
to_recurring_interval(recurring_interval),
|
recurring_interval,
|
||||||
subscription_plan,
|
subscription_plan,
|
||||||
&success_url,
|
&success_url,
|
||||||
)
|
)
|
||||||
@ -525,40 +523,39 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_workspace_subscriptions(&self) -> FutureResult<Vec<WorkspaceSubscription>, FlowyError> {
|
fn get_workspace_subscriptions(
|
||||||
|
&self,
|
||||||
|
) -> FutureResult<Vec<WorkspaceSubscriptionStatus>, FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let client = try_get_client?;
|
let client = try_get_client?;
|
||||||
let workspace_subscriptions = client
|
let workspace_subscriptions = client.list_subscription().await?;
|
||||||
.list_subscription()
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.map(to_workspace_subscription)
|
|
||||||
.collect();
|
|
||||||
Ok(workspace_subscriptions)
|
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();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let client = try_get_client?;
|
let client = try_get_client?;
|
||||||
client.cancel_subscription(&workspace_id).await?;
|
client.cancel_subscription(&workspace_id, &plan).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_workspace_usage(&self, workspace_id: String) -> FutureResult<WorkspaceUsage, FlowyError> {
|
fn get_workspace_usage(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
) -> FutureResult<WorkspaceUsageAndLimit, FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let client = try_get_client?;
|
let client = try_get_client?;
|
||||||
let usage = client.get_billing_workspace_usage(&workspace_id).await?;
|
let usage = client.get_workspace_usage_and_limit(&workspace_id).await?;
|
||||||
Ok(WorkspaceUsage {
|
Ok(usage)
|
||||||
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,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,51 +692,3 @@ fn oauth_params_from_box_any(any: BoxAny) -> Result<AFCloudOAuthParams, FlowyErr
|
|||||||
sign_in_url: sign_in_url.to_string(),
|
sign_in_url: sign_in_url.to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_recurring_interval(
|
|
||||||
r: flowy_user_pub::entities::RecurringInterval,
|
|
||||||
) -> 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<SubscriptionPlan, FlowyError> {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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};
|
pub use client_api::entity::{AFWorkspaceSettings, AFWorkspaceSettingsChange};
|
||||||
use collab_entity::{CollabObject, CollabType};
|
use collab_entity::{CollabObject, CollabType};
|
||||||
use flowy_error::{internal_error, ErrorCode, FlowyError};
|
use flowy_error::{internal_error, ErrorCode, FlowyError};
|
||||||
@ -13,9 +17,8 @@ use tokio_stream::wrappers::WatchStream;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::entities::{
|
use crate::entities::{
|
||||||
AuthResponse, Authenticator, RecurringInterval, Role, SubscriptionPlan, UpdateUserProfileParams,
|
AuthResponse, Authenticator, Role, UpdateUserProfileParams, UserCredentials, UserProfile,
|
||||||
UserCredentials, UserProfile, UserTokenState, UserWorkspace, WorkspaceInvitation,
|
UserTokenState, UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember,
|
||||||
WorkspaceInvitationStatus, WorkspaceMember, WorkspaceSubscription, WorkspaceUsage,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -281,15 +284,24 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||||||
FutureResult::new(async { Err(FlowyError::not_support()) })
|
FutureResult::new(async { Err(FlowyError::not_support()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_workspace_subscriptions(&self) -> FutureResult<Vec<WorkspaceSubscription>, FlowyError> {
|
fn get_workspace_subscriptions(
|
||||||
|
&self,
|
||||||
|
) -> FutureResult<Vec<WorkspaceSubscriptionStatus>, FlowyError> {
|
||||||
FutureResult::new(async { Err(FlowyError::not_support()) })
|
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()) })
|
FutureResult::new(async { Err(FlowyError::not_support()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_workspace_usage(&self, workspace_id: String) -> FutureResult<WorkspaceUsage, FlowyError> {
|
fn get_workspace_usage(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
) -> FutureResult<WorkspaceUsageAndLimit, FlowyError> {
|
||||||
FutureResult::new(async { Err(FlowyError::not_support()) })
|
FutureResult::new(async { Err(FlowyError::not_support()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
use client_api::entity::billing_dto::{
|
||||||
|
RecurringInterval, SubscriptionPlan, SubscriptionStatus, WorkspaceSubscriptionStatus,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use serde_repr::*;
|
use serde_repr::*;
|
||||||
@ -453,59 +456,6 @@ pub struct WorkspaceInvitation {
|
|||||||
pub updated_at: DateTime<Utc>,
|
pub updated_at: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum RecurringInterval {
|
|
||||||
Month,
|
|
||||||
Year,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<i64> for RecurringInterval {
|
|
||||||
fn into(self) -> i64 {
|
|
||||||
match self {
|
|
||||||
RecurringInterval::Month => 0,
|
|
||||||
RecurringInterval::Year => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i64> 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<i64> for SubscriptionPlan {
|
|
||||||
fn into(self) -> i64 {
|
|
||||||
match self {
|
|
||||||
SubscriptionPlan::None => 0,
|
|
||||||
SubscriptionPlan::Pro => 1,
|
|
||||||
SubscriptionPlan::Team => 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i64> for SubscriptionPlan {
|
|
||||||
fn from(value: i64) -> Self {
|
|
||||||
match value {
|
|
||||||
0 => SubscriptionPlan::None,
|
|
||||||
1 => SubscriptionPlan::Pro,
|
|
||||||
2 => SubscriptionPlan::Team,
|
|
||||||
_ => SubscriptionPlan::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WorkspaceSubscription {
|
pub struct WorkspaceSubscription {
|
||||||
pub workspace_id: String,
|
pub workspace_id: String,
|
||||||
pub subscription_plan: SubscriptionPlan,
|
pub subscription_plan: SubscriptionPlan,
|
||||||
@ -515,9 +465,15 @@ pub struct WorkspaceSubscription {
|
|||||||
pub canceled_at: Option<i64>,
|
pub canceled_at: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WorkspaceUsage {
|
impl From<WorkspaceSubscriptionStatus> for WorkspaceSubscription {
|
||||||
pub member_count: usize,
|
fn from(sub_status: WorkspaceSubscriptionStatus) -> Self {
|
||||||
pub member_count_limit: usize,
|
WorkspaceSubscription {
|
||||||
pub total_blob_bytes: usize,
|
workspace_id: sub_status.workspace_id,
|
||||||
pub total_blob_bytes_limit: usize,
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ collab-user = { workspace = true }
|
|||||||
collab-entity = { workspace = true }
|
collab-entity = { workspace = true }
|
||||||
collab-plugins = { workspace = true }
|
collab-plugins = { workspace = true }
|
||||||
flowy-user-pub = { workspace = true }
|
flowy-user-pub = { workspace = true }
|
||||||
|
client-api = { workspace = true }
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
bytes.workspace = true
|
bytes.workspace = true
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
|
use client_api::entity::billing_dto::{RecurringInterval, SubscriptionPlan};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
use flowy_user_pub::cloud::{AFWorkspaceSettings, AFWorkspaceSettingsChange};
|
use flowy_user_pub::cloud::{AFWorkspaceSettings, AFWorkspaceSettingsChange};
|
||||||
use flowy_user_pub::entities::{
|
use flowy_user_pub::entities::{Role, WorkspaceInvitation, WorkspaceMember, WorkspaceSubscription};
|
||||||
RecurringInterval, Role, SubscriptionPlan, WorkspaceInvitation, WorkspaceMember,
|
|
||||||
WorkspaceSubscription,
|
|
||||||
};
|
|
||||||
use lib_infra::validator_fn::required_not_empty_str;
|
use lib_infra::validator_fn::required_not_empty_str;
|
||||||
|
|
||||||
#[derive(ProtoBuf, Default, Clone)]
|
#[derive(ProtoBuf, Default, Clone)]
|
||||||
@ -180,6 +178,16 @@ pub struct UserWorkspaceIdPB {
|
|||||||
pub workspace_id: String,
|
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)]
|
#[derive(ProtoBuf, Default, Clone)]
|
||||||
pub struct WorkspaceMemberIdPB {
|
pub struct WorkspaceMemberIdPB {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
@ -261,6 +269,9 @@ pub enum SubscriptionPlanPB {
|
|||||||
None = 0,
|
None = 0,
|
||||||
Pro = 1,
|
Pro = 1,
|
||||||
Team = 2,
|
Team = 2,
|
||||||
|
|
||||||
|
AiMax = 3,
|
||||||
|
AiLocal = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SubscriptionPlanPB> for SubscriptionPlan {
|
impl From<SubscriptionPlanPB> for SubscriptionPlan {
|
||||||
@ -268,7 +279,9 @@ impl From<SubscriptionPlanPB> for SubscriptionPlan {
|
|||||||
match value {
|
match value {
|
||||||
SubscriptionPlanPB::Pro => SubscriptionPlan::Pro,
|
SubscriptionPlanPB::Pro => SubscriptionPlan::Pro,
|
||||||
SubscriptionPlanPB::Team => SubscriptionPlan::Team,
|
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<SubscriptionPlan> for SubscriptionPlanPB {
|
|||||||
match value {
|
match value {
|
||||||
SubscriptionPlan::Pro => SubscriptionPlanPB::Pro,
|
SubscriptionPlan::Pro => SubscriptionPlanPB::Pro,
|
||||||
SubscriptionPlan::Team => SubscriptionPlanPB::Team,
|
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)]
|
#[pb(index = 2)]
|
||||||
pub member_count_limit: u64,
|
pub member_count_limit: u64,
|
||||||
#[pb(index = 3)]
|
#[pb(index = 3)]
|
||||||
pub total_blob_bytes: u64,
|
pub storage_bytes: u64,
|
||||||
#[pb(index = 4)]
|
#[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)]
|
#[derive(Debug, ProtoBuf, Default, Clone)]
|
||||||
|
@ -789,12 +789,14 @@ pub async fn get_workspace_subscriptions_handler(
|
|||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||||
pub async fn cancel_workspace_subscription_handler(
|
pub async fn cancel_workspace_subscription_handler(
|
||||||
param: AFPluginData<UserWorkspaceIdPB>,
|
param: AFPluginData<CancelWorkspaceSubscriptionPB>,
|
||||||
manager: AFPluginState<Weak<UserManager>>,
|
manager: AFPluginState<Weak<UserManager>>,
|
||||||
) -> Result<(), FlowyError> {
|
) -> Result<(), FlowyError> {
|
||||||
let workspace_id = param.into_inner().workspace_id;
|
let params = param.into_inner();
|
||||||
let manager = upgrade_manager(manager)?;
|
let manager = upgrade_manager(manager)?;
|
||||||
manager.cancel_workspace_subscription(workspace_id).await?;
|
manager
|
||||||
|
.cancel_workspace_subscription(params.workspace_id, params.plan.into())
|
||||||
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,8 +811,13 @@ pub async fn get_workspace_usage_handler(
|
|||||||
data_result_ok(WorkspaceUsagePB {
|
data_result_ok(WorkspaceUsagePB {
|
||||||
member_count: workspace_usage.member_count as u64,
|
member_count: workspace_usage.member_count as u64,
|
||||||
member_count_limit: workspace_usage.member_count_limit as u64,
|
member_count_limit: workspace_usage.member_count_limit as u64,
|
||||||
total_blob_bytes: workspace_usage.total_blob_bytes as u64,
|
storage_bytes: workspace_usage.storage_bytes as u64,
|
||||||
total_blob_bytes_limit: workspace_usage.total_blob_bytes_limit 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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
|
use client_api::entity::billing_dto::{RecurringInterval, SubscriptionPlan};
|
||||||
use diesel::insert_into;
|
use diesel::insert_into;
|
||||||
use diesel::{RunQueryDsl, SqliteConnection};
|
use diesel::{RunQueryDsl, SqliteConnection};
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
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::schema::workspace_subscriptions_table::dsl;
|
||||||
use flowy_sqlite::DBConnection;
|
use flowy_sqlite::DBConnection;
|
||||||
use flowy_sqlite::{query_dsl::*, ExpressionMethods};
|
use flowy_sqlite::{query_dsl::*, ExpressionMethods};
|
||||||
use flowy_user_pub::entities::UserWorkspace;
|
use flowy_user_pub::entities::{UserWorkspace, WorkspaceSubscription};
|
||||||
use flowy_user_pub::entities::WorkspaceSubscription;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
#[derive(Clone, Default, Queryable, Identifiable, Insertable)]
|
#[derive(Clone, Default, Queryable, Identifiable, Insertable)]
|
||||||
@ -118,16 +118,17 @@ pub fn upsert_workspace_subscription<T: Into<WorkspaceSubscriptionsTable>>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<WorkspaceSubscriptionsTable> for WorkspaceSubscription {
|
impl TryFrom<WorkspaceSubscriptionsTable> for WorkspaceSubscription {
|
||||||
fn from(value: WorkspaceSubscriptionsTable) -> Self {
|
type Error = FlowyError;
|
||||||
Self {
|
fn try_from(value: WorkspaceSubscriptionsTable) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
workspace_id: value.workspace_id,
|
workspace_id: value.workspace_id,
|
||||||
subscription_plan: value.subscription_plan.into(),
|
subscription_plan: SubscriptionPlan::try_from(value.subscription_plan as i16)?,
|
||||||
recurring_interval: value.recurring_interval.into(),
|
recurring_interval: RecurringInterval::try_from(value.recurring_interval as i16)?,
|
||||||
is_active: value.is_active,
|
is_active: value.is_active,
|
||||||
has_canceled: value.has_canceled,
|
has_canceled: value.has_canceled,
|
||||||
canceled_at: value.canceled_at,
|
canceled_at: value.canceled_at,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use chrono::{Duration, NaiveDateTime, Utc};
|
use chrono::{Duration, NaiveDateTime, Utc};
|
||||||
|
use client_api::entity::billing_dto::{
|
||||||
|
RecurringInterval, SubscriptionPlan, WorkspaceUsageAndLimit,
|
||||||
|
};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
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::schema::user_workspace_table;
|
||||||
use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods};
|
use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods};
|
||||||
use flowy_user_pub::entities::{
|
use flowy_user_pub::entities::{
|
||||||
RecurringInterval, Role, SubscriptionPlan, UpdateUserProfileParams, UserWorkspace,
|
Role, UpdateUserProfileParams, UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus,
|
||||||
WorkspaceInvitation, WorkspaceInvitationStatus, WorkspaceMember, WorkspaceSubscription,
|
WorkspaceMember, WorkspaceSubscription,
|
||||||
WorkspaceUsage,
|
|
||||||
};
|
};
|
||||||
use lib_dispatch::prelude::af_spawn;
|
use lib_dispatch::prelude::af_spawn;
|
||||||
|
|
||||||
@ -462,9 +464,9 @@ impl UserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Ok(vec![WorkspaceSubscription {
|
return Ok(vec![WorkspaceSubscription {
|
||||||
workspace_id: subscription.workspace_id,
|
workspace_id,
|
||||||
subscription_plan: subscription.subscription_plan.into(),
|
subscription_plan: SubscriptionPlan::try_from(subscription.subscription_plan as i16)?,
|
||||||
recurring_interval: subscription.recurring_interval.into(),
|
recurring_interval: RecurringInterval::try_from(subscription.recurring_interval as i16)?,
|
||||||
is_active: subscription.is_active,
|
is_active: subscription.is_active,
|
||||||
has_canceled: subscription.has_canceled,
|
has_canceled: subscription.has_canceled,
|
||||||
canceled_at: subscription.canceled_at,
|
canceled_at: subscription.canceled_at,
|
||||||
@ -480,25 +482,24 @@ impl UserManager {
|
|||||||
&self,
|
&self,
|
||||||
uid: i64,
|
uid: i64,
|
||||||
) -> FlowyResult<Vec<WorkspaceSubscription>> {
|
) -> FlowyResult<Vec<WorkspaceSubscription>> {
|
||||||
let subscriptions = self
|
let subscriptions: Vec<WorkspaceSubscription> = self
|
||||||
.cloud_services
|
.cloud_services
|
||||||
.get_user_service()?
|
.get_user_service()?
|
||||||
.get_workspace_subscriptions()
|
.get_workspace_subscriptions()
|
||||||
.await?;
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(WorkspaceSubscription::from)
|
||||||
|
.collect();
|
||||||
|
|
||||||
for subscription in &subscriptions {
|
for subscription in &subscriptions {
|
||||||
let db = self.authenticate_user.get_sqlite_connection(uid)?;
|
let db = self.authenticate_user.get_sqlite_connection(uid)?;
|
||||||
let record = WorkspaceSubscriptionsTable {
|
let record = WorkspaceSubscriptionsTable {
|
||||||
workspace_id: subscription.workspace_id.clone(),
|
workspace_id: subscription.workspace_id.clone().into(),
|
||||||
subscription_plan: <SubscriptionPlan as Into<i64>>::into(
|
subscription_plan: subscription.subscription_plan.clone() as i64,
|
||||||
subscription.subscription_plan.clone(),
|
recurring_interval: subscription.recurring_interval.clone() as i64,
|
||||||
),
|
is_active: subscription.canceled_at.is_none(),
|
||||||
recurring_interval: <RecurringInterval as Into<i64>>::into(
|
has_canceled: subscription.canceled_at.is_some(),
|
||||||
subscription.recurring_interval.clone(),
|
canceled_at: subscription.canceled_at.into(),
|
||||||
),
|
|
||||||
is_active: subscription.is_active,
|
|
||||||
has_canceled: subscription.has_canceled,
|
|
||||||
canceled_at: subscription.canceled_at.clone().into(),
|
|
||||||
updated_at: Utc::now().naive_utc(),
|
updated_at: Utc::now().naive_utc(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -509,17 +510,24 @@ impl UserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "info", skip(self), err)]
|
#[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
|
self
|
||||||
.cloud_services
|
.cloud_services
|
||||||
.get_user_service()?
|
.get_user_service()?
|
||||||
.cancel_workspace_subscription(workspace_id)
|
.cancel_workspace_subscription(workspace_id, plan)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "info", skip(self), err)]
|
#[instrument(level = "info", skip(self), err)]
|
||||||
pub async fn get_workspace_usage(&self, workspace_id: String) -> FlowyResult<WorkspaceUsage> {
|
pub async fn get_workspace_usage(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
) -> FlowyResult<WorkspaceUsageAndLimit> {
|
||||||
let workspace_usage = self
|
let workspace_usage = self
|
||||||
.cloud_services
|
.cloud_services
|
||||||
.get_user_service()?
|
.get_user_service()?
|
||||||
|
Loading…
Reference in New Issue
Block a user