From 056e2d49d08954b8f543976e09ce6769b828bb32 Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Tue, 23 May 2023 23:55:21 +0800 Subject: [PATCH] feat: integrate postgres storage (#2604) * chore: env config * chore: get user workspace * feat: enable postgres storage * chore: add new env * chore: add set env ffi * chore: pass env before backend init * chore: update * fix: ci tests * chore: commit the generate env file * chore: remove unused import --- .../lib/core/config/config.dart | 19 + frontend/appflowy_flutter/lib/env/env.dart | 7 + .../document/application/doc_bloc.dart | 3 +- .../appflowy_flutter/lib/startup/startup.dart | 1 + .../lib/startup/tasks/rust_sdk.dart | 27 ++ .../lib/startup/tasks/supabase_task.dart | 3 + .../linux/flutter/dart_ffi/binding.h | 2 + .../lib/appflowy_backend.dart | 7 + .../appflowy_backend/lib/env_serde.dart | 64 +++ .../appflowy_backend/lib/env_serde.l.dart | 65 +++ .../packages/appflowy_backend/lib/ffi.dart | 16 + .../appflowy_backend/linux/Classes/binding.h | 2 + .../appflowy_backend/macos/Classes/binding.h | 2 + .../packages/appflowy_backend/pubspec.yaml | 2 + frontend/appflowy_tauri/src-tauri/Cargo.lock | 32 +- frontend/appflowy_tauri/src-tauri/Cargo.toml | 12 +- frontend/rust-lib/Cargo.lock | 90 ++-- frontend/rust-lib/Cargo.toml | 10 +- frontend/rust-lib/dart-ffi/Cargo.toml | 2 +- frontend/rust-lib/dart-ffi/binding.h | 2 + frontend/rust-lib/dart-ffi/src/env_serde.rs | 19 + frontend/rust-lib/dart-ffi/src/lib.rs | 9 + frontend/rust-lib/flowy-config/Cargo.toml | 1 + .../rust-lib/flowy-config/src/entities.rs | 94 +++- .../flowy-config/src/event_handler.rs | 26 +- .../rust-lib/flowy-config/src/event_map.rs | 7 + frontend/rust-lib/flowy-core/Cargo.toml | 4 +- .../src/deps_resolve/folder2_deps.rs | 8 +- .../flowy-core/src/integrate/server.rs | 133 +++++- frontend/rust-lib/flowy-core/src/lib.rs | 55 +-- .../flowy-database2/src/event_handler.rs | 3 +- .../rust-lib/flowy-database2/src/manager.rs | 6 +- .../src/services/database_view/view_group.rs | 34 +- .../type_options/number_type_option/format.rs | 8 +- .../number_type_option/number_type_option.rs | 4 +- .../number_type_option_entities.rs | 2 +- .../field/type_options/type_option_cell.rs | 2 +- .../src/services/sort/controller.rs | 2 +- .../tests/database/database_editor.rs | 8 +- .../flowy-database2/tests/database/script.rs | 425 ------------------ .../flowy-document2/tests/document/util.rs | 6 +- frontend/rust-lib/flowy-folder2/src/deps.rs | 17 + .../flowy-folder2/src/entities/workspace.rs | 2 +- .../rust-lib/flowy-folder2/src/event_map.rs | 1 + frontend/rust-lib/flowy-folder2/src/lib.rs | 2 + .../rust-lib/flowy-folder2/src/manager.rs | 27 +- .../tests/workspace/folder_test.rs | 7 +- .../flowy-folder2/tests/workspace/script.rs | 52 +-- frontend/rust-lib/flowy-server/Cargo.toml | 3 +- frontend/rust-lib/flowy-server/src/lib.rs | 16 + .../src/local_server/impls/folder.rs | 21 + .../src/local_server/impls/mod.rs | 5 + .../src/local_server/{ => impls}/user.rs | 0 .../flowy-server/src/local_server/mod.rs | 2 +- .../flowy-server/src/local_server/server.rs | 9 +- .../src/self_host/impls/folder.rs | 21 + .../flowy-server/src/self_host/impls/mod.rs | 5 + .../src/self_host/{ => impls}/user.rs | 0 .../flowy-server/src/self_host/mod.rs | 3 +- .../flowy-server/src/self_host/server.rs | 9 +- .../flowy-server/src/supabase/impls/folder.rs | 54 +++ .../flowy-server/src/supabase/impls/mod.rs | 5 + .../src/supabase/{ => impls}/user.rs | 54 +-- .../rust-lib/flowy-server/src/supabase/mod.rs | 2 +- .../flowy-server/src/supabase/request.rs | 127 ++++-- .../flowy-server/src/supabase/response.rs | 33 +- .../flowy-server/src/supabase/server.rs | 27 +- frontend/rust-lib/flowy-test/Cargo.toml | 12 +- .../rust-lib/flowy-test/src/event_builder.rs | 60 +-- .../rust-lib/flowy-test/src/folder_event.rs | 111 +++++ frontend/rust-lib/flowy-test/src/helper.rs | 216 --------- frontend/rust-lib/flowy-test/src/lib.rs | 87 ++-- .../rust-lib/flowy-test/src/user_event.rs | 103 +++++ frontend/rust-lib/flowy-test/tests/main.rs | 1 + .../tests/user/local_test}/auth_test.rs | 60 +-- .../tests/user/local_test}/helper.rs | 5 - .../tests/user/local_test/mod.rs} | 0 .../user/local_test}/user_profile_test.rs | 68 ++- .../rust-lib/flowy-test/tests/user/mod.rs | 2 + .../tests/user/supabase_test/auth_test.rs | 28 ++ .../tests/user/supabase_test/helper.rs | 20 + .../tests/user/supabase_test/mod.rs | 3 + .../user/supabase_test/workspace_test.rs | 38 ++ frontend/rust-lib/flowy-user/Cargo.toml | 1 - .../rust-lib/flowy-user/src/event_handler.rs | 1 + frontend/rust-lib/flowy-user/src/event_map.rs | 5 + .../flowy-user/src/services/user_session.rs | 3 + 87 files changed, 1421 insertions(+), 1131 deletions(-) create mode 100644 frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart create mode 100644 frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.l.dart create mode 100644 frontend/rust-lib/dart-ffi/src/env_serde.rs delete mode 100644 frontend/rust-lib/flowy-database2/tests/database/script.rs create mode 100644 frontend/rust-lib/flowy-folder2/src/deps.rs create mode 100644 frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs create mode 100644 frontend/rust-lib/flowy-server/src/local_server/impls/mod.rs rename frontend/rust-lib/flowy-server/src/local_server/{ => impls}/user.rs (100%) create mode 100644 frontend/rust-lib/flowy-server/src/self_host/impls/folder.rs create mode 100644 frontend/rust-lib/flowy-server/src/self_host/impls/mod.rs rename frontend/rust-lib/flowy-server/src/self_host/{ => impls}/user.rs (100%) create mode 100644 frontend/rust-lib/flowy-server/src/supabase/impls/folder.rs create mode 100644 frontend/rust-lib/flowy-server/src/supabase/impls/mod.rs rename frontend/rust-lib/flowy-server/src/supabase/{ => impls}/user.rs (77%) create mode 100644 frontend/rust-lib/flowy-test/src/folder_event.rs delete mode 100644 frontend/rust-lib/flowy-test/src/helper.rs create mode 100644 frontend/rust-lib/flowy-test/src/user_event.rs create mode 100644 frontend/rust-lib/flowy-test/tests/main.rs rename frontend/rust-lib/{flowy-user/tests/event => flowy-test/tests/user/local_test}/auth_test.rs (64%) rename frontend/rust-lib/{flowy-user/tests/event => flowy-test/tests/user/local_test}/helper.rs (91%) rename frontend/rust-lib/{flowy-user/tests/event/main.rs => flowy-test/tests/user/local_test/mod.rs} (100%) rename frontend/rust-lib/{flowy-user/tests/event => flowy-test/tests/user/local_test}/user_profile_test.rs (61%) create mode 100644 frontend/rust-lib/flowy-test/tests/user/mod.rs create mode 100644 frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs create mode 100644 frontend/rust-lib/flowy-test/tests/user/supabase_test/helper.rs create mode 100644 frontend/rust-lib/flowy-test/tests/user/supabase_test/mod.rs create mode 100644 frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs diff --git a/frontend/appflowy_flutter/lib/core/config/config.dart b/frontend/appflowy_flutter/lib/core/config/config.dart index 19c771c793..1c727f78f2 100644 --- a/frontend/appflowy_flutter/lib/core/config/config.dart +++ b/frontend/appflowy_flutter/lib/core/config/config.dart @@ -16,4 +16,23 @@ class Config { ..jwtSecret = secret, ).send(); } + + static Future setSupabaseCollabPluginConfig({ + required String url, + required String key, + required String jwtSecret, + required String collabTable, + }) async { + final payload = CollabPluginConfigPB.create(); + final collabTableConfig = CollabTableConfigPB.create() + ..tableName = collabTable; + + payload.supabaseConfig = SupabaseDBConfigPB.create() + ..supabaseUrl = url + ..key = key + ..jwtSecret = jwtSecret + ..collabTableConfig = collabTableConfig; + + await ConfigEventSetCollabPluginConfig(payload).send(); + } } diff --git a/frontend/appflowy_flutter/lib/env/env.dart b/frontend/appflowy_flutter/lib/env/env.dart index 311df8a3ce..e3a57b9848 100644 --- a/frontend/appflowy_flutter/lib/env/env.dart +++ b/frontend/appflowy_flutter/lib/env/env.dart @@ -29,6 +29,13 @@ abstract class Env { defaultValue: '', ) static final supabaseJwtSecret = _Env.supabaseJwtSecret; + + @EnviedField( + obfuscate: true, + varName: 'SUPABASE_COLLAB_TABLE', + defaultValue: '', + ) + static final supabaseCollabTable = _Env.supabaseCollabTable; } bool get isSupabaseEnable => diff --git a/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart b/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart index 0fa2a42bd3..7518548309 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart @@ -6,7 +6,6 @@ import 'package:appflowy/util/json_print.dart'; import 'package:appflowy/workspace/application/view/view_listener.dart'; import 'package:appflowy/workspace/application/doc/doc_listener.dart'; import 'package:appflowy/plugins/document/application/doc_service.dart'; -import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-document2/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pbserver.dart'; import 'package:appflowy_editor/appflowy_editor.dart' @@ -153,7 +152,7 @@ class DocumentBloc extends Bloc { editorState.logConfiguration ..level = LogLevel.all ..handler = (log) { - Log.debug(log); + // Log.debug(log); }; } } diff --git a/frontend/appflowy_flutter/lib/startup/startup.dart b/frontend/appflowy_flutter/lib/startup/startup.dart index aa7cd9d4a5..6f85f962f3 100644 --- a/frontend/appflowy_flutter/lib/startup/startup.dart +++ b/frontend/appflowy_flutter/lib/startup/startup.dart @@ -62,6 +62,7 @@ class FlowyRunner { anonKey: Env.supabaseAnonKey, key: Env.supabaseKey, jwtSecret: Env.supabaseJwtSecret, + collabTable: Env.supabaseCollabTable, ), const InitAppWidgetTask(), const InitPlatformServiceTask() diff --git a/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart b/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart index 7e389c491c..ea2a4ec916 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart @@ -1,6 +1,8 @@ import 'dart:io'; +import 'package:appflowy/env/env.dart'; import 'package:appflowy_backend/appflowy_backend.dart'; +import 'package:appflowy_backend/env_serde.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; @@ -20,10 +22,35 @@ class InitRustSDKTask extends LaunchTask { @override Future initialize(LaunchContext context) async { final dir = directory ?? await appFlowyDocumentDirectory(); + + context.getIt().setEnv(getAppFlowyEnv()); await context.getIt().init(dir); } } +AppFlowyEnv getAppFlowyEnv() { + final supabaseConfig = SupabaseConfiguration( + url: Env.supabaseUrl, + key: Env.supabaseKey, + jwt_secret: Env.supabaseJwtSecret, + ); + + final collabTableConfig = + CollabTableConfig(enable: true, table_name: Env.supabaseCollabTable); + + final supbaseDBConfig = SupabaseDBConfig( + url: Env.supabaseUrl, + key: Env.supabaseKey, + jwt_secret: Env.supabaseJwtSecret, + collab_table_config: collabTableConfig, + ); + + return AppFlowyEnv( + supabase_config: supabaseConfig, + supabase_db_config: supbaseDBConfig, + ); +} + Future appFlowyDocumentDirectory() async { switch (integrationEnv()) { case IntegrationMode.develop: diff --git a/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart b/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart index e7369cd331..f915fd883e 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart @@ -13,12 +13,14 @@ class InitSupabaseTask extends LaunchTask { required this.anonKey, required this.key, required this.jwtSecret, + this.collabTable = "", }); final String url; final String anonKey; final String key; final String jwtSecret; + final String collabTable; @override Future initialize(LaunchContext context) async { @@ -33,6 +35,7 @@ class InitSupabaseTask extends LaunchTask { await Supabase.initialize( url: url, anonKey: anonKey, + debug: false, ); await Config.setSupabaseConfig( url: url, diff --git a/frontend/appflowy_flutter/linux/flutter/dart_ffi/binding.h b/frontend/appflowy_flutter/linux/flutter/dart_ffi/binding.h index 02e3d78602..3d42bf55ce 100644 --- a/frontend/appflowy_flutter/linux/flutter/dart_ffi/binding.h +++ b/frontend/appflowy_flutter/linux/flutter/dart_ffi/binding.h @@ -14,3 +14,5 @@ int32_t set_stream_port(int64_t port); void link_me_please(void); void backend_log(int64_t level, const char *data); + +void set_env(const char *data); diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/lib/appflowy_backend.dart b/frontend/appflowy_flutter/packages/appflowy_backend/lib/appflowy_backend.dart index 168865ebd2..a31faedf9d 100644 --- a/frontend/appflowy_flutter/packages/appflowy_backend/lib/appflowy_backend.dart +++ b/frontend/appflowy_flutter/packages/appflowy_backend/lib/appflowy_backend.dart @@ -1,9 +1,11 @@ export 'package:async/async.dart'; +import 'dart:convert'; import 'dart:io'; import 'dart:async'; import 'package:appflowy_backend/rust_stream.dart'; import 'package:flutter/services.dart'; import 'dart:ffi'; +import 'env_serde.dart'; import 'ffi.dart' as ffi; import 'package:ffi/ffi.dart'; @@ -34,4 +36,9 @@ class FlowySDK { ffi.store_dart_post_cobject(NativeApi.postCObject); ffi.init_sdk(sdkDir.path.toNativeUtf8()); } + + void setEnv(AppFlowyEnv env) { + final jsonStr = jsonEncode(env.toJson()); + ffi.set_env(jsonStr.toNativeUtf8()); + } } diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart new file mode 100644 index 0000000000..957476dbd2 --- /dev/null +++ b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart @@ -0,0 +1,64 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'env_serde.l.dart'; + +@JsonSerializable() +class AppFlowyEnv { + final SupabaseConfiguration supabase_config; + final SupabaseDBConfig supabase_db_config; + + AppFlowyEnv( + {required this.supabase_config, required this.supabase_db_config}); + + factory AppFlowyEnv.fromJson(Map json) => + _$AppFlowyEnvFromJson(json); + + Map toJson() => _$AppFlowyEnvToJson(this); +} + +@JsonSerializable() +class SupabaseConfiguration { + final String url; + final String key; + final String jwt_secret; + + SupabaseConfiguration( + {required this.url, required this.key, required this.jwt_secret}); + + factory SupabaseConfiguration.fromJson(Map json) => + _$SupabaseConfigurationFromJson(json); + + Map toJson() => _$SupabaseConfigurationToJson(this); +} + +@JsonSerializable() +class SupabaseDBConfig { + final String url; + final String key; + final String jwt_secret; + final CollabTableConfig collab_table_config; + + SupabaseDBConfig( + {required this.url, + required this.key, + required this.jwt_secret, + required this.collab_table_config}); + + factory SupabaseDBConfig.fromJson(Map json) => + _$SupabaseDBConfigFromJson(json); + + Map toJson() => _$SupabaseDBConfigToJson(this); +} + +@JsonSerializable() +class CollabTableConfig { + final String table_name; + final bool enable; + + CollabTableConfig({required this.table_name, required this.enable}); + + factory CollabTableConfig.fromJson(Map json) => + _$CollabTableConfigFromJson(json); + + Map toJson() => _$CollabTableConfigToJson(this); +} diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.l.dart b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.l.dart new file mode 100644 index 0000000000..8fe70f71d9 --- /dev/null +++ b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.l.dart @@ -0,0 +1,65 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'env_serde.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AppFlowyEnv _$AppFlowyEnvFromJson(Map json) => AppFlowyEnv( + supabase_config: SupabaseConfiguration.fromJson( + json['supabase_config'] as Map), + supabase_db_config: SupabaseDBConfig.fromJson( + json['supabase_db_config'] as Map), + ); + +Map _$AppFlowyEnvToJson(AppFlowyEnv instance) => + { + 'supabase_config': instance.supabase_config, + 'supabase_db_config': instance.supabase_db_config, + }; + +SupabaseConfiguration _$SupabaseConfigurationFromJson( + Map json) => + SupabaseConfiguration( + url: json['url'] as String, + key: json['key'] as String, + jwt_secret: json['jwt_secret'] as String, + ); + +Map _$SupabaseConfigurationToJson( + SupabaseConfiguration instance) => + { + 'url': instance.url, + 'key': instance.key, + 'jwt_secret': instance.jwt_secret, + }; + +SupabaseDBConfig _$SupabaseDBConfigFromJson(Map json) => + SupabaseDBConfig( + url: json['url'] as String, + key: json['key'] as String, + jwt_secret: json['jwt_secret'] as String, + collab_table_config: CollabTableConfig.fromJson( + json['collab_table_config'] as Map), + ); + +Map _$SupabaseDBConfigToJson(SupabaseDBConfig instance) => + { + 'url': instance.url, + 'key': instance.key, + 'jwt_secret': instance.jwt_secret, + 'collab_table_config': instance.collab_table_config, + }; + +CollabTableConfig _$CollabTableConfigFromJson(Map json) => + CollabTableConfig( + table_name: json['table_name'] as String, + enable: json['enable'] as bool, + ); + +Map _$CollabTableConfigToJson(CollabTableConfig instance) => + { + 'table_name': instance.table_name, + 'enable': instance.enable, + }; diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/lib/ffi.dart b/frontend/appflowy_flutter/packages/appflowy_backend/lib/ffi.dart index 54aa545f09..9d4e17cca1 100644 --- a/frontend/appflowy_flutter/packages/appflowy_backend/lib/ffi.dart +++ b/frontend/appflowy_flutter/packages/appflowy_backend/lib/ffi.dart @@ -151,3 +151,19 @@ typedef _invoke_log_Dart = void Function( int level, Pointer, ); + +/// C function `set_env`. +void set_env( + Pointer data, +) { + _set_env(data); +} + +final _set_env_Dart _set_env = + _dart_ffi_lib.lookupFunction<_set_env_C, _set_env_Dart>('set_env'); +typedef _set_env_C = Void Function( + Pointer data, +); +typedef _set_env_Dart = void Function( + Pointer data, +); diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/linux/Classes/binding.h b/frontend/appflowy_flutter/packages/appflowy_backend/linux/Classes/binding.h index 78a4fbec57..9a1769c338 100644 --- a/frontend/appflowy_flutter/packages/appflowy_backend/linux/Classes/binding.h +++ b/frontend/appflowy_flutter/packages/appflowy_backend/linux/Classes/binding.h @@ -15,3 +15,5 @@ int32_t set_stream_port(int64_t port); void link_me_please(void); void backend_log(int64_t level, const char *data); + +void set_env(const char *data); diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/macos/Classes/binding.h b/frontend/appflowy_flutter/packages/appflowy_backend/macos/Classes/binding.h index 02e3d78602..3d42bf55ce 100644 --- a/frontend/appflowy_flutter/packages/appflowy_backend/macos/Classes/binding.h +++ b/frontend/appflowy_flutter/packages/appflowy_backend/macos/Classes/binding.h @@ -14,3 +14,5 @@ int32_t set_stream_port(int64_t port); void link_me_please(void); void backend_log(int64_t level, const char *data); + +void set_env(const char *data); diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/pubspec.yaml b/frontend/appflowy_flutter/packages/appflowy_backend/pubspec.yaml index 66505ea63f..3ae7337a34 100644 --- a/frontend/appflowy_flutter/packages/appflowy_backend/pubspec.yaml +++ b/frontend/appflowy_flutter/packages/appflowy_backend/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: freezed_annotation: logger: ^1.0.0 plugin_platform_interface: ^2.1.3 + json_annotation: ^4.7.0 dev_dependencies: flutter_test: @@ -25,6 +26,7 @@ dev_dependencies: build_runner: freezed: flutter_lints: ^2.0.1 + json_serializable: ^6.6.2 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index d0055f78ff..774aa10c5d 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -99,8 +99,9 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "appflowy-integrate" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ + "anyhow", "collab", "collab-database", "collab-document", @@ -109,6 +110,7 @@ dependencies = [ "collab-plugins", "serde", "serde_json", + "tracing", ] [[package]] @@ -1021,7 +1023,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "bytes", @@ -1038,7 +1040,7 @@ dependencies = [ [[package]] name = "collab-client-ws" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "bytes", "collab-sync", @@ -1056,7 +1058,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "async-trait", @@ -1075,12 +1077,13 @@ dependencies = [ "thiserror", "tokio", "tracing", + "uuid", ] [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "proc-macro2", "quote", @@ -1092,7 +1095,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "collab", @@ -1109,7 +1112,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "collab", @@ -1127,7 +1130,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "bincode", "chrono", @@ -1147,21 +1150,25 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "async-trait", "aws-config", "aws-credential-types", "aws-sdk-dynamodb", + "base64 0.21.0", "collab", "collab-client-ws", "collab-persistence", "collab-sync", "futures-util", "parking_lot 0.12.1", + "postgrest", "rand 0.8.5", "rusoto_credential", + "serde", + "serde_json", "thiserror", "tokio", "tokio-retry", @@ -1173,7 +1180,7 @@ dependencies = [ [[package]] name = "collab-sync" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "bytes", "collab", @@ -1773,6 +1780,7 @@ dependencies = [ "flowy-codegen", "flowy-derive", "flowy-error", + "flowy-server", "flowy-sqlite", "lib-dispatch", "protobuf", @@ -1803,6 +1811,7 @@ dependencies = [ "parking_lot 0.12.1", "serde", "serde_json", + "serde_repr", "tokio", "tracing", ] @@ -1972,9 +1981,10 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes", + "chrono", "config", - "flowy-config", "flowy-error", + "flowy-folder2", "flowy-user", "futures-util", "hyper", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 43055e5f77..2c60f20e01 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -34,12 +34,12 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } +collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } #collab = { path = "../../AppFlowy-Collab/collab" } #collab-folder = { path = "../../AppFlowy-Collab/collab-folder" } diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 9614eefc0b..0950dffacd 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -85,8 +85,9 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "appflowy-integrate" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ + "anyhow", "collab", "collab-database", "collab-document", @@ -95,6 +96,7 @@ dependencies = [ "collab-plugins", "serde", "serde_json", + "tracing", ] [[package]] @@ -884,7 +886,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "bytes", @@ -901,7 +903,7 @@ dependencies = [ [[package]] name = "collab-client-ws" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "bytes", "collab-sync", @@ -919,7 +921,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "async-trait", @@ -938,12 +940,13 @@ dependencies = [ "thiserror", "tokio", "tracing", + "uuid", ] [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "proc-macro2", "quote", @@ -955,7 +958,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "collab", @@ -972,7 +975,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "collab", @@ -990,7 +993,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "bincode", "chrono", @@ -1010,21 +1013,25 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "anyhow", "async-trait", "aws-config", "aws-credential-types", "aws-sdk-dynamodb", + "base64 0.21.0", "collab", "collab-client-ws", "collab-persistence", "collab-sync", "futures-util", "parking_lot 0.12.1", + "postgrest", "rand 0.8.5", "rusoto_credential", + "serde", + "serde_json", "thiserror", "tokio", "tokio-retry", @@ -1036,7 +1043,7 @@ dependencies = [ [[package]] name = "collab-sync" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bff164#bff1647076b2370c34f19d57d8d0da4bbb80ee55" dependencies = [ "bytes", "collab", @@ -1254,6 +1261,7 @@ name = "dart-ffi" version = "0.1.0" dependencies = [ "allo-isolate", + "appflowy-integrate", "byteorder", "bytes", "crossbeam-utils", @@ -1463,11 +1471,12 @@ dependencies = [ [[package]] name = "fake" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d68f517805463f3a896a9d29c1d6ff09d3579ded64a7201b4069f8f9c0d52fd" +checksum = "0a44c765350db469b774425ff1c833890b16ceb9612fb5d7c4bbdf4a1b55f876" dependencies = [ "rand 0.8.5", + "unidecode", ] [[package]] @@ -1551,6 +1560,7 @@ dependencies = [ "flowy-codegen", "flowy-derive", "flowy-error", + "flowy-server", "flowy-sqlite", "lib-dispatch", "protobuf", @@ -1582,6 +1592,7 @@ dependencies = [ "parking_lot 0.12.1", "serde", "serde_json", + "serde_repr", "tokio", "tracing", ] @@ -1757,10 +1768,11 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes", + "chrono", "config", "dotenv", - "flowy-config", "flowy-error", + "flowy-folder2", "flowy-user", "futures-util", "hyper", @@ -1820,28 +1832,26 @@ name = "flowy-test" version = "0.1.0" dependencies = [ "bytes", - "fake", + "dotenv", "flowy-core", "flowy-folder2", "flowy-net", "flowy-server", "flowy-user", - "futures", "futures-util", "lib-dispatch", "lib-infra", "lib-ot", - "log", "nanoid", + "parking_lot 0.12.1", "protobuf", - "quickcheck", - "quickcheck_macros 0.9.1", "serde", "serde_json", - "serial_test", "tempdir", "thread-id", "tokio", + "tracing", + "uuid", ] [[package]] @@ -1859,7 +1869,6 @@ dependencies = [ "flowy-error", "flowy-notification", "flowy-sqlite", - "flowy-test", "lazy_static", "lib-dispatch", "lib-infra", @@ -1869,7 +1878,7 @@ dependencies = [ "parking_lot 0.12.1", "protobuf", "quickcheck", - "quickcheck_macros 1.0.0", + "quickcheck_macros", "rand 0.8.5", "rand_core 0.6.4", "serde", @@ -3483,17 +3492,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "quickcheck_macros" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608c156fd8e97febc07dc9c2e2c80bf74cfc6ef26893eae3daf8bc2bc94a4b7f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "quickcheck_macros" version = "1.0.0" @@ -4121,28 +4119,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serial_test" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d" -dependencies = [ - "lazy_static", - "parking_lot 0.11.2", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "sha-1" version = "0.9.8" @@ -4978,6 +4954,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "unidecode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" + [[package]] name = "untrusted" version = "0.7.1" diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index d613ae3bea..18743f82e8 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -33,11 +33,11 @@ opt-level = 3 incremental = false [patch.crates-io] -collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } -appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" } +collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } +appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bff164" } #collab = { path = "../AppFlowy-Collab/collab" } #collab-folder = { path = "../AppFlowy-Collab/collab-folder" } diff --git a/frontend/rust-lib/dart-ffi/Cargo.toml b/frontend/rust-lib/dart-ffi/Cargo.toml index 0b0380d9e6..824b205e25 100644 --- a/frontend/rust-lib/dart-ffi/Cargo.toml +++ b/frontend/rust-lib/dart-ffi/Cargo.toml @@ -24,7 +24,7 @@ crossbeam-utils = "0.8.15" lazy_static = "1.4.0" parking_lot = "0.12.1" tracing = { version = "0.1", features = ["log"] } - +appflowy-integrate = {version = "0.1.0" } lib-dispatch = { path = "../lib-dispatch" } flowy-core = { path = "../flowy-core" } diff --git a/frontend/rust-lib/dart-ffi/binding.h b/frontend/rust-lib/dart-ffi/binding.h index 02e3d78602..3d42bf55ce 100644 --- a/frontend/rust-lib/dart-ffi/binding.h +++ b/frontend/rust-lib/dart-ffi/binding.h @@ -14,3 +14,5 @@ int32_t set_stream_port(int64_t port); void link_me_please(void); void backend_log(int64_t level, const char *data); + +void set_env(const char *data); diff --git a/frontend/rust-lib/dart-ffi/src/env_serde.rs b/frontend/rust-lib/dart-ffi/src/env_serde.rs new file mode 100644 index 0000000000..6c0add7e37 --- /dev/null +++ b/frontend/rust-lib/dart-ffi/src/env_serde.rs @@ -0,0 +1,19 @@ +use appflowy_integrate::SupabaseDBConfig; +use flowy_server::supabase::SupabaseConfiguration; +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +pub struct AppFlowyEnv { + supabase_config: SupabaseConfiguration, + supabase_db_config: SupabaseDBConfig, +} + +impl AppFlowyEnv { + pub fn parser(env_str: &str) { + if let Ok(env) = serde_json::from_str::(env_str) { + dbg!(&env); + env.supabase_config.write_env(); + env.supabase_db_config.write_env(); + } + } +} diff --git a/frontend/rust-lib/dart-ffi/src/lib.rs b/frontend/rust-lib/dart-ffi/src/lib.rs index 4b18368f90..e64ed40337 100644 --- a/frontend/rust-lib/dart-ffi/src/lib.rs +++ b/frontend/rust-lib/dart-ffi/src/lib.rs @@ -10,6 +10,7 @@ use flowy_notification::register_notification_sender; use lib_dispatch::prelude::ToBytes; use lib_dispatch::prelude::*; +use crate::env_serde::AppFlowyEnv; use crate::notification::DartNotificationSender; use crate::{ c::{extend_front_four_bytes_into_bytes, forget_rust}, @@ -17,6 +18,7 @@ use crate::{ }; mod c; +mod env_serde; mod model; mod notification; mod protobuf; @@ -134,3 +136,10 @@ pub extern "C" fn backend_log(level: i64, data: *const c_char) { _ => (), } } + +#[no_mangle] +pub extern "C" fn set_env(data: *const c_char) { + let c_str = unsafe { CStr::from_ptr(data) }; + let serde_str = c_str.to_str().unwrap(); + AppFlowyEnv::parser(serde_str); +} diff --git a/frontend/rust-lib/flowy-config/Cargo.toml b/frontend/rust-lib/flowy-config/Cargo.toml index 5751f53599..0725e7363e 100644 --- a/frontend/rust-lib/flowy-config/Cargo.toml +++ b/frontend/rust-lib/flowy-config/Cargo.toml @@ -14,6 +14,7 @@ bytes = { version = "1.4" } flowy-error = { path = "../flowy-error" } strum_macros = "0.21" appflowy-integrate = {version = "0.1.0" } +flowy-server = { path = "../flowy-server" } [build-dependencies] flowy-codegen = { path = "../../../shared-lib/flowy-codegen"} diff --git a/frontend/rust-lib/flowy-config/src/entities.rs b/frontend/rust-lib/flowy-config/src/entities.rs index 625e45f7d0..d1f963cd0c 100644 --- a/frontend/rust-lib/flowy-config/src/entities.rs +++ b/frontend/rust-lib/flowy-config/src/entities.rs @@ -1,4 +1,8 @@ +use appflowy_integrate::config::AWSDynamoDBConfig; +use appflowy_integrate::{CollabTableConfig, SupabaseDBConfig}; use flowy_derive::ProtoBuf; +use flowy_error::FlowyError; +use flowy_server::supabase::SupabaseConfiguration; #[derive(Default, ProtoBuf)] pub struct KeyValuePB { @@ -15,11 +19,6 @@ pub struct KeyPB { pub key: String, } -pub const SUPABASE_URL: &str = "SUPABASE_URL"; -pub const SUPABASE_ANON_KEY: &str = "SUPABASE_ANON_KEY"; -pub const SUPABASE_KEY: &str = "SUPABASE_KEY"; -pub const SUPABASE_JWT_SECRET: &str = "SUPABASE_JWT_SECRET"; - #[derive(Default, ProtoBuf)] pub struct SupabaseConfigPB { #[pb(index = 1)] @@ -35,28 +34,97 @@ pub struct SupabaseConfigPB { jwt_secret: String, } -impl SupabaseConfigPB { - pub(crate) fn write_to_env(self) { - std::env::set_var(SUPABASE_URL, self.supabase_url); - std::env::set_var(SUPABASE_ANON_KEY, self.anon_key); - std::env::set_var(SUPABASE_KEY, self.key); - std::env::set_var(SUPABASE_JWT_SECRET, self.jwt_secret); +impl TryFrom for SupabaseConfiguration { + type Error = FlowyError; + + fn try_from(value: SupabaseConfigPB) -> Result { + Ok(Self { + url: value.supabase_url, + key: value.key, + jwt_secret: value.jwt_secret, + }) } } #[derive(Default, ProtoBuf)] -pub struct AppFlowyCollabConfigPB { +pub struct CollabPluginConfigPB { #[pb(index = 1, one_of)] - aws_config: Option, + pub aws_config: Option, + + #[pb(index = 2, one_of)] + pub supabase_config: Option, } #[derive(Default, ProtoBuf)] pub struct AWSDynamoDBConfigPB { #[pb(index = 1)] pub access_key_id: String, + #[pb(index = 2)] pub secret_access_key: String, // Region list: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html #[pb(index = 3)] pub region: String, } + +impl TryFrom for AWSDynamoDBConfig { + type Error = FlowyError; + + fn try_from(config: AWSDynamoDBConfigPB) -> Result { + Ok(AWSDynamoDBConfig { + access_key_id: config.access_key_id, + secret_access_key: config.secret_access_key, + region: config.region, + enable: true, + }) + } +} + +#[derive(Default, ProtoBuf)] +pub struct SupabaseDBConfigPB { + #[pb(index = 1)] + pub supabase_url: String, + + #[pb(index = 2)] + pub key: String, + + #[pb(index = 3)] + pub jwt_secret: String, + + #[pb(index = 4)] + pub collab_table_config: CollabTableConfigPB, +} + +impl TryFrom for SupabaseDBConfig { + type Error = FlowyError; + + fn try_from(config: SupabaseDBConfigPB) -> Result { + let update_table_config = CollabTableConfig::try_from(config.collab_table_config)?; + Ok(SupabaseDBConfig { + url: config.supabase_url, + key: config.key, + jwt_secret: config.jwt_secret, + collab_table_config: update_table_config, + }) + } +} + +#[derive(Default, ProtoBuf)] +pub struct CollabTableConfigPB { + #[pb(index = 1)] + pub table_name: String, +} + +impl TryFrom for CollabTableConfig { + type Error = FlowyError; + + fn try_from(config: CollabTableConfigPB) -> Result { + if config.table_name.is_empty() { + return Err(FlowyError::internal().context("table_name is empty")); + } + Ok(CollabTableConfig { + table_name: config.table_name, + enable: true, + }) + } +} diff --git a/frontend/rust-lib/flowy-config/src/event_handler.rs b/frontend/rust-lib/flowy-config/src/event_handler.rs index 9915e83526..c5b7ef5fb8 100644 --- a/frontend/rust-lib/flowy-config/src/event_handler.rs +++ b/frontend/rust-lib/flowy-config/src/event_handler.rs @@ -1,8 +1,11 @@ +use appflowy_integrate::config::AWSDynamoDBConfig; +use appflowy_integrate::SupabaseDBConfig; use flowy_error::{FlowyError, FlowyResult}; +use flowy_server::supabase::SupabaseConfiguration; use flowy_sqlite::kv::KV; use lib_dispatch::prelude::{data_result_ok, AFPluginData, DataResult}; -use crate::entities::{KeyPB, KeyValuePB, SupabaseConfigPB}; +use crate::entities::{CollabPluginConfigPB, KeyPB, KeyValuePB, SupabaseConfigPB}; pub(crate) async fn set_key_value_handler(data: AFPluginData) -> FlowyResult<()> { let data = data.into_inner(); @@ -35,7 +38,24 @@ pub(crate) async fn remove_key_value_handler(data: AFPluginData) -> Flowy pub(crate) async fn set_supabase_config_handler( data: AFPluginData, ) -> FlowyResult<()> { - let config = data.into_inner(); - config.write_to_env(); + let config = SupabaseConfiguration::try_from(data.into_inner())?; + config.write_env(); + Ok(()) +} + +pub(crate) async fn set_collab_plugin_config_handler( + data: AFPluginData, +) -> FlowyResult<()> { + let config = data.into_inner(); + if let Some(aws_config_pb) = config.aws_config { + if let Ok(aws_config) = AWSDynamoDBConfig::try_from(aws_config_pb) { + aws_config.write_env(); + } + } + if let Some(supabase_config_pb) = config.supabase_config { + if let Ok(supabase_config) = SupabaseDBConfig::try_from(supabase_config_pb) { + supabase_config.write_env(); + } + } Ok(()) } diff --git a/frontend/rust-lib/flowy-config/src/event_map.rs b/frontend/rust-lib/flowy-config/src/event_map.rs index e9c5392547..24394f5678 100644 --- a/frontend/rust-lib/flowy-config/src/event_map.rs +++ b/frontend/rust-lib/flowy-config/src/event_map.rs @@ -12,6 +12,10 @@ pub fn init() -> AFPlugin { .event(ConfigEvent::GetKeyValue, get_key_value_handler) .event(ConfigEvent::RemoveKeyValue, remove_key_value_handler) .event(ConfigEvent::SetSupabaseConfig, set_supabase_config_handler) + .event( + ConfigEvent::SetCollabPluginConfig, + set_collab_plugin_config_handler, + ) } #[derive(Debug, Clone, PartialEq, Eq, Hash, Display, ProtoBuf_Enum, Flowy_Event)] @@ -30,4 +34,7 @@ pub enum ConfigEvent { /// Check out the `write_to_env` of [SupabaseConfigPB]. #[event(input = "SupabaseConfigPB")] SetSupabaseConfig = 3, + + #[event(input = "CollabPluginConfigPB")] + SetCollabPluginConfig = 4, } diff --git a/frontend/rust-lib/flowy-core/Cargo.toml b/frontend/rust-lib/flowy-core/Cargo.toml index 05597d4c2a..1c32d78231 100644 --- a/frontend/rust-lib/flowy-core/Cargo.toml +++ b/frontend/rust-lib/flowy-core/Cargo.toml @@ -11,12 +11,9 @@ lib-log = { path = "../lib-log" } flowy-user = { path = "../flowy-user" } flowy-net = { path = "../flowy-net" } flowy-folder2 = { path = "../flowy-folder2" } -#flowy-database = { path = "../flowy-database" } flowy-database2 = { path = "../flowy-database2" } flowy-sqlite = { path = "../flowy-sqlite", optional = true } -#flowy-document = { path = "../flowy-document" } flowy-document2 = { path = "../flowy-document2" } -#flowy-revision = { path = "../flowy-revision" } flowy-error = { path = "../flowy-error" } flowy-task = { path = "../flowy-task" } flowy-server = { path = "../flowy-server" } @@ -34,6 +31,7 @@ lib-ws = { path = "../../../shared-lib/lib-ws" } lib-infra = { path = "../../../shared-lib/lib-infra" } serde = "1.0" serde_json = "1.0" +serde_repr = "0.1" [features] default = ["rev-sqlite"] diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder2_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder2_deps.rs index b75ee72670..b6f4b7d634 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder2_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder2_deps.rs @@ -13,8 +13,9 @@ use flowy_document2::document_data::DocumentDataWrapper; use flowy_document2::entities::DocumentDataPB; use flowy_document2::manager::DocumentManager; use flowy_error::FlowyError; +use flowy_folder2::deps::{FolderCloudService, FolderUser}; use flowy_folder2::entities::ViewLayoutPB; -use flowy_folder2::manager::{Folder2Manager, FolderUser}; +use flowy_folder2::manager::Folder2Manager; use flowy_folder2::view_ext::{ViewDataProcessor, ViewDataProcessorMap}; use flowy_folder2::ViewLayout; use flowy_user::services::UserSession; @@ -27,13 +28,14 @@ impl Folder2DepsResolver { document_manager: &Arc, database_manager: &Arc, collab_builder: Arc, + folder_cloud: Arc, ) -> Arc { let user: Arc = Arc::new(FolderUserImpl(user_session.clone())); - let view_data_processor = + let view_processors = make_view_data_processor(document_manager.clone(), database_manager.clone()); Arc::new( - Folder2Manager::new(user.clone(), collab_builder, view_data_processor) + Folder2Manager::new(user.clone(), collab_builder, view_processors, folder_cloud) .await .unwrap(), ) diff --git a/frontend/rust-lib/flowy-core/src/integrate/server.rs b/frontend/rust-lib/flowy-core/src/integrate/server.rs index eb4a5bb0f9..e5cb539eee 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/server.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/server.rs @@ -1,64 +1,134 @@ +use lib_infra::future::FutureResult; use std::collections::HashMap; use std::sync::Arc; use parking_lot::RwLock; -use flowy_error::{ErrorCode, FlowyError}; +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_folder2::deps::{FolderCloudService, Workspace}; use flowy_server::local_server::LocalServer; use flowy_server::self_host::configuration::self_host_server_configuration; use flowy_server::self_host::SelfHostServer; use flowy_server::supabase::{SupabaseConfiguration, SupabaseServer}; use flowy_server::AppFlowyServer; +use flowy_sqlite::kv::KV; use flowy_user::event_map::{UserAuthService, UserCloudServiceProvider}; use flowy_user::services::AuthType; +use serde_repr::*; + +const SERVER_PROVIDER_TYPE_KEY: &str = "server_provider_type"; + +#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum ServerProviderType { + /// Local server provider. + /// Offline mode, no user authentication and the data is stored locally. + Local = 0, + /// Self-hosted server provider. + /// The [AppFlowy-Server](https://github.com/AppFlowy-IO/AppFlowy-Server) is still a work in + /// progress. + SelfHosted = 1, + /// Supabase server provider. + /// It uses supabase's postgresql database to store data and user authentication. + Supabase = 2, +} + /// The [AppFlowyServerProvider] provides list of [AppFlowyServer] base on the [AuthType]. Using /// the auth type, the [AppFlowyServerProvider] will create a new [AppFlowyServer] if it doesn't /// exist. /// Each server implements the [AppFlowyServer] trait, which provides the [UserAuthService], etc. -#[derive(Default)] pub struct AppFlowyServerProvider { - providers: RwLock>>, + provider_type: RwLock, + providers: RwLock>>, } impl AppFlowyServerProvider { pub fn new() -> Self { Self::default() } -} -impl UserCloudServiceProvider for AppFlowyServerProvider { - /// Returns the [UserAuthService] base on the current [AuthType]. - /// Creates a new [AppFlowyServer] if it doesn't exist. - fn get_auth_service(&self, auth_type: &AuthType) -> Result, FlowyError> { - if let Some(provider) = self.providers.read().get(auth_type) { - return Ok(provider.user_service()); + pub fn provider_type(&self) -> ServerProviderType { + self.provider_type.read().clone() + } + + /// Returns a [AppFlowyServer] trait implementation base on the provider_type. + fn get_provider( + &self, + provider_type: &ServerProviderType, + ) -> FlowyResult> { + if let Some(provider) = self.providers.read().get(provider_type) { + return Ok(provider.clone()); } - let server = server_from_auth_type(auth_type)?; - let user_service = server.user_service(); - self.providers.write().insert(auth_type.clone(), server); - Ok(user_service) + let server = server_from_auth_type(provider_type)?; + self + .providers + .write() + .insert(provider_type.clone(), server.clone()); + Ok(server) } } -fn server_from_auth_type(auth_type: &AuthType) -> Result, FlowyError> { - match auth_type { - AuthType::Local => { +impl Default for AppFlowyServerProvider { + fn default() -> Self { + Self { + provider_type: RwLock::new(current_server_provider()), + providers: RwLock::new(HashMap::new()), + } + } +} + +impl UserCloudServiceProvider for AppFlowyServerProvider { + /// When user login, the provider type is set by the [AuthType]. + /// Each [AuthType] has a corresponding [ServerProviderType]. The [ServerProviderType] is used + /// to create a new [AppFlowyServer] if it doesn't exist. Once the [ServerProviderType] is set, + /// it will be used when user open the app again. + fn set_auth_type(&self, auth_type: AuthType) { + let provider_type: ServerProviderType = auth_type.into(); + match KV::set_object(SERVER_PROVIDER_TYPE_KEY, provider_type.clone()) { + Ok(_) => tracing::trace!("Update server provider type to: {:?}", provider_type), + Err(e) => { + tracing::error!("🔴Failed to update server provider type: {:?}", e); + }, + } + } + + /// Returns the [UserAuthService] base on the current [ServerProviderType]. + /// Creates a new [AppFlowyServer] if it doesn't exist. + fn get_auth_service(&self, auth_type: &AuthType) -> Result, FlowyError> { + let provider_type: ServerProviderType = auth_type.into(); + Ok(self.get_provider(&provider_type)?.user_service()) + } +} + +impl FolderCloudService for AppFlowyServerProvider { + fn create_workspace(&self, uid: i64, name: &str) -> FutureResult { + let server = self.get_provider(&self.provider_type.read()); + let name = name.to_string(); + FutureResult::new(async move { server?.folder_service().create_workspace(uid, &name).await }) + } +} + +fn server_from_auth_type( + provider: &ServerProviderType, +) -> Result, FlowyError> { + match provider { + ServerProviderType::Local => { let server = Arc::new(LocalServer::new()); Ok(server) }, - AuthType::SelfHosted => { + ServerProviderType::SelfHosted => { let config = self_host_server_configuration().map_err(|e| { FlowyError::new( ErrorCode::InvalidAuthConfig, - format!("Missing self host config: {:?}. Error: {:?}", auth_type, e), + format!("Missing self host config: {:?}. Error: {:?}", provider, e), ) })?; let server = Arc::new(SelfHostServer::new(config)); Ok(server) }, - AuthType::Supabase => { + ServerProviderType::Supabase => { // init the SupabaseServerConfiguration from the environment variables. let config = SupabaseConfiguration::from_env()?; let server = Arc::new(SupabaseServer::new(config)); @@ -66,3 +136,26 @@ fn server_from_auth_type(auth_type: &AuthType) -> Result }, } } + +impl From for ServerProviderType { + fn from(auth_provider: AuthType) -> Self { + match auth_provider { + AuthType::Local => ServerProviderType::Local, + AuthType::SelfHosted => ServerProviderType::SelfHosted, + AuthType::Supabase => ServerProviderType::Supabase, + } + } +} + +impl From<&AuthType> for ServerProviderType { + fn from(auth_provider: &AuthType) -> Self { + Self::from(auth_provider.clone()) + } +} + +fn current_server_provider() -> ServerProviderType { + match KV::get_object::(SERVER_PROVIDER_TYPE_KEY) { + None => ServerProviderType::Local, + Some(provider_type) => provider_type, + } +} diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index c5b5b81a64..935e71ee4a 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -1,6 +1,5 @@ #![allow(unused_doc_comments)] -use std::str::FromStr; use std::time::Duration; use std::{ fmt, @@ -10,8 +9,8 @@ use std::{ }, }; -use appflowy_integrate::collab_builder::AppFlowyCollabBuilder; -use appflowy_integrate::config::{AWSDynamoDBConfig, AppFlowyCollabConfig}; +use appflowy_integrate::collab_builder::{AppFlowyCollabBuilder, CloudStorageType}; + use tokio::sync::RwLock; use flowy_database2::DatabaseManager2; @@ -28,9 +27,10 @@ use lib_dispatch::runtime::tokio_default_runtime; use lib_infra::future::{to_fut, Fut}; use module::make_plugins; pub use module::*; +use tracing::debug; use crate::deps_resolve::*; -use crate::integrate::server::AppFlowyServerProvider; +use crate::integrate::server::{AppFlowyServerProvider, ServerProviderType}; mod deps_resolve; mod integrate; @@ -92,10 +92,8 @@ fn create_log_filter(level: String, with_crates: Vec) -> String { filters.push(format!("flowy_document2={}", level)); filters.push(format!("flowy_database2={}", level)); filters.push(format!("flowy_notification={}", "info")); - filters.push(format!("lib_ot={}", level)); filters.push(format!("lib_infra={}", level)); filters.push(format!("flowy_task={}", level)); - // filters.push(format!("lib_dispatch={}", level)); filters.push(format!("dart_ffi={}", "info")); filters.push(format!("flowy_sqlite={}", "info")); @@ -136,22 +134,19 @@ impl AppFlowyCore { // Init the key value database init_kv(&config.storage_path); - // The collab config is used to build the [Collab] instance that used in document, - // database, folder, etc. - let collab_config = get_collab_config(); - inject_aws_env(collab_config.aws_config()); - - /// The shared collab builder is used to build the [Collab] instance. The plugins will be loaded - /// on demand based on the [AppFlowyCollabConfig]. - let collab_builder = Arc::new(AppFlowyCollabBuilder::new(collab_config)); - - tracing::debug!("🔥 {:?}", config); + debug!("🔥 {:?}", &config); let runtime = tokio_default_runtime().unwrap(); let task_scheduler = TaskDispatcher::new(Duration::from_secs(2)); let task_dispatcher = Arc::new(RwLock::new(task_scheduler)); runtime.spawn(TaskRunner::run(task_dispatcher.clone())); let server_provider = Arc::new(AppFlowyServerProvider::new()); + /// The shared collab builder is used to build the [Collab] instance. The plugins will be loaded + /// on demand based on the [CollabPluginConfig]. + let cloud_storage_type = + collab_storage_type_from_server_provider_type(&server_provider.provider_type()); + let collab_builder = Arc::new(AppFlowyCollabBuilder::new(cloud_storage_type)); + let (user_session, folder_manager, server_provider, database_manager, document_manager2) = runtime.block_on(async { let user_session = mk_user_session(&config, server_provider.clone()); @@ -173,6 +168,7 @@ impl AppFlowyCore { &document_manager2, &database_manager2, collab_builder.clone(), + server_provider.clone(), ) .await; @@ -233,23 +229,6 @@ fn init_kv(root: &str) { } } -fn get_collab_config() -> AppFlowyCollabConfig { - match KV::get_str("collab_config") { - None => AppFlowyCollabConfig::default(), - Some(s) => AppFlowyCollabConfig::from_str(&s).unwrap_or_default(), - } -} - -fn inject_aws_env(aws_config: Option<&AWSDynamoDBConfig>) { - if let Some(aws_config) = aws_config { - std::env::set_var("AWS_ACCESS_KEY_ID", aws_config.access_key_id.clone()); - std::env::set_var( - "AWS_SECRET_ACCESS_KEY", - aws_config.secret_access_key.clone(), - ); - } -} - fn init_log(config: &AppFlowyCoreConfig) { if !INIT_LOG.load(Ordering::SeqCst) { INIT_LOG.store(true, Ordering::SeqCst); @@ -334,3 +313,13 @@ impl UserStatusCallback for UserStatusCallbackImpl { to_fut(async move { listener.did_expired(&token, user_id).await }) } } + +fn collab_storage_type_from_server_provider_type( + server_provider_type: &ServerProviderType, +) -> CloudStorageType { + match server_provider_type { + ServerProviderType::Local => CloudStorageType::Local, + ServerProviderType::SelfHosted => CloudStorageType::Local, + ServerProviderType::Supabase => CloudStorageType::Supabase, + } +} diff --git a/frontend/rust-lib/flowy-database2/src/event_handler.rs b/frontend/rust-lib/flowy-database2/src/event_handler.rs index 64b04bb36f..c043a35a05 100644 --- a/frontend/rust-lib/flowy-database2/src/event_handler.rs +++ b/frontend/rust-lib/flowy-database2/src/event_handler.rs @@ -334,7 +334,7 @@ pub(crate) async fn create_row_handler( } } -#[tracing::instrument(level = "trace", skip_all, err)] +// #[tracing::instrument(level = "trace", skip_all, err)] pub(crate) async fn get_cell_handler( data: AFPluginData, manager: AFPluginState>, @@ -560,7 +560,6 @@ pub(crate) async fn set_layout_setting_handler( Ok(()) } -#[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn get_layout_setting_handler( data: AFPluginData, manager: AFPluginState>, diff --git a/frontend/rust-lib/flowy-database2/src/manager.rs b/frontend/rust-lib/flowy-database2/src/manager.rs index 97ad7c132c..9a2468da23 100644 --- a/frontend/rust-lib/flowy-database2/src/manager.rs +++ b/frontend/rust-lib/flowy-database2/src/manager.rs @@ -3,7 +3,7 @@ use std::ops::Deref; use std::sync::Arc; use appflowy_integrate::collab_builder::AppFlowyCollabBuilder; -use appflowy_integrate::{RocksCollabDB, RocksDBConfig}; +use appflowy_integrate::{CollabPersistenceConfig, RocksCollabDB}; use collab::core::collab::MutexCollab; use collab_database::database::DatabaseData; use collab_database::user::{UserDatabase as InnerUserDatabase, UserDatabaseCollabBuilder}; @@ -51,7 +51,7 @@ impl DatabaseManager2 { *self.user_database.lock() = Some(InnerUserDatabase::new( user_id, db, - RocksDBConfig::default(), + CollabPersistenceConfig::default(), UserDatabaseCollabBuilderImpl(self.collab_builder.clone()), )); // do nothing @@ -229,7 +229,7 @@ impl UserDatabaseCollabBuilder for UserDatabaseCollabBuilderImpl { uid: i64, object_id: &str, db: Arc, - config: &RocksDBConfig, + config: &CollabPersistenceConfig, ) -> Arc { self.0.build_with_config(uid, object_id, db, config) } diff --git a/frontend/rust-lib/flowy-database2/src/services/database_view/view_group.rs b/frontend/rust-lib/flowy-database2/src/services/database_view/view_group.rs index 69e64355f5..d52f79657e 100644 --- a/frontend/rust-lib/flowy-database2/src/services/database_view/view_group.rs +++ b/frontend/rust-lib/flowy-database2/src/services/database_view/view_group.rs @@ -3,8 +3,9 @@ use std::sync::Arc; use collab_database::fields::Field; use collab_database::rows::RowId; -use flowy_error::FlowyResult; +use flowy_error::{FlowyError, FlowyResult}; use lib_infra::future::{to_fut, Fut}; +use tracing::trace; use crate::entities::FieldType; use crate::services::database_view::DatabaseViewData; @@ -42,9 +43,10 @@ pub async fn new_group_controller( let fields = delegate.get_fields(&view_id, None).await; let rows = delegate.get_rows(&view_id).await; let layout = delegate.get_layout_for_view(&view_id); + trace!(?fields, ?rows, ?layout, "new_group_controller"); // Read the grouping field or find a new grouping field - let grouping_field = setting_reader + let mut grouping_field = setting_reader .get_group_setting(&view_id) .await .and_then(|setting| { @@ -52,17 +54,25 @@ pub async fn new_group_controller( .iter() .find(|field| field.id == setting.field_id) .cloned() - }) - .unwrap_or_else(|| find_new_grouping_field(&fields, &layout).unwrap()); + }); - make_group_controller( - view_id, - grouping_field, - rows, - setting_reader, - setting_writer, - ) - .await + if grouping_field.is_none() { + grouping_field = find_new_grouping_field(&fields, &layout); + } + + match grouping_field { + None => Err(FlowyError::internal().context("No grouping field found".to_owned())), + Some(_) => { + make_group_controller( + view_id, + grouping_field.unwrap(), + rows, + setting_reader, + setting_writer, + ) + .await + }, + } } pub(crate) struct GroupSettingReaderImpl(pub Arc); diff --git a/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/format.rs b/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/format.rs index ac24ee1a5d..ba66f257c7 100644 --- a/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/format.rs +++ b/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/format.rs @@ -7,15 +7,9 @@ use strum::IntoEnumIterator; use strum_macros::EnumIter; lazy_static! { - pub static ref CURRENCY_SYMBOL: Vec = sorted_symbol(); -} - -fn sorted_symbol() -> Vec { - let mut symbols = NumberFormat::iter() + pub static ref CURRENCY_SYMBOL: Vec = NumberFormat::iter() .map(|format| format.symbol()) .collect::>(); - symbols.sort_by(|a, b| b.len().cmp(&a.len())); - symbols } #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize)] diff --git a/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option.rs index 2b8edbce73..54fcb25472 100644 --- a/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option.rs @@ -137,9 +137,7 @@ impl NumberTypeOption { }; match Decimal::from_str(&num_str) { - Ok(decimal, ..) => { - return Ok(NumberCellFormat::from_decimal(decimal)); - }, + Ok(decimal, ..) => Ok(NumberCellFormat::from_decimal(decimal)), Err(_) => Ok(NumberCellFormat::new()), } } diff --git a/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option_entities.rs b/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option_entities.rs index 0380603c0a..c32e0529f2 100644 --- a/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option_entities.rs +++ b/frontend/rust-lib/flowy-database2/src/services/field/type_options/number_type_option/number_type_option_entities.rs @@ -27,7 +27,7 @@ impl NumberCellFormat { return Ok(Self::default()); } // If the first char is not '-', then it is a sign. - let sign_positive = match num_str.find("-") { + let sign_positive = match num_str.find('-') { None => true, Some(offset) => offset != 0, }; diff --git a/frontend/rust-lib/flowy-database2/src/services/field/type_options/type_option_cell.rs b/frontend/rust-lib/flowy-database2/src/services/field/type_options/type_option_cell.rs index bdc7974b5b..6f4dd799a6 100644 --- a/frontend/rust-lib/flowy-database2/src/services/field/type_options/type_option_cell.rs +++ b/frontend/rust-lib/flowy-database2/src/services/field/type_options/type_option_cell.rs @@ -162,7 +162,7 @@ where ) { if let Some(cell_data_cache) = self.cell_data_cache.as_ref() { let field_type = FieldType::from(field.field_type); - let key = CellDataCacheKey::new(field, field_type.clone(), cell); + let key = CellDataCacheKey::new(field, field_type, cell); // tracing::trace!( // "Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}", // field_type, diff --git a/frontend/rust-lib/flowy-database2/src/services/sort/controller.rs b/frontend/rust-lib/flowy-database2/src/services/sort/controller.rs index ca1d90a9c2..a8d0c28d61 100644 --- a/frontend/rust-lib/flowy-database2/src/services/sort/controller.rs +++ b/frontend/rust-lib/flowy-database2/src/services/sort/controller.rs @@ -85,7 +85,7 @@ impl SortController { self.gen_task(task_type, QualityOfService::Background).await; } - #[tracing::instrument(name = "process_sort_task", level = "debug", skip_all, err)] + // #[tracing::instrument(name = "process_sort_task", level = "trace", skip_all, err)] pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> { let event_type = SortEvent::from_str(predicate).unwrap(); let mut rows = self.delegate.get_rows(&self.view_id).await; diff --git a/frontend/rust-lib/flowy-database2/tests/database/database_editor.rs b/frontend/rust-lib/flowy-database2/tests/database/database_editor.rs index 395b55e6bb..7976c72039 100644 --- a/frontend/rust-lib/flowy-database2/tests/database/database_editor.rs +++ b/frontend/rust-lib/flowy-database2/tests/database/database_editor.rs @@ -13,13 +13,13 @@ use flowy_database2::services::field::{ SelectOptionCellChangeset, SingleSelectTypeOption, }; use flowy_error::FlowyResult; -use flowy_test::helper::ViewTest; -use flowy_test::FlowySDKTest; +use flowy_test::folder_event::ViewTest; +use flowy_test::FlowyCoreTest; use crate::database::mock_data::{make_test_board, make_test_calendar, make_test_grid}; pub struct DatabaseEditorTest { - pub sdk: FlowySDKTest, + pub sdk: FlowyCoreTest, pub app_id: String, pub view_id: String, pub editor: Arc, @@ -43,7 +43,7 @@ impl DatabaseEditorTest { } pub async fn new(layout: DatabaseLayoutPB) -> Self { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let _ = sdk.init_user().await; let test = match layout { DatabaseLayoutPB::Grid => { diff --git a/frontend/rust-lib/flowy-database2/tests/database/script.rs b/frontend/rust-lib/flowy-database2/tests/database/script.rs deleted file mode 100644 index 69511759c0..0000000000 --- a/frontend/rust-lib/flowy-database2/tests/database/script.rs +++ /dev/null @@ -1,425 +0,0 @@ -use bytes::Bytes; -use database_model::entities::{ - BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, - GridBlockInfoChangeset, GridBlockMetaSnapshot, InsertFieldParams, RowMeta, RowMetaChangeset, - RowOrder, TypeOptionDataFormat, -}; -use flowy_client_sync::client_grid::GridBuilder; -use flowy_database::services::field::*; -use flowy_database::services::grid_meta_editor::{GridMetaEditor, GridPadBuilder}; -use flowy_database::services::row::CreateRowMetaPayload; -use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_test::helper::ViewTest; -use flowy_test::FlowySDKTest; -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; -use strum::EnumCount; -use tokio::time::sleep; - -pub enum EditorScript { - CreateField { - params: InsertFieldParams, - }, - UpdateField { - changeset: FieldChangesetParams, - }, - DeleteField { - field_meta: FieldMeta, - }, - AssertFieldCount(usize), - AssertFieldEqual { - field_index: usize, - field_meta: FieldMeta, - }, - CreateBlock { - block: GridBlockMetaSnapshot, - }, - UpdateBlock { - changeset: GridBlockInfoChangeset, - }, - AssertBlockCount(usize), - AssertBlock { - block_index: usize, - row_count: i32, - start_row_index: i32, - }, - AssertBlockEqual { - block_index: usize, - block: GridBlockMetaSnapshot, - }, - CreateEmptyRow, - CreateRow { - context: CreateRowMetaPayload, - }, - UpdateRow { - changeset: RowMetaChangeset, - }, - AssertRow { - changeset: RowMetaChangeset, - }, - DeleteRow { - row_ids: Vec, - }, - UpdateCell { - changeset: CellChangeset, - is_err: bool, - }, - AssertRowCount(usize), - // AssertRowEqual{ row_index: usize, row: RowMeta}, - AssertGridMetaPad, -} - -pub struct GridEditorTest { - pub sdk: FlowySDKTest, - pub grid_id: String, - pub editor: Arc, - pub field_metas: Vec, - pub grid_blocks: Vec, - pub row_metas: Vec>, - pub field_count: usize, - - pub row_order_by_row_id: HashMap, -} - -impl GridEditorTest { - pub async fn new() -> Self { - let sdk = FlowySDKTest::default(); - let _ = sdk.init_user().await; - let build_context = make_template_1_grid(); - let view_data: Bytes = build_context.into(); - let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; - let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); - let field_metas = editor.get_field_metas::(None).await.unwrap(); - let grid_blocks = editor.get_block_metas().await.unwrap(); - let row_metas = get_row_metas(&editor).await; - - let grid_id = test.view.id; - Self { - sdk, - grid_id, - editor, - field_metas, - grid_blocks, - row_metas, - field_count: FieldType::COUNT, - row_order_by_row_id: HashMap::default(), - } - } - - pub async fn run_scripts(&mut self, scripts: Vec) { - for script in scripts { - self.run_script(script).await; - } - } - - pub async fn run_script(&mut self, script: EditorScript) { - let grid_manager = self.sdk.grid_manager.clone(); - let pool = self.sdk.user_session.db_pool().unwrap(); - let rev_manager = self.editor.rev_manager(); - let _cache = rev_manager.revision_cache().await; - - match script { - EditorScript::CreateField { params } => { - if !self.editor.contain_field(¶ms.field.id).await { - self.field_count += 1; - } - - self.editor.insert_field(params).await.unwrap(); - self.field_metas = self - .editor - .get_field_metas::(None) - .await - .unwrap(); - assert_eq!(self.field_count, self.field_metas.len()); - }, - EditorScript::UpdateField { changeset: change } => { - self.editor.update_field(change).await.unwrap(); - self.field_metas = self - .editor - .get_field_metas::(None) - .await - .unwrap(); - }, - EditorScript::DeleteField { field_meta } => { - if self.editor.contain_field(&field_meta.id).await { - self.field_count -= 1; - } - - self.editor.delete_field(&field_meta.id).await.unwrap(); - self.field_metas = self - .editor - .get_field_metas::(None) - .await - .unwrap(); - assert_eq!(self.field_count, self.field_metas.len()); - }, - EditorScript::AssertFieldCount(count) => { - assert_eq!( - self - .editor - .get_field_metas::(None) - .await - .unwrap() - .len(), - count - ); - }, - EditorScript::AssertFieldEqual { - field_index, - field_meta, - } => { - let field_metas = self - .editor - .get_field_metas::(None) - .await - .unwrap(); - assert_eq!(field_metas[field_index].clone(), field_meta); - }, - EditorScript::CreateBlock { block } => { - self.editor.create_block(block).await.unwrap(); - self.grid_blocks = self.editor.get_block_metas().await.unwrap(); - }, - EditorScript::UpdateBlock { changeset: change } => { - self.editor.update_block(change).await.unwrap(); - }, - EditorScript::AssertBlockCount(count) => { - assert_eq!(self.editor.get_block_metas().await.unwrap().len(), count); - }, - EditorScript::AssertBlock { - block_index, - row_count, - start_row_index, - } => { - assert_eq!(self.grid_blocks[block_index].row_count, row_count); - assert_eq!( - self.grid_blocks[block_index].start_row_index, - start_row_index - ); - }, - EditorScript::AssertBlockEqual { block_index, block } => { - let blocks = self.editor.get_block_metas().await.unwrap(); - let compared_block = blocks[block_index].clone(); - assert_eq!(compared_block, block); - }, - EditorScript::CreateEmptyRow => { - let row_order = self.editor.create_row(None).await.unwrap(); - self - .row_order_by_row_id - .insert(row_order.row_id.clone(), row_order); - self.row_metas = self.get_row_metas().await; - self.grid_blocks = self.editor.get_block_metas().await.unwrap(); - }, - EditorScript::CreateRow { context } => { - let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); - for row_order in row_orders { - self - .row_order_by_row_id - .insert(row_order.row_id.clone(), row_order); - } - self.row_metas = self.get_row_metas().await; - self.grid_blocks = self.editor.get_block_metas().await.unwrap(); - }, - EditorScript::UpdateRow { changeset: change } => { - self.editor.update_row(change).await.unwrap() - }, - EditorScript::DeleteRow { row_ids } => { - let row_orders = row_ids - .into_iter() - .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) - .collect::>(); - - self.editor.delete_rows(row_orders).await.unwrap(); - self.row_metas = self.get_row_metas().await; - self.grid_blocks = self.editor.get_block_metas().await.unwrap(); - }, - EditorScript::AssertRow { changeset } => { - let row = self - .row_metas - .iter() - .find(|row| row.id == changeset.row_id) - .unwrap(); - - if let Some(visibility) = changeset.visibility { - assert_eq!(row.visibility, visibility); - } - - if let Some(height) = changeset.height { - assert_eq!(row.height, height); - } - }, - EditorScript::UpdateCell { changeset, is_err } => { - let result = self.editor.update_cell(changeset).await; - if is_err { - assert!(result.is_err()) - } else { - let _ = result.unwrap(); - self.row_metas = self.get_row_metas().await; - } - }, - EditorScript::AssertRowCount(count) => { - assert_eq!(self.row_metas.len(), count); - }, - EditorScript::AssertGridMetaPad => { - sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; - let mut grid_rev_manager = grid_manager - .make_grid_rev_manager(&self.grid_id, pool.clone()) - .unwrap(); - let grid_pad = grid_rev_manager.load::(None).await.unwrap(); - println!("{}", grid_pad.delta_str()); - }, - } - } - - async fn get_row_metas(&self) -> Vec> { - get_row_metas(&self.editor).await - } -} - -async fn get_row_metas(editor: &Arc) -> Vec> { - editor - .grid_block_snapshots(None) - .await - .unwrap() - .pop() - .unwrap() - .row_metas -} - -pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) { - let field_meta = FieldBuilder::new(RichTextTypeOptionBuilder::default()) - .name("Name") - .visibility(true) - .build(); - - let cloned_field_meta = field_meta.clone(); - - let type_option_data = field_meta - .get_type_option_entry::(&field_meta.field_type) - .unwrap() - .protobuf_bytes() - .to_vec(); - - let field = Field { - id: field_meta.id, - name: field_meta.name, - desc: field_meta.desc, - field_type: field_meta.field_type, - frozen: field_meta.frozen, - visibility: field_meta.visibility, - width: field_meta.width, - is_primary: false, - }; - - let params = InsertFieldParams { - grid_id: grid_id.to_owned(), - field, - type_option_data, - start_field_id: None, - }; - (params, cloned_field_meta) -} - -pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) { - let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Done")) - .option(SelectOption::new("Progress")); - - let field_meta = FieldBuilder::new(single_select) - .name("Name") - .visibility(true) - .build(); - let cloned_field_meta = field_meta.clone(); - let type_option_data = field_meta - .get_type_option_entry::(&field_meta.field_type) - .unwrap() - .protobuf_bytes() - .to_vec(); - - let field = Field { - id: field_meta.id, - name: field_meta.name, - desc: field_meta.desc, - field_type: field_meta.field_type, - frozen: field_meta.frozen, - visibility: field_meta.visibility, - width: field_meta.width, - is_primary: false, - }; - - let params = InsertFieldParams { - grid_id: grid_id.to_owned(), - field, - type_option_data, - start_field_id: None, - }; - (params, cloned_field_meta) -} - -fn make_template_1_grid() -> BuildGridContext { - let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) - .name("Name") - .visibility(true) - .build(); - - // Single Select - let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Live")) - .option(SelectOption::new("Completed")) - .option(SelectOption::new("Planned")) - .option(SelectOption::new("Paused")); - let single_select_field = FieldBuilder::new(single_select) - .name("Status") - .visibility(true) - .build(); - - // MultiSelect - let multi_select = MultiSelectTypeOptionBuilder::default() - .option(SelectOption::new("Google")) - .option(SelectOption::new("Facebook")) - .option(SelectOption::new("Twitter")); - let multi_select_field = FieldBuilder::new(multi_select) - .name("Platform") - .visibility(true) - .build(); - - // Number - let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); - let number_field = FieldBuilder::new(number) - .name("Price") - .visibility(true) - .build(); - - // Date - let date = DateTypeOptionBuilder::default() - .date_format(DateFormat::US) - .time_format(TimeFormat::TwentyFourHour); - let date_field = FieldBuilder::new(date) - .name("Time") - .visibility(true) - .build(); - - // Checkbox - let checkbox = CheckboxTypeOptionBuilder::default(); - let checkbox_field = FieldBuilder::new(checkbox) - .name("is done") - .visibility(true) - .build(); - - // URL - let url = URLTypeOptionBuilder::default(); - let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); - - GridBuilder::default() - .add_field(text_field) - .add_field(single_select_field) - .add_field(multi_select_field) - .add_field(number_field) - .add_field(date_field) - .add_field(checkbox_field) - .add_field(url_field) - .add_empty_row() - .add_empty_row() - .add_empty_row() - .build() -} diff --git a/frontend/rust-lib/flowy-document2/tests/document/util.rs b/frontend/rust-lib/flowy-document2/tests/document/util.rs index 3d59b50af5..5dcb7eb68a 100644 --- a/frontend/rust-lib/flowy-document2/tests/document/util.rs +++ b/frontend/rust-lib/flowy-document2/tests/document/util.rs @@ -1,5 +1,5 @@ -use appflowy_integrate::collab_builder::AppFlowyCollabBuilder; -use appflowy_integrate::config::AppFlowyCollabConfig; +use appflowy_integrate::collab_builder::{AppFlowyCollabBuilder, CloudStorageType}; + use std::sync::Arc; use appflowy_integrate::RocksCollabDB; @@ -50,6 +50,6 @@ pub fn db() -> Arc { } pub fn default_collab_builder() -> Arc { - let builder = AppFlowyCollabBuilder::new(AppFlowyCollabConfig::default()); + let builder = AppFlowyCollabBuilder::new(CloudStorageType::Local); Arc::new(builder) } diff --git a/frontend/rust-lib/flowy-folder2/src/deps.rs b/frontend/rust-lib/flowy-folder2/src/deps.rs new file mode 100644 index 0000000000..3e46e4d127 --- /dev/null +++ b/frontend/rust-lib/flowy-folder2/src/deps.rs @@ -0,0 +1,17 @@ +use appflowy_integrate::RocksCollabDB; +pub use collab_folder::core::Workspace; +use flowy_error::FlowyError; +use lib_infra::future::FutureResult; +use std::sync::Arc; + +/// [FolderUser] represents the user for folder. +pub trait FolderUser: Send + Sync { + fn user_id(&self) -> Result; + fn token(&self) -> Result, FlowyError>; + fn collab_db(&self) -> Result, FlowyError>; +} + +/// [FolderCloudService] represents the cloud service for folder. +pub trait FolderCloudService: Send + Sync + 'static { + fn create_workspace(&self, uid: i64, name: &str) -> FutureResult; +} diff --git a/frontend/rust-lib/flowy-folder2/src/entities/workspace.rs b/frontend/rust-lib/flowy-folder2/src/entities/workspace.rs index c0b1553fd7..538fc29bbd 100644 --- a/frontend/rust-lib/flowy-folder2/src/entities/workspace.rs +++ b/frontend/rust-lib/flowy-folder2/src/entities/workspace.rs @@ -106,7 +106,7 @@ impl WorkspaceIdPB { } } -#[derive(Default, ProtoBuf, Clone)] +#[derive(Default, ProtoBuf, Debug, Clone)] pub struct WorkspaceSettingPB { #[pb(index = 1)] pub workspace: WorkspacePB, diff --git a/frontend/rust-lib/flowy-folder2/src/event_map.rs b/frontend/rust-lib/flowy-folder2/src/event_map.rs index ee72436baf..1e37718ce2 100644 --- a/frontend/rust-lib/flowy-folder2/src/event_map.rs +++ b/frontend/rust-lib/flowy-folder2/src/event_map.rs @@ -3,6 +3,7 @@ use crate::manager::Folder2Manager; use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; use lib_dispatch::prelude::*; + use std::sync::Arc; use strum_macros::Display; diff --git a/frontend/rust-lib/flowy-folder2/src/lib.rs b/frontend/rust-lib/flowy-folder2/src/lib.rs index 244caa9ab4..32411b2b67 100644 --- a/frontend/rust-lib/flowy-folder2/src/lib.rs +++ b/frontend/rust-lib/flowy-folder2/src/lib.rs @@ -7,7 +7,9 @@ pub mod protobuf; mod user_default; pub mod view_ext; +pub mod deps; #[cfg(feature = "test_helper")] mod test_helper; pub use collab_folder::core::ViewLayout; +pub use user_default::gen_workspace_id; diff --git a/frontend/rust-lib/flowy-folder2/src/manager.rs b/frontend/rust-lib/flowy-folder2/src/manager.rs index 253168d2af..c3d1ee0c43 100644 --- a/frontend/rust-lib/flowy-folder2/src/manager.rs +++ b/frontend/rust-lib/flowy-folder2/src/manager.rs @@ -3,7 +3,7 @@ use std::ops::Deref; use std::sync::Arc; use appflowy_integrate::collab_builder::AppFlowyCollabBuilder; -use appflowy_integrate::RocksCollabDB; + use collab_folder::core::{ Folder as InnerFolder, FolderContext, TrashChange, TrashChangeReceiver, TrashInfo, TrashRecord, View, ViewChange, ViewChangeReceiver, ViewLayout, Workspace, @@ -11,6 +11,7 @@ use collab_folder::core::{ use parking_lot::Mutex; use tracing::{event, Level}; +use crate::deps::{FolderCloudService, FolderUser}; use flowy_error::{FlowyError, FlowyResult}; use lib_infra::util::timestamp; @@ -22,22 +23,17 @@ use crate::notification::{ send_notification, send_workspace_notification, send_workspace_setting_notification, FolderNotification, }; -use crate::user_default::{gen_workspace_id, DefaultFolderBuilder}; +use crate::user_default::DefaultFolderBuilder; use crate::view_ext::{ gen_view_id, view_from_create_view_params, ViewDataProcessor, ViewDataProcessorMap, }; -pub trait FolderUser: Send + Sync { - fn user_id(&self) -> Result; - fn token(&self) -> Result, FlowyError>; - fn collab_db(&self) -> Result, FlowyError>; -} - pub struct Folder2Manager { folder: Folder, collab_builder: Arc, user: Arc, view_processors: ViewDataProcessorMap, + cloud_service: Arc, } unsafe impl Send for Folder2Manager {} @@ -48,6 +44,7 @@ impl Folder2Manager { user: Arc, collab_builder: Arc, view_processors: ViewDataProcessorMap, + cloud_service: Arc, ) -> FlowyResult { let folder = Folder::default(); let manager = Self { @@ -55,6 +52,7 @@ impl Folder2Manager { folder, collab_builder, view_processors, + cloud_service, }; Ok(manager) @@ -90,7 +88,7 @@ impl Folder2Manager { } /// Called immediately after the application launched fi the user already sign in/sign up. - #[tracing::instrument(level = "trace", skip(self), err)] + #[tracing::instrument(level = "debug", skip(self), err)] pub async fn initialize(&self, uid: i64, workspace_id: &str) -> FlowyResult<()> { if let Ok(collab_db) = self.user.collab_db() { let collab = self.collab_builder.build(uid, workspace_id, collab_db); @@ -139,13 +137,10 @@ impl Folder2Manager { pub async fn clear(&self, _user_id: i64) {} pub async fn create_workspace(&self, params: CreateWorkspaceParams) -> FlowyResult { - let workspace = Workspace { - id: gen_workspace_id(), - name: params.name, - belongings: Default::default(), - created_at: timestamp(), - }; - + let workspace = self + .cloud_service + .create_workspace(self.user.user_id()?, ¶ms.name) + .await?; self.with_folder((), |folder| { folder.workspaces.create_workspace(workspace.clone()); folder.set_current_workspace(&workspace.id); diff --git a/frontend/rust-lib/flowy-folder2/tests/workspace/folder_test.rs b/frontend/rust-lib/flowy-folder2/tests/workspace/folder_test.rs index 0bfd606f60..c68da3041c 100644 --- a/frontend/rust-lib/flowy-folder2/tests/workspace/folder_test.rs +++ b/frontend/rust-lib/flowy-folder2/tests/workspace/folder_test.rs @@ -1,7 +1,7 @@ use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest}; use collab_folder::core::ViewLayout; use flowy_folder2::entities::CreateWorkspacePayloadPB; -use flowy_test::{event_builder::*, FlowySDKTest}; +use flowy_test::{event_builder::*, FlowyCoreTest}; #[tokio::test] async fn workspace_read_all() { @@ -63,18 +63,19 @@ async fn workspace_create_with_apps() { #[tokio::test] async fn workspace_create_with_invalid_name() { for (name, code) in invalid_workspace_name_test_case() { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let request = CreateWorkspacePayloadPB { name, desc: "".to_owned(), }; assert_eq!( - Folder2EventBuilder::new(sdk) + EventBuilder::new(sdk) .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace) .payload(request) .async_send() .await .error() + .unwrap() .code, code.value() ) diff --git a/frontend/rust-lib/flowy-folder2/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder2/tests/workspace/script.rs index aadc7d2fcf..e00d9fc152 100644 --- a/frontend/rust-lib/flowy-folder2/tests/workspace/script.rs +++ b/frontend/rust-lib/flowy-folder2/tests/workspace/script.rs @@ -2,8 +2,8 @@ use collab_folder::core::ViewLayout; use flowy_error::ErrorCode; use flowy_folder2::entities::*; use flowy_folder2::event_map::FolderEvent::*; -use flowy_test::event_builder::Folder2EventBuilder; -use flowy_test::FlowySDKTest; +use flowy_test::event_builder::EventBuilder; +use flowy_test::FlowyCoreTest; pub enum FolderScript { // Workspace @@ -51,7 +51,7 @@ pub enum FolderScript { } pub struct FolderTest { - pub sdk: FlowySDKTest, + pub sdk: FlowyCoreTest, pub all_workspace: Vec, pub workspace: WorkspacePB, pub parent_view: ViewPB, @@ -61,7 +61,7 @@ pub struct FolderTest { impl FolderTest { pub async fn new() -> Self { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let _ = sdk.init_user().await; let workspace = create_workspace(&sdk, "FolderWorkspace", "Folder test workspace").await; let parent_view = create_app(&sdk, &workspace.id, "Folder App", "Folder test app").await; @@ -170,13 +170,13 @@ pub fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> { ] } -pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> WorkspacePB { +pub async fn create_workspace(sdk: &FlowyCoreTest, name: &str, desc: &str) -> WorkspacePB { let request = CreateWorkspacePayloadPB { name: name.to_owned(), desc: desc.to_owned(), }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(CreateWorkspace) .payload(request) .async_send() @@ -184,11 +184,11 @@ pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Wor .parse::() } -pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> Vec { +pub async fn read_workspace(sdk: &FlowyCoreTest, workspace_id: Option) -> Vec { let request = WorkspaceIdPB { value: workspace_id, }; - let repeated_workspace = Folder2EventBuilder::new(sdk.clone()) + let repeated_workspace = EventBuilder::new(sdk.clone()) .event(ReadWorkspaces) .payload(request.clone()) .async_send() @@ -210,7 +210,7 @@ pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> workspaces } -pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc: &str) -> ViewPB { +pub async fn create_app(sdk: &FlowyCoreTest, workspace_id: &str, name: &str, desc: &str) -> ViewPB { let create_view_request = CreateViewPayloadPB { belong_to_id: workspace_id.to_owned(), name: name.to_string(), @@ -221,7 +221,7 @@ pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc ext: Default::default(), }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(CreateView) .payload(create_view_request) .async_send() @@ -230,7 +230,7 @@ pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc } pub async fn create_view( - sdk: &FlowySDKTest, + sdk: &FlowyCoreTest, app_id: &str, name: &str, desc: &str, @@ -245,7 +245,7 @@ pub async fn create_view( initial_data: vec![], ext: Default::default(), }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(CreateView) .payload(request) .async_send() @@ -253,9 +253,9 @@ pub async fn create_view( .parse::() } -pub async fn read_view(sdk: &FlowySDKTest, view_id: &str) -> ViewPB { +pub async fn read_view(sdk: &FlowyCoreTest, view_id: &str) -> ViewPB { let view_id: ViewIdPB = view_id.into(); - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(ReadView) .payload(view_id) .async_send() @@ -264,7 +264,7 @@ pub async fn read_view(sdk: &FlowySDKTest, view_id: &str) -> ViewPB { } pub async fn update_view( - sdk: &FlowySDKTest, + sdk: &FlowyCoreTest, view_id: &str, name: Option, desc: Option, @@ -275,54 +275,54 @@ pub async fn update_view( desc, thumbnail: None, }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(UpdateView) .payload(request) .async_send() .await; } -pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { +pub async fn delete_view(sdk: &FlowyCoreTest, view_ids: Vec) { let request = RepeatedViewIdPB { items: view_ids }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(DeleteView) .payload(request) .async_send() .await; } -pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrashPB { - Folder2EventBuilder::new(sdk.clone()) +pub async fn read_trash(sdk: &FlowyCoreTest) -> RepeatedTrashPB { + EventBuilder::new(sdk.clone()) .event(ReadTrash) .async_send() .await .parse::() } -pub async fn restore_app_from_trash(sdk: &FlowySDKTest, app_id: &str) { +pub async fn restore_app_from_trash(sdk: &FlowyCoreTest, app_id: &str) { let id = TrashIdPB { id: app_id.to_owned(), }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(PutbackTrash) .payload(id) .async_send() .await; } -pub async fn restore_view_from_trash(sdk: &FlowySDKTest, view_id: &str) { +pub async fn restore_view_from_trash(sdk: &FlowyCoreTest, view_id: &str) { let id = TrashIdPB { id: view_id.to_owned(), }; - Folder2EventBuilder::new(sdk.clone()) + EventBuilder::new(sdk.clone()) .event(PutbackTrash) .payload(id) .async_send() .await; } -pub async fn delete_all_trash(sdk: &FlowySDKTest) { - Folder2EventBuilder::new(sdk.clone()) +pub async fn delete_all_trash(sdk: &FlowyCoreTest) { + EventBuilder::new(sdk.clone()) .event(DeleteAllTrash) .async_send() .await; diff --git a/frontend/rust-lib/flowy-server/Cargo.toml b/frontend/rust-lib/flowy-server/Cargo.toml index 86de966116..3a21a687bd 100644 --- a/frontend/rust-lib/flowy-server/Cargo.toml +++ b/frontend/rust-lib/flowy-server/Cargo.toml @@ -24,11 +24,12 @@ postgrest = "1.0" tokio-retry = "0.3" anyhow = "1.0" uuid = { version = "1.3.3", features = ["v4"] } +chrono = "0.4.24" lib-infra = { path = "../../../shared-lib/lib-infra" } flowy-user = { path = "../flowy-user" } +flowy-folder2 = { path = "../flowy-folder2" } flowy-error = { path = "../flowy-error" } -flowy-config = { path = "../flowy-config" } [dev-dependencies] uuid = { version = "1.3.3", features = ["v4"] } diff --git a/frontend/rust-lib/flowy-server/src/lib.rs b/frontend/rust-lib/flowy-server/src/lib.rs index a6df90122c..34bf7b9b23 100644 --- a/frontend/rust-lib/flowy-server/src/lib.rs +++ b/frontend/rust-lib/flowy-server/src/lib.rs @@ -1,3 +1,4 @@ +use flowy_folder2::deps::FolderCloudService; use std::sync::Arc; use flowy_user::event_map::UserAuthService; @@ -8,6 +9,21 @@ mod response; pub mod self_host; pub mod supabase; +/// In order to run this the supabase test, you need to create a .env file in the root directory of this project +/// and add the following environment variables: +/// - SUPABASE_URL +/// - SUPABASE_ANON_KEY +/// - SUPABASE_KEY +/// - SUPABASE_JWT_SECRET +/// +/// the .env file should look like this: +/// SUPABASE_URL=https://.supabase.co +/// SUPABASE_ANON_KEY= +/// SUPABASE_KEY= +/// SUPABASE_JWT_SECRET= +/// + pub trait AppFlowyServer: Send + Sync + 'static { fn user_service(&self) -> Arc; + fn folder_service(&self) -> Arc; } diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs new file mode 100644 index 0000000000..93ffc1d21c --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs @@ -0,0 +1,21 @@ +use flowy_error::FlowyError; +use flowy_folder2::deps::{FolderCloudService, Workspace}; +use flowy_folder2::gen_workspace_id; +use lib_infra::future::FutureResult; +use lib_infra::util::timestamp; + +pub(crate) struct LocalServerFolderCloudServiceImpl(); + +impl FolderCloudService for LocalServerFolderCloudServiceImpl { + fn create_workspace(&self, _uid: i64, name: &str) -> FutureResult { + let name = name.to_string(); + FutureResult::new(async move { + Ok(Workspace { + id: gen_workspace_id(), + name: name.to_string(), + belongings: Default::default(), + created_at: timestamp(), + }) + }) + } +} diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/mod.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/mod.rs new file mode 100644 index 0000000000..8a05c27f6b --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/mod.rs @@ -0,0 +1,5 @@ +mod folder; +mod user; + +pub(crate) use folder::*; +pub(crate) use user::*; diff --git a/frontend/rust-lib/flowy-server/src/local_server/user.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs similarity index 100% rename from frontend/rust-lib/flowy-server/src/local_server/user.rs rename to frontend/rust-lib/flowy-server/src/local_server/impls/user.rs diff --git a/frontend/rust-lib/flowy-server/src/local_server/mod.rs b/frontend/rust-lib/flowy-server/src/local_server/mod.rs index 27e033264b..6e67356fd9 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/mod.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/mod.rs @@ -1,5 +1,5 @@ pub use server::*; +pub mod impls; mod server; pub(crate) mod uid; -mod user; diff --git a/frontend/rust-lib/flowy-server/src/local_server/server.rs b/frontend/rust-lib/flowy-server/src/local_server/server.rs index 1074dae092..added89985 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/server.rs @@ -1,11 +1,14 @@ use std::sync::Arc; +use flowy_folder2::deps::FolderCloudService; use parking_lot::RwLock; use tokio::sync::mpsc; use flowy_user::event_map::UserAuthService; -use crate::local_server::user::LocalServerUserAuthServiceImpl; +use crate::local_server::impls::{ + LocalServerFolderCloudServiceImpl, LocalServerUserAuthServiceImpl, +}; use crate::AppFlowyServer; #[derive(Default)] @@ -31,4 +34,8 @@ impl AppFlowyServer for LocalServer { fn user_service(&self) -> Arc { Arc::new(LocalServerUserAuthServiceImpl()) } + + fn folder_service(&self) -> Arc { + Arc::new(LocalServerFolderCloudServiceImpl()) + } } diff --git a/frontend/rust-lib/flowy-server/src/self_host/impls/folder.rs b/frontend/rust-lib/flowy-server/src/self_host/impls/folder.rs new file mode 100644 index 0000000000..9bbbb9db45 --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/self_host/impls/folder.rs @@ -0,0 +1,21 @@ +use flowy_error::FlowyError; +use flowy_folder2::deps::{FolderCloudService, Workspace}; +use flowy_folder2::gen_workspace_id; +use lib_infra::future::FutureResult; +use lib_infra::util::timestamp; + +pub(crate) struct SelfHostedServerFolderCloudServiceImpl(); + +impl FolderCloudService for SelfHostedServerFolderCloudServiceImpl { + fn create_workspace(&self, _uid: i64, name: &str) -> FutureResult { + let name = name.to_string(); + FutureResult::new(async move { + Ok(Workspace { + id: gen_workspace_id(), + name: name.to_string(), + belongings: Default::default(), + created_at: timestamp(), + }) + }) + } +} diff --git a/frontend/rust-lib/flowy-server/src/self_host/impls/mod.rs b/frontend/rust-lib/flowy-server/src/self_host/impls/mod.rs new file mode 100644 index 0000000000..8a05c27f6b --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/self_host/impls/mod.rs @@ -0,0 +1,5 @@ +mod folder; +mod user; + +pub(crate) use folder::*; +pub(crate) use user::*; diff --git a/frontend/rust-lib/flowy-server/src/self_host/user.rs b/frontend/rust-lib/flowy-server/src/self_host/impls/user.rs similarity index 100% rename from frontend/rust-lib/flowy-server/src/self_host/user.rs rename to frontend/rust-lib/flowy-server/src/self_host/impls/user.rs diff --git a/frontend/rust-lib/flowy-server/src/self_host/mod.rs b/frontend/rust-lib/flowy-server/src/self_host/mod.rs index 4247b51760..90ba7604f7 100644 --- a/frontend/rust-lib/flowy-server/src/self_host/mod.rs +++ b/frontend/rust-lib/flowy-server/src/self_host/mod.rs @@ -1,6 +1,5 @@ pub use server::*; -pub use user::*; pub mod configuration; +pub mod impls; mod server; -mod user; diff --git a/frontend/rust-lib/flowy-server/src/self_host/server.rs b/frontend/rust-lib/flowy-server/src/self_host/server.rs index d10abbe600..0b9cf29582 100644 --- a/frontend/rust-lib/flowy-server/src/self_host/server.rs +++ b/frontend/rust-lib/flowy-server/src/self_host/server.rs @@ -1,9 +1,12 @@ +use flowy_folder2::deps::FolderCloudService; use std::sync::Arc; use flowy_user::event_map::UserAuthService; use crate::self_host::configuration::SelfHostedConfiguration; -use crate::self_host::SelfHostedUserAuthServiceImpl; +use crate::self_host::impls::{ + SelfHostedServerFolderCloudServiceImpl, SelfHostedUserAuthServiceImpl, +}; use crate::AppFlowyServer; pub struct SelfHostServer { @@ -20,4 +23,8 @@ impl AppFlowyServer for SelfHostServer { fn user_service(&self) -> Arc { Arc::new(SelfHostedUserAuthServiceImpl::new(self.config.clone())) } + + fn folder_service(&self) -> Arc { + Arc::new(SelfHostedServerFolderCloudServiceImpl()) + } } diff --git a/frontend/rust-lib/flowy-server/src/supabase/impls/folder.rs b/frontend/rust-lib/flowy-server/src/supabase/impls/folder.rs new file mode 100644 index 0000000000..f90b2e9788 --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/supabase/impls/folder.rs @@ -0,0 +1,54 @@ +use crate::supabase::request::create_workspace_with_uid; +use flowy_error::FlowyError; +use flowy_folder2::deps::{FolderCloudService, Workspace}; +use lib_infra::future::FutureResult; +use postgrest::Postgrest; +use std::sync::Arc; + +pub(crate) const WORKSPACE_TABLE: &str = "af_workspace"; +pub(crate) const WORKSPACE_NAME_COLUMN: &str = "workspace_name"; +pub(crate) struct SupabaseFolderCloudServiceImpl { + postgrest: Arc, +} + +impl FolderCloudService for SupabaseFolderCloudServiceImpl { + fn create_workspace(&self, uid: i64, name: &str) -> FutureResult { + let name = name.to_string(); + let postgrest = self.postgrest.clone(); + FutureResult::new(async move { create_workspace_with_uid(postgrest, uid, &name).await }) + } +} + +#[cfg(test)] +mod tests { + use crate::supabase::request::{ + create_user_with_uuid, create_workspace_with_uid, get_user_workspace_with_uid, + }; + use crate::supabase::{SupabaseConfiguration, SupabaseServer}; + use dotenv::dotenv; + use std::sync::Arc; + + #[tokio::test] + async fn create_user_workspace() { + dotenv().ok(); + if let Ok(config) = SupabaseConfiguration::from_env() { + let server = Arc::new(SupabaseServer::new(config)); + let uuid = uuid::Uuid::new_v4(); + let uid = create_user_with_uuid(server.postgres.clone(), uuid.to_string()) + .await + .unwrap() + .uid; + + create_workspace_with_uid(server.postgres.clone(), uid, "test") + .await + .unwrap(); + + let workspaces = get_user_workspace_with_uid(server.postgres.clone(), uid) + .await + .unwrap(); + assert_eq!(workspaces.len(), 2); + assert_eq!(workspaces[0].name, "My workspace"); + assert_eq!(workspaces[1].name, "test"); + } + } +} diff --git a/frontend/rust-lib/flowy-server/src/supabase/impls/mod.rs b/frontend/rust-lib/flowy-server/src/supabase/impls/mod.rs new file mode 100644 index 0000000000..8a05c27f6b --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/supabase/impls/mod.rs @@ -0,0 +1,5 @@ +mod folder; +mod user; + +pub(crate) use folder::*; +pub(crate) use user::*; diff --git a/frontend/rust-lib/flowy-server/src/supabase/user.rs b/frontend/rust-lib/flowy-server/src/supabase/impls/user.rs similarity index 77% rename from frontend/rust-lib/flowy-server/src/supabase/user.rs rename to frontend/rust-lib/flowy-server/src/supabase/impls/user.rs index 23c1b07018..cf55424120 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/user.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/impls/user.rs @@ -12,7 +12,8 @@ use crate::supabase::request::*; pub(crate) const USER_TABLE: &str = "af_user"; pub(crate) const USER_PROFILE_TABLE: &str = "af_user_profile"; -pub(crate) const USER_WORKSPACE_TABLE: &str = "af_user_workspace_view"; +#[allow(dead_code)] +pub(crate) const USER_WORKSPACE_TABLE: &str = "af_workspace"; pub(crate) struct PostgrestUserAuthServiceImpl { postgrest: Arc, } @@ -41,14 +42,12 @@ impl UserAuthService for PostgrestUserAuthServiceImpl { let postgrest = self.postgrest.clone(); FutureResult::new(async move { let uuid = uuid_from_box_any(params)?; - match get_user_workspace_with_uuid(postgrest, uuid).await? { - None => Err(FlowyError::user_not_exist()), - Some(user) => Ok(SignInResponse { - user_id: user.uid, - workspace_id: user.workspace_id, - ..Default::default() - }), - } + let user_profile = get_user_profile(postgrest, GetUserProfileParams::Uuid(uuid)).await?; + Ok(SignInResponse { + user_id: user_profile.uid, + workspace_id: user_profile.workspace_id, + ..Default::default() + }) }) } @@ -76,18 +75,19 @@ impl UserAuthService for PostgrestUserAuthServiceImpl { ) -> FutureResult, FlowyError> { let postgrest = self.postgrest.clone(); FutureResult::new(async move { - let profile = get_user_workspace_with_uid(postgrest, uid) - .await? - .map(|user_workspace| UserProfile { - id: user_workspace.uid, - email: "".to_string(), - name: user_workspace.name, - token: "".to_string(), - icon_url: "".to_string(), - openai_key: "".to_string(), - workspace_id: user_workspace.workspace_id, - }); - Ok(profile) + let user_profile_resp = get_user_profile(postgrest, GetUserProfileParams::Uid(uid)).await?; + + let profile = UserProfile { + id: user_profile_resp.uid, + email: user_profile_resp.email, + name: user_profile_resp.name, + token: "".to_string(), + icon_url: "".to_string(), + openai_key: "".to_string(), + workspace_id: user_profile_resp.workspace_id, + }; + + Ok(Some(profile)) }) } } @@ -100,8 +100,10 @@ mod tests { use flowy_user::entities::UpdateUserProfileParams; - use crate::supabase::request::{get_user_profile, get_user_workspace_with_uid}; - use crate::supabase::user::{create_user_with_uuid, get_user_id_with_uuid, update_user_profile}; + use crate::supabase::request::{ + create_user_with_uuid, get_user_id_with_uuid, get_user_profile, get_user_workspace_with_uid, + update_user_profile, GetUserProfileParams, + }; use crate::supabase::{SupabaseConfiguration, SupabaseServer}; #[tokio::test] @@ -151,17 +153,15 @@ mod tests { .unwrap(); println!("result: {:?}", result); - let result = get_user_profile(server.postgres.clone(), uid) + let result = get_user_profile(server.postgres.clone(), GetUserProfileParams::Uid(uid)) .await - .unwrap() .unwrap(); assert_eq!(result.name, "nathan".to_string()); let result = get_user_workspace_with_uid(server.postgres.clone(), uid) .await - .unwrap() .unwrap(); - assert!(!result.workspace_id.is_empty()); + assert!(!result.is_empty()); } } } diff --git a/frontend/rust-lib/flowy-server/src/supabase/mod.rs b/frontend/rust-lib/flowy-server/src/supabase/mod.rs index 6870d3f721..37ef0a6fdb 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/mod.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/mod.rs @@ -1,7 +1,7 @@ pub use server::*; +pub mod impls; mod request; mod response; mod retry; mod server; -pub mod user; diff --git a/frontend/rust-lib/flowy-server/src/supabase/request.rs b/frontend/rust-lib/flowy-server/src/supabase/request.rs index 5ff3a1747c..4dfce0f3d2 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/request.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/request.rs @@ -5,13 +5,16 @@ use postgrest::Postgrest; use serde_json::json; use flowy_error::{ErrorCode, FlowyError}; +use flowy_folder2::deps::Workspace; use flowy_user::entities::UpdateUserProfileParams; use lib_infra::box_any::BoxAny; -use crate::supabase::response::{ - InsertResponse, PostgrestError, UserProfile, UserProfileList, UserWorkspace, UserWorkspaceList, +use crate::supabase::impls::{ + USER_PROFILE_TABLE, USER_TABLE, USER_WORKSPACE_TABLE, WORKSPACE_NAME_COLUMN, WORKSPACE_TABLE, +}; +use crate::supabase::response::{ + InsertResponse, PostgrestError, UserProfileResponse, UserProfileResponseList, UserWorkspaceList, }; -use crate::supabase::user::{USER_PROFILE_TABLE, USER_TABLE, USER_WORKSPACE_TABLE}; const USER_ID: &str = "uid"; const USER_UUID: &str = "uuid"; @@ -19,13 +22,15 @@ const USER_UUID: &str = "uuid"; pub(crate) async fn create_user_with_uuid( postgrest: Arc, uuid: String, -) -> Result { - let insert = format!("{{\"{}\": \"{}\"}}", USER_UUID, &uuid); +) -> Result { + let mut insert = serde_json::Map::new(); + insert.insert(USER_UUID.to_string(), json!(&uuid)); + let insert_query = serde_json::to_string(&insert).unwrap(); // Create a new user with uuid. let resp = postgrest .from(USER_TABLE) - .insert(insert) + .insert(insert_query) .execute() .await .map_err(|e| FlowyError::new(ErrorCode::HttpError, e))?; @@ -44,13 +49,7 @@ pub(crate) async fn create_user_with_uuid( .map_err(|e| FlowyError::serde().context(e))? .first_or_error()?; - match get_user_workspace_with_uid(postgrest, record.uid).await { - Ok(Some(user)) => Ok(user), - _ => Err(FlowyError::new( - ErrorCode::Internal, - "Failed to get user workspace", - )), - } + get_user_profile(postgrest, GetUserProfileParams::Uid(record.uid)).await } else { let err = serde_json::from_str::(&content) .map_err(|e| FlowyError::serde().context(e))?; @@ -58,8 +57,8 @@ pub(crate) async fn create_user_with_uuid( // If there is a unique violation, try to get the user id with uuid. At this point, the user // should exist. if err.is_unique_violation() { - match get_user_workspace_with_uuid(postgrest, uuid).await { - Ok(Some(user)) => Ok(user), + match get_user_profile(postgrest, GetUserProfileParams::Uuid(uuid)).await { + Ok(user) => Ok(user), _ => Err(FlowyError::new( ErrorCode::Internal, "Failed to get user workspace", @@ -112,14 +111,21 @@ pub(crate) fn uuid_from_box_any(any: BoxAny) -> Result { Ok(uuid.to_string()) } -#[allow(dead_code)] +pub enum GetUserProfileParams { + Uid(i64), + Uuid(String), +} + pub(crate) async fn get_user_profile( postgrest: Arc, - uid: i64, -) -> Result, FlowyError> { - let resp = postgrest - .from(USER_PROFILE_TABLE) - .eq(USER_ID, uid.to_string()) + params: GetUserProfileParams, +) -> Result { + let mut builder = postgrest.from(USER_PROFILE_TABLE); + match params { + GetUserProfileParams::Uid(uid) => builder = builder.eq(USER_ID, uid.to_string()), + GetUserProfileParams::Uuid(uuid) => builder = builder.eq(USER_UUID, uuid), + } + let resp = builder .select("*") .execute() .await @@ -129,19 +135,35 @@ pub(crate) async fn get_user_profile( .text() .await .map_err(|e| FlowyError::new(ErrorCode::UnexpectedEmpty, e))?; - let resp = serde_json::from_str::(&content) - .map_err(|_e| FlowyError::new(ErrorCode::Serde, "Deserialize UserProfileList failed"))?; - Ok(resp.0.first().cloned()) + let mut user_profiles = + serde_json::from_str::(&content).map_err(|_e| { + FlowyError::new( + ErrorCode::Serde, + "Deserialize UserProfileResponseList failed", + ) + })?; + if user_profiles.0.is_empty() { + return Err(FlowyError::new( + ErrorCode::Internal, + "Failed to get user profile", + )); + } + Ok(user_profiles.0.remove(0)) } -pub(crate) async fn get_user_workspace_with_uuid( +pub(crate) async fn create_workspace_with_uid( postgrest: Arc, - uuid: String, -) -> Result, FlowyError> { + uid: i64, + name: &str, +) -> Result { + let mut insert = serde_json::Map::new(); + insert.insert(USER_ID.to_string(), json!(uid)); + insert.insert(WORKSPACE_NAME_COLUMN.to_string(), json!(name)); + let insert_query = serde_json::to_string(&insert).unwrap(); + let resp = postgrest - .from(USER_WORKSPACE_TABLE) - .eq(USER_UUID, uuid) - .select("*") + .from(WORKSPACE_TABLE) + .insert(insert_query) .execute() .await .map_err(|e| FlowyError::new(ErrorCode::HttpError, e))?; @@ -150,15 +172,31 @@ pub(crate) async fn get_user_workspace_with_uuid( .text() .await .map_err(|e| FlowyError::new(ErrorCode::UnexpectedEmpty, e))?; - let resp = serde_json::from_str::(&content) - .map_err(|_e| FlowyError::new(ErrorCode::Serde, "Deserialize UserWorkspaceList failed"))?; - Ok(resp.0.first().cloned()) + let mut workspace_list = serde_json::from_str::(&content) + .map_err(|_e| FlowyError::new(ErrorCode::Serde, "Deserialize UserWorkspaceList failed"))? + .into_inner(); + + debug_assert!(workspace_list.len() == 1); + if workspace_list.is_empty() { + return Err(FlowyError::new( + ErrorCode::Internal, + "Failed to create workspace", + )); + } + let user_workspace = workspace_list.remove(0); + Ok(Workspace { + id: user_workspace.workspace_id, + name: user_workspace.workspace_name, + belongings: Default::default(), + created_at: user_workspace.created_at.timestamp(), + }) } +#[allow(dead_code)] pub(crate) async fn get_user_workspace_with_uid( postgrest: Arc, uid: i64, -) -> Result, FlowyError> { +) -> Result, FlowyError> { let resp = postgrest .from(USER_WORKSPACE_TABLE) .eq(USER_ID, uid.to_string()) @@ -171,16 +209,27 @@ pub(crate) async fn get_user_workspace_with_uid( .text() .await .map_err(|e| FlowyError::new(ErrorCode::UnexpectedEmpty, e))?; - let resp = serde_json::from_str::(&content) - .map_err(|_e| FlowyError::new(ErrorCode::Serde, "Deserialize UserWorkspaceList failed"))?; - Ok(resp.0.first().cloned()) + let user_workspaces = serde_json::from_str::(&content) + .map_err(|_e| FlowyError::new(ErrorCode::Serde, "Deserialize UserWorkspaceList failed"))? + .0; + Ok( + user_workspaces + .into_iter() + .map(|user_workspace| Workspace { + id: user_workspace.workspace_id, + name: user_workspace.workspace_name, + belongings: Default::default(), + created_at: user_workspace.created_at.timestamp(), + }) + .collect(), + ) } #[allow(dead_code)] pub(crate) async fn update_user_profile( postgrest: Arc, params: UpdateUserProfileParams, -) -> Result, FlowyError> { +) -> Result, FlowyError> { if params.is_empty() { return Err(FlowyError::new( ErrorCode::UnexpectedEmpty, @@ -206,7 +255,7 @@ pub(crate) async fn update_user_profile( .await .map_err(|e| FlowyError::new(ErrorCode::UnexpectedEmpty, e))?; - let resp = serde_json::from_str::(&content) + let resp = serde_json::from_str::(&content) .map_err(|_e| FlowyError::new(ErrorCode::Serde, "Deserialize UserProfileList failed"))?; Ok(resp.0.first().cloned()) } diff --git a/frontend/rust-lib/flowy-server/src/supabase/response.rs b/frontend/rust-lib/flowy-server/src/supabase/response.rs index 15cb821345..07c5c41c7c 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/response.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/response.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::Value; use thiserror::Error; @@ -56,27 +57,39 @@ pub(crate) struct InsertRecord { #[allow(dead_code)] #[derive(Debug, Deserialize, Clone)] -pub(crate) struct UserProfile { +pub(crate) struct UserProfileResponse { pub uid: i64, #[serde(deserialize_with = "deserialize_null_or_default")] pub name: String, + #[serde(deserialize_with = "deserialize_null_or_default")] pub email: String, -} -#[derive(Debug, Deserialize)] -pub(crate) struct UserProfileList(pub Vec); - -#[derive(Debug, Deserialize, Clone)] -pub(crate) struct UserWorkspace { - pub uid: i64, #[serde(deserialize_with = "deserialize_null_or_default")] - pub name: String, pub workspace_id: String, } #[derive(Debug, Deserialize)] -pub(crate) struct UserWorkspaceList(pub Vec); +pub(crate) struct UserProfileResponseList(pub Vec); + +#[derive(Debug, Deserialize, Clone)] +pub(crate) struct UserWorkspace { + #[allow(dead_code)] + pub uid: i64, + #[serde(deserialize_with = "deserialize_null_or_default")] + pub workspace_name: String, + pub created_at: DateTime, + pub workspace_id: String, +} + +#[derive(Debug, Deserialize)] +pub(crate) struct UserWorkspaceList(pub(crate) Vec); + +impl UserWorkspaceList { + pub(crate) fn into_inner(self) -> Vec { + self.0 + } +} /// Handles the case where the value is null. If the value is null, return the default value of the /// type. Otherwise, deserialize the value. diff --git a/frontend/rust-lib/flowy-server/src/supabase/server.rs b/frontend/rust-lib/flowy-server/src/supabase/server.rs index e4238ddd9a..2650b28a8e 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/server.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/server.rs @@ -1,15 +1,21 @@ use std::sync::Arc; use postgrest::Postgrest; +use serde::Deserialize; -use flowy_config::entities::{SUPABASE_JWT_SECRET, SUPABASE_KEY, SUPABASE_URL}; use flowy_error::{ErrorCode, FlowyError}; +use flowy_folder2::deps::FolderCloudService; use flowy_user::event_map::UserAuthService; -use crate::supabase::user::PostgrestUserAuthServiceImpl; +use crate::supabase::impls::PostgrestUserAuthServiceImpl; use crate::AppFlowyServer; -#[derive(Debug)] +pub const SUPABASE_URL: &str = "SUPABASE_URL"; +pub const SUPABASE_ANON_KEY: &str = "SUPABASE_ANON_KEY"; +pub const SUPABASE_KEY: &str = "SUPABASE_KEY"; +pub const SUPABASE_JWT_SECRET: &str = "SUPABASE_JWT_SECRET"; + +#[derive(Debug, Deserialize)] pub struct SupabaseConfiguration { /// The url of the supabase server. pub url: String, @@ -20,6 +26,11 @@ pub struct SupabaseConfiguration { } impl SupabaseConfiguration { + /// Load the configuration from the environment variables. + /// SUPABASE_URL=https://.supabase.co + /// SUPABASE_KEY= + /// SUPABASE_JWT_SECRET= + /// pub fn from_env() -> Result { Ok(Self { url: std::env::var(SUPABASE_URL) @@ -31,6 +42,12 @@ impl SupabaseConfiguration { })?, }) } + + pub fn write_env(&self) { + std::env::set_var(SUPABASE_URL, &self.url); + std::env::set_var(SUPABASE_KEY, &self.key); + std::env::set_var(SUPABASE_JWT_SECRET, &self.jwt_secret); + } } pub struct SupabaseServer { @@ -53,4 +70,8 @@ impl AppFlowyServer for SupabaseServer { fn user_service(&self) -> Arc { Arc::new(PostgrestUserAuthServiceImpl::new(self.postgres.clone())) } + + fn folder_service(&self) -> Arc { + todo!() + } } diff --git a/frontend/rust-lib/flowy-test/Cargo.toml b/frontend/rust-lib/flowy-test/Cargo.toml index f9407dcb3a..b50294825e 100644 --- a/frontend/rust-lib/flowy-test/Cargo.toml +++ b/frontend/rust-lib/flowy-test/Cargo.toml @@ -10,7 +10,6 @@ flowy-core = { path = "../flowy-core" } flowy-user = { path = "../flowy-user"} flowy-net = { path = "../flowy-net"} flowy-folder2 = { path = "../flowy-folder2", features = ["test_helper"] } -#flowy-document= { path = "../flowy-document" } lib-dispatch = { path = "../lib-dispatch" } lib-ot = { path = "../../../shared-lib/lib-ot" } lib-infra = { path = "../../../shared-lib/lib-infra" } @@ -19,21 +18,18 @@ flowy-server = { path = "../flowy-server" } serde = { version = "1.0", features = ["derive"] } serde_json = {version = "1.0"} protobuf = {version = "2.28.0"} -#claim = "0.5.0" tokio = { version = "1.26", features = ["full"]} futures-util = "0.3.26" thread-id = "3.3.0" -log = "0.4" bytes = "1.4" nanoid = "0.4.0" tempdir = "0.3.7" +tracing = { version = "0.1.27" } +parking_lot = "0.12.1" +dotenv = "0.15.0" [dev-dependencies] -quickcheck = "1.0.3" -quickcheck_macros = "0.9.1" -fake = "2.5.0" -futures = "0.3.26" -serial_test = "0.5.1" +uuid = { version = "1.3.3", features = ["v4"] } [features] dart = ["flowy-core/dart"] diff --git a/frontend/rust-lib/flowy-test/src/event_builder.rs b/frontend/rust-lib/flowy-test/src/event_builder.rs index 764f6d087a..7f6a65b6b6 100644 --- a/frontend/rust-lib/flowy-test/src/event_builder.rs +++ b/frontend/rust-lib/flowy-test/src/event_builder.rs @@ -1,5 +1,5 @@ -use crate::FlowySDKTest; -use flowy_user::{entities::UserProfilePB, errors::FlowyError}; +use crate::FlowyCoreTest; +use flowy_user::errors::FlowyError; use lib_dispatch::prelude::{ AFPluginDispatcher, AFPluginEventResponse, AFPluginFromBytes, AFPluginRequest, StatusCode, ToBytes, *, @@ -8,38 +8,18 @@ use std::{ convert::TryFrom, fmt::{Debug, Display}, hash::Hash, - marker::PhantomData, sync::Arc, }; -pub type Folder2EventBuilder = EventBuilder; -impl Folder2EventBuilder { - pub fn new(sdk: FlowySDKTest) -> Self { - EventBuilder::test(TestContext::new(sdk)) - } - pub fn user_profile(&self) -> &Option { - &self.user_profile - } -} - -pub type UserModuleEventBuilder = Folder2EventBuilder; - #[derive(Clone)] -pub struct EventBuilder { +pub struct EventBuilder { context: TestContext, - user_profile: Option, - err_phantom: PhantomData, } -impl EventBuilder -where - E: AFPluginFromBytes + Debug, -{ - fn test(context: TestContext) -> Self { +impl EventBuilder { + pub fn new(sdk: FlowyCoreTest) -> Self { Self { - context, - user_profile: None, - err_phantom: PhantomData, + context: TestContext::new(sdk), } } @@ -53,7 +33,7 @@ where self.context.request = Some(module_request.payload(bytes)) }, Err(e) => { - log::error!("Set payload failed: {:?}", e); + tracing::error!("Set payload failed: {:?}", e); }, } self @@ -86,7 +66,7 @@ where R: AFPluginFromBytes, { let response = self.get_response(); - match response.clone().parse::() { + match response.clone().parse::() { Ok(Ok(data)) => data, Ok(Err(e)) => { panic!( @@ -105,22 +85,12 @@ where } } - pub fn error(self) -> E { + pub fn error(self) -> Option { let response = self.get_response(); assert_eq!(response.status_code, StatusCode::Err); - >::try_from(response.payload) - .unwrap() - .into_inner() - } - - pub fn assert_error(self) -> Self { - // self.context.assert_error(); - self - } - - pub fn assert_success(self) -> Self { - // self.context.assert_success(); - self + >::try_from(response.payload) + .ok() + .map(|data| data.into_inner()) } fn dispatch(&self) -> Arc { @@ -132,7 +102,7 @@ where .context .response .as_ref() - .expect("must call sync_send first") + .expect("must call sync_send/async_send first") .clone() } @@ -143,13 +113,13 @@ where #[derive(Clone)] pub struct TestContext { - pub sdk: FlowySDKTest, + pub sdk: FlowyCoreTest, request: Option, response: Option, } impl TestContext { - pub fn new(sdk: FlowySDKTest) -> Self { + pub fn new(sdk: FlowyCoreTest) -> Self { Self { sdk, request: None, diff --git a/frontend/rust-lib/flowy-test/src/folder_event.rs b/frontend/rust-lib/flowy-test/src/folder_event.rs new file mode 100644 index 0000000000..ada7f25fa3 --- /dev/null +++ b/frontend/rust-lib/flowy-test/src/folder_event.rs @@ -0,0 +1,111 @@ +use crate::event_builder::EventBuilder; +use crate::FlowyCoreTest; +use flowy_folder2::entities::*; +use flowy_folder2::event_map::FolderEvent::*; + +pub struct ViewTest { + pub sdk: FlowyCoreTest, + pub workspace: WorkspacePB, + pub parent_view: ViewPB, + pub child_view: ViewPB, +} + +impl ViewTest { + #[allow(dead_code)] + pub async fn new(sdk: &FlowyCoreTest, layout: ViewLayoutPB, data: Vec) -> Self { + let workspace = create_workspace(sdk, "Workspace", "").await; + open_workspace(sdk, &workspace.id).await; + let app = create_app(sdk, "App", "AppFlowy GitHub Project", &workspace.id).await; + let view = create_view(sdk, &app.id, layout, data).await; + Self { + sdk: sdk.clone(), + workspace, + parent_view: app, + child_view: view, + } + } + + pub async fn new_grid_view(sdk: &FlowyCoreTest, data: Vec) -> Self { + Self::new(sdk, ViewLayoutPB::Grid, data).await + } + + pub async fn new_board_view(sdk: &FlowyCoreTest, data: Vec) -> Self { + Self::new(sdk, ViewLayoutPB::Board, data).await + } + + pub async fn new_calendar_view(sdk: &FlowyCoreTest, data: Vec) -> Self { + Self::new(sdk, ViewLayoutPB::Calendar, data).await + } + + pub async fn new_document_view(sdk: &FlowyCoreTest) -> Self { + Self::new(sdk, ViewLayoutPB::Document, vec![]).await + } +} + +async fn create_workspace(sdk: &FlowyCoreTest, name: &str, desc: &str) -> WorkspacePB { + let request = CreateWorkspacePayloadPB { + name: name.to_owned(), + desc: desc.to_owned(), + }; + + EventBuilder::new(sdk.clone()) + .event(CreateWorkspace) + .payload(request) + .async_send() + .await + .parse::() +} + +async fn open_workspace(sdk: &FlowyCoreTest, workspace_id: &str) { + let payload = WorkspaceIdPB { + value: Some(workspace_id.to_owned()), + }; + let _ = EventBuilder::new(sdk.clone()) + .event(OpenWorkspace) + .payload(payload) + .async_send() + .await; +} + +async fn create_app(sdk: &FlowyCoreTest, name: &str, desc: &str, workspace_id: &str) -> ViewPB { + let create_app_request = CreateViewPayloadPB { + belong_to_id: workspace_id.to_owned(), + name: name.to_string(), + desc: desc.to_string(), + thumbnail: None, + layout: ViewLayoutPB::Document, + initial_data: vec![], + ext: Default::default(), + }; + + EventBuilder::new(sdk.clone()) + .event(CreateView) + .payload(create_app_request) + .async_send() + .await + .parse::() +} + +async fn create_view( + sdk: &FlowyCoreTest, + app_id: &str, + layout: ViewLayoutPB, + data: Vec, +) -> ViewPB { + let payload = CreateViewPayloadPB { + belong_to_id: app_id.to_string(), + name: "View A".to_string(), + desc: "".to_string(), + thumbnail: Some("http://1.png".to_string()), + layout, + initial_data: data, + ext: Default::default(), + }; + + EventBuilder::new(sdk.clone()) + .event(CreateView) + .payload(payload) + .async_send() + .await + .parse::() +} diff --git a/frontend/rust-lib/flowy-test/src/helper.rs b/frontend/rust-lib/flowy-test/src/helper.rs deleted file mode 100644 index 4a4566738b..0000000000 --- a/frontend/rust-lib/flowy-test/src/helper.rs +++ /dev/null @@ -1,216 +0,0 @@ -use std::sync::Arc; - -use flowy_folder2::entities::{ - CreateViewPayloadPB, CreateWorkspacePayloadPB, ViewLayoutPB, ViewPB, WorkspaceIdPB, WorkspacePB, -}; -use flowy_folder2::event_map::FolderEvent::{CreateView, CreateWorkspace, OpenWorkspace}; -use flowy_user::entities::AuthTypePB; -use flowy_user::{ - entities::{SignInPayloadPB, SignUpPayloadPB, UserProfilePB}, - errors::FlowyError, - event_map::UserEvent::{InitUser, SignIn, SignOut, SignUp}, -}; -use lib_dispatch::prelude::{AFPluginDispatcher, AFPluginRequest, ToBytes}; - -use crate::prelude::*; - -pub struct ViewTest { - pub sdk: FlowySDKTest, - pub workspace: WorkspacePB, - pub parent_view: ViewPB, - pub child_view: ViewPB, -} - -impl ViewTest { - #[allow(dead_code)] - pub async fn new(sdk: &FlowySDKTest, layout: ViewLayoutPB, data: Vec) -> Self { - let workspace = create_workspace(sdk, "Workspace", "").await; - open_workspace(sdk, &workspace.id).await; - let app = create_app(sdk, "App", "AppFlowy GitHub Project", &workspace.id).await; - let view = create_view(sdk, &app.id, layout, data).await; - Self { - sdk: sdk.clone(), - workspace, - parent_view: app, - child_view: view, - } - } - - pub async fn new_grid_view(sdk: &FlowySDKTest, data: Vec) -> Self { - Self::new(sdk, ViewLayoutPB::Grid, data).await - } - - pub async fn new_board_view(sdk: &FlowySDKTest, data: Vec) -> Self { - Self::new(sdk, ViewLayoutPB::Board, data).await - } - - pub async fn new_calendar_view(sdk: &FlowySDKTest, data: Vec) -> Self { - Self::new(sdk, ViewLayoutPB::Calendar, data).await - } - - pub async fn new_document_view(sdk: &FlowySDKTest) -> Self { - Self::new(sdk, ViewLayoutPB::Document, vec![]).await - } -} - -async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> WorkspacePB { - let request = CreateWorkspacePayloadPB { - name: name.to_owned(), - desc: desc.to_owned(), - }; - - Folder2EventBuilder::new(sdk.clone()) - .event(CreateWorkspace) - .payload(request) - .async_send() - .await - .parse::() -} - -async fn open_workspace(sdk: &FlowySDKTest, workspace_id: &str) { - let payload = WorkspaceIdPB { - value: Some(workspace_id.to_owned()), - }; - let _ = Folder2EventBuilder::new(sdk.clone()) - .event(OpenWorkspace) - .payload(payload) - .async_send() - .await; -} - -async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &str) -> ViewPB { - let create_app_request = CreateViewPayloadPB { - belong_to_id: workspace_id.to_owned(), - name: name.to_string(), - desc: desc.to_string(), - thumbnail: None, - layout: ViewLayoutPB::Document, - initial_data: vec![], - ext: Default::default(), - }; - - Folder2EventBuilder::new(sdk.clone()) - .event(CreateView) - .payload(create_app_request) - .async_send() - .await - .parse::() -} - -async fn create_view( - sdk: &FlowySDKTest, - app_id: &str, - layout: ViewLayoutPB, - data: Vec, -) -> ViewPB { - let payload = CreateViewPayloadPB { - belong_to_id: app_id.to_string(), - name: "View A".to_string(), - desc: "".to_string(), - thumbnail: Some("http://1.png".to_string()), - layout, - initial_data: data, - ext: Default::default(), - }; - - Folder2EventBuilder::new(sdk.clone()) - .event(CreateView) - .payload(payload) - .async_send() - .await - .parse::() -} - -pub fn random_email() -> String { - format!("{}@appflowy.io", nanoid!(20)) -} - -pub fn login_email() -> String { - "annie2@appflowy.io".to_string() -} - -pub fn login_password() -> String { - "HelloWorld!123".to_string() -} - -pub struct SignUpContext { - pub user_profile: UserProfilePB, - pub password: String, -} - -pub fn sign_up(dispatch: Arc) -> SignUpContext { - let password = login_password(); - let payload = SignUpPayloadPB { - email: random_email(), - name: "app flowy".to_string(), - password: password.clone(), - auth_type: AuthTypePB::Local, - } - .into_bytes() - .unwrap(); - - let request = AFPluginRequest::new(SignUp).payload(payload); - let user_profile = AFPluginDispatcher::sync_send(dispatch, request) - .parse::() - .unwrap() - .unwrap(); - - SignUpContext { - user_profile, - password, - } -} - -pub async fn async_sign_up(dispatch: Arc) -> SignUpContext { - let password = login_password(); - let email = random_email(); - let payload = SignUpPayloadPB { - email, - name: "app flowy".to_string(), - password: password.clone(), - auth_type: AuthTypePB::Local, - } - .into_bytes() - .unwrap(); - - let request = AFPluginRequest::new(SignUp).payload(payload); - let user_profile = AFPluginDispatcher::async_send(dispatch.clone(), request) - .await - .parse::() - .unwrap() - .unwrap(); - - // let _ = create_default_workspace_if_need(dispatch.clone(), &user_profile.id); - SignUpContext { - user_profile, - password, - } -} - -pub async fn init_user_setting(dispatch: Arc) { - let request = AFPluginRequest::new(InitUser); - let _ = AFPluginDispatcher::async_send(dispatch.clone(), request).await; -} - -#[allow(dead_code)] -fn sign_in(dispatch: Arc) -> UserProfilePB { - let payload = SignInPayloadPB { - email: login_email(), - password: login_password(), - name: "rust".to_owned(), - auth_type: AuthTypePB::Local, - } - .into_bytes() - .unwrap(); - - let request = AFPluginRequest::new(SignIn).payload(payload); - AFPluginDispatcher::sync_send(dispatch, request) - .parse::() - .unwrap() - .unwrap() -} - -#[allow(dead_code)] -fn logout(dispatch: Arc) { - let _ = AFPluginDispatcher::sync_send(dispatch, AFPluginRequest::new(SignOut)); -} diff --git a/frontend/rust-lib/flowy-test/src/lib.rs b/frontend/rust-lib/flowy-test/src/lib.rs index b023aa434e..377d36c069 100644 --- a/frontend/rust-lib/flowy-test/src/lib.rs +++ b/frontend/rust-lib/flowy-test/src/lib.rs @@ -1,57 +1,62 @@ use nanoid::nanoid; +use parking_lot::RwLock; use std::env::temp_dir; +use std::sync::Arc; use flowy_core::{AppFlowyCore, AppFlowyCoreConfig}; -use flowy_user::entities::UserProfilePB; - -use crate::helper::*; +use flowy_user::entities::{AuthTypePB, UserProfilePB}; +use crate::user_event::{async_sign_up, init_user_setting, SignUpContext}; pub mod event_builder; -pub mod helper; - -pub mod prelude { - pub use lib_dispatch::prelude::*; - - pub use crate::{event_builder::*, helper::*, *}; -} +pub mod folder_event; +pub mod user_event; #[derive(Clone)] -pub struct FlowySDKTest { - pub inner: AppFlowyCore, +pub struct FlowyCoreTest { + auth_type: Arc>, + inner: AppFlowyCore, } -impl std::ops::Deref for FlowySDKTest { +impl Default for FlowyCoreTest { + fn default() -> Self { + let temp_dir = temp_dir(); + let config = + AppFlowyCoreConfig::new(temp_dir.to_str().unwrap(), nanoid!(6)).log_filter("info", vec![]); + let inner = std::thread::spawn(|| AppFlowyCore::new(config)) + .join() + .unwrap(); + let auth_type = Arc::new(RwLock::new(AuthTypePB::Local)); + std::mem::forget(inner.dispatcher()); + Self { inner, auth_type } + } +} + +impl FlowyCoreTest { + pub fn new() -> Self { + Self::default() + } + + pub async fn sign_up(&self) -> SignUpContext { + let auth_type = self.auth_type.read().clone(); + async_sign_up(self.inner.dispatcher(), auth_type).await + } + + pub fn set_auth_type(&self, auth_type: AuthTypePB) { + *self.auth_type.write() = auth_type; + } + + pub async fn init_user(&self) -> UserProfilePB { + let auth_type = self.auth_type.read().clone(); + let context = async_sign_up(self.inner.dispatcher(), auth_type).await; + init_user_setting(self.inner.dispatcher()).await; + context.user_profile + } +} + +impl std::ops::Deref for FlowyCoreTest { type Target = AppFlowyCore; fn deref(&self) -> &Self::Target { &self.inner } } - -impl std::default::Default for FlowySDKTest { - fn default() -> Self { - Self::new() - } -} - -impl FlowySDKTest { - pub fn new() -> Self { - let config = - AppFlowyCoreConfig::new(temp_dir().to_str().unwrap(), nanoid!(6)).log_filter("info", vec![]); - let sdk = std::thread::spawn(|| AppFlowyCore::new(config)) - .join() - .unwrap(); - std::mem::forget(sdk.dispatcher()); - Self { inner: sdk } - } - - pub async fn sign_up(&self) -> SignUpContext { - async_sign_up(self.inner.dispatcher()).await - } - - pub async fn init_user(&self) -> UserProfilePB { - let context = async_sign_up(self.inner.dispatcher()).await; - init_user_setting(self.inner.dispatcher()).await; - context.user_profile - } -} diff --git a/frontend/rust-lib/flowy-test/src/user_event.rs b/frontend/rust-lib/flowy-test/src/user_event.rs new file mode 100644 index 0000000000..5bba21115b --- /dev/null +++ b/frontend/rust-lib/flowy-test/src/user_event.rs @@ -0,0 +1,103 @@ +use flowy_user::entities::{AuthTypePB, SignInPayloadPB, SignUpPayloadPB, UserProfilePB}; +use flowy_user::errors::FlowyError; +use flowy_user::event_map::UserEvent::*; +use lib_dispatch::prelude::{AFPluginDispatcher, AFPluginRequest, ToBytes}; +use nanoid::nanoid; +use std::sync::Arc; + +pub fn random_email() -> String { + format!("{}@appflowy.io", nanoid!(20)) +} + +pub fn login_email() -> String { + "annie2@appflowy.io".to_string() +} + +pub fn login_password() -> String { + "HelloWorld!123".to_string() +} + +pub struct SignUpContext { + pub user_profile: UserProfilePB, + pub password: String, +} + +pub fn sign_up(dispatch: Arc) -> SignUpContext { + let password = login_password(); + let payload = SignUpPayloadPB { + email: random_email(), + name: "app flowy".to_string(), + password: password.clone(), + auth_type: AuthTypePB::Local, + } + .into_bytes() + .unwrap(); + + let request = AFPluginRequest::new(SignUp).payload(payload); + let user_profile = AFPluginDispatcher::sync_send(dispatch, request) + .parse::() + .unwrap() + .unwrap(); + + SignUpContext { + user_profile, + password, + } +} + +pub async fn async_sign_up( + dispatch: Arc, + auth_type: AuthTypePB, +) -> SignUpContext { + let password = login_password(); + let email = random_email(); + let payload = SignUpPayloadPB { + email, + name: "app flowy".to_string(), + password: password.clone(), + auth_type, + } + .into_bytes() + .unwrap(); + + let request = AFPluginRequest::new(SignUp).payload(payload); + let user_profile = AFPluginDispatcher::async_send(dispatch.clone(), request) + .await + .parse::() + .unwrap() + .unwrap(); + + // let _ = create_default_workspace_if_need(dispatch.clone(), &user_profile.id); + SignUpContext { + user_profile, + password, + } +} + +pub async fn init_user_setting(dispatch: Arc) { + let request = AFPluginRequest::new(InitUser); + let _ = AFPluginDispatcher::async_send(dispatch.clone(), request).await; +} + +#[allow(dead_code)] +fn sign_in(dispatch: Arc) -> UserProfilePB { + let payload = SignInPayloadPB { + email: login_email(), + password: login_password(), + name: "rust".to_owned(), + auth_type: AuthTypePB::Local, + } + .into_bytes() + .unwrap(); + + let request = AFPluginRequest::new(SignIn).payload(payload); + AFPluginDispatcher::sync_send(dispatch, request) + .parse::() + .unwrap() + .unwrap() +} + +#[allow(dead_code)] +fn logout(dispatch: Arc) { + let _ = AFPluginDispatcher::sync_send(dispatch, AFPluginRequest::new(SignOut)); +} diff --git a/frontend/rust-lib/flowy-test/tests/main.rs b/frontend/rust-lib/flowy-test/tests/main.rs new file mode 100644 index 0000000000..0eba1100e5 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/main.rs @@ -0,0 +1 @@ +mod user; diff --git a/frontend/rust-lib/flowy-user/tests/event/auth_test.rs b/frontend/rust-lib/flowy-test/tests/user/local_test/auth_test.rs similarity index 64% rename from frontend/rust-lib/flowy-user/tests/event/auth_test.rs rename to frontend/rust-lib/flowy-test/tests/user/local_test/auth_test.rs index 408baa064a..e02f55e271 100644 --- a/frontend/rust-lib/flowy-user/tests/event/auth_test.rs +++ b/frontend/rust-lib/flowy-test/tests/user/local_test/auth_test.rs @@ -1,13 +1,15 @@ -use flowy_test::{event_builder::UserModuleEventBuilder, FlowySDKTest}; +use flowy_test::user_event::*; +use flowy_test::{event_builder::EventBuilder, FlowyCoreTest}; use flowy_user::entities::{AuthTypePB, SignInPayloadPB, SignUpPayloadPB, UserProfilePB}; -use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; +use flowy_user::errors::ErrorCode; +use flowy_user::event_map::UserEvent::*; -use crate::helper::*; +use crate::user::local_test::helper::*; #[tokio::test] async fn sign_up_with_invalid_email() { for email in invalid_email_test_case() { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let request = SignUpPayloadPB { email: email.to_string(), name: valid_name(), @@ -16,43 +18,45 @@ async fn sign_up_with_invalid_email() { }; assert_eq!( - UserModuleEventBuilder::new(sdk) + EventBuilder::new(sdk) .event(SignUp) .payload(request) .async_send() .await .error() + .unwrap() .code, ErrorCode::EmailFormatInvalid.value() ); } } #[tokio::test] -async fn sign_up_with_invalid_password() { - for password in invalid_password_test_case() { - let sdk = FlowySDKTest::default(); - let request = SignUpPayloadPB { - email: random_email(), - name: valid_name(), - password, - auth_type: AuthTypePB::Local, - }; +async fn sign_up_with_long_password() { + let sdk = FlowyCoreTest::new(); + let request = SignUpPayloadPB { + email: random_email(), + name: valid_name(), + password: "1234".repeat(100).as_str().to_string(), + auth_type: AuthTypePB::Local, + }; - UserModuleEventBuilder::new(sdk) + assert_eq!( + EventBuilder::new(sdk) .event(SignUp) .payload(request) .async_send() .await - .assert_error(); - } + .error() + .unwrap() + .code, + ErrorCode::PasswordTooLong.value() + ); } #[tokio::test] async fn sign_in_success() { - let test = FlowySDKTest::default(); - let _ = UserModuleEventBuilder::new(test.clone()) - .event(SignOut) - .sync_send(); + let test = FlowyCoreTest::new(); + let _ = EventBuilder::new(test.clone()).event(SignOut).sync_send(); let sign_up_context = test.sign_up().await; let request = SignInPayloadPB { @@ -62,7 +66,7 @@ async fn sign_in_success() { auth_type: AuthTypePB::Local, }; - let response = UserModuleEventBuilder::new(test.clone()) + let response = EventBuilder::new(test.clone()) .event(SignIn) .payload(request) .async_send() @@ -74,7 +78,7 @@ async fn sign_in_success() { #[tokio::test] async fn sign_in_with_invalid_email() { for email in invalid_email_test_case() { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let request = SignInPayloadPB { email: email.to_string(), password: login_password(), @@ -83,12 +87,13 @@ async fn sign_in_with_invalid_email() { }; assert_eq!( - UserModuleEventBuilder::new(sdk) + EventBuilder::new(sdk) .event(SignIn) .payload(request) .async_send() .await .error() + .unwrap() .code, ErrorCode::EmailFormatInvalid.value() ); @@ -98,7 +103,7 @@ async fn sign_in_with_invalid_email() { #[tokio::test] async fn sign_in_with_invalid_password() { for password in invalid_password_test_case() { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let request = SignInPayloadPB { email: random_email(), @@ -107,11 +112,12 @@ async fn sign_in_with_invalid_password() { auth_type: AuthTypePB::Local, }; - UserModuleEventBuilder::new(sdk) + assert!(EventBuilder::new(sdk) .event(SignIn) .payload(request) .async_send() .await - .assert_error(); + .error() + .is_some()) } } diff --git a/frontend/rust-lib/flowy-user/tests/event/helper.rs b/frontend/rust-lib/flowy-test/tests/user/local_test/helper.rs similarity index 91% rename from frontend/rust-lib/flowy-user/tests/event/helper.rs rename to frontend/rust-lib/flowy-test/tests/user/local_test/helper.rs index d35c923e6f..184abd3bd5 100644 --- a/frontend/rust-lib/flowy-user/tests/event/helper.rs +++ b/frontend/rust-lib/flowy-test/tests/user/local_test/helper.rs @@ -1,8 +1,3 @@ -pub use flowy_test::{ - event_builder::*, - prelude::{login_password, random_email}, -}; - pub(crate) fn invalid_email_test_case() -> Vec { // https://gist.github.com/cjaoude/fd9910626629b53c4d25 vec![ diff --git a/frontend/rust-lib/flowy-user/tests/event/main.rs b/frontend/rust-lib/flowy-test/tests/user/local_test/mod.rs similarity index 100% rename from frontend/rust-lib/flowy-user/tests/event/main.rs rename to frontend/rust-lib/flowy-test/tests/user/local_test/mod.rs diff --git a/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs b/frontend/rust-lib/flowy-test/tests/user/local_test/user_profile_test.rs similarity index 61% rename from frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs rename to frontend/rust-lib/flowy-test/tests/user/local_test/user_profile_test.rs index 3878cbb464..1dc9eddb13 100644 --- a/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs +++ b/frontend/rust-lib/flowy-test/tests/user/local_test/user_profile_test.rs @@ -1,5 +1,5 @@ -use crate::helper::*; -use flowy_test::{event_builder::UserModuleEventBuilder, FlowySDKTest}; +use crate::user::local_test::helper::*; +use flowy_test::{event_builder::EventBuilder, FlowyCoreTest}; use flowy_user::entities::{UpdateUserProfilePayloadPB, UserProfilePB}; use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; use nanoid::nanoid; @@ -8,20 +8,20 @@ use nanoid::nanoid; #[tokio::test] async fn user_profile_get_failed() { - let sdk = FlowySDKTest::default(); - let result = UserModuleEventBuilder::new(sdk) + let sdk = FlowyCoreTest::new(); + let result = EventBuilder::new(sdk) .event(GetUserProfile) - .assert_error() .async_send() - .await; - assert!(result.user_profile().is_none()) + .await + .error(); + assert!(result.is_some()) } #[tokio::test] async fn user_profile_get() { - let test = FlowySDKTest::default(); + let test = FlowyCoreTest::new(); let user_profile = test.init_user().await; - let user = UserModuleEventBuilder::new(test.clone()) + let user = EventBuilder::new(test.clone()) .event(GetUserProfile) .sync_send() .parse::(); @@ -30,18 +30,17 @@ async fn user_profile_get() { #[tokio::test] async fn user_update_with_name() { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let user = sdk.init_user().await; let new_name = "hello_world".to_owned(); let request = UpdateUserProfilePayloadPB::new(user.id).name(&new_name); - let _ = UserModuleEventBuilder::new(sdk.clone()) + let _ = EventBuilder::new(sdk.clone()) .event(UpdateUserProfile) .payload(request) .sync_send(); - let user_profile = UserModuleEventBuilder::new(sdk.clone()) + let user_profile = EventBuilder::new(sdk.clone()) .event(GetUserProfile) - .assert_error() .sync_send() .parse::(); @@ -50,49 +49,35 @@ async fn user_update_with_name() { #[tokio::test] async fn user_update_with_email() { - let sdk = FlowySDKTest::default(); + let sdk = FlowyCoreTest::new(); let user = sdk.init_user().await; let new_email = format!("{}@gmail.com", nanoid!(6)); let request = UpdateUserProfilePayloadPB::new(user.id).email(&new_email); - let _ = UserModuleEventBuilder::new(sdk.clone()) + let _ = EventBuilder::new(sdk.clone()) .event(UpdateUserProfile) .payload(request) .sync_send(); - let user_profile = UserModuleEventBuilder::new(sdk.clone()) + let user_profile = EventBuilder::new(sdk.clone()) .event(GetUserProfile) - .assert_error() .sync_send() .parse::(); assert_eq!(user_profile.email, new_email,); } -#[tokio::test] -async fn user_update_with_password() { - let sdk = FlowySDKTest::default(); - let user = sdk.init_user().await; - let new_password = "H123world!".to_owned(); - let request = UpdateUserProfilePayloadPB::new(user.id).password(&new_password); - - let _ = UserModuleEventBuilder::new(sdk.clone()) - .event(UpdateUserProfile) - .payload(request) - .sync_send() - .assert_success(); -} - #[tokio::test] async fn user_update_with_invalid_email() { - let test = FlowySDKTest::default(); + let test = FlowyCoreTest::new(); let user = test.init_user().await; for email in invalid_email_test_case() { let request = UpdateUserProfilePayloadPB::new(user.id).email(&email); assert_eq!( - UserModuleEventBuilder::new(test.clone()) + EventBuilder::new(test.clone()) .event(UpdateUserProfile) .payload(request) .sync_send() .error() + .unwrap() .code, ErrorCode::EmailFormatInvalid.value() ); @@ -101,27 +86,30 @@ async fn user_update_with_invalid_email() { #[tokio::test] async fn user_update_with_invalid_password() { - let test = FlowySDKTest::default(); + let test = FlowyCoreTest::new(); let user = test.init_user().await; for password in invalid_password_test_case() { let request = UpdateUserProfilePayloadPB::new(user.id).password(&password); - UserModuleEventBuilder::new(test.clone()) + assert!(EventBuilder::new(test.clone()) .event(UpdateUserProfile) .payload(request) - .sync_send() - .assert_error(); + .async_send() + .await + .error() + .is_some()); } } #[tokio::test] async fn user_update_with_invalid_name() { - let test = FlowySDKTest::default(); + let test = FlowyCoreTest::new(); let user = test.init_user().await; let request = UpdateUserProfilePayloadPB::new(user.id).name(""); - UserModuleEventBuilder::new(test.clone()) + assert!(EventBuilder::new(test.clone()) .event(UpdateUserProfile) .payload(request) .sync_send() - .assert_error(); + .error() + .is_some()) } diff --git a/frontend/rust-lib/flowy-test/tests/user/mod.rs b/frontend/rust-lib/flowy-test/tests/user/mod.rs new file mode 100644 index 0000000000..0d7ec93eed --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/mod.rs @@ -0,0 +1,2 @@ +mod local_test; +mod supabase_test; diff --git a/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs b/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs new file mode 100644 index 0000000000..2ee5182a52 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs @@ -0,0 +1,28 @@ +use crate::user::supabase_test::helper::get_supabase_config; + +use flowy_test::{event_builder::EventBuilder, FlowyCoreTest}; +use flowy_user::entities::{AuthTypePB, ThirdPartyAuthPB, UserProfilePB}; + +use flowy_user::event_map::UserEvent::*; +use std::collections::HashMap; + +#[tokio::test] +async fn sign_up_test() { + if get_supabase_config().is_some() { + let test = FlowyCoreTest::new(); + let mut map = HashMap::new(); + map.insert("uuid".to_string(), uuid::Uuid::new_v4().to_string()); + let payload = ThirdPartyAuthPB { + map, + auth_type: AuthTypePB::Supabase, + }; + + let response = EventBuilder::new(test.clone()) + .event(ThirdPartyAuth) + .payload(payload) + .async_send() + .await + .parse::(); + dbg!(&response); + } +} diff --git a/frontend/rust-lib/flowy-test/tests/user/supabase_test/helper.rs b/frontend/rust-lib/flowy-test/tests/user/supabase_test/helper.rs new file mode 100644 index 0000000000..fc78aafa90 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/supabase_test/helper.rs @@ -0,0 +1,20 @@ +use dotenv::dotenv; +use flowy_server::supabase::SupabaseConfiguration; + +/// In order to run this test, you need to create a .env file in the root directory of this project +/// and add the following environment variables: +/// - SUPABASE_URL +/// - SUPABASE_ANON_KEY +/// - SUPABASE_KEY +/// - SUPABASE_JWT_SECRET +/// +/// the .env file should look like this: +/// SUPABASE_URL=https://.supabase.co +/// SUPABASE_ANON_KEY= +/// SUPABASE_KEY= +/// SUPABASE_JWT_SECRET= +/// +pub fn get_supabase_config() -> Option { + dotenv().ok()?; + SupabaseConfiguration::from_env().ok() +} diff --git a/frontend/rust-lib/flowy-test/tests/user/supabase_test/mod.rs b/frontend/rust-lib/flowy-test/tests/user/supabase_test/mod.rs new file mode 100644 index 0000000000..35aaffc467 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/supabase_test/mod.rs @@ -0,0 +1,3 @@ +mod auth_test; +mod helper; +mod workspace_test; diff --git a/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs b/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs new file mode 100644 index 0000000000..446e197ac6 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs @@ -0,0 +1,38 @@ +use crate::user::supabase_test::helper::get_supabase_config; +use flowy_folder2::entities::WorkspaceSettingPB; +use flowy_folder2::event_map::FolderEvent::ReadCurrentWorkspace; + +use flowy_test::{event_builder::EventBuilder, FlowyCoreTest}; +use flowy_user::entities::{AuthTypePB, ThirdPartyAuthPB, UserProfilePB}; + +use flowy_user::event_map::UserEvent::*; +use std::collections::HashMap; + +#[tokio::test] +async fn initial_workspace_test() { + if get_supabase_config().is_some() { + let test = FlowyCoreTest::new(); + let mut map = HashMap::new(); + map.insert("uuid".to_string(), uuid::Uuid::new_v4().to_string()); + let payload = ThirdPartyAuthPB { + map, + auth_type: AuthTypePB::Supabase, + }; + + let _ = EventBuilder::new(test.clone()) + .event(ThirdPartyAuth) + .payload(payload) + .async_send() + .await + .parse::(); + + let workspace_settings = EventBuilder::new(test.clone()) + .event(ReadCurrentWorkspace) + .async_send() + .await + .parse::(); + + assert!(workspace_settings.latest_view.is_some()); + dbg!(&workspace_settings); + } +} diff --git a/frontend/rust-lib/flowy-user/Cargo.toml b/frontend/rust-lib/flowy-user/Cargo.toml index 1a2dee82e8..0cb42cb8f4 100644 --- a/frontend/rust-lib/flowy-user/Cargo.toml +++ b/frontend/rust-lib/flowy-user/Cargo.toml @@ -34,7 +34,6 @@ unicode-segmentation = "1.10" fancy-regex = "0.11.0" [dev-dependencies] -flowy-test = { path = "../flowy-test" } nanoid = "0.4.0" fake = "2.0.0" rand = "0.8.4" diff --git a/frontend/rust-lib/flowy-user/src/event_handler.rs b/frontend/rust-lib/flowy-user/src/event_handler.rs index 02cb5f407b..2e0a6ef193 100644 --- a/frontend/rust-lib/flowy-user/src/event_handler.rs +++ b/frontend/rust-lib/flowy-user/src/event_handler.rs @@ -16,6 +16,7 @@ pub async fn sign_in( ) -> DataResult { let params: SignInParams = data.into_inner().try_into()?; let auth_type = params.auth_type.clone(); + let user_profile: UserProfilePB = session .sign_in(&auth_type, BoxAny::new(params)) .await? diff --git a/frontend/rust-lib/flowy-user/src/event_map.rs b/frontend/rust-lib/flowy-user/src/event_map.rs index b0342c9285..48e5580319 100644 --- a/frontend/rust-lib/flowy-user/src/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/event_map.rs @@ -40,6 +40,7 @@ pub trait UserStatusCallback: Send + Sync + 'static { /// The user cloud service provider. /// The provider can be supabase, firebase, aws, or any other cloud service. pub trait UserCloudServiceProvider: Send + Sync + 'static { + fn set_auth_type(&self, auth_type: AuthType); fn get_auth_service(&self, auth_type: &AuthType) -> Result, FlowyError>; } @@ -47,6 +48,10 @@ impl UserCloudServiceProvider for Arc where T: UserCloudServiceProvider, { + fn set_auth_type(&self, auth_type: AuthType) { + (**self).set_auth_type(auth_type) + } + fn get_auth_service(&self, auth_type: &AuthType) -> Result, FlowyError> { (**self).get_auth_service(auth_type) } diff --git a/frontend/rust-lib/flowy-user/src/services/user_session.rs b/frontend/rust-lib/flowy-user/src/services/user_session.rs index fdd2f8c23a..502b891c32 100644 --- a/frontend/rust-lib/flowy-user/src/services/user_session.rs +++ b/frontend/rust-lib/flowy-user/src/services/user_session.rs @@ -104,6 +104,7 @@ impl UserSession { auth_type: &AuthType, params: BoxAny, ) -> Result { + self.cloud_services.set_auth_type(auth_type.clone()); let resp = self .cloud_services .get_auth_service(auth_type)? @@ -134,6 +135,7 @@ impl UserSession { auth_type: &AuthType, params: BoxAny, ) -> Result { + self.cloud_services.set_auth_type(auth_type.clone()); let resp = self .cloud_services .get_auth_service(auth_type)? @@ -163,6 +165,7 @@ impl UserSession { .execute(&*(self.db_connection()?))?; self.database.close_user_db(session.user_id)?; self.set_session(None)?; + let server = self.cloud_services.get_auth_service(auth_type)?; let token = session.token; let _ = tokio::spawn(async move {