296 lines
8.3 KiB
Dart
Raw Permalink Normal View History

import 'dart:async';
import 'package:flutter/foundation.dart';
feat: ai billing (#5741) * feat: start on AI plan+billing UI * chore: enable plan and billing * feat: cache workspace subscription + minor fixes (#5705) * feat: update api from billing * feat: add api for workspace subscription info (#5717) * feat: refactor and start integrating AI plans * feat: refine UI and add business logic for AI * feat: complete UIUX for AI and limits * chore: remove resolved todo * chore: localize remove addon dialog * chore: fix spacing issue for usage * fix: interpret subscription + usage on action * chore: update api for billing (#5735) * chore: update revisions * fix: remove subscription cache * fix: copy improvements + use consistent dialog * chore: update to the latest client api * feat: support updating billing period * Feat/ai billing cancel reason (#5752) * chore: add cancellation reason field * fix: ci add one retry for concurrent sign up * chore: merge with main * chore: half merge * chore: fix conflict * chore: observer error * chore: remove unneeded protobuf and remove unwrap * feat: added subscription plan details * chore: check error code and update sidebar toast * chore: periodically check billing state * chore: editor ai error * chore: return file upload error * chore: fmt * chore: clippy * chore: disable upload image when exceed storage limitation * chore: remove todo * chore: remove openai i18n * chore: update log * chore: update client-api to fix stream error * chore: clippy * chore: fix language file * chore: disable billing UI --------- Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg> Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 09:43:48 +02:00
import 'package:appflowy/workspace/application/settings/plan/workspace_subscription_ext.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:fixnum/fixnum.dart';
abstract class IUserBackendService {
feat: ai billing (#5741) * feat: start on AI plan+billing UI * chore: enable plan and billing * feat: cache workspace subscription + minor fixes (#5705) * feat: update api from billing * feat: add api for workspace subscription info (#5717) * feat: refactor and start integrating AI plans * feat: refine UI and add business logic for AI * feat: complete UIUX for AI and limits * chore: remove resolved todo * chore: localize remove addon dialog * chore: fix spacing issue for usage * fix: interpret subscription + usage on action * chore: update api for billing (#5735) * chore: update revisions * fix: remove subscription cache * fix: copy improvements + use consistent dialog * chore: update to the latest client api * feat: support updating billing period * Feat/ai billing cancel reason (#5752) * chore: add cancellation reason field * fix: ci add one retry for concurrent sign up * chore: merge with main * chore: half merge * chore: fix conflict * chore: observer error * chore: remove unneeded protobuf and remove unwrap * feat: added subscription plan details * chore: check error code and update sidebar toast * chore: periodically check billing state * chore: editor ai error * chore: return file upload error * chore: fmt * chore: clippy * chore: disable upload image when exceed storage limitation * chore: remove todo * chore: remove openai i18n * chore: update log * chore: update client-api to fix stream error * chore: clippy * chore: fix language file * chore: disable billing UI --------- Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg> Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 09:43:48 +02:00
Future<FlowyResult<void, FlowyError>> cancelSubscription(
String workspaceId,
SubscriptionPlanPB plan,
String? reason,
feat: ai billing (#5741) * feat: start on AI plan+billing UI * chore: enable plan and billing * feat: cache workspace subscription + minor fixes (#5705) * feat: update api from billing * feat: add api for workspace subscription info (#5717) * feat: refactor and start integrating AI plans * feat: refine UI and add business logic for AI * feat: complete UIUX for AI and limits * chore: remove resolved todo * chore: localize remove addon dialog * chore: fix spacing issue for usage * fix: interpret subscription + usage on action * chore: update api for billing (#5735) * chore: update revisions * fix: remove subscription cache * fix: copy improvements + use consistent dialog * chore: update to the latest client api * feat: support updating billing period * Feat/ai billing cancel reason (#5752) * chore: add cancellation reason field * fix: ci add one retry for concurrent sign up * chore: merge with main * chore: half merge * chore: fix conflict * chore: observer error * chore: remove unneeded protobuf and remove unwrap * feat: added subscription plan details * chore: check error code and update sidebar toast * chore: periodically check billing state * chore: editor ai error * chore: return file upload error * chore: fmt * chore: clippy * chore: disable upload image when exceed storage limitation * chore: remove todo * chore: remove openai i18n * chore: update log * chore: update client-api to fix stream error * chore: clippy * chore: fix language file * chore: disable billing UI --------- Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg> Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 09:43:48 +02:00
);
Future<FlowyResult<PaymentLinkPB, FlowyError>> createSubscription(
String workspaceId,
SubscriptionPlanPB plan,
);
}
const _baseBetaUrl = 'https://beta.appflowy.com';
const _baseProdUrl = 'https://appflowy.com';
class UserBackendService implements IUserBackendService {
UserBackendService({required this.userId});
final Int64 userId;
static Future<FlowyResult<UserProfilePB, FlowyError>>
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
getCurrentUserProfile() async {
final result = await UserEventGetUserProfile().send();
return result;
}
Future<FlowyResult<void, FlowyError>> updateUserProfile({
String? name,
String? password,
String? email,
2022-08-08 22:19:05 +08:00
String? iconUrl,
String? openAIKey,
String? stabilityAiKey,
}) {
final payload = UpdateUserProfilePayloadPB.create()..id = userId;
if (name != null) {
payload.name = name;
}
if (password != null) {
payload.password = password;
}
if (email != null) {
payload.email = email;
}
2022-08-08 22:19:05 +08:00
if (iconUrl != null) {
payload.iconUrl = iconUrl;
2022-08-06 22:31:55 +08:00
}
if (openAIKey != null) {
payload.openaiKey = openAIKey;
}
if (stabilityAiKey != null) {
payload.stabilityAiKey = stabilityAiKey;
}
return UserEventUpdateUserProfile(payload).send();
}
Future<FlowyResult<void, FlowyError>> deleteWorkspace({
required String workspaceId,
}) {
throw UnimplementedError();
}
static Future<FlowyResult<UserProfilePB, FlowyError>> signInWithMagicLink(
String email,
String redirectTo,
) async {
final payload = MagicLinkSignInPB(email: email, redirectTo: redirectTo);
return UserEventMagicLinkSignIn(payload).send();
}
static Future<FlowyResult<void, FlowyError>> signOut() {
return UserEventSignOut().send();
}
Future<FlowyResult<void, FlowyError>> initUser() async {
return UserEventInitUser().send();
}
static Future<FlowyResult<UserProfilePB, FlowyError>> getAnonUser() async {
return UserEventGetAnonUser().send();
}
static Future<FlowyResult<void, FlowyError>> openAnonUser() async {
return UserEventOpenAnonUser().send();
}
Future<FlowyResult<List<UserWorkspacePB>, FlowyError>> getWorkspaces() {
return UserEventGetAllWorkspace().send().then((value) {
return value.fold(
(workspaces) => FlowyResult.success(workspaces.items),
(error) => FlowyResult.failure(error),
);
});
}
Future<FlowyResult<void, FlowyError>> openWorkspace(String workspaceId) {
final payload = UserWorkspaceIdPB.create()..workspaceId = workspaceId;
return UserEventOpenWorkspace(payload).send();
}
static Future<FlowyResult<WorkspacePB, FlowyError>> getCurrentWorkspace() {
return FolderEventReadCurrentWorkspace().send().then((result) {
return result.fold(
(workspace) => FlowyResult.success(workspace),
(error) => FlowyResult.failure(error),
);
});
}
Future<FlowyResult<WorkspacePB, FlowyError>> createWorkspace(
String name,
String desc,
) {
2022-07-19 14:11:29 +08:00
final request = CreateWorkspacePayloadPB.create()
..name = name
..desc = desc;
return FolderEventCreateFolderWorkspace(request).send().then((result) {
return result.fold(
(workspace) => FlowyResult.success(workspace),
(error) => FlowyResult.failure(error),
);
});
}
Future<FlowyResult<UserWorkspacePB, FlowyError>> createUserWorkspace(
String name,
) {
final request = CreateWorkspacePB.create()..name = name;
return UserEventCreateWorkspace(request).send();
}
Future<FlowyResult<void, FlowyError>> deleteWorkspaceById(
String workspaceId,
) {
final request = UserWorkspaceIdPB.create()..workspaceId = workspaceId;
return UserEventDeleteWorkspace(request).send();
}
Future<FlowyResult<void, FlowyError>> renameWorkspace(
String workspaceId,
String name,
) {
final request = RenameWorkspacePB()
..workspaceId = workspaceId
..newName = name;
return UserEventRenameWorkspace(request).send();
}
Future<FlowyResult<void, FlowyError>> updateWorkspaceIcon(
String workspaceId,
String icon,
) {
final request = ChangeWorkspaceIconPB()
..workspaceId = workspaceId
..newIcon = icon;
return UserEventChangeWorkspaceIcon(request).send();
}
2024-03-21 11:02:03 +07:00
Future<FlowyResult<RepeatedWorkspaceMemberPB, FlowyError>>
getWorkspaceMembers(
String workspaceId,
) async {
final data = QueryWorkspacePB()..workspaceId = workspaceId;
return UserEventGetWorkspaceMembers(data).send();
2024-03-21 11:02:03 +07:00
}
Future<FlowyResult<void, FlowyError>> addWorkspaceMember(
String workspaceId,
String email,
) async {
final data = AddWorkspaceMemberPB()
..workspaceId = workspaceId
..email = email;
return UserEventAddWorkspaceMember(data).send();
}
Future<FlowyResult<void, FlowyError>> inviteWorkspaceMember(
String workspaceId,
String email, {
AFRolePB? role,
}) async {
final data = WorkspaceMemberInvitationPB()
..workspaceId = workspaceId
..inviteeEmail = email;
if (role != null) {
data.role = role;
}
return UserEventInviteWorkspaceMember(data).send();
}
2024-03-21 11:02:03 +07:00
Future<FlowyResult<void, FlowyError>> removeWorkspaceMember(
String workspaceId,
String email,
) async {
final data = RemoveWorkspaceMemberPB()
..workspaceId = workspaceId
..email = email;
return UserEventRemoveWorkspaceMember(data).send();
}
Future<FlowyResult<void, FlowyError>> updateWorkspaceMember(
String workspaceId,
String email,
AFRolePB role,
) async {
final data = UpdateWorkspaceMemberPB()
..workspaceId = workspaceId
..email = email
..role = role;
return UserEventUpdateWorkspaceMember(data).send();
}
Future<FlowyResult<void, FlowyError>> leaveWorkspace(
String workspaceId,
) async {
final data = UserWorkspaceIdPB.create()..workspaceId = workspaceId;
return UserEventLeaveWorkspace(data).send();
}
feat: ai billing (#5741) * feat: start on AI plan+billing UI * chore: enable plan and billing * feat: cache workspace subscription + minor fixes (#5705) * feat: update api from billing * feat: add api for workspace subscription info (#5717) * feat: refactor and start integrating AI plans * feat: refine UI and add business logic for AI * feat: complete UIUX for AI and limits * chore: remove resolved todo * chore: localize remove addon dialog * chore: fix spacing issue for usage * fix: interpret subscription + usage on action * chore: update api for billing (#5735) * chore: update revisions * fix: remove subscription cache * fix: copy improvements + use consistent dialog * chore: update to the latest client api * feat: support updating billing period * Feat/ai billing cancel reason (#5752) * chore: add cancellation reason field * fix: ci add one retry for concurrent sign up * chore: merge with main * chore: half merge * chore: fix conflict * chore: observer error * chore: remove unneeded protobuf and remove unwrap * feat: added subscription plan details * chore: check error code and update sidebar toast * chore: periodically check billing state * chore: editor ai error * chore: return file upload error * chore: fmt * chore: clippy * chore: disable upload image when exceed storage limitation * chore: remove todo * chore: remove openai i18n * chore: update log * chore: update client-api to fix stream error * chore: clippy * chore: fix language file * chore: disable billing UI --------- Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg> Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 09:43:48 +02:00
static Future<FlowyResult<WorkspaceSubscriptionInfoPB, FlowyError>>
getWorkspaceSubscriptionInfo(String workspaceId) {
final params = UserWorkspaceIdPB.create()..workspaceId = workspaceId;
return UserEventGetWorkspaceSubscriptionInfo(params).send();
}
Future<FlowyResult<WorkspaceMemberPB, FlowyError>>
getWorkspaceMember() async {
final data = WorkspaceMemberIdPB.create()..uid = userId;
return UserEventGetMemberInfo(data).send();
}
@override
Future<FlowyResult<PaymentLinkPB, FlowyError>> createSubscription(
String workspaceId,
SubscriptionPlanPB plan,
) {
final request = SubscribeWorkspacePB()
..workspaceId = workspaceId
..recurringInterval = RecurringIntervalPB.Year
..workspaceSubscriptionPlan = plan
..successUrl =
'${kDebugMode ? _baseBetaUrl : _baseProdUrl}/after-payment?plan=${plan.toRecognizable()}';
return UserEventSubscribeWorkspace(request).send();
}
@override
Future<FlowyResult<void, FlowyError>> cancelSubscription(
String workspaceId,
SubscriptionPlanPB plan, [
String? reason,
]) {
feat: ai billing (#5741) * feat: start on AI plan+billing UI * chore: enable plan and billing * feat: cache workspace subscription + minor fixes (#5705) * feat: update api from billing * feat: add api for workspace subscription info (#5717) * feat: refactor and start integrating AI plans * feat: refine UI and add business logic for AI * feat: complete UIUX for AI and limits * chore: remove resolved todo * chore: localize remove addon dialog * chore: fix spacing issue for usage * fix: interpret subscription + usage on action * chore: update api for billing (#5735) * chore: update revisions * fix: remove subscription cache * fix: copy improvements + use consistent dialog * chore: update to the latest client api * feat: support updating billing period * Feat/ai billing cancel reason (#5752) * chore: add cancellation reason field * fix: ci add one retry for concurrent sign up * chore: merge with main * chore: half merge * chore: fix conflict * chore: observer error * chore: remove unneeded protobuf and remove unwrap * feat: added subscription plan details * chore: check error code and update sidebar toast * chore: periodically check billing state * chore: editor ai error * chore: return file upload error * chore: fmt * chore: clippy * chore: disable upload image when exceed storage limitation * chore: remove todo * chore: remove openai i18n * chore: update log * chore: update client-api to fix stream error * chore: clippy * chore: fix language file * chore: disable billing UI --------- Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg> Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 09:43:48 +02:00
final request = CancelWorkspaceSubscriptionPB()
..workspaceId = workspaceId
..plan = plan;
if (reason != null) {
request.reason = reason;
}
return UserEventCancelWorkspaceSubscription(request).send();
}
feat: ai billing (#5741) * feat: start on AI plan+billing UI * chore: enable plan and billing * feat: cache workspace subscription + minor fixes (#5705) * feat: update api from billing * feat: add api for workspace subscription info (#5717) * feat: refactor and start integrating AI plans * feat: refine UI and add business logic for AI * feat: complete UIUX for AI and limits * chore: remove resolved todo * chore: localize remove addon dialog * chore: fix spacing issue for usage * fix: interpret subscription + usage on action * chore: update api for billing (#5735) * chore: update revisions * fix: remove subscription cache * fix: copy improvements + use consistent dialog * chore: update to the latest client api * feat: support updating billing period * Feat/ai billing cancel reason (#5752) * chore: add cancellation reason field * fix: ci add one retry for concurrent sign up * chore: merge with main * chore: half merge * chore: fix conflict * chore: observer error * chore: remove unneeded protobuf and remove unwrap * feat: added subscription plan details * chore: check error code and update sidebar toast * chore: periodically check billing state * chore: editor ai error * chore: return file upload error * chore: fmt * chore: clippy * chore: disable upload image when exceed storage limitation * chore: remove todo * chore: remove openai i18n * chore: update log * chore: update client-api to fix stream error * chore: clippy * chore: fix language file * chore: disable billing UI --------- Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg> Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 09:43:48 +02:00
Future<FlowyResult<void, FlowyError>> updateSubscriptionPeriod(
String workspaceId,
SubscriptionPlanPB plan,
RecurringIntervalPB interval,
) {
final request = UpdateWorkspaceSubscriptionPaymentPeriodPB()
..workspaceId = workspaceId
..plan = plan
..recurringInterval = interval;
return UserEventUpdateWorkspaceSubscriptionPaymentPeriod(request).send();
}
}