Skip to content

Commit 7750f22

Browse files
appflowyLucasXu0
andauthored
fix: anon user can not locate its data (AppFlowy-IO#7873)
* fix: anon user can not locate its data * chore: add test * chore: bump version 0.9.1 * chore: remove self-hosted ios ci --------- Co-authored-by: Lucas.Xu <[email protected]>
1 parent e6e2393 commit 7750f22

File tree

12 files changed

+108
-34
lines changed

12 files changed

+108
-34
lines changed

.github/workflows/ios_ci.yaml

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,7 @@ concurrency:
2626
cancel-in-progress: true
2727

2828
jobs:
29-
build-self-hosted:
30-
if: github.event.pull_request.head.repo.full_name == github.repository
31-
runs-on: self-hosted
32-
33-
steps:
34-
- name: Checkout source code
35-
uses: actions/checkout@v2
36-
37-
- name: Build AppFlowy
38-
working-directory: frontend
39-
run: |
40-
cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios
41-
cargo make --profile development-ios-arm64-sim code_generation
42-
43-
- uses: futureware-tech/simulator-action@v3
44-
id: simulator-action
45-
with:
46-
model: "iPhone 15"
47-
shutdown_after_job: false
48-
4929
integration-tests:
50-
if: github.event.pull_request.head.repo.full_name != github.repository
5130
runs-on: macos-latest
5231

5332
steps:

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,26 @@
11
# Release Notes
2+
## Version 0.9.1 - 01/05/2025
3+
### Desktop
4+
#### New Features
5+
- Added AppFlowy Prompt Library to AI Chat and Document's Ask AI
6+
- Revamped the desktop in-app notification center
7+
- Supported login with password, as well as forgot and change password options
8+
- Supported copying link to invite members
9+
- Improved the Settings' Members tab with new metadata: member avatar and joined time
10+
#### Bug Fixes
11+
- Fixed data loss when using anonymous local
12+
- Fixed crash when trying to delete an emoji
13+
- Fixed Windows scaling issue
14+
- Correctly displayed mention text by decoding web content
15+
### Mobile
16+
#### New Features
17+
- Supported workspace search
18+
- Improved UX for links in documents
19+
- Supported changing password in Mobile Settings
20+
- Added support for inviting members via links
21+
#### Bug Fixes
22+
- Correctly displayed mention text by decoding web content
23+
224
## Version 0.9.0 - 30/04/2025
325
### Desktop
426
#### New Features

frontend/Makefile.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
2626
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
2727
CARGO_MAKE_CRATE_NAME = "dart-ffi"
2828
LIB_NAME = "dart_ffi"
29-
APPFLOWY_VERSION = "0.9.0"
29+
APPFLOWY_VERSION = "0.9.1"
3030
FLUTTER_DESKTOP_FEATURES = "dart"
3131
PRODUCT_NAME = "AppFlowy"
3232
MACOSX_DEPLOYMENT_TARGET = "11.0"

frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class SpaceCancelOrConfirmButton extends StatelessWidget {
182182
final String confirmButtonName;
183183
final Color? confirmButtonColor;
184184
final WidgetBuilder? confirmButtonBuilder;
185+
185186
@override
186187
Widget build(BuildContext context) {
187188
final theme = AppFlowyTheme.of(context);
@@ -208,8 +209,16 @@ class SpaceCancelOrConfirmButton extends StatelessWidget {
208209
borderRadius: BorderRadius.circular(8),
209210
),
210211
),
211-
child: AFFilledTextButton.destructive(
212-
text: confirmButtonName,
212+
child: FlowyButton(
213+
useIntrinsicWidth: true,
214+
margin:
215+
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 9.0),
216+
radius: BorderRadius.circular(8),
217+
text: FlowyText.regular(
218+
confirmButtonName,
219+
lineHeight: 1.0,
220+
color: Theme.of(context).colorScheme.onPrimary,
221+
),
213222
onTap: onConfirm,
214223
),
215224
),

frontend/appflowy_flutter/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: Bring projects, wikis, and teams together with AI. AppFlowy is an
44
your data. The best open source alternative to Notion.
55
publish_to: "none"
66

7-
version: 0.9.0
7+
version: 0.9.1
88

99
environment:
1010
flutter: ">=3.27.4"

frontend/rust-lib/event-integration-test/src/user_event.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,10 @@ pub struct SignUpContext {
438438
pub user_profile: UserProfilePB,
439439
pub password: String,
440440
}
441-
441+
pub async fn use_local_mode() {
442+
AuthenticatorType::Local.write_env();
443+
AFCloudConfiguration::default().write_env();
444+
}
442445
pub async fn use_localhost_af_cloud() {
443446
AuthenticatorType::AppFlowyCloud.write_env();
444447
let base_url =
Binary file not shown.

frontend/rust-lib/event-integration-test/tests/user/af_cloud_test/workspace_test.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use crate::user::af_cloud_test::util::get_synced_workspaces;
2+
use crate::util::unzip;
23
use collab::core::collab::DataSource::DocStateV1;
34
use collab::core::origin::CollabOrigin;
45
use collab_entity::CollabType;
56
use collab_folder::Folder;
6-
use event_integration_test::user_event::use_localhost_af_cloud;
7+
use event_integration_test::user_event::{use_local_mode, use_localhost_af_cloud};
78
use event_integration_test::EventIntegrationTest;
9+
use flowy_core::DEFAULT_NAME;
810
use flowy_user::entities::AFRolePB;
911
use flowy_user_pub::cloud::UserCloudServiceProvider;
1012
use flowy_user_pub::entities::{AuthType, WorkspaceType};
@@ -415,3 +417,33 @@ async fn af_cloud_create_local_workspace_test() {
415417
"Server should only see 2 workspaces (the default and server workspace, not the local one)"
416418
);
417419
}
420+
421+
#[tokio::test]
422+
async fn af_cloud_open_089_anon_user_data_folder_test() {
423+
let user_db_path = unzip("./tests/asset", "089_local").unwrap();
424+
use_localhost_af_cloud().await;
425+
let test =
426+
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
427+
428+
// After 0.8.9, we store user workspace into user_workspace_table and refactor the Session serde struct
429+
// So, if everything is correct, we should be able to open the workspace and get the views
430+
let workspaces = test.get_all_workspaces().await.items;
431+
let views = test.get_all_views().await;
432+
dbg!(&views);
433+
assert!(views.iter().any(|view| view.name == "Anon 089 document"));
434+
assert_eq!(workspaces.len(), 1);
435+
}
436+
437+
#[tokio::test]
438+
async fn open_089_anon_user_data_folder_test() {
439+
use_local_mode().await;
440+
// Almost same as af_cloud_open_089_anon_user_data_folder_test but doesn't use af_cloud as the backend
441+
let user_db_path = unzip("./tests/asset", "089_local").unwrap();
442+
let test =
443+
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
444+
let workspaces = test.get_all_workspaces().await.items;
445+
let views = test.get_all_views().await;
446+
dbg!(&views);
447+
assert!(views.iter().any(|view| view.name == "Anon 089 document"));
448+
assert_eq!(workspaces.len(), 1);
449+
}

frontend/rust-lib/flowy-user/src/migrations/anon_user_workspace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use flowy_sqlite::kv::KVStorePreferences;
99
use flowy_user_pub::entities::{AuthType, WorkspaceType};
1010

1111
use crate::migrations::migration::UserDataMigration;
12-
use crate::migrations::session_migration::get_session_workspace;
12+
use crate::migrations::session_migration::get_v0_session_workspace;
1313
use flowy_user_pub::session::Session;
1414
use flowy_user_pub::sql::{select_user_workspace, upsert_user_workspace};
1515

@@ -43,7 +43,7 @@ impl UserDataMigration for AnonUserWorkspaceTableMigration {
4343
// For historical reason, anon user doesn't have a workspace in user_workspace_table.
4444
// So we need to create a new entry for the anon user in the user_workspace_table.
4545
if matches!(user_auth_type, AuthType::Local) {
46-
if let Some(mut user_workspace) = get_session_workspace(store_preferences) {
46+
if let Some(mut user_workspace) = get_v0_session_workspace(store_preferences) {
4747
if select_user_workspace(&user_workspace.id, db).ok().is_none() {
4848
user_workspace.workspace_type = WorkspaceType::Local;
4949
upsert_user_workspace(user.user_id, WorkspaceType::Local, user_workspace, db)?;

frontend/rust-lib/flowy-user/src/migrations/session_migration.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::user_manager::manager_history_user::ANON_USER;
12
use chrono::Utc;
23
use flowy_sqlite::kv::KVStorePreferences;
34
use flowy_user_pub::entities::{Role, UserWorkspace, WorkspaceType};
@@ -19,6 +20,15 @@ pub fn migrate_session(
1920
if !store_preferences.get_bool_or_default(MIGRATION_SESSION)
2021
&& store_preferences.set_bool(MIGRATION_SESSION, true).is_ok()
2122
{
23+
if let Some(anon_session) = store_preferences.get_object::<SessionBackup>(ANON_USER) {
24+
let new_anon_session = Session {
25+
user_id: anon_session.user_id,
26+
user_uuid: anon_session.user_uuid,
27+
workspace_id: anon_session.user_workspace.id,
28+
};
29+
let _ = store_preferences.set_object(ANON_USER, &new_anon_session);
30+
}
31+
2232
if let Some(session) = store_preferences.get_object::<SessionBackup>(session_cache_key) {
2333
let _ = store_preferences.set_object(SESSION_CACHE_KEY_BACKUP, &session);
2434
let new_session = Session {
@@ -29,7 +39,6 @@ pub fn migrate_session(
2939
let _ = store_preferences.set_object(session_cache_key, &new_session);
3040
}
3141
}
32-
3342
store_preferences.get_object::<Session>(session_cache_key)
3443
}
3544

@@ -39,7 +48,9 @@ struct SessionBackup {
3948
user_uuid: Uuid,
4049
user_workspace: UserWorkspace,
4150
}
42-
pub fn get_session_workspace(store_preferences: &Arc<KVStorePreferences>) -> Option<UserWorkspace> {
51+
pub fn get_v0_session_workspace(
52+
store_preferences: &Arc<KVStorePreferences>,
53+
) -> Option<UserWorkspace> {
4354
store_preferences
4455
.get_object::<SessionBackup>(SESSION_CACHE_KEY_BACKUP)
4556
.map(|v| v.user_workspace)

frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::migrations::session_migration::{get_session_workspace, migrate_session};
1+
use crate::migrations::session_migration::{get_v0_session_workspace, migrate_session};
22

33
use crate::services::data_import::importer::load_collab_by_object_ids;
44
use crate::services::db::UserDBPath;
@@ -108,7 +108,7 @@ pub(crate) fn prepare_import(
108108
{
109109
Ok(w) => w.database_storage_id,
110110
Err(_) => {
111-
let session_workspace = get_session_workspace(&other_store_preferences)
111+
let session_workspace = get_v0_session_workspace(&other_store_preferences)
112112
.ok_or(anyhow!("Can't find the session workspace"))?;
113113
session_workspace.workspace_database_id
114114
},

frontend/rust-lib/flowy-user/src/user_manager/manager.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,25 @@ impl UserManager {
151151
);
152152
let workspace_uuid = Uuid::parse_str(&session.workspace_id)?;
153153
let mut conn = self.db_connection(session.user_id)?;
154-
let workspace_type = select_user_workspace_type(&session.workspace_id, &mut conn)?;
154+
let workspace_type =
155+
select_user_workspace_type(&session.workspace_id, &mut conn).or_else(|err| {
156+
// Anonymous workspaces aren’t yet recorded in user_workspace_table,
157+
// so calling select_user_workspace_type(...) will Err for anon users.
158+
// As a temporary workaround, if we detect the current user is anonymous,
159+
// we force the workspace type to WorkspaceType::Local.
160+
// In the upcoming run_data_migration, we’ll insert proper anon‐user records
161+
// and can remove this special case.
162+
if self
163+
.get_anon_user_id()
164+
.ok()
165+
.filter(|&anon_id| anon_id == session.user_id)
166+
.is_some()
167+
{
168+
Ok(WorkspaceType::Local)
169+
} else {
170+
Err(err)
171+
}
172+
})?;
155173

156174
let uid = session.user_id;
157175
let auth_type = AuthType::from(workspace_type);

0 commit comments

Comments
 (0)