mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: show server url (#3956)
* chore: data folder for cloud * chore: display server url * chore: fix test
This commit is contained in:
@ -1,15 +1,18 @@
|
|||||||
# Initial Setup
|
# Copy the 'dev.env' file to '.env':
|
||||||
|
# Use the command 'cp dev.env .env' to create a copy of 'dev.env' named '.env'.
|
||||||
|
# After copying, update the '.env' file with the necessary environment parameters.
|
||||||
|
|
||||||
# 1. Copy the dev.env file to .env:
|
# Generate the 'env.dart' from this '.env' file:
|
||||||
# cp dev.env .env
|
# Option 1: Use the "Generate Env File" task in VSCode.
|
||||||
# Update the environment parameters as needed.
|
# Option 2: Execute the commands in the appflowy_flutter directory:
|
||||||
|
|
||||||
# 2. Generate the env.dart from this .env file:
|
|
||||||
# You can use the "Generate Env File" task in VSCode.
|
|
||||||
# Alternatively, execute the following commands:
|
|
||||||
# cd appflowy_flutter
|
# cd appflowy_flutter
|
||||||
# dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
|
# dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
|
||||||
|
|
||||||
|
# Note on Configuration Priority:
|
||||||
|
# If both Supabase config and AppFlowy cloud config are provided in the '.env' file,
|
||||||
|
# the AppFlowy cloud config will be prioritized and the Supabase config ignored.
|
||||||
|
# Ensure only one of these configurations is active at any given time.
|
||||||
|
|
||||||
|
|
||||||
# Cloud Type Configuration
|
# Cloud Type Configuration
|
||||||
# Use this configuration file to specify the cloud type and its associated settings. The available cloud types are:
|
# Use this configuration file to specify the cloud type and its associated settings. The available cloud types are:
|
||||||
@ -25,17 +28,9 @@ SUPABASE_URL=
|
|||||||
SUPABASE_ANON_KEY=
|
SUPABASE_ANON_KEY=
|
||||||
|
|
||||||
# AppFlowy Cloud Configuration
|
# AppFlowy Cloud Configuration
|
||||||
# If using AppFlowy Cloud (CLOUD_TYPE=2), provide the following details:
|
# If using Supabase (CLOUD_TYPE=2), provide the following details:
|
||||||
# For instance:
|
|
||||||
# APPFLOWY_CLOUD_BASE_URL=https://xxxxxxxxx
|
|
||||||
# APPFLOWY_CLOUD_WS_BASE_URL=wss://xxxxxxxxx
|
|
||||||
# APPFLOWY_CLOUD_GOTRUE_URL=https://xxxxxxxxx
|
|
||||||
#
|
#
|
||||||
# When using localhost for development, you must run AppFlowy Cloud locally
|
# When using localhost for development. you can use the following settings:
|
||||||
# first. Plese Please follow the instructions below:
|
|
||||||
# https://github.com/AppFlowy-IO/AppFlowy-Cloud#development
|
|
||||||
#
|
|
||||||
# After running AppFlowy Cloud locally, you can use the following settings:
|
|
||||||
# APPFLOWY_CLOUD_BASE_URL=http://localhost:8000
|
# APPFLOWY_CLOUD_BASE_URL=http://localhost:8000
|
||||||
# APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws
|
# APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws
|
||||||
# APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998
|
# APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998
|
||||||
|
@ -39,7 +39,7 @@ void main() {
|
|||||||
|
|
||||||
// should not see the sync setting page when sign in as annoymous
|
// should not see the sync setting page when sign in as annoymous
|
||||||
await tester.openSettings();
|
await tester.openSettings();
|
||||||
await tester.expectNoSettingsPage(SettingsPage.syncSetting);
|
await tester.expectNoSettingsPage(SettingsPage.cloud);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('enable encryption', (tester) async {
|
testWidgets('enable encryption', (tester) async {
|
||||||
@ -48,7 +48,7 @@ void main() {
|
|||||||
|
|
||||||
// Open the setting page and sign out
|
// Open the setting page and sign out
|
||||||
await tester.openSettings();
|
await tester.openSettings();
|
||||||
await tester.openSettingsPage(SettingsPage.syncSetting);
|
await tester.openSettingsPage(SettingsPage.cloud);
|
||||||
|
|
||||||
// the switch should be off by default
|
// the switch should be off by default
|
||||||
tester.assertEnableEncryptSwitchValue(false);
|
tester.assertEnableEncryptSwitchValue(false);
|
||||||
@ -68,7 +68,7 @@ void main() {
|
|||||||
|
|
||||||
// Open the setting page and sign out
|
// Open the setting page and sign out
|
||||||
await tester.openSettings();
|
await tester.openSettings();
|
||||||
await tester.openSettingsPage(SettingsPage.syncSetting);
|
await tester.openSettingsPage(SettingsPage.cloud);
|
||||||
|
|
||||||
// the switch should be on by default
|
// the switch should be on by default
|
||||||
tester.assertEnableSyncSwitchValue(true);
|
tester.assertEnableSyncSwitchValue(true);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
|
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/sync_setting_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/setting_cloud_view.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
@ -70,9 +70,8 @@ class DartKeyValue implements KeyValueStorage {
|
|||||||
|
|
||||||
/// Key-value store
|
/// Key-value store
|
||||||
/// The data is stored in the local storage of the device.
|
/// The data is stored in the local storage of the device.
|
||||||
class RustKeyValue implements KeyValueStorage {
|
class RustKeyValue {
|
||||||
@override
|
static Future<void> set(String key, String value) async {
|
||||||
Future<void> set(String key, String value) async {
|
|
||||||
await ConfigEventSetKeyValue(
|
await ConfigEventSetKeyValue(
|
||||||
KeyValuePB.create()
|
KeyValuePB.create()
|
||||||
..key = key
|
..key = key
|
||||||
@ -80,15 +79,13 @@ class RustKeyValue implements KeyValueStorage {
|
|||||||
).send();
|
).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
static Future<Either<FlowyError, String>> get(String key) async {
|
||||||
Future<Either<FlowyError, String>> get(String key) async {
|
|
||||||
final payload = KeyPB.create()..key = key;
|
final payload = KeyPB.create()..key = key;
|
||||||
final response = await ConfigEventGetKeyValue(payload).send();
|
final response = await ConfigEventGetKeyValue(payload).send();
|
||||||
return response.swap().map((r) => r.value);
|
return response.swap().map((r) => r.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
static Future<Either<FlowyError, T>> getWithFormat<T>(
|
||||||
Future<Either<FlowyError, T>> getWithFormat<T>(
|
|
||||||
String key,
|
String key,
|
||||||
T Function(String value) formatter,
|
T Function(String value) formatter,
|
||||||
) async {
|
) async {
|
||||||
@ -99,15 +96,9 @@ class RustKeyValue implements KeyValueStorage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
static Future<void> remove(String key) async {
|
||||||
Future<void> remove(String key) async {
|
|
||||||
await ConfigEventRemoveKeyValue(
|
await ConfigEventRemoveKeyValue(
|
||||||
KeyPB.create()..key = key,
|
KeyPB.create()..key = key,
|
||||||
).send();
|
).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> clear() async {
|
|
||||||
// TODO(Lucas): implement clear
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,6 @@ class KVKeys {
|
|||||||
/// The key for the path location of the local data for the whole app.
|
/// The key for the path location of the local data for the whole app.
|
||||||
static const String pathLocation = '$prefix.path_location';
|
static const String pathLocation = '$prefix.path_location';
|
||||||
|
|
||||||
/// The key for the last time login type.
|
|
||||||
///
|
|
||||||
/// The value is one of the following:
|
|
||||||
/// - local
|
|
||||||
/// - supabase
|
|
||||||
static const String loginType = '$prefix.login_type';
|
|
||||||
|
|
||||||
/// The key for saving the window size
|
/// The key for saving the window size
|
||||||
///
|
///
|
||||||
/// The value is a json string with the following format:
|
/// The value is a json string with the following format:
|
||||||
|
@ -5,10 +5,12 @@ part 'backend_env.g.dart';
|
|||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class AppFlowyEnv {
|
class AppFlowyEnv {
|
||||||
|
final int cloud_type;
|
||||||
final SupabaseConfiguration supabase_config;
|
final SupabaseConfiguration supabase_config;
|
||||||
final AppFlowyCloudConfiguration appflowy_cloud_config;
|
final AppFlowyCloudConfiguration appflowy_cloud_config;
|
||||||
|
|
||||||
AppFlowyEnv({
|
AppFlowyEnv({
|
||||||
|
required this.cloud_type,
|
||||||
required this.supabase_config,
|
required this.supabase_config,
|
||||||
required this.appflowy_cloud_config,
|
required this.appflowy_cloud_config,
|
||||||
});
|
});
|
||||||
@ -22,12 +24,10 @@ class AppFlowyEnv {
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class SupabaseConfiguration {
|
class SupabaseConfiguration {
|
||||||
/// Indicates whether the sync feature is enabled.
|
/// Indicates whether the sync feature is enabled.
|
||||||
final bool enable_sync;
|
|
||||||
final String url;
|
final String url;
|
||||||
final String anon_key;
|
final String anon_key;
|
||||||
|
|
||||||
SupabaseConfiguration({
|
SupabaseConfiguration({
|
||||||
this.enable_sync = true,
|
|
||||||
required this.url,
|
required this.url,
|
||||||
required this.anon_key,
|
required this.anon_key,
|
||||||
});
|
});
|
||||||
|
@ -34,22 +34,38 @@ class InitRustSDKTask extends LaunchTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AppFlowyEnv getAppFlowyEnv() {
|
AppFlowyEnv getAppFlowyEnv() {
|
||||||
final supabaseConfig = SupabaseConfiguration(
|
if (isCloudEnabled) {
|
||||||
enable_sync: true,
|
final supabaseConfig = SupabaseConfiguration(
|
||||||
url: Env.supabaseUrl,
|
url: Env.supabaseUrl,
|
||||||
anon_key: Env.supabaseAnonKey,
|
anon_key: Env.supabaseAnonKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
final appflowyCloudConfig = AppFlowyCloudConfiguration(
|
final appflowyCloudConfig = AppFlowyCloudConfiguration(
|
||||||
base_url: Env.afCloudBaseUrl,
|
base_url: Env.afCloudBaseUrl,
|
||||||
ws_base_url: Env.afCloudWSBaseUrl,
|
ws_base_url: Env.afCloudWSBaseUrl,
|
||||||
gotrue_url: Env.afCloudGoTrueUrl,
|
gotrue_url: Env.afCloudGoTrueUrl,
|
||||||
);
|
);
|
||||||
|
|
||||||
return AppFlowyEnv(
|
return AppFlowyEnv(
|
||||||
supabase_config: supabaseConfig,
|
cloud_type: Env.cloudType,
|
||||||
appflowy_cloud_config: appflowyCloudConfig,
|
supabase_config: supabaseConfig,
|
||||||
);
|
appflowy_cloud_config: appflowyCloudConfig,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Use the default configuration if the cloud feature is disabled
|
||||||
|
final supabaseConfig = SupabaseConfiguration(url: '', anon_key: '');
|
||||||
|
final appflowyCloudConfig = AppFlowyCloudConfiguration(
|
||||||
|
base_url: '',
|
||||||
|
ws_base_url: '',
|
||||||
|
gotrue_url: '',
|
||||||
|
);
|
||||||
|
|
||||||
|
return AppFlowyEnv(
|
||||||
|
cloud_type: 0,
|
||||||
|
supabase_config: supabaseConfig,
|
||||||
|
appflowy_cloud_config: appflowyCloudConfig,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The default directory to store the user data. The directory can be
|
/// The default directory to store the user data. The directory can be
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'package:appflowy/core/config/kv.dart';
|
|
||||||
import 'package:appflowy/core/config/kv_keys.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/user/application/historical_user_bloc.dart';
|
import 'package:appflowy/user/application/historical_user_bloc.dart';
|
||||||
@ -41,7 +39,6 @@ class SignInAnonymousButton extends StatelessWidget {
|
|||||||
: LocaleKeys.signIn_continueAnonymousUser.tr();
|
: LocaleKeys.signIn_continueAnonymousUser.tr();
|
||||||
final onTap = state.historicalUsers.isEmpty
|
final onTap = state.historicalUsers.isEmpty
|
||||||
? () {
|
? () {
|
||||||
getIt<KeyValueStorage>().set(KVKeys.loginType, 'local');
|
|
||||||
context
|
context
|
||||||
.read<SignInBloc>()
|
.read<SignInBloc>()
|
||||||
.add(const SignInEvent.signedInAsGuest());
|
.add(const SignInEvent.signedInAsGuest());
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import 'package:appflowy/core/config/kv.dart';
|
|
||||||
import 'package:appflowy/core/config/kv_keys.dart';
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/user/application/sign_in_bloc.dart';
|
import 'package:appflowy/user/application/sign_in_bloc.dart';
|
||||||
import 'package:appflowy/user/presentation/presentation.dart';
|
import 'package:appflowy/user/presentation/presentation.dart';
|
||||||
import 'package:appflowy/util/platform_extension.dart';
|
import 'package:appflowy/util/platform_extension.dart';
|
||||||
@ -165,19 +162,16 @@ class _ThirdPartySignInButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _signInWithGoogle(BuildContext context) {
|
void _signInWithGoogle(BuildContext context) {
|
||||||
getIt<KeyValueStorage>().set(KVKeys.loginType, 'supabase');
|
|
||||||
context.read<SignInBloc>().add(
|
context.read<SignInBloc>().add(
|
||||||
const SignInEvent.signedInWithOAuth('google'),
|
const SignInEvent.signedInWithOAuth('google'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _signInWithGithub(BuildContext context) {
|
void _signInWithGithub(BuildContext context) {
|
||||||
getIt<KeyValueStorage>().set(KVKeys.loginType, 'supabase');
|
|
||||||
context.read<SignInBloc>().add(const SignInEvent.signedInWithOAuth('github'));
|
context.read<SignInBloc>().add(const SignInEvent.signedInWithOAuth('github'));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _signInWithDiscord(BuildContext context) {
|
void _signInWithDiscord(BuildContext context) {
|
||||||
getIt<KeyValueStorage>().set(KVKeys.loginType, 'supabase');
|
|
||||||
context
|
context
|
||||||
.read<SignInBloc>()
|
.read<SignInBloc>()
|
||||||
.add(const SignInEvent.signedInWithOAuth('discord'));
|
.add(const SignInEvent.signedInWithOAuth('discord'));
|
||||||
|
@ -12,7 +12,7 @@ import '../../../core/notification/user_notification.dart';
|
|||||||
class UserCloudConfigListener {
|
class UserCloudConfigListener {
|
||||||
final String userId;
|
final String userId;
|
||||||
StreamSubscription<SubscribeObject>? _subscription;
|
StreamSubscription<SubscribeObject>? _subscription;
|
||||||
void Function(Either<UserCloudConfigPB, FlowyError>)? _onSettingChanged;
|
void Function(Either<CloudSettingPB, FlowyError>)? _onSettingChanged;
|
||||||
|
|
||||||
UserNotificationParser? _userParser;
|
UserNotificationParser? _userParser;
|
||||||
UserCloudConfigListener({
|
UserCloudConfigListener({
|
||||||
@ -20,7 +20,7 @@ class UserCloudConfigListener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
void start({
|
void start({
|
||||||
void Function(Either<UserCloudConfigPB, FlowyError>)? onSettingChanged,
|
void Function(Either<CloudSettingPB, FlowyError>)? onSettingChanged,
|
||||||
}) {
|
}) {
|
||||||
_onSettingChanged = onSettingChanged;
|
_onSettingChanged = onSettingChanged;
|
||||||
_userParser = UserNotificationParser(
|
_userParser = UserNotificationParser(
|
||||||
@ -45,8 +45,8 @@ class UserCloudConfigListener {
|
|||||||
switch (ty) {
|
switch (ty) {
|
||||||
case UserNotification.DidUpdateCloudConfig:
|
case UserNotification.DidUpdateCloudConfig:
|
||||||
result.fold(
|
result.fold(
|
||||||
(payload) => _onSettingChanged
|
(payload) =>
|
||||||
?.call(left(UserCloudConfigPB.fromBuffer(payload))),
|
_onSettingChanged?.call(left(CloudSettingPB.fromBuffer(payload))),
|
||||||
(error) => _onSettingChanged?.call(right(error)),
|
(error) => _onSettingChanged?.call(right(error)),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,7 @@ class CloudSettingBloc extends Bloc<CloudSettingEvent, CloudSettingState> {
|
|||||||
|
|
||||||
CloudSettingBloc({
|
CloudSettingBloc({
|
||||||
required String userId,
|
required String userId,
|
||||||
required UserCloudConfigPB config,
|
required CloudSettingPB config,
|
||||||
}) : _listener = UserCloudConfigListener(userId: userId),
|
}) : _listener = UserCloudConfigListener(userId: userId),
|
||||||
super(CloudSettingState.initial(config)) {
|
super(CloudSettingState.initial(config)) {
|
||||||
on<CloudSettingEvent>((event, emit) async {
|
on<CloudSettingEvent>((event, emit) async {
|
||||||
@ -38,7 +38,7 @@ class CloudSettingBloc extends Bloc<CloudSettingEvent, CloudSettingState> {
|
|||||||
final update = UpdateCloudConfigPB.create()..enableSync = enable;
|
final update = UpdateCloudConfigPB.create()..enableSync = enable;
|
||||||
updateCloudConfig(update);
|
updateCloudConfig(update);
|
||||||
},
|
},
|
||||||
didReceiveConfig: (UserCloudConfigPB config) {
|
didReceiveConfig: (CloudSettingPB config) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
config: config,
|
config: config,
|
||||||
@ -64,7 +64,7 @@ class CloudSettingBloc extends Bloc<CloudSettingEvent, CloudSettingState> {
|
|||||||
class CloudSettingEvent with _$CloudSettingEvent {
|
class CloudSettingEvent with _$CloudSettingEvent {
|
||||||
const factory CloudSettingEvent.initial() = _Initial;
|
const factory CloudSettingEvent.initial() = _Initial;
|
||||||
const factory CloudSettingEvent.didReceiveConfig(
|
const factory CloudSettingEvent.didReceiveConfig(
|
||||||
UserCloudConfigPB config,
|
CloudSettingPB config,
|
||||||
) = _DidSyncSupabaseConfig;
|
) = _DidSyncSupabaseConfig;
|
||||||
const factory CloudSettingEvent.enableSync(bool enable) = _EnableSync;
|
const factory CloudSettingEvent.enableSync(bool enable) = _EnableSync;
|
||||||
const factory CloudSettingEvent.enableEncrypt(bool enable) = _EnableEncrypt;
|
const factory CloudSettingEvent.enableEncrypt(bool enable) = _EnableEncrypt;
|
||||||
@ -73,13 +73,12 @@ class CloudSettingEvent with _$CloudSettingEvent {
|
|||||||
@freezed
|
@freezed
|
||||||
class CloudSettingState with _$CloudSettingState {
|
class CloudSettingState with _$CloudSettingState {
|
||||||
const factory CloudSettingState({
|
const factory CloudSettingState({
|
||||||
required UserCloudConfigPB config,
|
required CloudSettingPB config,
|
||||||
required Either<Unit, String> successOrFailure,
|
required Either<Unit, String> successOrFailure,
|
||||||
required LoadingState loadingState,
|
required LoadingState loadingState,
|
||||||
}) = _CloudSettingState;
|
}) = _CloudSettingState;
|
||||||
|
|
||||||
factory CloudSettingState.initial(UserCloudConfigPB config) =>
|
factory CloudSettingState.initial(CloudSettingPB config) => CloudSettingState(
|
||||||
CloudSettingState(
|
|
||||||
config: config,
|
config: config,
|
||||||
successOrFailure: left(unit),
|
successOrFailure: left(unit),
|
||||||
loadingState: LoadingState.finish(left(unit)),
|
loadingState: LoadingState.finish(left(unit)),
|
||||||
|
@ -14,7 +14,7 @@ enum SettingsPage {
|
|||||||
files,
|
files,
|
||||||
user,
|
user,
|
||||||
notifications,
|
notifications,
|
||||||
syncSetting,
|
cloud,
|
||||||
shortcuts,
|
shortcuts,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
|
import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
|
||||||
|
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||||
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
@ -32,7 +34,13 @@ class SettingsLocationCubit extends Cubit<SettingsLocationState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _init() async {
|
Future<void> _init() async {
|
||||||
final path = await getIt<ApplicationDataStorage>().getPath();
|
// The backend might change the real path that storge the data. So it needs
|
||||||
emit(SettingsLocationState.didReceivedPath(path));
|
// to get the path from the backend instead of the KeyValueStorage
|
||||||
|
await UserEventGetUserSetting().send().then((result) {
|
||||||
|
result.fold(
|
||||||
|
(l) => emit(SettingsLocationState.didReceivedPath(l.userFolder)),
|
||||||
|
(r) => Log.error(r),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_notifications_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/settings_notifications_view.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/sync_setting_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/setting_cloud_view.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance_view.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_customize_shortcuts_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/settings_customize_shortcuts_view.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_file_system_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/settings_file_system_view.dart';
|
||||||
@ -104,8 +104,8 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
case SettingsPage.notifications:
|
case SettingsPage.notifications:
|
||||||
return const SettingsNotificationsView();
|
return const SettingsNotificationsView();
|
||||||
case SettingsPage.syncSetting:
|
case SettingsPage.cloud:
|
||||||
return SyncSettingView(userId: user.id.toString());
|
return SettingCloudView(userId: user.id.toString());
|
||||||
case SettingsPage.shortcuts:
|
case SettingsPage.shortcuts:
|
||||||
return const SettingsCustomizeShortcutsWrapper();
|
return const SettingsCustomizeShortcutsWrapper();
|
||||||
default:
|
default:
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy/env/env.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/setting_supabase_bloc.dart';
|
import 'package:appflowy/workspace/application/settings/setting_supabase_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||||
@ -14,13 +15,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class SyncSettingView extends StatelessWidget {
|
class SettingCloudView extends StatelessWidget {
|
||||||
final String userId;
|
final String userId;
|
||||||
const SyncSettingView({required this.userId, super.key});
|
const SettingCloudView({required this.userId, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder<Either<UserCloudConfigPB, FlowyError>>(
|
return FutureBuilder<Either<CloudSettingPB, FlowyError>>(
|
||||||
future: UserEventGetCloudConfig().send(),
|
future: UserEventGetCloudConfig().send(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.data != null &&
|
if (snapshot.data != null &&
|
||||||
@ -34,10 +35,15 @@ class SyncSettingView extends StatelessWidget {
|
|||||||
)..add(const CloudSettingEvent.initial()),
|
)..add(const CloudSettingEvent.initial()),
|
||||||
child: BlocBuilder<CloudSettingBloc, CloudSettingState>(
|
child: BlocBuilder<CloudSettingBloc, CloudSettingState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return const Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
EnableSync(),
|
const EnableSync(),
|
||||||
EnableEncrypt(),
|
// Currently the appflowy cloud is not support end-to-end encryption.
|
||||||
|
if (!isAppFlowyCloudEnabled) const EnableEncrypt(),
|
||||||
|
if (isAppFlowyCloudEnabled)
|
||||||
|
AppFlowyCloudInformationWidget(
|
||||||
|
url: state.config.serverUrl,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -58,6 +64,34 @@ class SyncSettingView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AppFlowyCloudInformationWidget extends StatelessWidget {
|
||||||
|
final String url;
|
||||||
|
|
||||||
|
const AppFlowyCloudInformationWidget({required this.url, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
// Wrap the Opacity widget with Expanded
|
||||||
|
child: Opacity(
|
||||||
|
opacity: 0.6,
|
||||||
|
child: FlowyText(
|
||||||
|
"${LocaleKeys.settings_menu_cloudURL.tr()}: $url",
|
||||||
|
maxLines: null, // Allow the text to wrap
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class EnableEncrypt extends StatelessWidget {
|
class EnableEncrypt extends StatelessWidget {
|
||||||
const EnableEncrypt({super.key});
|
const EnableEncrypt({super.key});
|
||||||
|
|
||||||
@ -121,7 +155,6 @@ class EnableEncrypt extends StatelessWidget {
|
|||||||
await Clipboard.setData(
|
await Clipboard.setData(
|
||||||
ClipboardData(text: state.config.encryptSecret),
|
ClipboardData(text: state.config.encryptSecret),
|
||||||
);
|
);
|
||||||
// TODO(Lucas): bring the toast to the top of the dialog.
|
|
||||||
showMessageToast(LocaleKeys.message_copy_success.tr());
|
showMessageToast(LocaleKeys.message_copy_success.tr());
|
||||||
},
|
},
|
||||||
),
|
),
|
@ -48,45 +48,10 @@ class SettingsFileLocationCustomizerState
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
// display file paths.
|
// display file paths.
|
||||||
Flexible(
|
_path(path),
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
FlowyText.medium(
|
|
||||||
LocaleKeys.settings_files_defaultLocation.tr(),
|
|
||||||
fontSize: 13,
|
|
||||||
overflow: TextOverflow.visible,
|
|
||||||
).padding(horizontal: 5),
|
|
||||||
const VSpace(5),
|
|
||||||
_CopyableText(
|
|
||||||
usingPath: path,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// display the icons
|
// display the icons
|
||||||
Flexible(
|
_buttons(path),
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: _ChangeStoragePathButton(
|
|
||||||
usingPath: path,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const HSpace(10),
|
|
||||||
_OpenStorageButton(
|
|
||||||
usingPath: path,
|
|
||||||
),
|
|
||||||
_RecoverDefaultStorageButton(
|
|
||||||
usingPath: path,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -95,6 +60,55 @@ class SettingsFileLocationCustomizerState
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _path(String path) {
|
||||||
|
return Flexible(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
FlowyText.medium(
|
||||||
|
LocaleKeys.settings_files_defaultLocation.tr(),
|
||||||
|
fontSize: 13,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
).padding(horizontal: 5),
|
||||||
|
const VSpace(5),
|
||||||
|
_CopyableText(
|
||||||
|
usingPath: path,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buttons(String path) {
|
||||||
|
final List<Widget> children = [];
|
||||||
|
children.addAll([
|
||||||
|
Flexible(
|
||||||
|
child: _ChangeStoragePathButton(
|
||||||
|
usingPath: path,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(10),
|
||||||
|
]);
|
||||||
|
|
||||||
|
children.add(
|
||||||
|
_OpenStorageButton(
|
||||||
|
usingPath: path,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
children.add(
|
||||||
|
_RecoverDefaultStorageButton(
|
||||||
|
usingPath: path,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Flexible(
|
||||||
|
child: Row(mainAxisAlignment: MainAxisAlignment.end, children: children),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CopyableText extends StatelessWidget {
|
class _CopyableText extends StatelessWidget {
|
||||||
|
@ -67,9 +67,9 @@ class SettingsMenu extends StatelessWidget {
|
|||||||
if (showSyncSetting) ...[
|
if (showSyncSetting) ...[
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
SettingsMenuElement(
|
SettingsMenuElement(
|
||||||
page: SettingsPage.syncSetting,
|
page: SettingsPage.cloud,
|
||||||
selectedPage: currentPage,
|
selectedPage: currentPage,
|
||||||
label: LocaleKeys.settings_menu_syncSetting.tr(),
|
label: LocaleKeys.settings_menu_cloudSetting.tr(),
|
||||||
icon: Icons.sync,
|
icon: Icons.sync,
|
||||||
changeSelectedPage: changeSelectedPage,
|
changeSelectedPage: changeSelectedPage,
|
||||||
),
|
),
|
||||||
|
16
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
16
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -138,7 +138,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
|||||||
[[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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -768,7 +768,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-api"
|
name = "client-api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -1449,7 +1449,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2808,7 +2808,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -2824,7 +2824,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -3251,7 +3251,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -4994,7 +4994,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "realtime-entity"
|
name = "realtime-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -5739,7 +5739,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
|
@ -56,7 +56,7 @@ custom-protocol = ["tauri/custom-protocol"]
|
|||||||
# Run the script:
|
# Run the script:
|
||||||
# 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 = "fe977fc8285addd5386e940738cdffbbda9eb44e" }
|
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b578c83cc912255e48dea9e33a203a069ce7d0c5" }
|
||||||
# Please use the following script to update collab.
|
# Please use the following script to update collab.
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
#
|
#
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use flowy_core::{AppFlowyCore, AppFlowyCoreConfig, DEFAULT_NAME};
|
use flowy_core::config::AppFlowyCoreConfig;
|
||||||
|
use flowy_core::{AppFlowyCore, DEFAULT_NAME};
|
||||||
|
|
||||||
pub fn init_flowy_core() -> AppFlowyCore {
|
pub fn init_flowy_core() -> AppFlowyCore {
|
||||||
let config_json = include_str!("../tauri.conf.json");
|
let config_json = include_str!("../tauri.conf.json");
|
||||||
|
@ -262,6 +262,8 @@
|
|||||||
"logoutPrompt": "Are you sure to logout?",
|
"logoutPrompt": "Are you sure to logout?",
|
||||||
"selfEncryptionLogoutPrompt": "Are you sure you want to log out? Please ensure you have copied the encryption secret",
|
"selfEncryptionLogoutPrompt": "Are you sure you want to log out? Please ensure you have copied the encryption secret",
|
||||||
"syncSetting": "Sync Setting",
|
"syncSetting": "Sync Setting",
|
||||||
|
"cloudSetting": "Cloud Setting",
|
||||||
|
"cloudURL": "Server URL",
|
||||||
"enableSync": "Enable sync",
|
"enableSync": "Enable sync",
|
||||||
"enableEncrypt": "Encrypt data",
|
"enableEncrypt": "Encrypt data",
|
||||||
"enableEncryptPrompt": "Activate encryption to secure your data with this secret. Store it safely; once enabled, it can't be turned off. If lost, your data becomes irretrievable. Click to copy",
|
"enableEncryptPrompt": "Activate encryption to secure your data with this secret. Store it safely; once enabled, it can't be turned off. If lost, your data becomes irretrievable. Click to copy",
|
||||||
|
39
frontend/rust-lib/Cargo.lock
generated
39
frontend/rust-lib/Cargo.lock
generated
@ -124,7 +124,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
|||||||
[[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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -666,7 +666,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-api"
|
name = "client-api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -1150,7 +1150,7 @@ dependencies = [
|
|||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa",
|
"itoa",
|
||||||
"phf 0.11.2",
|
"phf 0.8.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1250,6 +1250,7 @@ dependencies = [
|
|||||||
"protobuf",
|
"protobuf",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_repr",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@ -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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2467,7 +2468,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -2483,7 +2484,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2844,7 +2845,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -3657,7 +3658,7 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros 0.8.0",
|
"phf_macros",
|
||||||
"phf_shared 0.8.0",
|
"phf_shared 0.8.0",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
]
|
]
|
||||||
@ -3677,7 +3678,6 @@ version = "0.11.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros 0.11.2",
|
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3745,19 +3745,6 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_macros"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
|
||||||
dependencies = [
|
|
||||||
"phf_generator 0.11.2",
|
|
||||||
"phf_shared 0.11.2",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.31",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -3961,7 +3948,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"heck 0.4.1",
|
"heck 0.4.1",
|
||||||
"itertools 0.11.0",
|
"itertools 0.10.5",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -3982,7 +3969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.11.0",
|
"itertools 0.10.5",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.31",
|
"syn 2.0.31",
|
||||||
@ -4321,7 +4308,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "realtime-entity"
|
name = "realtime-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -4965,7 +4952,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=fe977fc8285addd5386e940738cdffbbda9eb44e#fe977fc8285addd5386e940738cdffbbda9eb44e"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
|
@ -99,7 +99,7 @@ incremental = false
|
|||||||
# Run the script:
|
# Run the script:
|
||||||
# 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 = "fe977fc8285addd5386e940738cdffbbda9eb44e" }
|
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b578c83cc912255e48dea9e33a203a069ce7d0c5" }
|
||||||
# Please use the following script to update collab.
|
# Please use the following script to update collab.
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
#
|
#
|
||||||
|
@ -17,6 +17,7 @@ byteorder = { version = "1.4.3" }
|
|||||||
protobuf.workspace = true
|
protobuf.workspace = true
|
||||||
tokio = { workspace = true, features = ["full", "rt-multi-thread", "tracing"] }
|
tokio = { workspace = true, features = ["full", "rt-multi-thread", "tracing"] }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
serde_repr.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
bytes.workspace = true
|
bytes.workspace = true
|
||||||
crossbeam-utils = "0.8.15"
|
crossbeam-utils = "0.8.15"
|
||||||
|
@ -1,21 +1,63 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use serde_repr::Deserialize_repr;
|
||||||
|
|
||||||
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||||
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct AppFlowyEnv {
|
pub struct AppFlowyEnv {
|
||||||
|
cloud_type: CloudType,
|
||||||
supabase_config: SupabaseConfiguration,
|
supabase_config: SupabaseConfiguration,
|
||||||
appflowy_cloud_config: AFCloudConfiguration,
|
appflowy_cloud_config: AFCloudConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CLOUT_TYPE_STR: &str = "APPFLOWY_CLOUD_ENV_CLOUD_TYPE";
|
||||||
|
|
||||||
|
#[derive(Deserialize_repr, Debug, Clone)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum CloudType {
|
||||||
|
Local = 0,
|
||||||
|
Supabase = 1,
|
||||||
|
AppFlowyCloud = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CloudType {
|
||||||
|
fn write_env(&self) {
|
||||||
|
let s = self.clone() as u8;
|
||||||
|
std::env::set_var(CLOUT_TYPE_STR, s.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn from_str(s: &str) -> Self {
|
||||||
|
match s {
|
||||||
|
"0" => CloudType::Local,
|
||||||
|
"1" => CloudType::Supabase,
|
||||||
|
"2" => CloudType::AppFlowyCloud,
|
||||||
|
_ => CloudType::Local,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn from_env() -> Self {
|
||||||
|
let cloud_type_str = std::env::var(CLOUT_TYPE_STR).unwrap_or_default();
|
||||||
|
CloudType::from_str(&cloud_type_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AppFlowyEnv {
|
impl AppFlowyEnv {
|
||||||
/// Parse the environment variable from the frontend application. The frontend will
|
/// Parse the environment variable from the frontend application. The frontend will
|
||||||
/// pass the environment variable as a json string after launching.
|
/// pass the environment variable as a json string after launching.
|
||||||
pub fn write_env_from(env_str: &str) {
|
pub fn write_env_from(env_str: &str) {
|
||||||
if let Ok(env) = serde_json::from_str::<AppFlowyEnv>(env_str) {
|
if let Ok(env) = serde_json::from_str::<AppFlowyEnv>(env_str) {
|
||||||
env.supabase_config.write_env();
|
let _ = env.cloud_type.write_env();
|
||||||
env.appflowy_cloud_config.write_env();
|
let is_valid = env.appflowy_cloud_config.write_env().is_ok();
|
||||||
|
// Note on Configuration Priority:
|
||||||
|
// If both Supabase config and AppFlowy cloud config are provided in the '.env' file,
|
||||||
|
// the AppFlowy cloud config will be prioritized and the Supabase config ignored.
|
||||||
|
// Ensure only one of these configurations is active at any given time.
|
||||||
|
if !is_valid {
|
||||||
|
let _ = env.supabase_config.write_env();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use lazy_static::lazy_static;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tracing::{error, trace};
|
use tracing::{error, trace};
|
||||||
|
|
||||||
|
use flowy_core::config::AppFlowyCoreConfig;
|
||||||
use flowy_core::*;
|
use flowy_core::*;
|
||||||
use flowy_notification::{register_notification_sender, unregister_all_notification_sender};
|
use flowy_notification::{register_notification_sender, unregister_all_notification_sender};
|
||||||
use lib_dispatch::prelude::ToBytes;
|
use lib_dispatch::prelude::ToBytes;
|
||||||
|
@ -5,7 +5,8 @@ use std::sync::Arc;
|
|||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
use flowy_core::{AppFlowyCore, AppFlowyCoreConfig};
|
use flowy_core::config::AppFlowyCoreConfig;
|
||||||
|
use flowy_core::AppFlowyCore;
|
||||||
use flowy_notification::register_notification_sender;
|
use flowy_notification::register_notification_sender;
|
||||||
use flowy_user::entities::AuthTypePB;
|
use flowy_user::entities::AuthTypePB;
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ use flowy_notification::entities::SubscribeObject;
|
|||||||
use flowy_notification::NotificationSender;
|
use flowy_notification::NotificationSender;
|
||||||
use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_URL, USER_UUID};
|
use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_URL, USER_UUID};
|
||||||
use flowy_user::entities::{
|
use flowy_user::entities::{
|
||||||
AuthTypePB, OauthSignInPB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB, UpdateCloudConfigPB,
|
AuthTypePB, CloudSettingPB, OauthSignInPB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB,
|
||||||
UpdateUserProfilePayloadPB, UserCloudConfigPB, UserProfilePB,
|
UpdateCloudConfigPB, UpdateUserProfilePayloadPB, UserProfilePB,
|
||||||
};
|
};
|
||||||
use flowy_user::errors::{FlowyError, FlowyResult};
|
use flowy_user::errors::{FlowyError, FlowyResult};
|
||||||
use flowy_user::event_map::UserEvent::*;
|
use flowy_user::event_map::UserEvent::*;
|
||||||
@ -29,7 +29,7 @@ impl EventIntegrationTest {
|
|||||||
.event(GetCloudConfig)
|
.event(GetCloudConfig)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
.parse::<UserCloudConfigPB>();
|
.parse::<CloudSettingPB>();
|
||||||
let update = UpdateCloudConfigPB {
|
let update = UpdateCloudConfigPB {
|
||||||
enable_sync: None,
|
enable_sync: None,
|
||||||
enable_encrypt: Some(true),
|
enable_encrypt: Some(true),
|
||||||
|
86
frontend/rust-lib/flowy-core/src/config.rs
Normal file
86
frontend/rust-lib/flowy-core/src/config.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use base64::Engine;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||||
|
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||||
|
use flowy_user::manager::URL_SAFE_ENGINE;
|
||||||
|
|
||||||
|
use crate::integrate::log::create_log_filter;
|
||||||
|
use crate::integrate::util::copy_dir_recursive;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppFlowyCoreConfig {
|
||||||
|
/// Different `AppFlowyCoreConfig` instance should have different name
|
||||||
|
pub(crate) name: String,
|
||||||
|
/// Panics if the `root` path is not existing
|
||||||
|
pub storage_path: String,
|
||||||
|
pub(crate) log_filter: String,
|
||||||
|
cloud_config: Option<AFCloudConfiguration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for AppFlowyCoreConfig {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut debug = f.debug_struct("AppFlowy Configuration");
|
||||||
|
debug.field("storage_path", &self.storage_path);
|
||||||
|
if let Some(config) = &self.cloud_config {
|
||||||
|
debug.field("base_url", &config.base_url);
|
||||||
|
debug.field("ws_url", &config.ws_base_url);
|
||||||
|
}
|
||||||
|
debug.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_local_version_data_folder(root: &str, url: &str) -> String {
|
||||||
|
// Isolate the user data folder by using the base url of AppFlowy cloud. This is to avoid
|
||||||
|
// the user data folder being shared by different AppFlowy cloud.
|
||||||
|
let server_base64 = URL_SAFE_ENGINE.encode(&url);
|
||||||
|
let storage_path = format!("{}_{}", root, server_base64);
|
||||||
|
|
||||||
|
// Copy the user data folder from the root path to the isolated path
|
||||||
|
// The root path without any suffix is the created by the local version AppFlowy
|
||||||
|
if !Path::new(&storage_path).exists() && Path::new(root).exists() {
|
||||||
|
info!("Copy dir from {} to {}", root, storage_path);
|
||||||
|
let src = Path::new(root);
|
||||||
|
match copy_dir_recursive(&src, Path::new(&storage_path)) {
|
||||||
|
Ok(_) => storage_path,
|
||||||
|
Err(err) => {
|
||||||
|
// when the copy dir failed, use the root path as the storage path
|
||||||
|
error!("Copy dir failed: {}", err);
|
||||||
|
root.to_string()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
storage_path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppFlowyCoreConfig {
|
||||||
|
pub fn new(root: &str, name: String) -> Self {
|
||||||
|
let cloud_config = AFCloudConfiguration::from_env().ok();
|
||||||
|
let storage_path = match &cloud_config {
|
||||||
|
None => {
|
||||||
|
let supabase_config = SupabaseConfiguration::from_env().ok();
|
||||||
|
match &supabase_config {
|
||||||
|
None => root.to_string(),
|
||||||
|
Some(config) => migrate_local_version_data_folder(root, &config.url),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(config) => migrate_local_version_data_folder(root, &config.base_url),
|
||||||
|
};
|
||||||
|
|
||||||
|
AppFlowyCoreConfig {
|
||||||
|
name,
|
||||||
|
storage_path,
|
||||||
|
log_filter: create_log_filter("info".to_owned(), vec![]),
|
||||||
|
cloud_config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_filter(mut self, level: &str, with_crates: Vec<String>) -> Self {
|
||||||
|
self.log_filter = create_log_filter(level.to_owned(), with_crates);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
@ -124,13 +124,7 @@ impl ServerProvider {
|
|||||||
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
|
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
|
||||||
},
|
},
|
||||||
ServerType::Supabase => {
|
ServerType::Supabase => {
|
||||||
let config = match SupabaseConfiguration::from_env() {
|
let config = SupabaseConfiguration::from_env()?;
|
||||||
Ok(config) => config,
|
|
||||||
Err(e) => {
|
|
||||||
*self.enable_sync.write() = false;
|
|
||||||
return Err(e);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let uid = self.uid.clone();
|
let uid = self.uid.clone();
|
||||||
tracing::trace!("🔑Supabase config: {:?}", config);
|
tracing::trace!("🔑Supabase config: {:?}", config);
|
||||||
let encryption = Arc::downgrade(&*self.encryption.read());
|
let encryption = Arc::downgrade(&*self.encryption.read());
|
||||||
|
@ -21,6 +21,8 @@ use flowy_error::FlowyError;
|
|||||||
use flowy_folder_deps::cloud::{
|
use flowy_folder_deps::cloud::{
|
||||||
FolderCloudService, FolderData, FolderSnapshot, Workspace, WorkspaceRecord,
|
FolderCloudService, FolderData, FolderSnapshot, Workspace, WorkspaceRecord,
|
||||||
};
|
};
|
||||||
|
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||||
|
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||||
use flowy_storage::{FileStorageService, StorageObject};
|
use flowy_storage::{FileStorageService, StorageObject};
|
||||||
use flowy_user::event_map::UserCloudServiceProvider;
|
use flowy_user::event_map::UserCloudServiceProvider;
|
||||||
use flowy_user_deps::cloud::UserCloudService;
|
use flowy_user_deps::cloud::UserCloudService;
|
||||||
@ -68,13 +70,10 @@ impl UserCloudServiceProvider for ServerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_enable_sync(&self, uid: i64, enable_sync: bool) {
|
fn set_enable_sync(&self, uid: i64, enable_sync: bool) {
|
||||||
match self.get_server(&self.get_server_type()) {
|
if let Ok(server) = self.get_server(&self.get_server_type()) {
|
||||||
Ok(server) => {
|
server.set_enable_sync(uid, enable_sync);
|
||||||
server.set_enable_sync(uid, enable_sync);
|
*self.enable_sync.write() = enable_sync;
|
||||||
*self.enable_sync.write() = enable_sync;
|
*self.uid.write() = Some(uid);
|
||||||
*self.uid.write() = Some(uid);
|
|
||||||
},
|
|
||||||
Err(e) => tracing::error!("🔴Failed to enable sync: {:?}", e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +135,16 @@ impl UserCloudServiceProvider for ServerProvider {
|
|||||||
Ok(user_service)
|
Ok(user_service)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn service_name(&self) -> String {
|
fn service_url(&self) -> String {
|
||||||
self.get_server_type().to_string()
|
match self.get_server_type() {
|
||||||
|
ServerType::Local => "".to_string(),
|
||||||
|
ServerType::AFCloud => AFCloudConfiguration::from_env()
|
||||||
|
.map(|config| config.base_url)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
ServerType::Supabase => SupabaseConfiguration::from_env()
|
||||||
|
.map(|config| config.url)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
|||||||
self
|
self
|
||||||
.server_provider
|
.server_provider
|
||||||
.set_enable_sync(user_id, cloud_config.enable_sync);
|
.set_enable_sync(user_id, cloud_config.enable_sync);
|
||||||
if cloud_config.enable_encrypt() {
|
if cloud_config.enable_encrypt {
|
||||||
self
|
self
|
||||||
.server_provider
|
.server_provider
|
||||||
.set_encrypt_secret(cloud_config.encrypt_secret.clone());
|
.set_encrypt_secret(cloud_config.encrypt_secret.clone());
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#![allow(unused_doc_comments)]
|
#![allow(unused_doc_comments)]
|
||||||
|
|
||||||
use std::path::Path;
|
use std::sync::Arc;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{fmt, sync::Arc};
|
|
||||||
|
|
||||||
use base64::Engine;
|
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tracing::{debug, error, event, info, instrument};
|
use tracing::{debug, error, event, info, instrument};
|
||||||
|
|
||||||
@ -13,24 +11,24 @@ use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabSource};
|
|||||||
use flowy_database2::DatabaseManager;
|
use flowy_database2::DatabaseManager;
|
||||||
use flowy_document2::manager::DocumentManager;
|
use flowy_document2::manager::DocumentManager;
|
||||||
use flowy_folder2::manager::FolderManager;
|
use flowy_folder2::manager::FolderManager;
|
||||||
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
|
||||||
use flowy_sqlite::kv::StorePreferences;
|
use flowy_sqlite::kv::StorePreferences;
|
||||||
use flowy_storage::FileStorageService;
|
use flowy_storage::FileStorageService;
|
||||||
use flowy_task::{TaskDispatcher, TaskRunner};
|
use flowy_task::{TaskDispatcher, TaskRunner};
|
||||||
use flowy_user::event_map::UserCloudServiceProvider;
|
use flowy_user::event_map::UserCloudServiceProvider;
|
||||||
use flowy_user::manager::{UserManager, UserSessionConfig, URL_SAFE_ENGINE};
|
use flowy_user::manager::{UserManager, UserSessionConfig};
|
||||||
use lib_dispatch::prelude::*;
|
use lib_dispatch::prelude::*;
|
||||||
use lib_dispatch::runtime::AFPluginRuntime;
|
use lib_dispatch::runtime::AFPluginRuntime;
|
||||||
use module::make_plugins;
|
use module::make_plugins;
|
||||||
pub use module::*;
|
pub use module::*;
|
||||||
|
|
||||||
|
use crate::config::AppFlowyCoreConfig;
|
||||||
use crate::deps_resolve::*;
|
use crate::deps_resolve::*;
|
||||||
use crate::integrate::collab_interact::CollabInteractImpl;
|
use crate::integrate::collab_interact::CollabInteractImpl;
|
||||||
use crate::integrate::log::{create_log_filter, init_log};
|
use crate::integrate::log::init_log;
|
||||||
use crate::integrate::server::{current_server_type, ServerProvider, ServerType};
|
use crate::integrate::server::{current_server_type, ServerProvider, ServerType};
|
||||||
use crate::integrate::user::UserStatusCallbackImpl;
|
use crate::integrate::user::UserStatusCallbackImpl;
|
||||||
use crate::integrate::util::copy_dir_recursive;
|
|
||||||
|
|
||||||
|
pub mod config;
|
||||||
mod deps_resolve;
|
mod deps_resolve;
|
||||||
mod integrate;
|
mod integrate;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
@ -39,72 +37,6 @@ pub mod module;
|
|||||||
/// Don't change this.
|
/// Don't change this.
|
||||||
pub const DEFAULT_NAME: &str = "appflowy";
|
pub const DEFAULT_NAME: &str = "appflowy";
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct AppFlowyCoreConfig {
|
|
||||||
/// Different `AppFlowyCoreConfig` instance should have different name
|
|
||||||
name: String,
|
|
||||||
/// Panics if the `root` path is not existing
|
|
||||||
pub storage_path: String,
|
|
||||||
log_filter: String,
|
|
||||||
cloud_config: Option<AFCloudConfiguration>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for AppFlowyCoreConfig {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let mut debug = f.debug_struct("AppFlowy Configuration");
|
|
||||||
debug.field("storage_path", &self.storage_path);
|
|
||||||
if let Some(config) = &self.cloud_config {
|
|
||||||
debug.field("base_url", &config.base_url);
|
|
||||||
debug.field("ws_url", &config.ws_base_url);
|
|
||||||
}
|
|
||||||
debug.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppFlowyCoreConfig {
|
|
||||||
pub fn new(root: &str, name: String) -> Self {
|
|
||||||
let cloud_config = AFCloudConfiguration::from_env().ok();
|
|
||||||
let storage_path = match &cloud_config {
|
|
||||||
None => root.to_string(),
|
|
||||||
Some(config) => {
|
|
||||||
// Isolate the user data folder by the base url of AppFlowy cloud. This is to avoid
|
|
||||||
// the user data folder being shared by different AppFlowy cloud.
|
|
||||||
let server_base64 = URL_SAFE_ENGINE.encode(&config.base_url);
|
|
||||||
let storage_path = format!("{}_{}", root, server_base64);
|
|
||||||
|
|
||||||
// Copy the user data folder from the root path to the isolated path
|
|
||||||
// The root path only exists when using the local version of appflowy
|
|
||||||
if !Path::new(&storage_path).exists() && Path::new(root).exists() {
|
|
||||||
info!("Copy dir from {} to {}", root, storage_path);
|
|
||||||
let src = Path::new(root);
|
|
||||||
match copy_dir_recursive(&src, Path::new(&storage_path)) {
|
|
||||||
Ok(_) => storage_path,
|
|
||||||
Err(err) => {
|
|
||||||
// when the copy dir failed, use the root path as the storage path
|
|
||||||
error!("Copy dir failed: {}", err);
|
|
||||||
root.to_string()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
storage_path
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
AppFlowyCoreConfig {
|
|
||||||
name,
|
|
||||||
storage_path,
|
|
||||||
log_filter: create_log_filter("info".to_owned(), vec![]),
|
|
||||||
cloud_config: AFCloudConfiguration::from_env().ok(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn log_filter(mut self, level: &str, with_crates: Vec<String>) -> Self {
|
|
||||||
self.log_filter = create_log_filter(level.to_owned(), with_crates);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppFlowyCore {
|
pub struct AppFlowyCore {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -159,7 +159,7 @@ impl FolderManager {
|
|||||||
} => {
|
} => {
|
||||||
let is_exist = is_exist_in_local_disk(&self.user, &workspace_id).unwrap_or(false);
|
let is_exist = is_exist_in_local_disk(&self.user, &workspace_id).unwrap_or(false);
|
||||||
if is_exist {
|
if is_exist {
|
||||||
event!(Level::INFO, "Restore folder from local disk");
|
event!(Level::INFO, "Init folder from local disk");
|
||||||
let collab = self
|
let collab = self
|
||||||
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -2,11 +2,11 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use flowy_error::{ErrorCode, FlowyError};
|
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||||
|
|
||||||
pub const APPFLOWY_CLOUD_BASE_URL: &str = "APPFLOWY_CLOUD_BASE_URL";
|
pub const APPFLOWY_CLOUD_BASE_URL: &str = "APPFLOWY_CLOUD_ENV_APPFLOWY_CLOUD_BASE_URL";
|
||||||
pub const APPFLOWY_CLOUD_WS_BASE_URL: &str = "APPFLOWY_CLOUD_WS_BASE_URL";
|
pub const APPFLOWY_CLOUD_WS_BASE_URL: &str = "APPFLOWY_CLOUD_ENV_APPFLOWY_CLOUD_WS_BASE_URL";
|
||||||
pub const APPFLOWY_CLOUD_GOTRUE_URL: &str = "APPFLOWY_CLOUD_GOTRUE_URL";
|
pub const APPFLOWY_CLOUD_GOTRUE_URL: &str = "APPFLOWY_CLOUD_ENV_APPFLOWY_CLOUD_GOTRUE_URL";
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
pub struct AFCloudConfiguration {
|
pub struct AFCloudConfiguration {
|
||||||
@ -60,10 +60,25 @@ impl AFCloudConfiguration {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validate(&self) -> Result<(), FlowyError> {
|
||||||
|
if self.base_url.is_empty() || self.ws_base_url.is_empty() || self.gotrue_url.is_empty() {
|
||||||
|
return Err(FlowyError::new(
|
||||||
|
ErrorCode::InvalidAuthConfig,
|
||||||
|
format!(
|
||||||
|
"Invalid APPFLOWY_CLOUD_BASE_URL: {}, APPFLOWY_CLOUD_WS_BASE_URL: {}, APPFLOWY_CLOUD_GOTRUE_URL: {}",
|
||||||
|
self.base_url, self.ws_base_url, self.gotrue_url,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Write the configuration to the environment variables.
|
/// Write the configuration to the environment variables.
|
||||||
pub fn write_env(&self) {
|
pub fn write_env(&self) -> FlowyResult<()> {
|
||||||
|
self.validate()?;
|
||||||
std::env::set_var(APPFLOWY_CLOUD_BASE_URL, &self.base_url);
|
std::env::set_var(APPFLOWY_CLOUD_BASE_URL, &self.base_url);
|
||||||
std::env::set_var(APPFLOWY_CLOUD_WS_BASE_URL, &self.ws_base_url);
|
std::env::set_var(APPFLOWY_CLOUD_WS_BASE_URL, &self.ws_base_url);
|
||||||
std::env::set_var(APPFLOWY_CLOUD_GOTRUE_URL, &self.gotrue_url);
|
std::env::set_var(APPFLOWY_CLOUD_GOTRUE_URL, &self.gotrue_url);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use flowy_error::{ErrorCode, FlowyError};
|
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||||
|
|
||||||
pub const ENABLE_SUPABASE_SYNC: &str = "ENABLE_SUPABASE_SYNC";
|
pub const SUPABASE_URL: &str = "APPFLOWY_CLOUD_ENV_SUPABASE_URL";
|
||||||
pub const SUPABASE_URL: &str = "SUPABASE_URL";
|
pub const SUPABASE_ANON_KEY: &str = "APPFLOWY_CLOUD_ENV_SUPABASE_ANON_KEY";
|
||||||
pub const SUPABASE_ANON_KEY: &str = "SUPABASE_ANON_KEY";
|
|
||||||
|
|
||||||
pub const SUPABASE_DB: &str = "SUPABASE_DB";
|
|
||||||
pub const SUPABASE_DB_USER: &str = "SUPABASE_DB_USER";
|
|
||||||
pub const SUPABASE_DB_PASSWORD: &str = "SUPABASE_DB_PASSWORD";
|
|
||||||
pub const SUPABASE_DB_PORT: &str = "SUPABASE_DB_PORT";
|
|
||||||
|
|
||||||
/// The configuration for the postgres database. It supports deserializing from the json string that
|
/// The configuration for the postgres database. It supports deserializing from the json string that
|
||||||
/// passed from the frontend application. [AppFlowyEnv::parser]
|
/// passed from the frontend application. [AppFlowyEnv::parser]
|
||||||
@ -39,9 +33,21 @@ impl SupabaseConfiguration {
|
|||||||
Ok(Self { url, anon_key })
|
Ok(Self { url, anon_key })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validate(&self) -> Result<(), FlowyError> {
|
||||||
|
if self.url.is_empty() || self.anon_key.is_empty() {
|
||||||
|
return Err(FlowyError::new(
|
||||||
|
ErrorCode::InvalidAuthConfig,
|
||||||
|
"Missing SUPABASE_URL or SUPABASE_ANON_KEY",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Write the configuration to the environment variables.
|
/// Write the configuration to the environment variables.
|
||||||
pub fn write_env(&self) {
|
pub fn write_env(&self) -> FlowyResult<()> {
|
||||||
|
self.validate()?;
|
||||||
std::env::set_var(SUPABASE_URL, &self.url);
|
std::env::set_var(SUPABASE_URL, &self.url);
|
||||||
std::env::set_var(SUPABASE_ANON_KEY, &self.anon_key);
|
std::env::set_var(SUPABASE_ANON_KEY, &self.anon_key);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ const DB_NAME: &str = "cache.db";
|
|||||||
pub struct StorePreferences {
|
pub struct StorePreferences {
|
||||||
database: Option<Database>,
|
database: Option<Database>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StorePreferences {
|
impl StorePreferences {
|
||||||
#[tracing::instrument(level = "trace", err)]
|
#[tracing::instrument(level = "trace", err)]
|
||||||
pub fn new(root: &str) -> Result<Self, anyhow::Error> {
|
pub fn new(root: &str) -> Result<Self, anyhow::Error> {
|
||||||
@ -86,7 +85,6 @@ impl StorePreferences {
|
|||||||
.and_then(|v| serde_json::from_str(&v).ok())
|
.and_then(|v| serde_json::from_str(&v).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn remove(&self, key: &str) {
|
pub fn remove(&self, key: &str) {
|
||||||
if let Some(conn) = self
|
if let Some(conn) = self
|
||||||
.database
|
.database
|
||||||
|
@ -20,7 +20,7 @@ use crate::entities::{
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct UserCloudConfig {
|
pub struct UserCloudConfig {
|
||||||
pub enable_sync: bool,
|
pub enable_sync: bool,
|
||||||
enable_encrypt: bool,
|
pub enable_encrypt: bool,
|
||||||
// The secret used to encrypt the user's data
|
// The secret used to encrypt the user's data
|
||||||
pub encrypt_secret: String,
|
pub encrypt_secret: String,
|
||||||
}
|
}
|
||||||
@ -34,10 +34,6 @@ impl UserCloudConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_encrypt(&self) -> bool {
|
|
||||||
self.enable_encrypt
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_enable_encrypt(mut self, enable_encrypt: bool) -> Self {
|
pub fn with_enable_encrypt(mut self, enable_encrypt: bool) -> Self {
|
||||||
self.enable_encrypt = enable_encrypt;
|
self.enable_encrypt = enable_encrypt;
|
||||||
// When the enable_encrypt is true, the encrypt_secret should not be empty
|
// When the enable_encrypt is true, the encrypt_secret should not be empty
|
||||||
|
@ -176,8 +176,8 @@ pub struct OauthProviderDataPB {
|
|||||||
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
|
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
|
||||||
pub enum AuthTypePB {
|
pub enum AuthTypePB {
|
||||||
Local = 0,
|
Local = 0,
|
||||||
AFCloud = 1,
|
Supabase = 1,
|
||||||
Supabase = 2,
|
AFCloud = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AuthTypePB {
|
impl Default for AuthTypePB {
|
||||||
|
@ -3,7 +3,6 @@ use std::collections::HashMap;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
use flowy_user_deps::cloud::UserCloudConfig;
|
|
||||||
|
|
||||||
use crate::entities::EncryptionTypePB;
|
use crate::entities::EncryptionTypePB;
|
||||||
|
|
||||||
@ -137,15 +136,18 @@ impl std::default::Default for AppearanceSettingsPB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, ProtoBuf)]
|
#[derive(Default, ProtoBuf)]
|
||||||
pub struct UserCloudConfigPB {
|
pub struct CloudSettingPB {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
enable_sync: bool,
|
pub(crate) enable_sync: bool,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
enable_encrypt: bool,
|
pub(crate) enable_encrypt: bool,
|
||||||
|
|
||||||
#[pb(index = 3)]
|
#[pb(index = 3)]
|
||||||
pub encrypt_secret: String,
|
pub encrypt_secret: String,
|
||||||
|
|
||||||
|
#[pb(index = 4)]
|
||||||
|
pub server_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, ProtoBuf)]
|
#[derive(Default, ProtoBuf)]
|
||||||
@ -178,16 +180,6 @@ pub struct UserEncryptionConfigurationPB {
|
|||||||
pub require_secret: bool,
|
pub require_secret: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<UserCloudConfig> for UserCloudConfigPB {
|
|
||||||
fn from(value: UserCloudConfig) -> Self {
|
|
||||||
Self {
|
|
||||||
enable_sync: value.enable_sync,
|
|
||||||
enable_encrypt: value.enable_encrypt(),
|
|
||||||
encrypt_secret: value.encrypt_secret,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Default)]
|
#[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Default)]
|
||||||
pub enum NetworkTypePB {
|
pub enum NetworkTypePB {
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -385,7 +385,6 @@ pub async fn set_cloud_config_handler(
|
|||||||
manager
|
manager
|
||||||
.set_encrypt_secret(session.user_id, encrypt_secret, encryption_type.clone())
|
.set_encrypt_secret(session.user_id, encrypt_secret, encryption_type.clone())
|
||||||
.await?;
|
.await?;
|
||||||
save_cloud_config(session.user_id, &store_preferences, config.clone())?;
|
|
||||||
|
|
||||||
let params =
|
let params =
|
||||||
UpdateUserProfileParams::new(session.user_id).with_encryption_type(encryption_type);
|
UpdateUserProfileParams::new(session.user_id).with_encryption_type(encryption_type);
|
||||||
@ -393,28 +392,40 @@ pub async fn set_cloud_config_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_pb = UserCloudConfigPB::from(config);
|
save_cloud_config(session.user_id, &store_preferences, config.clone())?;
|
||||||
|
|
||||||
|
let payload = CloudSettingPB {
|
||||||
|
enable_sync: config.enable_sync,
|
||||||
|
enable_encrypt: config.enable_encrypt,
|
||||||
|
encrypt_secret: config.encrypt_secret,
|
||||||
|
server_url: manager.cloud_services.service_url(),
|
||||||
|
};
|
||||||
|
|
||||||
send_notification(
|
send_notification(
|
||||||
&session.user_id.to_string(),
|
&session.user_id.to_string(),
|
||||||
UserNotification::DidUpdateCloudConfig,
|
UserNotification::DidUpdateCloudConfig,
|
||||||
)
|
)
|
||||||
.payload(config_pb)
|
.payload(payload)
|
||||||
.send();
|
.send();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "info", skip_all, err)]
|
||||||
pub async fn get_cloud_config_handler(
|
pub async fn get_cloud_config_handler(
|
||||||
manager: AFPluginState<Weak<UserManager>>,
|
manager: AFPluginState<Weak<UserManager>>,
|
||||||
store_preferences: AFPluginState<Weak<StorePreferences>>,
|
store_preferences: AFPluginState<Weak<StorePreferences>>,
|
||||||
) -> DataResult<UserCloudConfigPB, FlowyError> {
|
) -> DataResult<CloudSettingPB, FlowyError> {
|
||||||
let manager = upgrade_manager(manager)?;
|
let manager = upgrade_manager(manager)?;
|
||||||
let session = manager.get_session()?;
|
let session = manager.get_session()?;
|
||||||
|
|
||||||
let store_preferences = upgrade_store_preferences(store_preferences)?;
|
let store_preferences = upgrade_store_preferences(store_preferences)?;
|
||||||
// Generate the default config if the config is not exist
|
// Generate the default config if the config is not exist
|
||||||
let config = get_or_create_cloud_config(session.user_id, &store_preferences);
|
let config = get_or_create_cloud_config(session.user_id, &store_preferences);
|
||||||
data_result_ok(config.into())
|
data_result_ok(CloudSettingPB {
|
||||||
|
enable_sync: config.enable_sync,
|
||||||
|
enable_encrypt: config.enable_encrypt,
|
||||||
|
encrypt_secret: config.encrypt_secret,
|
||||||
|
server_url: manager.cloud_services.service_url(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(manager), err)]
|
#[tracing::instrument(level = "debug", skip(manager), err)]
|
||||||
|
@ -119,7 +119,7 @@ pub enum UserEvent {
|
|||||||
#[event(input = "UpdateCloudConfigPB")]
|
#[event(input = "UpdateCloudConfigPB")]
|
||||||
SetCloudConfig = 13,
|
SetCloudConfig = 13,
|
||||||
|
|
||||||
#[event(output = "UserCloudConfigPB")]
|
#[event(output = "CloudSettingPB")]
|
||||||
GetCloudConfig = 14,
|
GetCloudConfig = 14,
|
||||||
|
|
||||||
#[event(input = "UserSecretPB")]
|
#[event(input = "UserSecretPB")]
|
||||||
@ -248,7 +248,7 @@ pub trait UserCloudServiceProvider: Send + Sync + 'static {
|
|||||||
fn get_authenticator(&self) -> Authenticator;
|
fn get_authenticator(&self) -> Authenticator;
|
||||||
fn set_device_id(&self, device_id: &str);
|
fn set_device_id(&self, device_id: &str);
|
||||||
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError>;
|
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError>;
|
||||||
fn service_name(&self) -> String;
|
fn service_url(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> UserCloudServiceProvider for Arc<T>
|
impl<T> UserCloudServiceProvider for Arc<T>
|
||||||
@ -283,8 +283,8 @@ where
|
|||||||
(**self).get_user_service()
|
(**self).get_user_service()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn service_name(&self) -> String {
|
fn service_url(&self) -> String {
|
||||||
(**self).service_name()
|
(**self).service_url()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user