mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-02 10:10:16 +00:00
fix: import data (#6483)
* chore: import into space * chore: par insert * fix: migrate from anon * chore: fix test * chore: update test * chore: add test * chore: update test * chore: update test * chore: update docs * fix: space collab * chore: update test
This commit is contained in:
parent
1a82f3fff1
commit
fd9b01ca27
31
.github/workflows/flutter_ci.yaml
vendored
31
.github/workflows/flutter_ci.yaml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
os: [ ubuntu-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
@ -73,7 +73,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [windows-2019]
|
||||
os: [ windows-2019 ]
|
||||
include:
|
||||
- os: windows-2019
|
||||
flutter_profile: development-windows-x86
|
||||
@ -100,7 +100,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [macos-latest]
|
||||
os: [ macos-latest ]
|
||||
include:
|
||||
- os: macos-latest
|
||||
flutter_profile: development-mac-x86_64
|
||||
@ -122,12 +122,12 @@ jobs:
|
||||
flutter_profile: ${{ matrix.flutter_profile }}
|
||||
|
||||
unit_test:
|
||||
needs: [prepare-linux]
|
||||
needs: [ prepare-linux ]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
os: [ ubuntu-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
@ -216,11 +216,11 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
cloud_integration_test:
|
||||
needs: [prepare-linux]
|
||||
needs: [ prepare-linux ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
os: [ ubuntu-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
@ -241,12 +241,15 @@ jobs:
|
||||
cp deploy.env .env
|
||||
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
|
||||
sed -i 's/GOTRUE_EXTERNAL_GOOGLE_ENABLED=.*/GOTRUE_EXTERNAL_GOOGLE_ENABLED=true/' .env
|
||||
sed -i 's|GOTRUE_MAILER_AUTOCONFIRM=.*|GOTRUE_MAILER_AUTOCONFIRM=true|' .env
|
||||
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
|
||||
|
||||
- name: Run Docker-Compose
|
||||
working-directory: AppFlowy-Cloud
|
||||
env:
|
||||
APPFLOWY_CLOUD_VERSION: 0.6.4-amd64
|
||||
APPFLOWY_CLOUD_VERSION: 0.6.29-amd64
|
||||
APPFLOWY_HISTORY_VERSION: 0.6.29-amd64
|
||||
APPFLOWY_WORKER_VERSION: 0.6.29-amd64
|
||||
run: |
|
||||
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
|
||||
if [ -z "$container_id" ]; then
|
||||
@ -322,12 +325,12 @@ jobs:
|
||||
|
||||
# split the integration tests into different machines to minimize the time
|
||||
integration_test_1:
|
||||
needs: [prepare-linux]
|
||||
needs: [ prepare-linux ]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
os: [ ubuntu-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: "x86_64-unknown-linux-gnu"
|
||||
@ -352,12 +355,12 @@ jobs:
|
||||
rust_target: ${{ matrix.target }}
|
||||
|
||||
integration_test_2:
|
||||
needs: [prepare-linux]
|
||||
needs: [ prepare-linux ]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
os: [ ubuntu-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: "x86_64-unknown-linux-gnu"
|
||||
@ -382,12 +385,12 @@ jobs:
|
||||
rust_target: ${{ matrix.target }}
|
||||
|
||||
integration_test_3:
|
||||
needs: [prepare-linux]
|
||||
needs: [ prepare-linux ]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
os: [ ubuntu-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: "x86_64-unknown-linux-gnu"
|
||||
|
||||
5
.github/workflows/rust_ci.yaml
vendored
5
.github/workflows/rust_ci.yaml
vendored
@ -47,6 +47,8 @@ jobs:
|
||||
working-directory: AppFlowy-Cloud
|
||||
env:
|
||||
APPFLOWY_CLOUD_VERSION: 0.6.4-amd64
|
||||
APPFLOWY_HISTORY_VERSION: 0.6.29-amd64
|
||||
APPFLOWY_WORKER_VERSION: 0.6.29-amd64
|
||||
run: |
|
||||
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
|
||||
if [ -z "$container_id" ]; then
|
||||
@ -127,12 +129,15 @@ jobs:
|
||||
run: |
|
||||
cp deploy.env .env
|
||||
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
|
||||
sed -i 's|GOTRUE_MAILER_AUTOCONFIRM=.*|GOTRUE_MAILER_AUTOCONFIRM=true|' .env
|
||||
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
|
||||
|
||||
- name: Ensure AppFlowy-Cloud is Running with Correct Version
|
||||
working-directory: AppFlowy-Cloud
|
||||
env:
|
||||
APPFLOWY_CLOUD_VERSION: 0.6.4-amd64
|
||||
APPFLOWY_HISTORY_VERSION: 0.6.29-amd64
|
||||
APPFLOWY_WORKER_VERSION: 0.6.29-amd64
|
||||
run: |
|
||||
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
|
||||
if [ -z "$container_id" ]; then
|
||||
|
||||
@ -3,8 +3,10 @@ import 'sidebar/sidebar_move_page_test.dart' as sidebar_move_page_test;
|
||||
import 'uncategorized/uncategorized_test_runner.dart'
|
||||
as uncategorized_test_runner;
|
||||
import 'workspace/workspace_test_runner.dart' as workspace_test_runner;
|
||||
import 'data_migration/data_migration_test_runner.dart' as data_migration_test_runner;
|
||||
|
||||
Future<void> main() async {
|
||||
data_migration_test_runner.main();
|
||||
// uncategorized
|
||||
uncategorized_test_runner.main();
|
||||
|
||||
@ -16,4 +18,5 @@ Future<void> main() async {
|
||||
|
||||
// sidebar
|
||||
sidebar_move_page_test.main();
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('appflowy cloud', () {
|
||||
testWidgets('anon user and then sign in', (tester) async {
|
||||
testWidgets('anon user -> sign in -> open imported space', (tester) async {
|
||||
await tester.initializeAppFlowy(
|
||||
cloudType: AuthenticatorType.appflowyCloudSelfHost,
|
||||
);
|
||||
@ -42,6 +42,10 @@ void main() {
|
||||
await tester.tapAnonymousSignInButton();
|
||||
await tester.expectToSeeHomePageWithGetStartedPage();
|
||||
|
||||
const pageName = 'Test Document';
|
||||
await tester.createNewPageWithNameUnderParent(name: pageName);
|
||||
tester.expectToSeePageName(pageName);
|
||||
|
||||
// rename the name of the anon user
|
||||
await tester.openSettings();
|
||||
await tester.openSettingsPage(SettingsPage.account);
|
||||
@ -60,20 +64,16 @@ void main() {
|
||||
|
||||
// sign up with Google
|
||||
await tester.tapGoogleLoginInButton();
|
||||
// await tester.pumpAndSettle(const Duration(seconds: 16));
|
||||
|
||||
// sign out
|
||||
// open the imported space
|
||||
await tester.expectToSeeHomePage();
|
||||
await tester.openSettings();
|
||||
await tester.openSettingsPage(SettingsPage.account);
|
||||
await tester.clickSpaceHeader();
|
||||
|
||||
// Scroll to sign-out
|
||||
await tester.scrollUntilVisible(
|
||||
find.byType(AccountSignInOutButton),
|
||||
100,
|
||||
scrollable: find.findSettingsScrollable(),
|
||||
);
|
||||
// After import the anon user data, we will create a new space for it
|
||||
await tester.openSpace("Getting started");
|
||||
await tester.openPage(pageName);
|
||||
|
||||
await tester.logout();
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
import 'anon_user_data_migration_test.dart' as anon_user_test;
|
||||
|
||||
void main() async {
|
||||
anon_user_test.main();
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
import 'anon_user_continue_test.dart' as anon_user_continue_test;
|
||||
import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
|
||||
import 'empty_test.dart' as preset_af_cloud_env_test;
|
||||
import 'user_setting_sync_test.dart' as user_sync_test;
|
||||
@ -7,5 +6,4 @@ void main() async {
|
||||
preset_af_cloud_env_test.main();
|
||||
appflowy_cloud_auth_test.main();
|
||||
user_sync_test.main();
|
||||
anon_user_continue_test.main();
|
||||
}
|
||||
|
||||
@ -10,9 +10,10 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'util.dart';
|
||||
|
||||
extension AppFlowyAuthTest on WidgetTester {
|
||||
Future<void> tapGoogleLoginInButton() async {
|
||||
Future<void> tapGoogleLoginInButton({bool pumpAndSettle = true}) async {
|
||||
await tapButton(
|
||||
find.byKey(signInWithGoogleButtonKey),
|
||||
pumpAndSettle: pumpAndSettle,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -174,7 +174,7 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
await this.pumpAndSettle(
|
||||
Duration(milliseconds: milliseconds),
|
||||
EnginePhase.sendSemanticsUpdate,
|
||||
const Duration(seconds: 5),
|
||||
const Duration(seconds: 15),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -411,6 +412,19 @@ extension CommonOperations on WidgetTester {
|
||||
await tapButton(addPageButton);
|
||||
}
|
||||
|
||||
/// Click the + button in the space header
|
||||
Future<void> clickSpaceHeader() async {
|
||||
await tapButton(find.byType(SidebarSpaceHeader));
|
||||
}
|
||||
|
||||
Future<void> openSpace(String spaceName) async {
|
||||
final space = find.descendant(
|
||||
of: find.byType(SidebarSpaceMenuItem),
|
||||
matching: find.text(spaceName),
|
||||
);
|
||||
await tapButton(space);
|
||||
}
|
||||
|
||||
/// Create a new page on the top level
|
||||
Future<void> createNewPage({
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import 'package:appflowy/core/config/kv.dart';
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:appflowy/plugins/database/application/defines.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
@ -19,9 +22,17 @@ class SettingFileImportBloc
|
||||
importAppFlowyDataFolder: (String path) async {
|
||||
final formattedDate =
|
||||
DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
|
||||
final spaceId =
|
||||
await getIt<KeyValueStorage>().get(KVKeys.lastOpenedSpaceId);
|
||||
|
||||
final payload = ImportAppFlowyDataPB.create()
|
||||
..path = path
|
||||
..importContainerName = "appflowy_import_$formattedDate";
|
||||
..importContainerName = "import_$formattedDate";
|
||||
|
||||
if (spaceId != null) {
|
||||
payload.parentViewId = spaceId;
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(loadingState: const LoadingState.loading()),
|
||||
);
|
||||
|
||||
@ -31,7 +31,7 @@ class SidebarSpaceMenu extends StatelessWidget {
|
||||
for (final space in state.spaces)
|
||||
SizedBox(
|
||||
height: HomeSpaceViewSizes.viewHeight,
|
||||
child: _SidebarSpaceMenuItem(
|
||||
child: SidebarSpaceMenuItem(
|
||||
space: space,
|
||||
isSelected: state.currentSpace?.id == space.id,
|
||||
),
|
||||
@ -53,8 +53,9 @@ class SidebarSpaceMenu extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _SidebarSpaceMenuItem extends StatelessWidget {
|
||||
const _SidebarSpaceMenuItem({
|
||||
class SidebarSpaceMenuItem extends StatelessWidget {
|
||||
const SidebarSpaceMenuItem({
|
||||
super.key,
|
||||
required this.space,
|
||||
required this.isSelected,
|
||||
});
|
||||
|
||||
@ -1535,10 +1535,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.5"
|
||||
version: "3.1.4"
|
||||
plugin_platform_interface:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -1933,10 +1933,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.2.0"
|
||||
string_validator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -2238,10 +2238,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "14.2.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -121,23 +121,23 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
<<<<<<< Updated upstream
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
= = = = = = =
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
|
||||
|
||||
17
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
17
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
@ -986,7 +986,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1011,7 +1011,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1050,7 +1050,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1071,7 +1071,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1091,7 +1091,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1113,7 +1113,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@ -1168,7 +1168,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1248,7 +1248,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -2738,6 +2738,7 @@ dependencies = [
|
||||
"lib-infra",
|
||||
"once_cell",
|
||||
"protobuf",
|
||||
"rayon",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@ -118,14 +118,14 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
|
||||
|
||||
# Working directory: frontend
|
||||
|
||||
17
frontend/rust-lib/Cargo.lock
generated
17
frontend/rust-lib/Cargo.lock
generated
@ -849,7 +849,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -874,7 +874,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -913,7 +913,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -934,7 +934,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -954,7 +954,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -976,7 +976,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@ -1031,7 +1031,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1111,7 +1111,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d7dc26a906e3ce5d72a309e933f853f1e75da1cb#d7dc26a906e3ce5d72a309e933f853f1e75da1cb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d73579b0269b33856690c4b4d68bf22b4eb17a99#d73579b0269b33856690c4b4d68bf22b4eb17a99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -2538,6 +2538,7 @@ dependencies = [
|
||||
"quickcheck_macros",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"rayon",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@ -142,14 +142,14 @@ rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d7dc26a906e3ce5d72a309e933f853f1e75da1cb" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d73579b0269b33856690c4b4d68bf22b4eb17a99" }
|
||||
|
||||
# Working directory: frontend
|
||||
# To update the commit ID, run:
|
||||
|
||||
@ -77,7 +77,7 @@ impl EventIntegrationTest {
|
||||
let path = path_buf.to_str().unwrap().to_string();
|
||||
let device_id = uuid::Uuid::new_v4().to_string();
|
||||
let config = AppFlowyCoreConfig::new(
|
||||
Version::new(0, 5, 8),
|
||||
Version::new(0, 7, 0),
|
||||
path.clone(),
|
||||
path,
|
||||
device_id,
|
||||
|
||||
@ -175,6 +175,7 @@ impl EventIntegrationTest {
|
||||
let payload = ImportAppFlowyDataPB {
|
||||
path,
|
||||
import_container_name: name,
|
||||
parent_view_id: None,
|
||||
};
|
||||
match EventBuilder::new(self.clone())
|
||||
.event(UserEvent::ImportAppFlowyDataFolder)
|
||||
@ -431,7 +432,7 @@ pub struct SignUpContext {
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
pub async fn user_localhost_af_cloud() {
|
||||
pub async fn use_localhost_af_cloud() {
|
||||
AuthenticatorType::AppFlowyCloud.write_env();
|
||||
let base_url =
|
||||
std::env::var("af_cloud_test_base_url").unwrap_or("http://localhost:8000".to_string());
|
||||
@ -454,5 +455,5 @@ pub async fn user_localhost_af_cloud_with_nginx() {
|
||||
std::env::set_var("af_cloud_test_base_url", "http://localhost");
|
||||
std::env::set_var("af_cloud_test_ws_url", "ws://localhost/ws/v1");
|
||||
std::env::set_var("af_cloud_test_gotrue_url", "http://localhost/gotrue");
|
||||
user_localhost_af_cloud().await
|
||||
use_localhost_af_cloud().await
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_ai::entities::CompletionTypePB;
|
||||
|
||||
@ -6,7 +6,7 @@ use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_complete_text_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.af_cloud_sign_up().await;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::util::receive_with_timeout;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_ai::entities::ChatMessageListPB;
|
||||
use flowy_ai::notification::ChatNotification;
|
||||
@ -10,7 +10,7 @@ use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_create_chat_message_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.af_cloud_sign_up().await;
|
||||
|
||||
@ -65,7 +65,7 @@ async fn af_cloud_create_chat_message_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_load_remote_system_message_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.af_cloud_sign_up().await;
|
||||
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
use crate::util::{receive_with_timeout, unzip};
|
||||
use collab_document::blocks::DocumentData;
|
||||
use serde_json::json;
|
||||
use std::time::Duration;
|
||||
|
||||
use collab_folder::SpaceInfo;
|
||||
use event_integration_test::document_event::assert_document_data_equal;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_document::entities::{DocumentSyncState, DocumentSyncStatePB};
|
||||
|
||||
use crate::util::{receive_with_timeout, unzip};
|
||||
use serde_json::json;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_edit_document_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.af_cloud_sign_up().await;
|
||||
test.wait_ws_connected().await;
|
||||
@ -44,7 +43,7 @@ async fn af_cloud_edit_document_test() {
|
||||
#[tokio::test]
|
||||
async fn af_cloud_sync_anon_user_document_test() {
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "040_sync_local_document").unwrap();
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
|
||||
.await;
|
||||
@ -56,6 +55,11 @@ async fn af_cloud_sync_anon_user_document_test() {
|
||||
// view: SyncDocument
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
for view in views.iter() {
|
||||
let space_info = serde_json::from_str::<SpaceInfo>(view.extra.as_ref().unwrap()).unwrap();
|
||||
assert!(space_info.is_space);
|
||||
}
|
||||
|
||||
let document_id = views[2].id.clone();
|
||||
test.open_document(document_id.clone()).await;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::document::generate_random_bytes;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_storage_pub::storage::FileUploadState;
|
||||
use lib_infra::util::md5;
|
||||
@ -14,7 +14,7 @@ use tokio::time::timeout;
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_upload_big_file_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let mut test = EventIntegrationTest::new().await;
|
||||
test.af_cloud_sign_up().await;
|
||||
tokio::time::sleep(Duration::from_secs(6)).await;
|
||||
@ -78,7 +78,7 @@ async fn af_cloud_upload_big_file_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_upload_6_files_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.af_cloud_sign_up().await;
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_user::entities::AuthenticatorPB;
|
||||
@ -49,7 +49,7 @@ async fn migrate_anon_user_data_to_af_cloud_test() {
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
|
||||
.await;
|
||||
@ -103,7 +103,6 @@ async fn migrate_anon_user_data_to_af_cloud_test() {
|
||||
);
|
||||
|
||||
// check second level
|
||||
assert_eq!(anon_second_level_views.len(), user_second_level_views.len());
|
||||
assert_ne!(anon_second_level_views[0].id, user_second_level_views[0].id);
|
||||
assert_eq!(
|
||||
anon_second_level_views[0].name,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_user::entities::UpdateUserProfilePayloadPB;
|
||||
|
||||
@ -7,7 +7,7 @@ use crate::util::generate_test_email;
|
||||
#[tokio::test]
|
||||
async fn af_cloud_sign_up_test() {
|
||||
// user_localhost_af_cloud_with_nginx().await;
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let email = generate_test_email();
|
||||
let user = test.af_cloud_sign_in_with_email(&email).await.unwrap();
|
||||
@ -16,7 +16,7 @@ async fn af_cloud_sign_up_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_update_user_metadata() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let user = test.af_cloud_sign_up().await;
|
||||
|
||||
|
||||
@ -1,70 +1,40 @@
|
||||
use crate::util::unzip;
|
||||
use assert_json_diff::assert_json_include;
|
||||
use collab_database::rows::database_row_document_id_from_row_id;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_user::errors::ErrorCode;
|
||||
use serde_json::{json, Value};
|
||||
use std::env::temp_dir;
|
||||
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_need_migration_test() {
|
||||
// In 037, the workspace array will be migrated to view.
|
||||
let import_container_name = "037_local".to_string();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
// Getting started
|
||||
// Document1
|
||||
// Document2(fav)
|
||||
user_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
test
|
||||
.import_appflowy_data(
|
||||
user_db_path.to_str().unwrap().to_string(),
|
||||
Some(import_container_name.clone()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// after import, the structure is:
|
||||
// workspace:
|
||||
// view: Generate
|
||||
// view: Shared
|
||||
// view: 037_local
|
||||
// view: Getting Started
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
assert_eq!(views[2].name, import_container_name);
|
||||
|
||||
let child_views = test.get_view(&views[2].id).await.child_views;
|
||||
assert_eq!(child_views.len(), 1);
|
||||
|
||||
let child_views = test.get_view(&child_views[0].id).await.child_views;
|
||||
assert_eq!(child_views.len(), 2);
|
||||
assert_eq!(child_views[0].name, "Document1");
|
||||
assert_eq!(child_views[1].name, "Document2");
|
||||
drop(cleaner);
|
||||
}
|
||||
|
||||
#[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("./tests/asset", &import_container_name).unwrap();
|
||||
// In the 040_local, the structure is:
|
||||
// workspace:
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
user_localhost_af_cloud().await;
|
||||
// Document1
|
||||
// Document2
|
||||
// Grid1
|
||||
// Grid2
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views[0].name, "General");
|
||||
assert_eq!(views[1].name, "Shared");
|
||||
assert_eq!(views.len(), 2);
|
||||
let shared_space_id = views[1].id.clone();
|
||||
let shared_space = test.get_view(&shared_space_id).await;
|
||||
|
||||
// by default, shared space is empty
|
||||
assert!(shared_space.child_views.is_empty());
|
||||
// after sign up, the initial workspace is created, so the structure is:
|
||||
// workspace:
|
||||
// view: Getting Started
|
||||
// General
|
||||
// template_document
|
||||
// template_document
|
||||
// Shared
|
||||
|
||||
test
|
||||
.import_appflowy_data(
|
||||
@ -75,24 +45,26 @@ async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
.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(), 3);
|
||||
assert_eq!(views[2].name, import_container_name);
|
||||
// General
|
||||
// template_document
|
||||
// template_document
|
||||
// 040_local
|
||||
// Shared
|
||||
let general_space = test.get_view(&shared_space_id).await;
|
||||
let shared_sub_views = &general_space.child_views;
|
||||
assert_eq!(shared_sub_views.len(), 1);
|
||||
assert_eq!(shared_sub_views[0].name, import_container_name);
|
||||
|
||||
// the 040_local should be an empty document, so try to get the document data
|
||||
let _ = test.get_document_data(&views[2].id).await;
|
||||
let _ = test.get_document_data(&shared_sub_views[0].id).await;
|
||||
|
||||
let local_child_views = test.get_view(&views[2].id).await.child_views;
|
||||
assert_eq!(local_child_views.len(), 1);
|
||||
assert_eq!(local_child_views[0].name, "Document1");
|
||||
let t_040_local_child_views = test.get_view(&shared_sub_views[0].id).await.child_views;
|
||||
assert_eq!(t_040_local_child_views[0].name, "Document1");
|
||||
|
||||
let document1_child_views = test.get_view(&local_child_views[0].id).await.child_views;
|
||||
let document1_child_views = test
|
||||
.get_view(&t_040_local_child_views[0].id)
|
||||
.await
|
||||
.child_views;
|
||||
assert_eq!(document1_child_views.len(), 1);
|
||||
assert_eq!(document1_child_views[0].name, "Document2");
|
||||
|
||||
@ -122,12 +94,11 @@ async fn import_appflowy_data_folder_into_current_workspace_test() {
|
||||
let import_container_name = "040_local".to_string();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
// In the 040_local, the structure is:
|
||||
// workspace:
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
user_localhost_af_cloud().await;
|
||||
// Document1
|
||||
// Document2
|
||||
// Grid1
|
||||
// Grid2
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
// after sign up, the initial workspace is created, so the structure is:
|
||||
@ -138,20 +109,25 @@ async fn import_appflowy_data_folder_into_current_workspace_test() {
|
||||
.import_appflowy_data(user_db_path.to_str().unwrap().to_string(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views[0].name, "General");
|
||||
assert_eq!(views[1].name, "Shared");
|
||||
assert_eq!(views.len(), 2);
|
||||
let shared_space_id = views[1].id.clone();
|
||||
let shared_space_child_views = test.get_view(&shared_space_id).await.child_views;
|
||||
assert_eq!(shared_space_child_views.len(), 1);
|
||||
|
||||
// after import, the structure is:
|
||||
// workspace:
|
||||
// view: General
|
||||
// view: Shared
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
assert_eq!(views[2].name, "Document1");
|
||||
|
||||
let document_1_child_views = test.get_view(&views[2].id).await.child_views;
|
||||
assert_eq!(document_1_child_views.len(), 1);
|
||||
// General
|
||||
// Shared
|
||||
// Document1
|
||||
// Document2
|
||||
// Grid1
|
||||
// Grid2
|
||||
let document_1 = test.get_view(&shared_space_child_views[0].id).await;
|
||||
assert_eq!(document_1.name, "Document1");
|
||||
let document_1_child_views = test.get_view(&document_1.id).await.child_views;
|
||||
assert_eq!(document_1_child_views[0].name, "Document2");
|
||||
|
||||
let document2_child_views = test
|
||||
@ -165,33 +141,10 @@ async fn import_appflowy_data_folder_into_current_workspace_test() {
|
||||
drop(cleaner);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_into_new_view_test2() {
|
||||
let import_container_name = "040_local_2".to_string();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
user_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
test
|
||||
.import_appflowy_data(
|
||||
user_db_path.to_str().unwrap().to_string(),
|
||||
Some(import_container_name.clone()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
assert_eq!(views[2].name, import_container_name);
|
||||
assert_040_local_2_import_content(&test, &views[2].id).await;
|
||||
|
||||
drop(cleaner);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn import_empty_appflowy_data_folder_test() {
|
||||
let path = temp_dir();
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
let error = test
|
||||
@ -217,9 +170,18 @@ async fn import_appflowy_data_folder_multiple_times_test() {
|
||||
// Doc3_grid_1
|
||||
// Doc3_grid_2
|
||||
// Doc3_calendar_1
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views[0].name, "General");
|
||||
assert_eq!(views[1].name, "Shared");
|
||||
assert_eq!(views.len(), 2);
|
||||
let shared_space_id = views[1].id.clone();
|
||||
let shared_space = test.get_view(&shared_space_id).await;
|
||||
// by default, shared space is empty
|
||||
assert!(shared_space.child_views.is_empty());
|
||||
|
||||
test
|
||||
.import_appflowy_data(
|
||||
user_db_path.to_str().unwrap().to_string(),
|
||||
@ -230,12 +192,22 @@ async fn import_appflowy_data_folder_multiple_times_test() {
|
||||
// after import, the structure is:
|
||||
// General
|
||||
// Shared
|
||||
// 040_local_2
|
||||
// 040_local_2
|
||||
// Getting Started
|
||||
// Doc1
|
||||
// Doc2
|
||||
// Grid1
|
||||
// Doc3
|
||||
// Doc3_grid_1
|
||||
// Doc3_grid_2
|
||||
// Doc3_calendar_1
|
||||
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
assert_eq!(views[2].name, import_container_name);
|
||||
assert_040_local_2_import_content(&test, &views[2].id).await;
|
||||
let shared_space_children_views = test.get_view(&shared_space_id).await.child_views;
|
||||
assert_eq!(shared_space_children_views.len(), 1);
|
||||
let _040_local_view_id = shared_space_children_views[0].id.clone();
|
||||
let _040_local_view = test.get_view(&_040_local_view_id).await;
|
||||
assert_eq!(_040_local_view.name, import_container_name);
|
||||
assert_040_local_2_import_content(&test, &_040_local_view_id).await;
|
||||
|
||||
test
|
||||
.import_appflowy_data(
|
||||
@ -247,15 +219,13 @@ async fn import_appflowy_data_folder_multiple_times_test() {
|
||||
// after import, the structure is:
|
||||
// Generate
|
||||
// Shared
|
||||
// 040_local_2
|
||||
// Getting started
|
||||
// 040_local_2
|
||||
// Getting started
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 4);
|
||||
assert_eq!(views[3].name, import_container_name);
|
||||
assert_040_local_2_import_content(&test, &views[2].id).await;
|
||||
assert_040_local_2_import_content(&test, &views[3].id).await;
|
||||
// 040_local_2
|
||||
// 040_local_2
|
||||
let shared_space_children_views = test.get_view(&shared_space_id).await.child_views;
|
||||
assert_eq!(shared_space_children_views.len(), 2);
|
||||
for view in shared_space_children_views {
|
||||
assert_040_local_2_import_content(&test, &view.id).await;
|
||||
}
|
||||
drop(cleaner);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::user::af_cloud_test::util::get_synced_workspaces;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
|
||||
#[tokio::test]
|
||||
@ -35,7 +35,7 @@ async fn af_cloud_invite_workspace_member() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_add_workspace_member_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test_1 = EventIntegrationTest::new().await;
|
||||
let user_1 = test_1.af_cloud_sign_up().await;
|
||||
let workspace_id_1 = test_1.get_current_workspace().await.id;
|
||||
@ -57,7 +57,7 @@ async fn af_cloud_add_workspace_member_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_delete_workspace_member_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test_1 = EventIntegrationTest::new().await;
|
||||
let user_1 = test_1.af_cloud_sign_up().await;
|
||||
let workspace_id_1 = test_1.get_current_workspace().await.id;
|
||||
@ -78,7 +78,7 @@ async fn af_cloud_delete_workspace_member_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_leave_workspace_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test_1 = EventIntegrationTest::new().await;
|
||||
test_1.af_cloud_sign_up().await;
|
||||
let workspace_id_1 = test_1.get_current_workspace().await.id;
|
||||
|
||||
@ -2,7 +2,7 @@ use collab::core::collab::DataSource::DocStateV1;
|
||||
use collab::core::origin::CollabOrigin;
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::Folder;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use std::time::Duration;
|
||||
use tokio::task::LocalSet;
|
||||
@ -12,7 +12,7 @@ use crate::user::af_cloud_test::util::get_synced_workspaces;
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_workspace_delete() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let user_profile_pb = test.af_cloud_sign_up().await;
|
||||
let workspaces = get_synced_workspaces(&test, user_profile_pb.id).await;
|
||||
@ -33,7 +33,7 @@ async fn af_cloud_workspace_delete() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_workspace_change_name_and_icon() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let user_profile_pb = test.af_cloud_sign_up().await;
|
||||
let workspaces = test.get_all_workspaces().await;
|
||||
@ -58,7 +58,7 @@ async fn af_cloud_workspace_change_name_and_icon() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_create_workspace_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let user_profile_pb = test.af_cloud_sign_up().await;
|
||||
|
||||
@ -98,7 +98,7 @@ async fn af_cloud_create_workspace_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_open_workspace_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
let default_document_name = "General";
|
||||
@ -160,7 +160,7 @@ async fn af_cloud_open_workspace_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_different_open_same_workspace_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
|
||||
// Set up the primary client and sign them up to the cloud.
|
||||
let test_runner = EventIntegrationTest::new().await;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::util::unzip;
|
||||
use event_integration_test::user_event::user_localhost_af_cloud;
|
||||
use event_integration_test::user_event::use_localhost_af_cloud;
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use std::time::Duration;
|
||||
@ -11,7 +11,7 @@ async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
let (imported_af_folder_cleaner, imported_af_data_path) =
|
||||
unzip("./tests/asset", &import_container_name).unwrap();
|
||||
|
||||
user_localhost_af_cloud().await;
|
||||
use_localhost_af_cloud().await;
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
|
||||
.await;
|
||||
@ -34,15 +34,22 @@ async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
|
||||
// after import, the structure is:
|
||||
// workspace:
|
||||
// view: Getting Started
|
||||
// view: 040_local
|
||||
// view: Document1
|
||||
// view: Document2
|
||||
// view: Grid1
|
||||
// view: Grid2
|
||||
// Document1
|
||||
// Document2
|
||||
// Grid1
|
||||
// Grid2
|
||||
// 040_local
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 2);
|
||||
assert_eq!(views[1].name, import_container_name);
|
||||
assert_eq!(views.len(), 1);
|
||||
assert_eq!(views[0].name, "Document1");
|
||||
assert_eq!(views[0].child_views.len(), 2);
|
||||
|
||||
for (index, view) in views[0].child_views.iter().enumerate() {
|
||||
let view = test.get_view(&view.id).await;
|
||||
if index == 1 {
|
||||
assert_eq!(view.name, import_container_name);
|
||||
}
|
||||
}
|
||||
|
||||
drop(cleaner);
|
||||
drop(imported_af_folder_cleaner);
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
|
||||
use crate::util::unzip;
|
||||
|
||||
#[tokio::test]
|
||||
async fn collab_db_restore_test() {
|
||||
let (cleaner, user_db_path) = unzip(
|
||||
"./tests/user/migration_test/history_user_db",
|
||||
"038_collab_db_corrupt_restore",
|
||||
)
|
||||
.unwrap();
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
|
||||
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 1);
|
||||
|
||||
drop(cleaner);
|
||||
}
|
||||
@ -1,4 +1,2 @@
|
||||
mod document_test;
|
||||
mod version_test;
|
||||
|
||||
mod collab_db_restore;
|
||||
|
||||
@ -138,7 +138,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
||||
let json_str = include_str!("../../assets/read_me.json");
|
||||
let document_pb = JsonToDocumentParser::json_str_to_document(json_str).unwrap();
|
||||
manager
|
||||
.create_document(uid, &view.parent_view.id, Some(document_pb.into()))
|
||||
.create_document(uid, &view.view.id, Some(document_pb.into()))
|
||||
.await
|
||||
.unwrap();
|
||||
view
|
||||
@ -355,6 +355,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
||||
|
||||
let database_row_encoded_collabs =
|
||||
load_collab_by_object_ids(uid, &collab_read_txn, &row_oids)
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(oid, collab)| {
|
||||
collab
|
||||
@ -380,6 +381,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
||||
|
||||
let database_row_document_encoded_collabs =
|
||||
load_collab_by_object_ids(uid, &collab_read_txn, &row_document_ids)
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(oid, collab)| {
|
||||
collab
|
||||
|
||||
@ -4,6 +4,7 @@ use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_folder::manager::FolderManager;
|
||||
use flowy_folder_pub::entities::ImportFrom;
|
||||
use flowy_sqlite::kv::KVStorePreferences;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use flowy_user::user_manager::UserManager;
|
||||
@ -45,12 +46,31 @@ pub struct UserWorkspaceServiceImpl {
|
||||
|
||||
#[async_trait]
|
||||
impl UserWorkspaceService for UserWorkspaceServiceImpl {
|
||||
async fn did_import_views(&self, views: Vec<ParentChildViews>) -> FlowyResult<()> {
|
||||
self.folder_manager.insert_parent_child_views(views).await?;
|
||||
async fn import_views(
|
||||
&self,
|
||||
source: &ImportFrom,
|
||||
views: Vec<ParentChildViews>,
|
||||
orphan_views: Vec<ParentChildViews>,
|
||||
parent_view_id: Option<String>,
|
||||
) -> FlowyResult<()> {
|
||||
match source {
|
||||
ImportFrom::AnonUser => {
|
||||
self
|
||||
.folder_manager
|
||||
.insert_views_as_spaces(views, orphan_views)
|
||||
.await?;
|
||||
},
|
||||
ImportFrom::AppFlowyDataFolder => {
|
||||
self
|
||||
.folder_manager
|
||||
.insert_views_with_parent(views, orphan_views, parent_view_id)
|
||||
.await?;
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn did_import_database_views(
|
||||
async fn import_database_views(
|
||||
&self,
|
||||
ids_by_database_id: HashMap<String, Vec<String>>,
|
||||
) -> FlowyResult<()> {
|
||||
|
||||
@ -322,12 +322,10 @@ impl DatabaseViewEditor {
|
||||
} else {
|
||||
(None, None, vec![])
|
||||
}
|
||||
} else if let Ok(result) = controller.did_delete_row(row) {
|
||||
(None, result.deleted_group, result.row_changesets)
|
||||
} else {
|
||||
if let Ok(result) = controller.did_delete_row(&row) {
|
||||
(None, result.deleted_group, result.row_changesets)
|
||||
} else {
|
||||
(None, None, vec![])
|
||||
}
|
||||
(None, None, vec![])
|
||||
};
|
||||
|
||||
if let Some(inserted_group) = inserted_group {
|
||||
|
||||
@ -18,7 +18,7 @@ impl DateFilterPB {
|
||||
let timestamp = if self.condition.is_filter_on_start_timestamp() {
|
||||
cell_data.timestamp
|
||||
} else {
|
||||
cell_data.end_timestamp.or_else(|| cell_data.timestamp)
|
||||
cell_data.end_timestamp.or(cell_data.timestamp)
|
||||
};
|
||||
|
||||
Some(strategy.filter(timestamp))
|
||||
|
||||
@ -17,8 +17,8 @@ use collab_entity::CollabType;
|
||||
use collab_plugins::CollabKVDB;
|
||||
use dashmap::DashMap;
|
||||
use lib_infra::util::timestamp;
|
||||
use tracing::trace;
|
||||
use tracing::{event, instrument};
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::document::{
|
||||
subscribe_document_changed, subscribe_document_snapshot_state, subscribe_document_sync_state,
|
||||
@ -214,6 +214,10 @@ impl DocumentManager {
|
||||
// If the document does not exist in local disk, try get the doc state from the cloud. This happens
|
||||
// When user_device_a create a document and user_device_b open the document.
|
||||
if !self.is_doc_exist(doc_id).await? {
|
||||
info!(
|
||||
"document {} not found in local disk, try to get the doc state from the cloud",
|
||||
doc_id
|
||||
);
|
||||
doc_state = DataSource::DocStateV1(
|
||||
self
|
||||
.cloud_service
|
||||
|
||||
@ -3,21 +3,28 @@ use collab_folder::{ViewIcon, ViewLayout};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub enum ImportData {
|
||||
AppFlowyDataFolder { items: Vec<AppFlowyData> },
|
||||
pub struct ImportedAppFlowyData {
|
||||
pub source: ImportFrom,
|
||||
pub folder_data: ImportedFolderData,
|
||||
pub collab_data: ImportedCollabData,
|
||||
pub parent_view_id: Option<String>,
|
||||
}
|
||||
|
||||
pub enum AppFlowyData {
|
||||
Folder {
|
||||
views: Vec<ParentChildViews>,
|
||||
/// Used to update the [DatabaseViewTrackerList] when importing the database.
|
||||
database_view_ids_by_database_id: HashMap<String, Vec<String>>,
|
||||
},
|
||||
CollabObject {
|
||||
row_object_ids: Vec<String>,
|
||||
document_object_ids: Vec<String>,
|
||||
database_object_ids: Vec<String>,
|
||||
},
|
||||
pub enum ImportFrom {
|
||||
AnonUser,
|
||||
AppFlowyDataFolder,
|
||||
}
|
||||
|
||||
pub struct ImportedFolderData {
|
||||
pub views: Vec<ParentChildViews>,
|
||||
pub orphan_views: Vec<ParentChildViews>,
|
||||
/// Used to update the [DatabaseViewTrackerList] when importing the database.
|
||||
pub database_view_ids_by_database_id: HashMap<String, Vec<String>>,
|
||||
}
|
||||
pub struct ImportedCollabData {
|
||||
pub row_object_ids: Vec<String>,
|
||||
pub document_object_ids: Vec<String>,
|
||||
pub database_object_ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct ImportViews {
|
||||
|
||||
@ -14,9 +14,7 @@ use crate::notification::{
|
||||
};
|
||||
use crate::publish_util::{generate_publish_name, view_pb_to_publish_view};
|
||||
use crate::share::{ImportParams, ImportValue};
|
||||
use crate::util::{
|
||||
folder_not_init_error, insert_parent_child_views, workspace_data_not_sync_error,
|
||||
};
|
||||
use crate::util::{folder_not_init_error, workspace_data_not_sync_error};
|
||||
use crate::view_operation::{
|
||||
create_view, EncodedCollabWrapper, FolderOperationHandler, FolderOperationHandlers,
|
||||
};
|
||||
@ -24,7 +22,7 @@ use arc_swap::ArcSwapOption;
|
||||
use collab::core::collab::DataSource;
|
||||
use collab::lock::RwLock;
|
||||
use collab_entity::{CollabType, EncodedCollab};
|
||||
use collab_folder::hierarchy_builder::ParentChildViews;
|
||||
use collab_folder::hierarchy_builder::{ParentChildViews, SpacePermission, ViewExtraBuilder};
|
||||
use collab_folder::{
|
||||
Folder, FolderData, FolderNotify, Section, SectionItem, TrashInfo, View, ViewLayout, ViewUpdate,
|
||||
Workspace,
|
||||
@ -346,20 +344,99 @@ impl FolderManager {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn insert_parent_child_views(
|
||||
/// All the views will become a space under the workspace.
|
||||
pub async fn insert_views_as_spaces(
|
||||
&self,
|
||||
views: Vec<ParentChildViews>,
|
||||
mut views: Vec<ParentChildViews>,
|
||||
orphan_views: Vec<ParentChildViews>,
|
||||
) -> Result<(), FlowyError> {
|
||||
match self.mutex_folder.load_full() {
|
||||
None => Err(FlowyError::internal().with_context("The folder is not initialized")),
|
||||
Some(lock) => {
|
||||
let mut folder = lock.write().await;
|
||||
for view in views {
|
||||
insert_parent_child_views(&mut folder, view);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
let lock = self
|
||||
.mutex_folder
|
||||
.load_full()
|
||||
.ok_or_else(|| FlowyError::internal().with_context("The folder is not initialized"))?;
|
||||
let mut folder = lock.write().await;
|
||||
let workspace_id = folder
|
||||
.get_workspace_id()
|
||||
.ok_or_else(|| FlowyError::internal().with_context("Cannot find the workspace ID"))?;
|
||||
|
||||
views.iter_mut().for_each(|view| {
|
||||
view.view.parent_view_id = workspace_id.clone();
|
||||
view.view.extra = Some(
|
||||
serde_json::to_string(
|
||||
&ViewExtraBuilder::new()
|
||||
.is_space(true, SpacePermission::PublicToAll)
|
||||
.build(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
});
|
||||
let all_views = views.into_iter().chain(orphan_views.into_iter()).collect();
|
||||
folder.insert_nested_views(all_views);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts parent-child views into the folder. If a `parent_view_id` is provided,
|
||||
/// it will be used to set the `parent_view_id` for all child views. If not, the latest
|
||||
/// view (by `last_edited_time`) from the workspace will be used as the parent view.
|
||||
///
|
||||
pub async fn insert_views_with_parent(
|
||||
&self,
|
||||
mut views: Vec<ParentChildViews>,
|
||||
orphan_views: Vec<ParentChildViews>,
|
||||
parent_view_id: Option<String>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let lock = self
|
||||
.mutex_folder
|
||||
.load_full()
|
||||
.ok_or_else(|| FlowyError::internal().with_context("The folder is not initialized"))?;
|
||||
|
||||
// Obtain a write lock on the folder.
|
||||
let mut folder = lock.write().await;
|
||||
|
||||
// Set the parent view ID for the child views.
|
||||
if let Some(parent_view_id) = parent_view_id {
|
||||
// If a valid parent_view_id is provided, set it for each child view.
|
||||
if folder.get_view(&parent_view_id).is_some() {
|
||||
info!(
|
||||
"[AppFlowyData]: Attach parent-child views with the latest view: {:?}",
|
||||
parent_view_id
|
||||
);
|
||||
views.iter_mut().for_each(|child_view| {
|
||||
child_view.view.parent_view_id = parent_view_id.clone();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If no parent_view_id is provided, find the latest view in the workspace.
|
||||
let workspace_id = folder
|
||||
.get_workspace_id()
|
||||
.ok_or_else(|| FlowyError::internal().with_context("Cannot find the workspace ID"))?;
|
||||
|
||||
// Get the latest view based on the last_edited_time in the workspace.
|
||||
match folder
|
||||
.get_views_belong_to(&workspace_id)
|
||||
.iter()
|
||||
.max_by_key(|view| view.last_edited_time)
|
||||
{
|
||||
None => info!("[AppFlowyData]: No views found in the workspace"),
|
||||
Some(latest_view) => {
|
||||
info!(
|
||||
"[AppFlowyData]: Attach parent-child views with the latest view: {}:{}, is_space: {:?}",
|
||||
latest_view.id,
|
||||
latest_view.name,
|
||||
latest_view.space_info(),
|
||||
);
|
||||
views.iter_mut().for_each(|child_view| {
|
||||
child_view.view.parent_view_id = latest_view.id.clone();
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the views into the folder.
|
||||
let all_views = views.into_iter().chain(orphan_views.into_iter()).collect();
|
||||
folder.insert_nested_views(all_views);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_workspace_pb(&self) -> FlowyResult<WorkspacePB> {
|
||||
|
||||
@ -28,12 +28,12 @@ impl DefaultFolderBuilder {
|
||||
|
||||
let views = workspace_view_builder.write().await.build();
|
||||
// Safe to unwrap because we have at least one view. check out the DocumentFolderOperation.
|
||||
let first_view = views.first().unwrap().parent_view.clone();
|
||||
let first_view = views.first().unwrap().view.clone();
|
||||
|
||||
let first_level_views = views
|
||||
.iter()
|
||||
.map(|value| ViewIdentifier {
|
||||
id: value.parent_view.id.clone(),
|
||||
id: value.view.id.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -62,11 +62,11 @@ impl DefaultFolderBuilder {
|
||||
impl From<&ParentChildViews> for ViewPB {
|
||||
fn from(value: &ParentChildViews) -> Self {
|
||||
view_pb_with_child_views(
|
||||
Arc::new(value.parent_view.clone()),
|
||||
Arc::new(value.view.clone()),
|
||||
value
|
||||
.child_views
|
||||
.children
|
||||
.iter()
|
||||
.map(|v| Arc::new(v.parent_view.clone()))
|
||||
.map(|v| Arc::new(v.view.clone()))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
use crate::entities::UserFolderPB;
|
||||
use collab_folder::hierarchy_builder::ParentChildViews;
|
||||
use collab_folder::Folder;
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
use tracing::{event, instrument};
|
||||
|
||||
pub(crate) fn folder_not_init_error() -> FlowyError {
|
||||
FlowyError::internal().with_context("Folder not initialized")
|
||||
@ -14,17 +11,3 @@ pub(crate) fn workspace_data_not_sync_error(uid: i64, workspace_id: &str) -> Flo
|
||||
workspace_id: workspace_id.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(folder, view))]
|
||||
pub(crate) fn insert_parent_child_views(folder: &mut Folder, view: ParentChildViews) {
|
||||
event!(
|
||||
tracing::Level::DEBUG,
|
||||
"Inserting view: {}, view children: {}",
|
||||
view.parent_view.id,
|
||||
view.child_views.len()
|
||||
);
|
||||
folder.insert_view(view.parent_view, None);
|
||||
for child_view in view.child_views {
|
||||
insert_parent_child_views(folder, child_view);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,6 @@ pub fn user_profile_from_af_profile(
|
||||
icon_url: icon_url.unwrap_or_default(),
|
||||
openai_key: openai_key.unwrap_or_default(),
|
||||
stability_ai_key: stability_ai_key.unwrap_or_default(),
|
||||
workspace_id: profile.latest_workspace_id.to_string(),
|
||||
authenticator: Authenticator::AppFlowyCloud,
|
||||
encryption_type,
|
||||
uid: profile.uid,
|
||||
|
||||
@ -167,7 +167,6 @@ pub struct UserProfile {
|
||||
pub icon_url: String,
|
||||
pub openai_key: String,
|
||||
pub stability_ai_key: String,
|
||||
pub workspace_id: String,
|
||||
pub authenticator: Authenticator,
|
||||
// If the encryption_sign is not empty, which means the user has enabled the encryption.
|
||||
pub encryption_type: EncryptionType,
|
||||
@ -246,7 +245,6 @@ where
|
||||
token: value.user_token().unwrap_or_default(),
|
||||
icon_url,
|
||||
openai_key,
|
||||
workspace_id: value.latest_workspace().id.to_owned(),
|
||||
authenticator: auth_type.clone(),
|
||||
encryption_type: value.encryption_type(),
|
||||
stability_ai_key,
|
||||
|
||||
@ -1,12 +1,19 @@
|
||||
use collab_folder::hierarchy_builder::ParentChildViews;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_folder_pub::entities::ImportFrom;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserWorkspaceService: Send + Sync {
|
||||
async fn did_import_views(&self, views: Vec<ParentChildViews>) -> FlowyResult<()>;
|
||||
async fn did_import_database_views(
|
||||
async fn import_views(
|
||||
&self,
|
||||
source: &ImportFrom,
|
||||
views: Vec<ParentChildViews>,
|
||||
orphan_views: Vec<ParentChildViews>,
|
||||
parent_view_id: Option<String>,
|
||||
) -> FlowyResult<()>;
|
||||
async fn import_database_views(
|
||||
&self,
|
||||
ids_by_database_id: HashMap<String, Vec<String>>,
|
||||
) -> FlowyResult<()>;
|
||||
|
||||
@ -49,6 +49,7 @@ base64 = "^0.21"
|
||||
tokio-stream = "0.1.14"
|
||||
semver = "1.0.22"
|
||||
validator = { workspace = true, features = ["derive"] }
|
||||
rayon = "1.10.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nanoid = "0.4.0"
|
||||
|
||||
@ -9,4 +9,7 @@ pub struct ImportAppFlowyDataPB {
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub import_container_name: Option<String>,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub parent_view_id: Option<String>,
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ pub async fn import_appflowy_data_folder_handler(
|
||||
af_spawn(async move {
|
||||
let result = async {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let imported_folder = prepare_import(&data.path)
|
||||
let imported_folder = prepare_import(&data.path, data.parent_view_id)
|
||||
.map_err(|err| FlowyError::new(ErrorCode::AppFlowyDataFolderImportError, err.to_string()))?
|
||||
.with_container_name(data.import_container_name);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,34 +1,35 @@
|
||||
use collab::preclude::Collab;
|
||||
use collab_integrate::{CollabKVAction, PersistenceError};
|
||||
use std::collections::HashMap;
|
||||
use tracing::instrument;
|
||||
|
||||
/// This function loads collab objects by their object_ids.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn load_collab_by_object_ids<'a, R>(
|
||||
uid: i64,
|
||||
collab_read_txn: &R,
|
||||
object_ids: &[String],
|
||||
) -> HashMap<String, Collab>
|
||||
) -> (HashMap<String, Collab>, Vec<String>)
|
||||
where
|
||||
R: CollabKVAction<'a>,
|
||||
PersistenceError: From<R::Error>,
|
||||
{
|
||||
let mut invalid_object_ids = vec![];
|
||||
let mut collab_by_oid = HashMap::new();
|
||||
for object_id in object_ids {
|
||||
match load_collab_by_object_id(uid, collab_read_txn, object_id) {
|
||||
Ok(collab) => {
|
||||
collab_by_oid.insert(object_id.clone(), collab);
|
||||
},
|
||||
Err(err) => tracing::error!("🔴load collab: {} failed: {:?} ", object_id, err),
|
||||
Err(err) => {
|
||||
invalid_object_ids.push(object_id.clone());
|
||||
tracing::error!("🔴load collab: {} failed: {:?} ", object_id, err)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
collab_by_oid
|
||||
(collab_by_oid, invalid_object_ids)
|
||||
}
|
||||
|
||||
/// This function loads single collab object by its object_id.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn load_collab_by_object_id<'a, R>(
|
||||
uid: i64,
|
||||
collab_read_txn: &R,
|
||||
|
||||
@ -44,18 +44,8 @@ impl UserDB {
|
||||
}
|
||||
|
||||
/// Performs a conditional backup or restoration of the collaboration database (CollabDB) for a specific user.
|
||||
///
|
||||
/// This function takes a user ID and conducts the following operations:
|
||||
///
|
||||
/// **Backup or Restoration**:
|
||||
/// - If the CollabDB exists, it tries to open the database:
|
||||
/// - **Successful Open**: If the database opens successfully, it attempts to back it up.
|
||||
/// - **Failed Open**: If the database cannot be opened, it indicates a potential issue, and the function
|
||||
/// attempts to restore the database from the latest backup.
|
||||
/// - If the CollabDB does not exist, it immediately attempts to restore from the latest backup.
|
||||
///
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn backup_or_restore(&self, uid: i64, workspace_id: &str) {
|
||||
pub fn backup(&self, uid: i64, workspace_id: &str) {
|
||||
// Obtain the path for the collaboration database.
|
||||
let collab_db_path = self.paths.collab_db_path(uid);
|
||||
|
||||
@ -63,12 +53,10 @@ impl UserDB {
|
||||
if let Ok(history_folder) = self.paths.collab_db_history(uid, true) {
|
||||
// Initialize the backup utility for the collaboration database.
|
||||
let zip_backup = CollabDBZipBackup::new(collab_db_path.clone(), history_folder);
|
||||
|
||||
if collab_db_path.exists() {
|
||||
// Validate the existing collaboration database.
|
||||
let result = self.open_collab_db(collab_db_path, uid);
|
||||
let is_ok = validate_collab_db(result, uid, workspace_id);
|
||||
|
||||
if is_ok {
|
||||
// If database is valid, update the shared map and initiate backup.
|
||||
// Asynchronous backup operation.
|
||||
@ -77,9 +65,6 @@ impl UserDB {
|
||||
error!("Backup of collab db failed: {:?}", err);
|
||||
}
|
||||
});
|
||||
} else if let Err(err) = zip_backup.restore_latest_backup() {
|
||||
// If validation fails, attempt to restore from the latest backup.
|
||||
error!("Restoring collab db failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,21 +81,6 @@ impl UserDB {
|
||||
vec![]
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn restore_if_need(&self, uid: i64, workspace_id: &str) {
|
||||
if let Ok(history_folder) = self.paths.collab_db_history(uid, false) {
|
||||
let collab_db_path = self.paths.collab_db_path(uid);
|
||||
let result = self.open_collab_db(&collab_db_path, uid);
|
||||
let is_ok = validate_collab_db(result, uid, workspace_id);
|
||||
if !is_ok {
|
||||
let zip_backup = CollabDBZipBackup::new(collab_db_path, history_folder);
|
||||
if let Err(err) = zip_backup.restore_latest_backup() {
|
||||
error!("restore collab db failed, {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Close the database connection for the user.
|
||||
pub(crate) fn close(&self, user_id: i64) -> Result<(), FlowyError> {
|
||||
if self.sqlite_map.remove(&user_id).is_some() {
|
||||
@ -277,8 +247,9 @@ impl CollabDBZipBackup {
|
||||
Ok(backups)
|
||||
}
|
||||
|
||||
#[instrument(skip_all, err)]
|
||||
pub fn restore_latest_backup(&self) -> io::Result<()> {
|
||||
#[deprecated(note = "This function is deprecated", since = "0.7.1")]
|
||||
#[allow(dead_code)]
|
||||
fn restore_latest_backup(&self) -> io::Result<()> {
|
||||
let mut latest_zip: Option<(String, PathBuf)> = None;
|
||||
// When the history folder does not exist, there is no backup to restore
|
||||
if !self.history_folder.exists() {
|
||||
|
||||
@ -15,6 +15,9 @@ use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods};
|
||||
pub struct UserTable {
|
||||
pub(crate) id: String,
|
||||
pub(crate) name: String,
|
||||
#[deprecated(
|
||||
note = "The workspace_id is deprecated, please use the [Session::UserWorkspace] instead"
|
||||
)]
|
||||
pub(crate) workspace: String,
|
||||
pub(crate) icon_url: String,
|
||||
pub(crate) openai_key: String,
|
||||
@ -27,13 +30,7 @@ pub struct UserTable {
|
||||
pub(crate) ai_model: String,
|
||||
}
|
||||
|
||||
impl UserTable {
|
||||
pub fn set_workspace(mut self, workspace: String) -> Self {
|
||||
self.workspace = workspace;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl From<(UserProfile, Authenticator)> for UserTable {
|
||||
fn from(value: (UserProfile, Authenticator)) -> Self {
|
||||
let (user_profile, auth_type) = value;
|
||||
@ -41,7 +38,8 @@ impl From<(UserProfile, Authenticator)> for UserTable {
|
||||
UserTable {
|
||||
id: user_profile.uid.to_string(),
|
||||
name: user_profile.name,
|
||||
workspace: user_profile.workspace_id,
|
||||
#[allow(deprecated)]
|
||||
workspace: "".to_string(),
|
||||
icon_url: user_profile.icon_url,
|
||||
openai_key: user_profile.openai_key,
|
||||
token: user_profile.token,
|
||||
@ -64,7 +62,6 @@ impl From<UserTable> for UserProfile {
|
||||
token: table.token,
|
||||
icon_url: table.icon_url,
|
||||
openai_key: table.openai_key,
|
||||
workspace_id: table.workspace,
|
||||
authenticator: Authenticator::from(table.auth_type),
|
||||
encryption_type: EncryptionType::from_str(&table.encryption_type).unwrap_or_default(),
|
||||
stability_ai_key: table.stability_ai_key,
|
||||
|
||||
@ -554,7 +554,7 @@ impl UserManager {
|
||||
self
|
||||
.authenticate_user
|
||||
.database
|
||||
.backup_or_restore(session.user_id, &session.user_workspace.id);
|
||||
.backup(session.user_id, &session.user_workspace.id);
|
||||
}
|
||||
|
||||
/// Fetches the user profile for the given user ID.
|
||||
@ -873,7 +873,7 @@ pub(crate) fn run_collab_data_migration(
|
||||
sqlite_pool: Arc<ConnectionPool>,
|
||||
version: Option<Version>,
|
||||
) {
|
||||
trace!("Run collab data migration: {:?}", version);
|
||||
trace!("[AppflowyData]:Run collab data migration: {:?}", version);
|
||||
let migrations = collab_migration_list();
|
||||
match UserLocalDataMigration::new(session.clone(), collab_db, sqlite_pool).run(
|
||||
migrations,
|
||||
@ -882,10 +882,13 @@ pub(crate) fn run_collab_data_migration(
|
||||
) {
|
||||
Ok(applied_migrations) => {
|
||||
if !applied_migrations.is_empty() {
|
||||
info!("Did apply migrations: {:?}", applied_migrations);
|
||||
info!(
|
||||
"[AppflowyData]:Did apply migrations: {:?}",
|
||||
applied_migrations
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(e) => error!("User data migration failed: {:?}", e),
|
||||
Err(e) => error!("[AppflowyData]:User data migration failed: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ use collab_integrate::CollabKVDB;
|
||||
use tracing::{error, info, instrument, trace, warn};
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_folder_pub::entities::{AppFlowyData, ImportData};
|
||||
use flowy_folder_pub::entities::{ImportFrom, ImportedCollabData, ImportedFolderData};
|
||||
use flowy_sqlite::schema::user_workspace_table;
|
||||
use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods};
|
||||
use flowy_user_pub::entities::{
|
||||
@ -63,89 +63,87 @@ impl UserManager {
|
||||
})
|
||||
.await??;
|
||||
|
||||
match import_data {
|
||||
ImportData::AppFlowyDataFolder { items } => {
|
||||
for item in items {
|
||||
self
|
||||
.upload_appflowy_data_item(¤t_session, item)
|
||||
.await?;
|
||||
}
|
||||
},
|
||||
}
|
||||
info!(
|
||||
"[AppflowyData]: upload {} document, {} database, {}, rows",
|
||||
import_data.collab_data.document_object_ids.len(),
|
||||
import_data.collab_data.database_object_ids.len(),
|
||||
import_data.collab_data.row_object_ids.len()
|
||||
);
|
||||
self
|
||||
.upload_collab_data(¤t_session, import_data.collab_data)
|
||||
.await?;
|
||||
|
||||
self
|
||||
.upload_folder_data(
|
||||
¤t_session,
|
||||
&import_data.source,
|
||||
import_data.parent_view_id,
|
||||
import_data.folder_data,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn upload_appflowy_data_item(
|
||||
async fn upload_folder_data(
|
||||
&self,
|
||||
_current_session: &Session,
|
||||
source: &ImportFrom,
|
||||
parent_view_id: Option<String>,
|
||||
folder_data: ImportedFolderData,
|
||||
) -> Result<(), FlowyError> {
|
||||
let ImportedFolderData {
|
||||
views,
|
||||
orphan_views,
|
||||
database_view_ids_by_database_id,
|
||||
} = folder_data;
|
||||
self
|
||||
.user_workspace_service
|
||||
.import_database_views(database_view_ids_by_database_id)
|
||||
.await?;
|
||||
self
|
||||
.user_workspace_service
|
||||
.import_views(source, views, orphan_views, parent_view_id)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn upload_collab_data(
|
||||
&self,
|
||||
current_session: &Session,
|
||||
item: AppFlowyData,
|
||||
collab_data: ImportedCollabData,
|
||||
) -> Result<(), FlowyError> {
|
||||
match item {
|
||||
AppFlowyData::Folder {
|
||||
views,
|
||||
database_view_ids_by_database_id,
|
||||
} => {
|
||||
// Since `async_trait` does not implement `Sync`, and the handler requires `Sync`, we use a
|
||||
// channel to synchronize the operation. This approach allows asynchronous trait methods to be compatible
|
||||
// with synchronous handler requirements."
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
let cloned_workspace_service = self.user_workspace_service.clone();
|
||||
af_spawn(async move {
|
||||
let result = async {
|
||||
cloned_workspace_service
|
||||
.did_import_database_views(database_view_ids_by_database_id)
|
||||
.await?;
|
||||
cloned_workspace_service.did_import_views(views).await?;
|
||||
Ok::<(), FlowyError>(())
|
||||
}
|
||||
.await;
|
||||
let _ = tx.send(result);
|
||||
})
|
||||
.await?;
|
||||
rx.await??;
|
||||
},
|
||||
AppFlowyData::CollabObject {
|
||||
row_object_ids,
|
||||
document_object_ids,
|
||||
database_object_ids,
|
||||
} => {
|
||||
let user = self
|
||||
.get_user_profile_from_disk(current_session.user_id)
|
||||
.await?;
|
||||
let user_collab_db = self
|
||||
.get_collab_db(current_session.user_id)?
|
||||
.upgrade()
|
||||
.ok_or_else(|| FlowyError::internal().with_context("Collab db not found"))?;
|
||||
let user = self
|
||||
.get_user_profile_from_disk(current_session.user_id)
|
||||
.await?;
|
||||
let user_collab_db = self
|
||||
.get_collab_db(current_session.user_id)?
|
||||
.upgrade()
|
||||
.ok_or_else(|| FlowyError::internal().with_context("Collab db not found"))?;
|
||||
|
||||
let user_id = current_session.user_id;
|
||||
let weak_user_collab_db = Arc::downgrade(&user_collab_db);
|
||||
let weak_user_cloud_service = self.cloud_services.get_user_service()?;
|
||||
match upload_collab_objects_data(
|
||||
user_id,
|
||||
weak_user_collab_db,
|
||||
&user.workspace_id,
|
||||
&user.authenticator,
|
||||
AppFlowyData::CollabObject {
|
||||
row_object_ids,
|
||||
document_object_ids,
|
||||
database_object_ids,
|
||||
},
|
||||
weak_user_cloud_service,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => info!(
|
||||
"Successfully uploaded collab objects data for user:{}",
|
||||
user_id
|
||||
),
|
||||
Err(err) => {
|
||||
error!(
|
||||
"Failed to upload collab objects data: {:?} for user:{}",
|
||||
err, user_id
|
||||
);
|
||||
// TODO(nathan): retry uploading the collab objects data.
|
||||
},
|
||||
}
|
||||
let user_id = current_session.user_id;
|
||||
let weak_user_collab_db = Arc::downgrade(&user_collab_db);
|
||||
let weak_user_cloud_service = self.cloud_services.get_user_service()?;
|
||||
match upload_collab_objects_data(
|
||||
user_id,
|
||||
weak_user_collab_db,
|
||||
¤t_session.user_workspace.id,
|
||||
&user.authenticator,
|
||||
collab_data,
|
||||
weak_user_cloud_service,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => info!(
|
||||
"Successfully uploaded collab objects data for user:{}",
|
||||
user_id
|
||||
),
|
||||
Err(err) => {
|
||||
error!(
|
||||
"Failed to upload collab objects data: {:?} for user:{}",
|
||||
err, user_id
|
||||
);
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
@ -160,6 +158,7 @@ impl UserManager {
|
||||
imported_session: old_user.session.as_ref().clone(),
|
||||
imported_collab_db: old_collab_db.clone(),
|
||||
container_name: None,
|
||||
parent_view_id: None,
|
||||
source: ImportedSource::AnonUser,
|
||||
};
|
||||
self.perform_import(import_context).await?;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user