mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: token refresh on local (#4650)
* fix: refresh user token on local * chore: add test
This commit is contained in:
parent
b356927e60
commit
e81a2ff577
@ -1,5 +1,5 @@
|
||||
# Release Notes
|
||||
## Version 0.4.7 - 02/08/2024
|
||||
## Version 0.4.8 - 02/13/2024
|
||||
### Bug Fixes
|
||||
- Fixed a possible error when loading workspaces
|
||||
|
||||
|
@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
||||
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
|
||||
CARGO_MAKE_CRATE_NAME = "dart-ffi"
|
||||
LIB_NAME = "dart_ffi"
|
||||
APPFLOWY_VERSION = "0.4.7"
|
||||
APPFLOWY_VERSION = "0.4.8"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
|
||||
PRODUCT_NAME = "AppFlowy"
|
||||
MACOSX_DEPLOYMENT_TARGET = "11.0"
|
||||
|
@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 0.4.7
|
||||
version: 0.4.8
|
||||
|
||||
environment:
|
||||
flutter: ">=3.18.0-0.2.pre"
|
||||
|
@ -0,0 +1,50 @@
|
||||
use crate::util::unzip_history_user_db;
|
||||
use event_integration::user_event::user_localhost_af_cloud;
|
||||
use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
let import_container_name = "040_local".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (imported_af_folder_cleaner, imported_af_data_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
|
||||
user_localhost_af_cloud().await;
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
|
||||
.await;
|
||||
// In the 040_local, the structure is:
|
||||
// workspace:
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
// Sleep for 2 seconds to wait for the initial workspace to be created
|
||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||
|
||||
test
|
||||
.import_appflowy_data(
|
||||
imported_af_data_path.to_str().unwrap().to_string(),
|
||||
Some(import_container_name.clone()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// after import, the structure is:
|
||||
// workspace:
|
||||
// view: Getting Started
|
||||
// view: 040_local
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 2);
|
||||
assert_eq!(views[1].name, import_container_name);
|
||||
|
||||
drop(cleaner);
|
||||
drop(imported_af_folder_cleaner);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
mod auth_test;
|
||||
mod helper;
|
||||
mod import_af_data_local_test;
|
||||
mod user_awareness_test;
|
||||
mod user_profile_test;
|
||||
|
@ -17,7 +17,7 @@ use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{debug, error, event, info, instrument};
|
||||
use tracing::{debug, error, event, info, instrument, warn};
|
||||
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use lib_infra::box_any::BoxAny;
|
||||
@ -152,56 +152,88 @@ impl UserManager {
|
||||
user.email
|
||||
);
|
||||
|
||||
self.prepare_user(&session).await;
|
||||
self.prepare_backup(&session).await;
|
||||
|
||||
// Set the token if the current cloud service using token to authenticate
|
||||
// Currently, only the AppFlowy cloud using token to init the client api.
|
||||
if let Err(err) = self.cloud_services.set_token(&user.token) {
|
||||
error!("Set token failed: {}", err);
|
||||
}
|
||||
// TODO(nathan): using trait to separate the init process for different cloud service
|
||||
if user.authenticator.is_appflowy_cloud() {
|
||||
if let Err(err) = self.cloud_services.set_token(&user.token) {
|
||||
error!("Set token failed: {}", err);
|
||||
}
|
||||
|
||||
// Subscribe the token state
|
||||
let weak_cloud_services = Arc::downgrade(&self.cloud_services);
|
||||
let weak_authenticate_user = Arc::downgrade(&self.authenticate_user);
|
||||
let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?);
|
||||
let cloned_session = session.clone();
|
||||
if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() {
|
||||
event!(tracing::Level::DEBUG, "Listen token state change");
|
||||
let user_uid = user.uid;
|
||||
let local_token = user.token.clone();
|
||||
af_spawn(async move {
|
||||
while let Some(token_state) = token_state_rx.next().await {
|
||||
debug!("Token state changed: {:?}", token_state);
|
||||
match token_state {
|
||||
UserTokenState::Refresh { token: new_token } => {
|
||||
// Only save the token if the token is different from the current token
|
||||
if new_token != local_token {
|
||||
if let Some(conn) = weak_pool.upgrade().and_then(|pool| pool.get().ok()) {
|
||||
// Save the new token
|
||||
if let Err(err) = save_user_token(user_uid, conn, new_token) {
|
||||
error!("Save user token failed: {}", err);
|
||||
// Subscribe the token state
|
||||
let weak_cloud_services = Arc::downgrade(&self.cloud_services);
|
||||
let weak_authenticate_user = Arc::downgrade(&self.authenticate_user);
|
||||
let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?);
|
||||
let cloned_session = session.clone();
|
||||
if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() {
|
||||
event!(tracing::Level::DEBUG, "Listen token state change");
|
||||
let user_uid = user.uid;
|
||||
let local_token = user.token.clone();
|
||||
af_spawn(async move {
|
||||
while let Some(token_state) = token_state_rx.next().await {
|
||||
debug!("Token state changed: {:?}", token_state);
|
||||
match token_state {
|
||||
UserTokenState::Refresh { token: new_token } => {
|
||||
// Only save the token if the token is different from the current token
|
||||
if new_token != local_token {
|
||||
if let Some(conn) = weak_pool.upgrade().and_then(|pool| pool.get().ok()) {
|
||||
// Save the new token
|
||||
if let Err(err) = save_user_token(user_uid, conn, new_token) {
|
||||
error!("Save user token failed: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
UserTokenState::Invalid => {
|
||||
// Force user to sign out when the token is invalid
|
||||
if let (Some(cloud_services), Some(authenticate_user), Some(conn)) = (
|
||||
weak_cloud_services.upgrade(),
|
||||
weak_authenticate_user.upgrade(),
|
||||
weak_pool.upgrade().and_then(|pool| pool.get().ok()),
|
||||
) {
|
||||
},
|
||||
UserTokenState::Invalid => {
|
||||
// Attempt to upgrade the weak reference for cloud_services
|
||||
let cloud_services = match weak_cloud_services.upgrade() {
|
||||
Some(cloud_services) => cloud_services,
|
||||
None => {
|
||||
error!("Failed to upgrade weak reference for cloud_services");
|
||||
return; // Exit early if the upgrade fails
|
||||
},
|
||||
};
|
||||
|
||||
// Attempt to upgrade the weak reference for authenticate_user
|
||||
let authenticate_user = match weak_authenticate_user.upgrade() {
|
||||
Some(authenticate_user) => authenticate_user,
|
||||
None => {
|
||||
warn!("Failed to upgrade weak reference for authenticate_user");
|
||||
return; // Exit early if the upgrade fails
|
||||
},
|
||||
};
|
||||
|
||||
// Attempt to upgrade the weak reference for pool and then get a connection
|
||||
let conn = match weak_pool.upgrade() {
|
||||
Some(pool) => match pool.get() {
|
||||
Ok(conn) => conn,
|
||||
Err(_) => {
|
||||
warn!("Failed to get connection from pool");
|
||||
return; // Exit early if getting connection fails
|
||||
},
|
||||
},
|
||||
None => {
|
||||
warn!("Failed to upgrade weak reference for pool");
|
||||
return; // Exit early if the upgrade fails
|
||||
},
|
||||
};
|
||||
|
||||
// If all upgrades succeed, proceed with the sign_out operation
|
||||
if let Err(err) =
|
||||
sign_out(&cloud_services, &cloned_session, &authenticate_user, conn).await
|
||||
{
|
||||
error!("Sign out when token invalid failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
},
|
||||
// Force user to sign out when the token is invalid
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
self.prepare_user(&session).await;
|
||||
self.prepare_backup(&session).await;
|
||||
|
||||
// Do the user data migration if needed
|
||||
event!(tracing::Level::INFO, "Prepare user data migration");
|
||||
@ -270,7 +302,7 @@ impl UserManager {
|
||||
///
|
||||
/// A sign-in notification is also sent after a successful sign-in.
|
||||
///
|
||||
#[tracing::instrument(level = "debug", skip(self, params))]
|
||||
#[tracing::instrument(level = "info", skip(self, params))]
|
||||
pub async fn sign_in(
|
||||
&self,
|
||||
params: SignInParams,
|
||||
|
Loading…
Reference in New Issue
Block a user