fix: anon user error (#3772)

* fix: anon user error

* ci: fix tests
This commit is contained in:
Nathan.fooo 2023-10-24 23:13:51 +08:00 committed by GitHub
parent 71f80be8f7
commit cceee80799
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 227 additions and 230 deletions

View File

@ -27,8 +27,8 @@ class NetworkListener {
return _updateConnectionStatus(result); return _updateConnectionStatus(result);
} }
void stop() { Future<void> stop() async {
_connectivitySubscription.cancel(); await _connectivitySubscription.cancel();
} }
Future<void> _updateConnectionStatus(ConnectivityResult result) async { Future<void> _updateConnectionStatus(ConnectivityResult result) async {

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:appflowy/workspace/application/settings/prelude.dart'; import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy_backend/appflowy_backend.dart'; import 'package:appflowy_backend/appflowy_backend.dart';
import 'package:appflowy_backend/log.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
@ -104,6 +105,9 @@ Future<void> initGetIt(
config, config,
), ),
), ),
dispose: (launcher) async {
await launcher.dispose();
},
); );
getIt.registerSingleton<PluginSandbox>(PluginSandbox()); getIt.registerSingleton<PluginSandbox>(PluginSandbox());
@ -130,6 +134,7 @@ abstract class LaunchTask {
LaunchTaskType get type => LaunchTaskType.dataProcessing; LaunchTaskType get type => LaunchTaskType.dataProcessing;
Future<void> initialize(LaunchContext context); Future<void> initialize(LaunchContext context);
Future<void> dispose();
} }
class AppLauncher { class AppLauncher {
@ -153,6 +158,14 @@ class AppLauncher {
await task.initialize(context); await task.initialize(context);
} }
} }
Future<void> dispose() async {
Log.info('AppLauncher dispose');
for (final task in tasks) {
await task.dispose();
}
tasks.clear();
}
} }
enum IntegrationMode { enum IntegrationMode {

View File

@ -86,6 +86,9 @@ class InitAppWidgetTask extends LaunchTask {
return; return;
} }
@override
Future<void> dispose() async {}
} }
class ApplicationWidget extends StatefulWidget { class ApplicationWidget extends StatefulWidget {

View File

@ -1,11 +1,10 @@
import 'package:appflowy/env/env.dart'; import 'package:appflowy/env/env.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/user_auth_listener.dart'; import 'package:appflowy/user/application/user_auth_listener.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
class InitAppFlowyCloudTask extends LaunchTask { class InitAppFlowyCloudTask extends LaunchTask {
final _authStateListener = UserAuthStateListener(); UserAuthStateListener? _authStateListener;
bool isLoggingOut = false; bool isLoggingOut = false;
@override @override
@ -13,19 +12,24 @@ class InitAppFlowyCloudTask extends LaunchTask {
if (!isAppFlowyCloudEnabled) { if (!isAppFlowyCloudEnabled) {
return; return;
} }
_authStateListener = UserAuthStateListener();
_authStateListener.start( _authStateListener?.start(
didSignIn: () { didSignIn: () {
isLoggingOut = false; isLoggingOut = false;
}, },
onInvalidAuth: (message) async { onInvalidAuth: (message) async {
Log.error(message); Log.error(message);
await getIt<AuthService>().signOut();
// TODO(nathan): Show a dialog to notify the user that the session is expired.
if (!isLoggingOut) { if (!isLoggingOut) {
await runAppFlowy(); await runAppFlowy();
} }
}, },
); );
} }
@override
Future<void> dispose() async {
await _authStateListener?.stop();
_authStateListener = null;
}
} }

View File

@ -14,4 +14,7 @@ class HotKeyTask extends LaunchTask {
} }
await hotKeyManager.unregisterAll(); await hotKeyManager.unregisterAll();
} }
@override
Future<void> dispose() async {}
} }

View File

@ -25,4 +25,7 @@ class PluginLoadTask extends LaunchTask {
config: CalendarPluginConfig(), config: CalendarPluginConfig(),
); );
} }
@override
Future<void> dispose() async {}
} }

View File

@ -10,4 +10,7 @@ class InitLocalizationTask extends LaunchTask {
await EasyLocalization.ensureInitialized(); await EasyLocalization.ensureInitialized();
EasyLocalization.logger.enableBuildModes = []; EasyLocalization.logger.enableBuildModes = [];
} }
@override
Future<void> dispose() async {}
} }

View File

@ -18,4 +18,7 @@ class PlatformErrorCatcherTask extends LaunchTask {
}; };
} }
} }
@override
Future<void> dispose() async {}
} }

View File

@ -11,4 +11,9 @@ class InitPlatformServiceTask extends LaunchTask {
Future<void> initialize(LaunchContext context) async { Future<void> initialize(LaunchContext context) async {
getIt<NetworkListener>().start(); getIt<NetworkListener>().start();
} }
@override
Future<void> dispose() async {
await getIt<NetworkListener>().stop();
}
} }

View File

@ -27,6 +27,9 @@ class InitRustSDKTask extends LaunchTask {
context.getIt<FlowySDK>().setEnv(env); context.getIt<FlowySDK>().setEnv(env);
await context.getIt<FlowySDK>().init(dir); await context.getIt<FlowySDK>().init(dir);
} }
@override
Future<void> dispose() async {}
} }
AppFlowyEnv getAppFlowyEnv() { AppFlowyEnv getAppFlowyEnv() {

View File

@ -54,6 +54,12 @@ class InitSupabaseTask extends LaunchTask {
registerProtocolHandler(appflowyDeepLinkSchema); registerProtocolHandler(appflowyDeepLinkSchema);
} }
} }
@override
Future<void> dispose() async {
await realtimeService?.dispose();
supabase?.dispose();
}
} }
/// customize the supabase auth storage /// customize the supabase auth storage

View File

@ -71,4 +71,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener {
final position = await windowManager.getPosition(); final position = await windowManager.getPosition();
WindowSizeManager().setPosition(position); WindowSizeManager().setPosition(position);
} }
@override
Future<void> dispose() async {}
} }

View File

@ -63,15 +63,22 @@ class BackendAuthService implements AuthService {
@override @override
Future<Either<FlowyError, UserProfilePB>> signUpAsGuest({ Future<Either<FlowyError, UserProfilePB>> signUpAsGuest({
Map<String, String> params = const {}, Map<String, String> params = const {},
}) { }) async {
const password = "Guest!@123456"; const password = "Guest!@123456";
final uid = uuid(); final uid = uuid();
final userEmail = "$uid@appflowy.io"; final userEmail = "$uid@appflowy.io";
return signUp(
name: LocaleKeys.defaultUsername.tr(), final request = SignUpPayloadPB.create()
password: password, ..name = LocaleKeys.defaultUsername.tr()
email: userEmail, ..email = userEmail
); ..password = password
// When sign up as guest, the auth type is always local.
..authType = AuthTypePB.Local
..deviceId = await getDeviceId();
final response = await UserEventSignUp(request).send().then(
(value) => value.swap(),
);
return response;
} }
@override @override

View File

@ -36,6 +36,7 @@ class SupbaseRealtimeService {
isLoggingOut = false; isLoggingOut = false;
}, },
onInvalidAuth: (message) async { onInvalidAuth: (message) async {
Log.error(message);
await getIt<AuthService>().signOut(); await getIt<AuthService>().signOut();
channel?.unsubscribe(); channel?.unsubscribe();
channel = null; channel = null;

View File

@ -54,7 +54,7 @@ class SettingsUserView extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
_buildUserIconSetting(context), _buildUserIconSetting(context),
if (isCloudEnabled) ...[ if (isCloudEnabled && user.authType != AuthTypePB.Local) ...[
const VSpace(12), const VSpace(12),
UserEmailInput(user.email) UserEmailInput(user.email)
], ],

View File

@ -762,7 +762,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -1292,7 +1292,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa 1.0.6", "itoa 1.0.6",
"phf 0.11.2", "phf 0.8.0",
"smallvec", "smallvec",
] ]
@ -1438,7 +1438,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -2781,7 +2781,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2797,7 +2797,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"jsonwebtoken", "jsonwebtoken",
@ -3232,7 +3232,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -4307,7 +4307,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [ dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2", "phf_shared 0.11.2",
] ]
@ -4399,19 +4398,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.8.0" version = "0.8.0"
@ -4915,7 +4901,7 @@ dependencies = [
[[package]] [[package]]
name = "realtime-entity" name = "realtime-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"bytes", "bytes",
"collab", "collab",
@ -5637,7 +5623,7 @@ dependencies = [
[[package]] [[package]]
name = "shared_entity" name = "shared_entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab-entity", "collab-entity",

View File

@ -38,7 +38,7 @@ custom-protocol = ["tauri/custom-protocol"]
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "141354bfa9d08c387cf9beb9697b89b052790e89" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cc6b451104e7154b38df5ae9c4e7215a61fcf172" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #

View File

@ -660,7 +660,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -1138,7 +1138,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa", "itoa",
"phf 0.11.2", "phf 0.8.0",
"smallvec", "smallvec",
] ]
@ -1265,7 +1265,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -2440,7 +2440,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2456,7 +2456,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"jsonwebtoken", "jsonwebtoken",
@ -2816,7 +2816,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -3623,7 +3623,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [ dependencies = [
"phf_macros 0.8.0", "phf_macros",
"phf_shared 0.8.0", "phf_shared 0.8.0",
"proc-macro-hack", "proc-macro-hack",
] ]
@ -3643,7 +3643,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [ dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2", "phf_shared 0.11.2",
] ]
@ -3711,19 +3710,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.31",
]
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.8.0" version = "0.8.0"
@ -4265,7 +4251,7 @@ dependencies = [
[[package]] [[package]]
name = "realtime-entity" name = "realtime-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"bytes", "bytes",
"collab", "collab",
@ -4886,7 +4872,7 @@ dependencies = [
[[package]] [[package]]
name = "shared_entity" name = "shared_entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=141354bfa9d08c387cf9beb9697b89b052790e89#141354bfa9d08c387cf9beb9697b89b052790e89" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab-entity", "collab-entity",

View File

@ -82,7 +82,7 @@ incremental = false
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "141354bfa9d08c387cf9beb9697b89b052790e89" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cc6b451104e7154b38df5ae9c4e7215a61fcf172" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #

View File

@ -107,7 +107,7 @@ impl EventIntegrationTest {
*self.auth_type.write() = auth_type; *self.auth_type.write() = auth_type;
} }
pub async fn init_user(&self) -> UserProfilePB { pub async fn init_anon_user(&self) -> UserProfilePB {
self.sign_up_as_guest().await.user_profile self.sign_up_as_guest().await.user_profile
} }

View File

@ -76,7 +76,7 @@ pub struct FolderTest {
impl FolderTest { impl FolderTest {
pub async fn new() -> Self { pub async fn new() -> Self {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let _ = sdk.init_user().await; let _ = sdk.init_anon_user().await;
let workspace = create_workspace(&sdk, "FolderWorkspace", "Folder test workspace").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; let parent_view = create_app(&sdk, &workspace.id, "Folder App", "Folder test app").await;
let view = create_view( let view = create_view(

View File

@ -14,7 +14,7 @@ async fn af_cloud_sign_up_test() {
} }
#[tokio::test] #[tokio::test]
async fn af_cloud_update_user_metadata_of_open_ai_key() { async fn af_cloud_update_user_metadata() {
if get_af_cloud_config().is_some() { if get_af_cloud_config().is_some() {
let test = EventIntegrationTest::new(); let test = EventIntegrationTest::new();
let user = test.af_cloud_sign_up().await; let user = test.af_cloud_sign_up().await;
@ -25,12 +25,17 @@ async fn af_cloud_update_user_metadata_of_open_ai_key() {
test test
.update_user_profile(UpdateUserProfilePayloadPB { .update_user_profile(UpdateUserProfilePayloadPB {
id: user.id, id: user.id,
openai_key: Some("new openai_key".to_string()), openai_key: Some("new openai key".to_string()),
stability_ai_key: Some("new stability ai key".to_string()),
..Default::default() ..Default::default()
}) })
.await; .await;
let new_profile = test.get_user_profile().await.unwrap(); let new_profile = test.get_user_profile().await.unwrap();
assert_eq!(new_profile.openai_key, "new openai_key".to_string()); assert_eq!(new_profile.openai_key, "new openai key".to_string());
assert_eq!(
new_profile.stability_ai_key,
"new stability ai key".to_string()
);
} }
} }

View File

@ -1,7 +1,7 @@
use nanoid::nanoid; use nanoid::nanoid;
use event_integration::{event_builder::EventBuilder, EventIntegrationTest}; use event_integration::{event_builder::EventBuilder, EventIntegrationTest};
use flowy_user::entities::{UpdateUserProfilePayloadPB, UserProfilePB}; use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB, UserProfilePB};
use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; use flowy_user::{errors::ErrorCode, event_map::UserEvent::*};
use crate::user::local_test::helper::*; use crate::user::local_test::helper::*;
@ -20,20 +20,24 @@ async fn user_profile_get_failed() {
} }
#[tokio::test] #[tokio::test]
async fn user_profile_get() { async fn anon_user_profile_get() {
let test = EventIntegrationTest::new(); let test = EventIntegrationTest::new();
let user_profile = test.init_user().await; let user_profile = test.init_anon_user().await;
let user = EventBuilder::new(test.clone()) let user = EventBuilder::new(test.clone())
.event(GetUserProfile) .event(GetUserProfile)
.sync_send() .sync_send()
.parse::<UserProfilePB>(); .parse::<UserProfilePB>();
assert_eq!(user_profile, user); assert_eq!(user_profile.id, user.id);
assert_eq!(user_profile.openai_key, user.openai_key);
assert_eq!(user_profile.stability_ai_key, user.stability_ai_key);
assert_eq!(user_profile.workspace_id, user.workspace_id);
assert_eq!(user_profile.auth_type, AuthTypePB::Local);
} }
#[tokio::test] #[tokio::test]
async fn user_update_with_name() { async fn user_update_with_name() {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let user = sdk.init_user().await; let user = sdk.init_anon_user().await;
let new_name = "hello_world".to_owned(); let new_name = "hello_world".to_owned();
let request = UpdateUserProfilePayloadPB::new(user.id).name(&new_name); let request = UpdateUserProfilePayloadPB::new(user.id).name(&new_name);
let _ = EventBuilder::new(sdk.clone()) let _ = EventBuilder::new(sdk.clone())
@ -52,7 +56,7 @@ async fn user_update_with_name() {
#[tokio::test] #[tokio::test]
async fn user_update_with_ai_key() { async fn user_update_with_ai_key() {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let user = sdk.init_user().await; let user = sdk.init_anon_user().await;
let openai_key = "openai_key".to_owned(); let openai_key = "openai_key".to_owned();
let stability_ai_key = "stability_ai_key".to_owned(); let stability_ai_key = "stability_ai_key".to_owned();
let request = UpdateUserProfilePayloadPB::new(user.id) let request = UpdateUserProfilePayloadPB::new(user.id)
@ -73,9 +77,9 @@ async fn user_update_with_ai_key() {
} }
#[tokio::test] #[tokio::test]
async fn user_update_with_email() { async fn anon_user_update_with_email() {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let user = sdk.init_user().await; let user = sdk.init_anon_user().await;
let new_email = format!("{}@gmail.com", nanoid!(6)); let new_email = format!("{}@gmail.com", nanoid!(6));
let request = UpdateUserProfilePayloadPB::new(user.id).email(&new_email); let request = UpdateUserProfilePayloadPB::new(user.id).email(&new_email);
let _ = EventBuilder::new(sdk.clone()) let _ = EventBuilder::new(sdk.clone())
@ -87,13 +91,14 @@ async fn user_update_with_email() {
.sync_send() .sync_send()
.parse::<UserProfilePB>(); .parse::<UserProfilePB>();
assert_eq!(user_profile.email, new_email,); // When the user is anonymous, the email is empty no matter what you set
assert!(user_profile.email.is_empty());
} }
#[tokio::test] #[tokio::test]
async fn user_update_with_invalid_email() { async fn user_update_with_invalid_email() {
let test = EventIntegrationTest::new(); let test = EventIntegrationTest::new();
let user = test.init_user().await; let user = test.init_anon_user().await;
for email in invalid_email_test_case() { for email in invalid_email_test_case() {
let request = UpdateUserProfilePayloadPB::new(user.id).email(&email); let request = UpdateUserProfilePayloadPB::new(user.id).email(&email);
assert_eq!( assert_eq!(
@ -112,7 +117,7 @@ async fn user_update_with_invalid_email() {
#[tokio::test] #[tokio::test]
async fn user_update_with_invalid_password() { async fn user_update_with_invalid_password() {
let test = EventIntegrationTest::new(); let test = EventIntegrationTest::new();
let user = test.init_user().await; let user = test.init_anon_user().await;
for password in invalid_password_test_case() { for password in invalid_password_test_case() {
let request = UpdateUserProfilePayloadPB::new(user.id).password(&password); let request = UpdateUserProfilePayloadPB::new(user.id).password(&password);
@ -129,7 +134,7 @@ async fn user_update_with_invalid_password() {
#[tokio::test] #[tokio::test]
async fn user_update_with_invalid_name() { async fn user_update_with_invalid_name() {
let test = EventIntegrationTest::new(); let test = EventIntegrationTest::new();
let user = test.init_user().await; let user = test.init_anon_user().await;
let request = UpdateUserProfilePayloadPB::new(user.id).name(""); let request = UpdateUserProfilePayloadPB::new(user.id).name("");
assert!(EventBuilder::new(test.clone()) assert!(EventBuilder::new(test.clone())
.event(UpdateUserProfile) .event(UpdateUserProfile)

View File

@ -194,17 +194,6 @@ async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() {
} }
} }
#[tokio::test]
async fn check_not_exist_user_test() {
if let Some(test) = FlowySupabaseTest::new() {
let err = test
.check_user_with_uuid(&uuid::Uuid::new_v4().to_string())
.await
.unwrap_err();
assert_eq!(err.code, ErrorCode::RecordNotFound);
}
}
#[tokio::test] #[tokio::test]
async fn get_user_profile_test() { async fn get_user_profile_test() {
if let Some(test) = FlowySupabaseTest::new() { if let Some(test) = FlowySupabaseTest::new() {

View File

@ -23,7 +23,7 @@ use flowy_server::supabase::api::*;
use flowy_server::{AppFlowyEncryption, EncryptionImpl}; use flowy_server::{AppFlowyEncryption, EncryptionImpl};
use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_server_config::af_cloud_config::AFCloudConfiguration;
use flowy_server_config::supabase_config::SupabaseConfiguration; use flowy_server_config::supabase_config::SupabaseConfiguration;
use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB, UserCredentialsPB}; use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB};
use flowy_user::errors::FlowyError; use flowy_user::errors::FlowyError;
use flowy_user::event_map::UserCloudServiceProvider; use flowy_user::event_map::UserCloudServiceProvider;
use flowy_user::event_map::UserEvent::*; use flowy_user::event_map::UserEvent::*;
@ -49,19 +49,6 @@ impl FlowySupabaseTest {
Some(Self { inner: test }) Some(Self { inner: test })
} }
pub async fn check_user_with_uuid(&self, uuid: &str) -> Result<(), FlowyError> {
match EventBuilder::new(self.inner.clone())
.event(CheckUser)
.payload(UserCredentialsPB::from_uuid(uuid))
.async_send()
.await
.error()
{
None => Ok(()),
Some(error) => Err(error),
}
}
pub async fn update_user_profile( pub async fn update_user_profile(
&self, &self,
payload: UpdateUserProfilePayloadPB, payload: UpdateUserProfilePayloadPB,

View File

@ -91,6 +91,11 @@ impl ServerProvider {
} }
pub fn set_server_type(&self, server_type: ServerType) { pub fn set_server_type(&self, server_type: ServerType) {
let old_server_type = self.server_type.read().clone();
if server_type != old_server_type {
self.providers.write().remove(&old_server_type);
}
*self.server_type.write() = server_type; *self.server_type.write() = server_type;
} }
@ -179,9 +184,9 @@ struct LocalServerDBImpl {
} }
impl LocalServerDB for LocalServerDBImpl { impl LocalServerDB for LocalServerDBImpl {
fn get_user_profile(&self, uid: i64) -> Result<Option<UserProfile>, FlowyError> { fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError> {
let sqlite_db = open_user_db(&self.storage_path, uid)?; let sqlite_db = open_user_db(&self.storage_path, uid)?;
let user_profile = get_user_profile(&sqlite_db, uid).ok(); let user_profile = get_user_profile(&sqlite_db, uid)?;
Ok(user_profile) Ok(user_profile)
} }

View File

@ -38,7 +38,7 @@ pub struct DatabaseEditorTest {
impl DatabaseEditorTest { impl DatabaseEditorTest {
pub async fn new_grid() -> Self { pub async fn new_grid() -> Self {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let _ = sdk.init_user().await; let _ = sdk.init_anon_user().await;
let params = make_test_grid(); let params = make_test_grid();
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await; let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;
@ -47,7 +47,7 @@ impl DatabaseEditorTest {
pub async fn new_no_date_grid() -> Self { pub async fn new_no_date_grid() -> Self {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let _ = sdk.init_user().await; let _ = sdk.init_anon_user().await;
let params = make_no_date_test_grid(); let params = make_no_date_test_grid();
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await; let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;
@ -56,7 +56,7 @@ impl DatabaseEditorTest {
pub async fn new_board() -> Self { pub async fn new_board() -> Self {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let _ = sdk.init_user().await; let _ = sdk.init_anon_user().await;
let params = make_test_board(); let params = make_test_board();
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await; let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;
@ -65,7 +65,7 @@ impl DatabaseEditorTest {
pub async fn new_calendar() -> Self { pub async fn new_calendar() -> Self {
let sdk = EventIntegrationTest::new(); let sdk = EventIntegrationTest::new();
let _ = sdk.init_user().await; let _ = sdk.init_anon_user().await;
let params = make_test_calendar(); let params = make_test_calendar();
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await; let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;

View File

@ -58,10 +58,9 @@ async fn get_checklist_cell_options(test: &DatabaseFilterTest) -> Vec<String> {
.get_cell(&field.id, &test.row_details[0].row.id) .get_cell(&field.id, &test.row_details[0].row.id)
.await; .await;
row_cell row_cell
.map_or_else( .map_or(ChecklistCellData::default(), |cell| {
|| ChecklistCellData::default(), ChecklistCellData::from(&cell)
|cell| ChecklistCellData::from(&cell), })
)
.options .options
.into_iter() .into_iter()
.map(|option| option.id) .map(|option| option.id)

View File

@ -102,15 +102,14 @@ where
fn get_user_profile( fn get_user_profile(
&self, &self,
_credential: UserCredentials, _credential: UserCredentials,
) -> FutureResult<Option<UserProfile>, FlowyError> { ) -> FutureResult<UserProfile, FlowyError> {
let try_get_client = self.server.try_get_client(); let try_get_client = self.server.try_get_client();
FutureResult::new(async move { FutureResult::new(async move {
let client = try_get_client?; let client = try_get_client?;
let profile = client.get_profile().await?; let profile = client.get_profile().await?;
let token = client.get_token()?; let token = client.get_token()?;
let profile = user_profile_from_af_profile(token, profile)?; let profile = user_profile_from_af_profile(token, profile)?;
Ok(profile)
Ok(Some(profile))
}) })
} }
@ -122,29 +121,6 @@ where
}) })
} }
fn check_user(&self, credential: UserCredentials) -> FutureResult<(), Error> {
let try_get_client = self.server.try_get_client();
FutureResult::new(async move {
// from params
let token = credential.token.ok_or(anyhow!("expecting token"))?;
let uid = credential.uid.ok_or(anyhow!("expecting uid"))?;
// from cloud
let client = try_get_client?;
let profile = client.get_profile().await?;
let client_token = client.access_token()?;
// compare and check
if uid != profile.uid {
return Err(anyhow!("uid mismatch"));
}
if token != client_token {
return Err(anyhow!("token mismatch"));
}
Ok(())
})
}
fn add_workspace_member( fn add_workspace_member(
&self, &self,
user_email: String, user_email: String,

View File

@ -86,7 +86,7 @@ impl AppFlowyServer for AFCloudServer {
fn set_token(&self, token: &str) -> Result<(), Error> { fn set_token(&self, token: &str) -> Result<(), Error> {
self self
.client .client
.set_token(token) .restore_token(token)
.map_err(|err| Error::new(FlowyError::unauthorized().with_context(err))) .map_err(|err| Error::new(FlowyError::unauthorized().with_context(err)))
} }

View File

@ -102,21 +102,24 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
FutureResult::new(async { Ok(()) }) FutureResult::new(async { Ok(()) })
} }
fn get_user_profile( fn get_user_profile(&self, credential: UserCredentials) -> FutureResult<UserProfile, FlowyError> {
&self, let result = match credential.uid {
_credential: UserCredentials, None => Err(FlowyError::record_not_found()),
) -> FutureResult<Option<UserProfile>, FlowyError> { Some(uid) => {
FutureResult::new(async { Ok(None) }) self.db.get_user_profile(uid).map(|mut profile| {
// We don't want to expose the email in the local server
profile.email = "".to_string();
profile
})
},
};
FutureResult::new(async { result })
} }
fn get_all_user_workspaces(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> { fn get_all_user_workspaces(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
FutureResult::new(async { Ok(vec![]) }) FutureResult::new(async { Ok(vec![]) })
} }
fn check_user(&self, _credential: UserCredentials) -> FutureResult<(), Error> {
FutureResult::new(async { Ok(()) })
}
fn add_workspace_member( fn add_workspace_member(
&self, &self,
_user_email: String, _user_email: String,

View File

@ -21,7 +21,7 @@ use crate::local_server::impls::{
use crate::AppFlowyServer; use crate::AppFlowyServer;
pub trait LocalServerDB: Send + Sync + 'static { pub trait LocalServerDB: Send + Sync + 'static {
fn get_user_profile(&self, uid: i64) -> Result<Option<UserProfile>, FlowyError>; fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError>;
fn get_user_workspace(&self, uid: i64) -> Result<Option<UserWorkspace>, FlowyError>; fn get_user_workspace(&self, uid: i64) -> Result<Option<UserWorkspace>, FlowyError>;
fn get_collab_updates(&self, uid: i64, object_id: &str) -> Result<Vec<Vec<u8>>, FlowyError>; fn get_collab_updates(&self, uid: i64, object_id: &str) -> Result<Vec<Vec<u8>>, FlowyError>;
} }

View File

@ -2,7 +2,6 @@ use std::collections::HashMap;
use std::future::Future; use std::future::Future;
use std::iter::Take; use std::iter::Take;
use std::pin::Pin; use std::pin::Pin;
use std::str::FromStr;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::time::Duration; use std::time::Duration;
@ -199,10 +198,7 @@ where
}) })
} }
fn get_user_profile( fn get_user_profile(&self, credential: UserCredentials) -> FutureResult<UserProfile, FlowyError> {
&self,
credential: UserCredentials,
) -> FutureResult<Option<UserProfile>, FlowyError> {
let try_get_postgrest = self.server.try_get_postgrest(); let try_get_postgrest = self.server.try_get_postgrest();
let uid = credential let uid = credential
.uid .uid
@ -212,8 +208,8 @@ where
let postgrest = try_get_postgrest?; let postgrest = try_get_postgrest?;
let user_profile_resp = get_user_profile(postgrest, GetUserProfileParams::Uid(uid)).await?; let user_profile_resp = get_user_profile(postgrest, GetUserProfileParams::Uid(uid)).await?;
match user_profile_resp { match user_profile_resp {
None => Ok(None), None => Err(FlowyError::record_not_found()),
Some(response) => Ok(Some(UserProfile { Some(response) => Ok(UserProfile {
uid: response.uid, uid: response.uid,
email: response.email, email: response.email,
name: response.name, name: response.name,
@ -225,7 +221,7 @@ where
auth_type: AuthType::Supabase, auth_type: AuthType::Supabase,
encryption_type: EncryptionType::from_sign(&response.encryption_sign), encryption_type: EncryptionType::from_sign(&response.encryption_sign),
updated_at: response.updated_at.timestamp(), updated_at: response.updated_at.timestamp(),
})), }),
} }
}) })
} }
@ -238,18 +234,6 @@ where
Ok(user_workspaces) Ok(user_workspaces)
}) })
} }
fn check_user(&self, credential: UserCredentials) -> FutureResult<(), Error> {
let try_get_postgrest = self.server.try_get_postgrest();
let uuid = credential.uuid.and_then(|uuid| Uuid::from_str(&uuid).ok());
let uid = credential.uid;
FutureResult::new(async move {
let postgrest = try_get_postgrest?;
check_user(postgrest, uid, uuid).await?;
Ok(())
})
}
fn add_workspace_member( fn add_workspace_member(
&self, &self,
_user_email: String, _user_email: String,
@ -512,6 +496,7 @@ async fn update_user_profile(
Ok(()) Ok(())
} }
#[allow(dead_code)]
async fn check_user( async fn check_user(
postgrest: Arc<PostgresWrapper>, postgrest: Arc<PostgresWrapper>,
uid: Option<i64>, uid: Option<i64>,

View File

@ -1,6 +1,7 @@
use uuid::Uuid; use uuid::Uuid;
use flowy_encrypt::{encrypt_text, generate_encryption_secret}; use flowy_encrypt::{encrypt_text, generate_encryption_secret};
use flowy_error::FlowyError;
use flowy_user_deps::entities::*; use flowy_user_deps::entities::*;
use lib_infra::box_any::BoxAny; use lib_infra::box_any::BoxAny;
@ -66,7 +67,6 @@ async fn supabase_update_user_profile_test() {
let user_profile = user_service let user_profile = user_service
.get_user_profile(UserCredentials::from_uid(user.user_id)) .get_user_profile(UserCredentials::from_uid(user.user_id))
.await .await
.unwrap()
.unwrap(); .unwrap();
assert_eq!(user_profile.name, "123"); assert_eq!(user_profile.name, "123");
@ -89,7 +89,6 @@ async fn supabase_get_user_profile_test() {
user_service user_service
.get_user_profile(credential.clone()) .get_user_profile(credential.clone())
.await .await
.unwrap()
.unwrap(); .unwrap();
} }
@ -100,12 +99,12 @@ async fn supabase_get_not_exist_user_profile_test() {
} }
let user_service = user_auth_service(); let user_service = user_auth_service();
let result = user_service let result: FlowyError = user_service
.get_user_profile(UserCredentials::from_uid(i64::MAX)) .get_user_profile(UserCredentials::from_uid(i64::MAX))
.await .await
.unwrap(); .unwrap_err();
// user not found // user not found
assert!(result.is_none()); assert!(result.is_record_not_found());
} }
#[tokio::test] #[tokio::test]
@ -134,7 +133,6 @@ async fn user_encryption_sign_test() {
let user_profile: UserProfile = user_service let user_profile: UserProfile = user_service
.get_user_profile(UserCredentials::from_uid(user.user_id)) .get_user_profile(UserCredentials::from_uid(user.user_id))
.await .await
.unwrap()
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
user_profile.encryption_type, user_profile.encryption_type,

View File

@ -89,16 +89,11 @@ pub trait UserCloudService: Send + Sync + 'static {
/// Get the user information using the user's token or uid /// Get the user information using the user's token or uid
/// return None if the user is not found /// return None if the user is not found
fn get_user_profile( fn get_user_profile(&self, credential: UserCredentials) -> FutureResult<UserProfile, FlowyError>;
&self,
credential: UserCredentials,
) -> FutureResult<Option<UserProfile>, FlowyError>;
/// Return the all the workspaces of the user /// Return the all the workspaces of the user
fn get_all_user_workspaces(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error>; fn get_all_user_workspaces(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error>;
fn check_user(&self, credential: UserCredentials) -> FutureResult<(), Error>;
fn add_workspace_member( fn add_workspace_member(
&self, &self,
user_email: String, user_email: String,

View File

@ -82,30 +82,29 @@ pub async fn init_user_handler(
} }
#[tracing::instrument(level = "debug", skip(manager))] #[tracing::instrument(level = "debug", skip(manager))]
pub async fn check_user_handler(
manager: AFPluginState<Weak<UserManager>>,
) -> Result<(), FlowyError> {
let manager = upgrade_manager(manager)?;
manager.check_user().await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip(manager), err)]
pub async fn get_user_profile_handler( pub async fn get_user_profile_handler(
manager: AFPluginState<Weak<UserManager>>, manager: AFPluginState<Weak<UserManager>>,
) -> DataResult<UserProfilePB, FlowyError> { ) -> DataResult<UserProfilePB, FlowyError> {
let manager = upgrade_manager(manager)?; let manager = upgrade_manager(manager)?;
let uid = manager.get_session()?.user_id; let uid = manager.get_session()?.user_id;
let user_profile = manager.get_user_profile(uid).await?; let mut user_profile = manager.get_user_profile(uid).await?;
let weak_manager = Arc::downgrade(&manager); let weak_manager = Arc::downgrade(&manager);
let cloned_user_profile = user_profile.clone(); let cloned_user_profile = user_profile.clone();
// Refresh the user profile in the background
tokio::spawn(async move { tokio::spawn(async move {
if let Some(manager) = weak_manager.upgrade() { if let Some(manager) = weak_manager.upgrade() {
let _ = manager.refresh_user_profile(&cloned_user_profile).await; let _ = manager.refresh_user_profile(&cloned_user_profile).await;
} }
}); });
// When the user is logged in with a local account, the email field is a placeholder and should
// not be exposed to the client. So we set the email field to an empty string.
if user_profile.auth_type == AuthType::Local {
user_profile.email = "".to_string();
}
event!( event!(
tracing::Level::DEBUG, tracing::Level::DEBUG,
"Get user profile: {:?}", "Get user profile: {:?}",

View File

@ -30,7 +30,6 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
.event(UserEvent::GetUserProfile, get_user_profile_handler) .event(UserEvent::GetUserProfile, get_user_profile_handler)
.event(UserEvent::SignOut, sign_out) .event(UserEvent::SignOut, sign_out)
.event(UserEvent::UpdateUserProfile, update_user_profile_handler) .event(UserEvent::UpdateUserProfile, update_user_profile_handler)
.event(UserEvent::CheckUser, check_user_handler)
.event(UserEvent::SetAppearanceSetting, set_appearance_setting) .event(UserEvent::SetAppearanceSetting, set_appearance_setting)
.event(UserEvent::GetAppearanceSetting, get_appearance_setting) .event(UserEvent::GetAppearanceSetting, get_appearance_setting)
.event(UserEvent::GetUserSetting, get_user_setting) .event(UserEvent::GetUserSetting, get_user_setting)
@ -232,11 +231,8 @@ pub enum UserEvent {
#[event(output = "UserProfilePB")] #[event(output = "UserProfilePB")]
GetUserProfile = 4, GetUserProfile = 4,
/// Check the user current session is valid or not
#[event(output = "UserProfilePB")]
CheckUser = 5,
/// Initialize resources for the current user after launching the application /// Initialize resources for the current user after launching the application
///
#[event()] #[event()]
InitUser = 6, InitUser = 6,

View File

@ -97,7 +97,7 @@ impl UserManager {
while let Ok(update) = rx.recv().await { while let Ok(update) = rx.recv().await {
if let Some(user_manager) = weak_user_manager.upgrade() { if let Some(user_manager) = weak_user_manager.upgrade() {
if let Err(err) = user_manager.handler_user_update(update).await { if let Err(err) = user_manager.handler_user_update(update).await {
tracing::error!("handler_user_update failed: {:?}", err); error!("handler_user_update failed: {:?}", err);
} }
} }
} }
@ -172,10 +172,10 @@ impl UserManager {
info!("Did apply migrations: {:?}", applied_migrations); info!("Did apply migrations: {:?}", applied_migrations);
} }
}, },
Err(e) => tracing::error!("User data migration failed: {:?}", e), Err(e) => error!("User data migration failed: {:?}", e),
} }
}, },
_ => tracing::error!("Failed to get collab db or sqlite pool"), _ => error!("Failed to get collab db or sqlite pool"),
} }
self.set_collab_config(&session); self.set_collab_config(&session);
// Init the user awareness // Init the user awareness
@ -193,7 +193,7 @@ impl UserManager {
) )
.await .await
{ {
tracing::error!("Failed to call did_init callback: {:?}", e); error!("Failed to call did_init callback: {:?}", e);
} }
} }
*self.user_status_callback.write().await = Arc::new(user_status_callback); *self.user_status_callback.write().await = Arc::new(user_status_callback);
@ -253,7 +253,7 @@ impl UserManager {
.did_sign_in(user_profile.uid, &latest_workspace, &session.device_id) .did_sign_in(user_profile.uid, &latest_workspace, &session.device_id)
.await .await
{ {
tracing::error!("Failed to call did_sign_in callback: {:?}", e); error!("Failed to call did_sign_in callback: {:?}", e);
} }
send_auth_state_notification(AuthStateChangedPB { send_auth_state_notification(AuthStateChangedPB {
state: AuthStatePB::AuthStateSignIn, state: AuthStatePB::AuthStateSignIn,
@ -349,7 +349,6 @@ impl UserManager {
UserAwarenessDataSource::Remote UserAwarenessDataSource::Remote
}; };
event!(tracing::Level::DEBUG, "Sign up response: {:?}", response);
if response.is_new_user { if response.is_new_user {
if let Some(old_user) = migration_user { if let Some(old_user) = migration_user {
let new_user = MigrationUser { let new_user = MigrationUser {
@ -403,9 +402,8 @@ impl UserManager {
let server = self.cloud_services.get_user_service()?; let server = self.cloud_services.get_user_service()?;
tokio::spawn(async move { tokio::spawn(async move {
match server.sign_out(None).await { if let Err(err) = server.sign_out(None).await {
Ok(_) => {}, event!(tracing::Level::ERROR, "{:?}", err);
Err(e) => event!(tracing::Level::ERROR, "{:?}", e),
} }
}); });
Ok(()) Ok(())
@ -437,15 +435,6 @@ impl UserManager {
Ok(()) Ok(())
} }
pub async fn check_user(&self) -> Result<(), FlowyError> {
let user_id = self.get_session()?.user_id;
let user = self.get_user_profile(user_id).await?;
let credential = UserCredentials::new(Some(user.token), Some(user_id), None);
let auth_service = self.cloud_services.get_user_service()?;
auth_service.check_user(credential).await?;
Ok(())
}
/// Fetches the user profile for the given user ID. /// Fetches the user profile for the given user ID.
pub async fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError> { pub async fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError> {
let user: UserProfile = user_table::dsl::user_table let user: UserProfile = user_table::dsl::user_table
@ -457,27 +446,63 @@ impl UserManager {
} }
#[tracing::instrument(level = "info", skip_all)] #[tracing::instrument(level = "info", skip_all)]
pub async fn refresh_user_profile( pub async fn refresh_user_profile(&self, old_user_profile: &UserProfile) -> FlowyResult<()> {
&self,
old_user_profile: &UserProfile,
) -> FlowyResult<UserProfile> {
let uid = old_user_profile.uid; let uid = old_user_profile.uid;
let new_user_profile: UserProfile = self let result: Result<UserProfile, FlowyError> = self
.cloud_services .cloud_services
.get_user_service()? .get_user_service()?
.get_user_profile(UserCredentials::from_uid(uid)) .get_user_profile(UserCredentials::from_uid(uid))
.await? .await;
.ok_or_else(|| FlowyError::new(ErrorCode::RecordNotFound, "User not found"))?;
if new_user_profile.updated_at > old_user_profile.updated_at { match result {
check_encryption_sign(old_user_profile, &new_user_profile.encryption_type.sign()); Ok(new_user_profile) => {
// If the authentication type has changed, it indicates that the user has signed in
// using a different release package but is sharing the same data folder.
// In such cases, notify the frontend to log out.
if old_user_profile.auth_type != AuthType::Local
&& new_user_profile.auth_type != old_user_profile.auth_type
{
event!(
tracing::Level::INFO,
"User login with different cloud: {:?} -> {:?}",
old_user_profile.auth_type,
new_user_profile.auth_type
);
// Save the new user profile send_auth_state_notification(AuthStateChangedPB {
let changeset = UserTableChangeset::from_user_profile(new_user_profile.clone()); state: AuthStatePB::InvalidAuth,
let _ = upsert_user_profile_change(uid, self.database.get_pool(uid)?, changeset); message: "User login with different cloud".to_string(),
})
.send();
return Ok(());
}
// If the user profile is updated, save the new user profile
if new_user_profile.updated_at > old_user_profile.updated_at {
check_encryption_sign(old_user_profile, &new_user_profile.encryption_type.sign());
// Save the new user profile
let changeset = UserTableChangeset::from_user_profile(new_user_profile);
let _ = upsert_user_profile_change(uid, self.database.get_pool(uid)?, changeset);
}
Ok(())
},
Err(err) => {
// If the user is not found, notify the frontend to logout
if err.is_record_not_found() {
event!(
tracing::Level::INFO,
"User is not found on the server when refreshing profile"
);
send_auth_state_notification(AuthStateChangedPB {
state: AuthStatePB::InvalidAuth,
message: "User is not found on the server".to_string(),
})
.send();
}
Err(err)
},
} }
Ok(new_user_profile)
} }
pub fn user_dir(&self, uid: i64) -> String { pub fn user_dir(&self, uid: i64) -> String {
@ -680,7 +705,7 @@ impl UserManager {
) )
.await .await
{ {
tracing::error!("Sync user data to cloud failed: {:?}", err); error!("Sync user data to cloud failed: {:?}", err);
} }
// Save the old user workspace setting. // Save the old user workspace setting.

View File

@ -26,6 +26,7 @@ pub(crate) fn send_notification(id: &str, ty: UserNotification) -> NotificationB
NotificationBuilder::new(id, ty, USER_OBSERVABLE_SOURCE) NotificationBuilder::new(id, ty, USER_OBSERVABLE_SOURCE)
} }
#[tracing::instrument(level = "trace")]
pub(crate) fn send_auth_state_notification(payload: AuthStateChangedPB) -> NotificationBuilder { pub(crate) fn send_auth_state_notification(payload: AuthStateChangedPB) -> NotificationBuilder {
NotificationBuilder::new( NotificationBuilder::new(
"auth_state_change_notification", "auth_state_change_notification",