tests: more cloud test (#4204)

* test: add anon user test

* chore: add to runner

* test: fix

* test: fix

* test: add tests

* chore: add test

* chore: fix warn

* chore: fix warn

* fix: build

* fix: test

* chore: rename

* chore: fix test

* chore: fix test

* chore: fix test

* chore: disable test
This commit is contained in:
Nathan.fooo 2023-12-26 02:03:42 +08:00 committed by GitHub
parent 9b55f5bc7f
commit a49b009980
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 776 additions and 450 deletions

View File

@ -68,6 +68,31 @@ jobs:
echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
- name: Checkout appflowy cloud code
uses: actions/checkout@v3
with:
repository: AppFlowy-IO/AppFlowy-Cloud
path: AppFlowy-Cloud
depth: 1
- name: Prepare appflowy cloud env
working-directory: AppFlowy-Cloud
run: |
# log level
cp dev.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's/GOTRUE_SMTP_USER=.*/GOTRUE_SMTP_USER=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_USER }}/' .env
sed -i 's/GOTRUE_SMTP_PASS=.*/GOTRUE_SMTP_PASS=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_PASS }}/' .env
sed -i 's/GOTRUE_SMTP_ADMIN_EMAIL=.*/GOTRUE_SMTP_ADMIN_EMAIL=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_ADMIN_EMAIL }}/' .env
sed -i 's/GOTRUE_EXTERNAL_GOOGLE_ENABLED=.*/GOTRUE_EXTERNAL_GOOGLE_ENABLED=true/' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
cat .env
- name: Run Docker-Compose
working-directory: AppFlowy-Cloud
run: |
docker compose up -d
- name: Run rust-lib tests
working-directory: frontend/rust-lib
run: RUST_LOG=info RUST_BACKTRACE=1 cargo test --no-default-features --features="rev-sqlite"

View File

@ -16,7 +16,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@ -48,7 +48,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);

View File

@ -0,0 +1,68 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:integration_test/integration_test.dart';
import '../util/dir.dart';
import '../util/mock/mock_file_picker.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('appflowy cloud', () {
testWidgets('anon user and then sign in', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloud,
);
tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr());
await tester.tapGoButton();
await tester.expectToSeeHomePage();
// reanme the name of the anon user
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userNameFinder = find.descendant(
of: find.byType(SettingsUserView),
matching: find.byType(UserNameInput),
);
await tester.enterText(userNameFinder, 'local_user');
await tester.pumpAndSettle();
// sign up with Google
await tester.tapGoogleLoginInButton();
await tester.pumpAndSettle();
// sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.logout();
await tester.pumpAndSettle();
// tap the continue as anonymous button
await tester
.tapButton(find.text(LocaleKeys.signIn_continueAnonymousUser.tr()));
await tester.expectToSeeHomePage();
// assert the name of the anon user is local_user
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userNameInput = tester.widget(userNameFinder) as UserNameInput;
expect(userNameInput.name, 'local_user');
});
});
}

View File

@ -0,0 +1,74 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/sign_in_anonymous_button.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:integration_test/integration_test.dart';
import '../util/database_test_op.dart';
import '../util/dir.dart';
import '../util/mock/mock_file_picker.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('appflowy cloud', () {
testWidgets('anon user -> af cloud -> continue anon', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloud,
);
tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr());
await tester.tapGoButton();
await tester.expectToSeeHomePage();
// reanme the name of the anon user
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userNameFinder = find.descendant(
of: find.byType(SettingsUserView),
matching: find.byType(UserNameInput),
);
await tester.enterText(userNameFinder, 'local_user');
await tester.openSettingsPage(SettingsPage.user);
await tester.tapEscButton();
await tester.expectToSeeHomePage();
// sign up with Google
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
// sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.logout();
await tester.pumpAndSettle();
tester.expectToSeeText(LocaleKeys.signIn_continueAnonymousUser.tr());
// tap the continue as anonymous button
await tester.tapButton(find.byType(SignInAnonymousButton));
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userNameInput = tester.widget(userNameFinder) as UserNameInput;
expect(userNameInput.name, 'local_user');
});
});
}

View File

@ -25,7 +25,7 @@ void main() {
cloudType: AuthenticatorType.appflowyCloud,
);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
});
testWidgets('sign out', (tester) async {

View File

@ -1,14 +1,17 @@
import 'empty_test.dart' as empty_test;
import 'empty_test.dart' as preset_af_cloud_env_test;
import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
import 'document_sync_test.dart' as document_sync_test;
import 'user_setting_sync_test.dart' as user_sync_test;
// import 'anon_user_continue_test.dart' as anon_user_continue_test;
Future<void> main() async {
empty_test.main();
preset_af_cloud_env_test.main();
appflowy_cloud_auth_test.main();
document_sync_test.main();
user_sync_test.main();
// anon_user_continue_test.main();
}

View File

@ -35,7 +35,7 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
// create a new document called Sample
await tester.createNewPageWithName(
@ -52,8 +52,7 @@ void main() {
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.tapButton(find.byType(SettingLogoutButton));
tester.expectToSeeText(LocaleKeys.button_ok.tr());
await tester.logout();
});
testWidgets('sync doc from server', (tester) async {
@ -62,7 +61,7 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.pumpAndSettle(const Duration(seconds: 2));
// The document will be synced from the server

View File

@ -15,7 +15,7 @@ void main() {
testWidgets('sign in with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
});
testWidgets('sign out with supabase', (tester) async {

View File

@ -36,7 +36,7 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
@ -74,7 +74,7 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.pumpAndSettle();
await tester.openSettings();

View File

@ -19,7 +19,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@ -71,7 +71,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.pumpAndSettle();

View File

@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.language);

View File

@ -33,7 +33,7 @@ void main() {
);
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
// switch to user B
{
@ -51,7 +51,7 @@ void main() {
);
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
// set user name for userB
await tester.openSettings();
@ -71,7 +71,7 @@ void main() {
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
tester.expectToSeeUserName(userA);
}
@ -88,7 +88,7 @@ void main() {
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
tester.expectToSeeUserName(userB);
}
});
@ -99,7 +99,7 @@ void main() {
await tester.tapGoButton();
// home and readme document
tester.expectToSeeHomePage();
await tester.expectToSeeHomePage();
// open settings and restore the location
await tester.openSettings();

View File

@ -1,16 +1,27 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'base.dart';
import 'expectation.dart';
extension AppFlowyAuthTest on WidgetTester {
Future<void> tapGoogleLoginInButton() async {
await tapButton(find.byKey(const Key('signInWithGoogleButton')));
}
Future<void> logout() async {
await tapButton(find.byType(SettingLogoutButton));
expectToSeeText(LocaleKeys.button_ok.tr());
await tapButtonWithName(LocaleKeys.button_ok.tr());
}
Future<void> tapSignInAsGuest() async {
await tapButton(find.byType(SignInAnonymousButton));
}

View File

@ -15,7 +15,6 @@ import 'package:dartz/dartz.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
@ -33,21 +32,24 @@ extension AppFlowyTestBase on WidgetTester {
Future<FlowyTestContext> initializeAppFlowy({
// use to append after the application data directory
String? pathExtension,
// use to specify the application data directory, if not specified, a temporary directory will be used.
String? dataDirectory,
Size windowsSize = const Size(1600, 1200),
AuthenticatorType? cloudType,
String? email,
}) async {
// view.physicalSize = windowsSize;
binding.setSurfaceSize(windowsSize);
// addTearDown(() => binding.setSurfaceSize(null));
mockHotKeyManagerHandlers();
final directory = await mockApplicationDataStorage(
pathExtension: pathExtension,
);
WidgetsFlutterBinding.ensureInitialized();
final applicationDataDirectory = dataDirectory ??
await mockApplicationDataStorage(
pathExtension: pathExtension,
);
await FlowyRunner.run(
FlowyApp(),
AppFlowyApplication(),
IntegrationMode.integrationTest,
rustEnvsBuilder: () {
final rustEnvs = <String, String>{};
@ -93,9 +95,10 @@ extension AppFlowyTestBase on WidgetTester {
);
},
);
await waitUntilSignInPageShow();
return FlowyTestContext(
applicationDataDirectory: directory,
applicationDataDirectory: applicationDataDirectory,
);
}
@ -110,27 +113,6 @@ extension AppFlowyTestBase on WidgetTester {
});
}
Future<String> mockApplicationDataStorage({
// use to append after the application data directory
String? pathExtension,
}) async {
final dir = await getTemporaryDirectory();
// Use a random uuid to avoid conflict.
String path = p.join(dir.path, 'appflowy_integration_test', uuid());
if (pathExtension != null && pathExtension.isNotEmpty) {
path = '$path/$pathExtension';
}
final directory = Directory(path);
if (!directory.existsSync()) {
await directory.create(recursive: true);
}
MockApplicationDataStorage.initialPath = directory.path;
return directory.path;
}
Future<void> waitUntilSignInPageShow() async {
if (isAuthEnabled) {
final finder = find.byType(SignInAnonymousButton);
@ -143,16 +125,22 @@ extension AppFlowyTestBase on WidgetTester {
}
}
Future<void> waitForSeconds(int seconds) async {
await Future.delayed((Duration(seconds: seconds)), () {});
}
Future<void> pumpUntilFound(
Finder finder, {
Duration timeout = const Duration(seconds: 10),
Duration pumpInterval =
const Duration(milliseconds: 50), // Interval between pumps
}) async {
bool timerDone = false;
final timer = Timer(timeout, () => timerDone = true);
while (timerDone != true) {
await pump();
while (!timerDone) {
await pump(pumpInterval); // Pump with an interval
if (any(finder)) {
timerDone = true;
break;
}
}
timer.cancel();
@ -273,3 +261,24 @@ Future<void> useAppFlowyCloud() async {
await setAuthenticatorType(AuthenticatorType.appflowyCloud);
await setAppFlowyCloudUrl(Some(TestEnv.afCloudUrl));
}
Future<String> mockApplicationDataStorage({
// use to append after the application data directory
String? pathExtension,
}) async {
final dir = await getTemporaryDirectory();
// Use a random uuid to avoid conflict.
String path = p.join(dir.path, 'appflowy_integration_test', uuid());
if (pathExtension != null && pathExtension.isNotEmpty) {
path = '$path/$pathExtension';
}
final directory = Directory(path);
if (!directory.existsSync()) {
await directory.create(recursive: true);
}
MockApplicationDataStorage.initialPath = directory.path;
return directory.path;
}

View File

@ -1,5 +1,6 @@
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:archive/archive.dart';
Future<void> deleteDirectoriesWithSameBaseNameAsPrefix(
String path,
@ -28,3 +29,25 @@ Future<void> deleteDirectoriesWithSameBaseNameAsPrefix(
}
}
}
Future<void> unzipFile(File zipFile, Directory targetDirectory) async {
// Read the Zip file from disk.
final bytes = zipFile.readAsBytesSync();
// Decode the Zip file
final archive = ZipDecoder().decodeBytes(bytes);
// Extract the contents of the Zip archive to disk.
for (final file in archive) {
final filename = file.name;
if (file.isFile) {
final data = file.content as List<int>;
File(p.join(targetDirectory.path, filename))
..createSync(recursive: true)
..writeAsBytesSync(data);
} else {
Directory(p.join(targetDirectory.path, filename))
.createSync(recursive: true);
}
}
}

View File

@ -11,14 +11,20 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_test/flutter_test.dart';
import 'util.dart';
// const String readme = 'Read me';
const String gettingStarted = 'Getting started';
extension Expectation on WidgetTester {
/// Expect to see the home page and with a default read me page.
void expectToSeeHomePage() {
expect(find.byType(HomeStack), findsOneWidget);
expect(find.textContaining(gettingStarted), findsWidgets);
Future<void> expectToSeeHomePage() async {
final finder = find.byType(HomeStack);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
final docFinder = find.textContaining(gettingStarted);
await pumpUntilFound(docFinder);
}
/// Expect to see the page name on the home page.

View File

@ -1,6 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_user.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
@ -13,7 +14,7 @@ import 'base.dart';
extension AppFlowySettings on WidgetTester {
/// Open settings page
Future<void> openSettings() async {
final settingsButton = find.byTooltip(LocaleKeys.settings_menu_open.tr());
final settingsButton = find.byType(UserSettingButton);
expect(settingsButton, findsOneWidget);
await tapButton(settingsButton);
final settingsDialog = find.byType(SettingsDialog);

View File

@ -131,7 +131,7 @@ void _resolveUserDeps(GetIt getIt, IntegrationMode mode) {
case AuthenticatorType.local:
getIt.registerFactory<AuthService>(
() => BackendAuthService(
AuthTypePB.Local,
AuthenticatorPB.Local,
),
);
break;

View File

@ -3,7 +3,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/screens/splash_screen.dart';
import 'package:flutter/material.dart';
class FlowyApp implements EntryPoint {
class AppFlowyApplication implements EntryPoint {
@override
Widget create(LaunchConfiguration config) {
return SplashScreen(

View File

@ -29,14 +29,30 @@ class FlowyRunnerContext {
FlowyRunnerContext({required this.applicationDataDirectory});
}
Future<void> runAppFlowy() async {
await FlowyRunner.run(
FlowyApp(),
integrationMode(),
);
Future<void> runAppFlowy({bool isAnon = false}) async {
if (kReleaseMode) {
await FlowyRunner.run(
AppFlowyApplication(),
integrationMode(),
isAnon: isAnon,
);
} else {
// When running the app in integration test mode, we need to
// specify the mode to run the app again.
await FlowyRunner.run(
AppFlowyApplication(),
FlowyRunner.currentMode,
didInitGetItCallback: IntegrationTestHelper.didInitGetItCallback,
rustEnvsBuilder: IntegrationTestHelper.rustEnvsBuilder,
isAnon: isAnon,
);
}
}
class FlowyRunner {
// This variable specifies the initial mode of the app when it is launched for the first time.
// The same mode will be automatically applied in subsequent executions when the runAppFlowy()
// method is called.
static var currentMode = integrationMode();
static Future<FlowyRunnerContext> run(
@ -55,6 +71,13 @@ class FlowyRunner {
bool isAnon = false,
}) async {
currentMode = mode;
// Only set the mode when it's not release mode
if (!kReleaseMode) {
IntegrationTestHelper.didInitGetItCallback = didInitGetItCallback;
IntegrationTestHelper.rustEnvsBuilder = rustEnvsBuilder;
}
// Clear all the states in case of rebuilding.
await getIt.reset();
@ -220,3 +243,9 @@ IntegrationMode integrationMode() {
return IntegrationMode.develop;
}
/// Only used for integration test
class IntegrationTestHelper {
static Future Function()? didInitGetItCallback;
static Map<String, String> Function()? rustEnvsBuilder;
}

View File

@ -87,7 +87,7 @@ class AppFlowyCloudDeepLink {
(_) async {
final deviceId = await getDeviceId();
final payload = OauthSignInPB(
authType: AuthTypePB.AFCloud,
authType: AuthenticatorPB.AppFlowyCloud,
map: {
AuthServiceMapKeys.signInURL: uri.toString(),
AuthServiceMapKeys.deviceId: deviceId,

View File

@ -17,7 +17,7 @@ class AppFlowyCloudAuthService implements AuthService {
AppFlowyCloudAuthService();
final BackendAuthService _backendAuthService = BackendAuthService(
AuthTypePB.AFCloud,
AuthenticatorPB.AppFlowyCloud,
);
@override

View File

@ -18,7 +18,7 @@ class AppFlowyCloudMockAuthService implements AuthService {
: userEmail = email ?? "${uuid()}@appflowy.io";
final BackendAuthService _appFlowyAuthService =
BackendAuthService(AuthTypePB.Supabase);
BackendAuthService(AuthenticatorPB.Supabase);
@override
Future<Either<FlowyError, UserProfilePB>> signUp({
@ -45,7 +45,7 @@ class AppFlowyCloudMockAuthService implements AuthService {
Map<String, String> params = const {},
}) async {
final payload = SignInUrlPayloadPB.create()
..authType = AuthTypePB.AFCloud
..authType = AuthenticatorPB.AppFlowyCloud
// don't use nanoid here, the gotrue server will transform the email
..email = userEmail;
@ -55,7 +55,7 @@ class AppFlowyCloudMockAuthService implements AuthService {
return getSignInURLResult.fold(
(urlPB) async {
final payload = OauthSignInPB(
authType: AuthTypePB.AFCloud,
authType: AuthenticatorPB.AppFlowyCloud,
map: {
AuthServiceMapKeys.signInURL: urlPB.signInUrl,
AuthServiceMapKeys.deviceId: deviceId,

View File

@ -14,7 +14,7 @@ import '../../../generated/locale_keys.g.dart';
import 'device_id.dart';
class BackendAuthService implements AuthService {
final AuthTypePB authType;
final AuthenticatorPB authType;
BackendAuthService(this.authType);
@ -73,7 +73,7 @@ class BackendAuthService implements AuthService {
..email = userEmail
..password = password
// When sign up as guest, the auth type is always local.
..authType = AuthTypePB.Local
..authType = AuthenticatorPB.Local
..deviceId = await getDeviceId();
final response = await UserEventSignUp(request).send().then(
(value) => value.swap(),
@ -84,7 +84,7 @@ class BackendAuthService implements AuthService {
@override
Future<Either<FlowyError, UserProfilePB>> signUpWithOAuth({
required String platform,
AuthTypePB authType = AuthTypePB.Local,
AuthenticatorPB authType = AuthenticatorPB.Local,
Map<String, String> params = const {},
}) async {
return left(

View File

@ -22,7 +22,7 @@ class SupabaseAuthService implements AuthService {
GoTrueClient get _auth => _client.auth;
final BackendAuthService _backendAuthService = BackendAuthService(
AuthTypePB.Supabase,
AuthenticatorPB.Supabase,
);
@override
@ -171,7 +171,7 @@ class SupabaseAuthService implements AuthService {
required Map<String, String> map,
}) async {
final payload = OauthSignInPB(
authType: AuthTypePB.Supabase,
authType: AuthenticatorPB.Supabase,
map: map,
);

View File

@ -21,7 +21,7 @@ class SupabaseMockAuthService implements AuthService {
GoTrueClient get _auth => _client.auth;
final BackendAuthService _appFlowyAuthService =
BackendAuthService(AuthTypePB.Supabase);
BackendAuthService(AuthenticatorPB.Supabase);
@override
Future<Either<FlowyError, UserProfilePB>> signUp({
@ -67,7 +67,7 @@ class SupabaseMockAuthService implements AuthService {
// Create the OAuth sign-in payload.
final payload = OauthSignInPB(
authType: AuthTypePB.Supabase,
authType: AuthenticatorPB.Supabase,
map: {
AuthServiceMapKeys.uuid: uuid,
AuthServiceMapKeys.email: email,

View File

@ -72,8 +72,9 @@ class AnonUserItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final icon = isSelected ? const FlowySvg(FlowySvgs.check_s) : null;
final isDisabled = isSelected || user.authType != AuthTypePB.Local;
final desc = "${user.name}\t ${user.authType}\t";
final isDisabled =
isSelected || user.authenticator != AuthenticatorPB.Local;
final desc = "${user.name}\t ${user.authenticator}\t";
final child = SizedBox(
height: 30,
child: FlowyButton(

View File

@ -1,7 +1,6 @@
import 'package:appflowy/core/frameless_window.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/entry_point.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/anon_user_bloc.dart';
@ -101,11 +100,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
}
Future<void> _relaunchAppAndAutoRegister() async {
await FlowyRunner.run(
FlowyApp(),
integrationMode(),
isAnon: true,
);
await runAppFlowy(isAnon: true);
}
}

View File

@ -46,7 +46,7 @@ class SidebarUser extends StatelessWidget {
Expanded(
child: _buildUserName(context, state),
),
_buildSettingsButton(context, state),
UserSettingButton(userProfile: state.userProfile),
const HSpace(4),
NotificationButton(views: views),
],
@ -64,8 +64,22 @@ class SidebarUser extends StatelessWidget {
);
}
Widget _buildSettingsButton(BuildContext context, MenuUserState state) {
final userProfile = state.userProfile;
/// Return the user name, if the user name is empty, return the default user name.
String _userName(UserProfilePB userProfile) {
String name = userProfile.name;
if (name.isEmpty) {
name = LocaleKeys.defaultUsername.tr();
}
return name;
}
}
class UserSettingButton extends StatelessWidget {
final UserProfilePB userProfile;
const UserSettingButton({required this.userProfile, super.key});
@override
Widget build(BuildContext context) {
return FlowyTooltip(
message: LocaleKeys.settings_menu_open.tr(),
child: IconButton(
@ -109,13 +123,4 @@ class SidebarUser extends StatelessWidget {
),
);
}
/// Return the user name, if the user name is empty, return the default user name.
String _userName(UserProfilePB userProfile) {
String name = userProfile.name;
if (name.isEmpty) {
name = LocaleKeys.defaultUsername.tr();
}
return name;
}
}

View File

@ -1,7 +1,6 @@
import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/startup/entry_point.dart';
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart';
@ -207,11 +206,7 @@ class _ChangeStoragePathButtonState extends State<_ChangeStoragePathButton> {
return;
}
await context.read<SettingsLocationCubit>().setCustomPath(path);
await FlowyRunner.run(
FlowyApp(),
FlowyRunner.currentMode,
isAnon: true,
);
await runAppFlowy(isAnon: true);
if (mounted) {
Navigator.of(context).pop();
}
@ -283,11 +278,7 @@ class _RecoverDefaultStorageButtonState
await context
.read<SettingsLocationCubit>()
.resetDataStoragePathToApplicationDefault();
await FlowyRunner.run(
FlowyApp(),
FlowyRunner.currentMode,
isAnon: true,
);
await runAppFlowy(isAnon: true);
if (mounted) {
Navigator.of(context).pop();
}

View File

@ -54,7 +54,8 @@ class SettingsUserView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
_buildUserIconSetting(context),
if (isAuthEnabled && user.authType != AuthTypePB.Local) ...[
if (isAuthEnabled &&
user.authenticator != AuthenticatorPB.Local) ...[
const VSpace(12),
UserEmailInput(user.email),
],
@ -146,7 +147,7 @@ class SettingsUserView extends StatelessWidget {
}
// If the user is logged in locally, render a third-party login button.
if (state.userProfile.authType == AuthTypePB.Local) {
if (state.userProfile.authenticator == AuthenticatorPB.Local) {
return SettingThirdPartyLogin(didLogin: didLogin);
}
@ -284,6 +285,7 @@ class UserNameInputState extends State<UserNameInput> {
@override
void dispose() {
_controller.dispose();
_debounce?.cancel();
super.dispose();
}
}
@ -348,6 +350,7 @@ class UserEmailInputState extends State<UserEmailInput> {
@override
void dispose() {
_controller.dispose();
_debounce?.cancel();
super.dispose();
}
}

View File

@ -35,7 +35,7 @@ class AppFlowyUnitTest {
_pathProviderInitialized();
await FlowyRunner.run(
FlowyTestApp(),
AppFlowyApplicationUniTest(),
IntegrationMode.unitTest,
);
@ -111,7 +111,7 @@ void _pathProviderInitialized() {
});
}
class FlowyTestApp implements EntryPoint {
class AppFlowyApplicationUniTest implements EntryPoint {
@override
Widget create(LaunchConfiguration config) {
return Container();

View File

@ -139,7 +139,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"reqwest",
@ -786,7 +786,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -883,7 +883,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -902,7 +902,7 @@ dependencies = [
[[package]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -932,7 +932,7 @@ dependencies = [
[[package]]
name = "collab-derive"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"proc-macro2",
"quote",
@ -944,7 +944,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"collab",
@ -963,7 +963,7 @@ dependencies = [
[[package]]
name = "collab-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"bytes",
@ -977,7 +977,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"chrono",
@ -1019,7 +1019,7 @@ dependencies = [
[[package]]
name = "collab-persistence"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -1040,7 +1040,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -1066,7 +1066,7 @@ dependencies = [
[[package]]
name = "collab-user"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"collab",
@ -1471,7 +1471,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -2842,7 +2842,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"futures-util",
@ -2858,7 +2858,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -3280,7 +3280,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"reqwest",
@ -5040,7 +5040,7 @@ dependencies = [
[[package]]
name = "realtime-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"bincode",
@ -5062,7 +5062,7 @@ dependencies = [
[[package]]
name = "realtime-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"bincode",
@ -5809,7 +5809,7 @@ dependencies = [
[[package]]
name = "shared_entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -7699,7 +7699,7 @@ dependencies = [
[[package]]
name = "workspace-template"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"async-trait",

View File

@ -57,7 +57,7 @@ custom-protocol = ["tauri/custom-protocol"]
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1a16cec52e628e2fb7648455581d6fe5e84be1" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "80d4048c69a22c0af77b2f2e9b13b1004b2156e2" }
# Please use the following script to update collab.
# Working directory: frontend
#
@ -67,14 +67,14 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1
# To switch to the local path, run:
# scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }

View File

@ -125,7 +125,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"reqwest",
@ -667,7 +667,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -733,7 +733,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -752,7 +752,7 @@ dependencies = [
[[package]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -782,7 +782,7 @@ dependencies = [
[[package]]
name = "collab-derive"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"proc-macro2",
"quote",
@ -794,7 +794,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"collab",
@ -813,7 +813,7 @@ dependencies = [
[[package]]
name = "collab-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"bytes",
@ -827,7 +827,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"chrono",
@ -869,7 +869,7 @@ dependencies = [
[[package]]
name = "collab-persistence"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -890,7 +890,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"async-trait",
@ -916,7 +916,7 @@ dependencies = [
[[package]]
name = "collab-user"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869"
dependencies = [
"anyhow",
"collab",
@ -1277,7 +1277,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -2483,7 +2483,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"futures-util",
@ -2499,7 +2499,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -2860,7 +2860,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"reqwest",
@ -4329,7 +4329,7 @@ dependencies = [
[[package]]
name = "realtime-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"bincode",
@ -4351,7 +4351,7 @@ dependencies = [
[[package]]
name = "realtime-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"bincode",
@ -5020,7 +5020,7 @@ dependencies = [
[[package]]
name = "shared_entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"app-error",
@ -6401,7 +6401,7 @@ dependencies = [
[[package]]
name = "workspace-template"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
dependencies = [
"anyhow",
"async-trait",

View File

@ -99,7 +99,7 @@ incremental = false
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1a16cec52e628e2fb7648455581d6fe5e84be1" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "80d4048c69a22c0af77b2f2e9b13b1004b2156e2" }
# Please use the following script to update collab.
# Working directory: frontend
#
@ -109,11 +109,11 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1
# To switch to the local path, run:
# scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" }

View File

@ -7,7 +7,7 @@ edition = "2018"
[lib]
name = "dart_ffi"
# this value will change depending on the target os
# default staticlib
# default static library
crate-type = ["staticlib"]

View File

@ -8,7 +8,7 @@ use parking_lot::RwLock;
use flowy_core::config::AppFlowyCoreConfig;
use flowy_core::AppFlowyCore;
use flowy_notification::register_notification_sender;
use flowy_user::entities::AuthTypePB;
use flowy_user::entities::AuthenticatorPB;
use crate::user_event::TestNotificationSender;
@ -21,7 +21,7 @@ pub mod user_event;
#[derive(Clone)]
pub struct EventIntegrationTest {
pub auth_type: Arc<RwLock<AuthTypePB>>,
pub auth_type: Arc<RwLock<AuthenticatorPB>>,
pub inner: AppFlowyCore,
#[allow(dead_code)]
cleaner: Arc<Cleaner>,
@ -48,7 +48,7 @@ impl EventIntegrationTest {
let inner = init_core(config).await;
let notification_sender = TestNotificationSender::new();
let auth_type = Arc::new(RwLock::new(AuthTypePB::Local));
let auth_type = Arc::new(RwLock::new(AuthenticatorPB::Local));
register_notification_sender(notification_sender.clone());
std::mem::forget(inner.dispatcher());
Self {

View File

@ -15,7 +15,7 @@ use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_UR
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
use flowy_server_config::AuthenticatorType;
use flowy_user::entities::{
AuthTypePB, CloudSettingPB, OauthSignInPB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB,
AuthenticatorPB, CloudSettingPB, OauthSignInPB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB,
UpdateCloudConfigPB, UpdateUserProfilePayloadPB, UserProfilePB,
};
use flowy_user::errors::{FlowyError, FlowyResult};
@ -59,7 +59,7 @@ impl EventIntegrationTest {
email,
name: "appflowy".to_string(),
password: password.clone(),
auth_type: AuthTypePB::Local,
auth_type: AuthenticatorPB::Local,
device_id: uuid::Uuid::new_v4().to_string(),
}
.into_bytes()
@ -88,7 +88,7 @@ impl EventIntegrationTest {
let map = third_party_sign_up_param(Uuid::new_v4().to_string());
let payload = OauthSignInPB {
map,
auth_type: AuthTypePB::Supabase,
auth_type: AuthenticatorPB::Supabase,
};
EventBuilder::new(self.clone())
@ -106,7 +106,7 @@ impl EventIntegrationTest {
.await;
}
pub fn set_auth_type(&self, auth_type: AuthTypePB) {
pub fn set_auth_type(&self, auth_type: AuthenticatorPB) {
*self.auth_type.write() = auth_type;
}
@ -133,7 +133,7 @@ impl EventIntegrationTest {
pub async fn af_cloud_sign_in_with_email(&self, email: &str) -> FlowyResult<UserProfilePB> {
let payload = SignInUrlPayloadPB {
email: email.to_string(),
auth_type: AuthTypePB::AFCloud,
auth_type: AuthenticatorPB::AppFlowyCloud,
};
let sign_in_url = EventBuilder::new(self.clone())
.event(GenerateSignInURL)
@ -148,7 +148,7 @@ impl EventIntegrationTest {
map.insert(USER_DEVICE_ID.to_string(), Uuid::new_v4().to_string());
let payload = OauthSignInPB {
map,
auth_type: AuthTypePB::AFCloud,
auth_type: AuthenticatorPB::AppFlowyCloud,
};
let user_profile = EventBuilder::new(self.clone())
@ -175,7 +175,7 @@ impl EventIntegrationTest {
);
let payload = OauthSignInPB {
map,
auth_type: AuthTypePB::Supabase,
auth_type: AuthenticatorPB::Supabase,
};
let user_profile = EventBuilder::new(self.clone())

View File

@ -1,9 +1,7 @@
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use flowy_core::DEFAULT_NAME;
use flowy_user::entities::AuthTypePB;
use crate::util::{get_af_cloud_config, unzip_history_user_db};
use crate::util::unzip_history_user_db;
#[tokio::test]
async fn reading_039_anon_user_data_test() {
@ -36,70 +34,43 @@ async fn reading_039_anon_user_data_test() {
drop(cleaner);
}
#[tokio::test]
async fn anon_user_to_af_cloud_test() {
if get_af_cloud_config().is_none() {
return;
}
let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "039_local").unwrap();
user_localhost_af_cloud().await;
let test =
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
let anon_first_level_views = test.get_all_workspace_views().await;
let _anon_second_level_views = test
.get_views(&anon_first_level_views[0].id)
.await
.child_views;
let user = test.af_cloud_sign_up().await;
assert_eq!(user.auth_type, AuthTypePB::AFCloud);
// let mut sync_state = test
// .folder_manager
// .get_mutex_folder()
// .lock()
// .as_ref()
// .unwrap()
// .subscribe_sync_state();
//
// // TODO(nathan): will be removed when supporting merge FolderData
// // wait until the state is SyncFinished with 10 secs timeout
// loop {
// select! {
// _ = tokio::time::sleep(Duration::from_secs(10)) => {
// panic!("Timeout waiting for sync finished");
// }
// state = sync_state.next() => {
// if let Some(state) = &state {
// if state == &SyncState::SyncFinished {
// break;
// }
// }
// }
// }
// }
//
// let user_first_level_views = test.get_all_workspace_views().await;
// let user_second_level_views = test
// .get_views(&user_first_level_views[1].id)
// .await
// .child_views;
//
// // first
// assert_eq!(anon_first_level_views.len(), 1);
// assert_eq!(user_first_level_views.len(), 2);
// assert_eq!(
// anon_first_level_views[0].name,
// // The first one is the get started document
// user_first_level_views[1].name
// );
// assert_ne!(anon_first_level_views[0].id, user_first_level_views[1].id);
//
// // second
// assert_eq!(anon_second_level_views.len(), user_second_level_views.len());
// assert_eq!(
// anon_second_level_views[0].name,
// user_second_level_views[0].name
// );
// assert_ne!(anon_second_level_views[0].id, user_second_level_views[0].id);
drop(cleaner);
}
// #[tokio::test]
// async fn migrate_anon_user_data_to_af_cloud_test() {
// let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "039_local").unwrap();
// user_localhost_af_cloud().await;
// let test =
// EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
// let anon_first_level_views = test.get_all_workspace_views().await;
// let anon_second_level_views = test
// .get_views(&anon_first_level_views[0].id)
// .await
// .child_views;
//
// // The anon user data will be migrated to the AppFlowy cloud after sign up
// let user = test.af_cloud_sign_up().await;
// assert_eq!(user.authenticator, AuthenticatorPB::AppFlowyCloud);
//
// let user_first_level_views = test.get_all_workspace_views().await;
// let user_second_level_views = test
// .get_views(&user_first_level_views[0].id)
// .await
// .child_views;
//
// // first
// assert_eq!(anon_first_level_views.len(), 1);
// assert_eq!(user_first_level_views.len(), 1);
// assert_eq!(
// anon_first_level_views[0].name,
// user_first_level_views[0].name
// );
// assert_ne!(anon_first_level_views[0].id, user_first_level_views[0].id);
//
// // second
// assert_eq!(anon_second_level_views.len(), user_second_level_views.len());
// assert_eq!(
// anon_second_level_views[0].name,
// user_second_level_views[0].name
// );
// assert_ne!(anon_second_level_views[0].id, user_second_level_views[0].id);
// drop(cleaner);
// }

View File

@ -1,6 +1,6 @@
use event_integration::user_event::{login_password, unique_email};
use event_integration::{event_builder::EventBuilder, EventIntegrationTest};
use flowy_user::entities::{AuthTypePB, SignInPayloadPB, SignUpPayloadPB};
use flowy_user::entities::{AuthenticatorPB, SignInPayloadPB, SignUpPayloadPB};
use flowy_user::errors::ErrorCode;
use flowy_user::event_map::UserEvent::*;
@ -14,7 +14,7 @@ async fn sign_up_with_invalid_email() {
email: email.to_string(),
name: valid_name(),
password: login_password(),
auth_type: AuthTypePB::Local,
auth_type: AuthenticatorPB::Local,
device_id: "".to_string(),
};
@ -38,7 +38,7 @@ async fn sign_up_with_long_password() {
email: unique_email(),
name: valid_name(),
password: "1234".repeat(100).as_str().to_string(),
auth_type: AuthTypePB::Local,
auth_type: AuthenticatorPB::Local,
device_id: "".to_string(),
};
@ -63,7 +63,7 @@ async fn sign_in_with_invalid_email() {
email: email.to_string(),
password: login_password(),
name: "".to_string(),
auth_type: AuthTypePB::Local,
auth_type: AuthenticatorPB::Local,
device_id: "".to_string(),
};
@ -90,7 +90,7 @@ async fn sign_in_with_invalid_password() {
email: unique_email(),
password,
name: "".to_string(),
auth_type: AuthTypePB::Local,
auth_type: AuthenticatorPB::Local,
device_id: "".to_string(),
};

View File

@ -1,7 +1,7 @@
use nanoid::nanoid;
use event_integration::{event_builder::EventBuilder, EventIntegrationTest};
use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB, UserProfilePB};
use flowy_user::entities::{AuthenticatorPB, UpdateUserProfilePayloadPB, UserProfilePB};
use flowy_user::{errors::ErrorCode, event_map::UserEvent::*};
use crate::user::local_test::helper::*;
@ -32,7 +32,7 @@ async fn anon_user_profile_get() {
assert_eq!(user_profile.openai_key, user.openai_key);
assert_eq!(user_profile.stability_ai_key, user.stability_ai_key);
assert_eq!(user_profile.workspace_id, user.workspace_id);
assert_eq!(user_profile.auth_type, AuthTypePB::Local);
assert_eq!(user_profile.authenticator, AuthenticatorPB::Local);
}
#[tokio::test]

View File

@ -14,7 +14,9 @@ use event_integration::EventIntegrationTest;
use flowy_core::DEFAULT_NAME;
use flowy_encrypt::decrypt_text;
use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_UUID};
use flowy_user::entities::{AuthTypePB, OauthSignInPB, UpdateUserProfilePayloadPB, UserProfilePB};
use flowy_user::entities::{
AuthenticatorPB, OauthSignInPB, UpdateUserProfilePayloadPB, UserProfilePB,
};
use flowy_user::errors::ErrorCode;
use flowy_user::event_map::UserEvent::*;
@ -33,7 +35,7 @@ async fn third_party_sign_up_test() {
map.insert(USER_DEVICE_ID.to_string(), uuid::Uuid::new_v4().to_string());
let payload = OauthSignInPB {
map,
auth_type: AuthTypePB::Supabase,
auth_type: AuthenticatorPB::Supabase,
};
let response = EventBuilder::new(test.clone())
@ -77,7 +79,7 @@ async fn third_party_sign_up_with_duplicated_uuid() {
.event(OauthSignIn)
.payload(OauthSignInPB {
map: map.clone(),
auth_type: AuthTypePB::Supabase,
auth_type: AuthenticatorPB::Supabase,
})
.async_send()
.await
@ -88,7 +90,7 @@ async fn third_party_sign_up_with_duplicated_uuid() {
.event(OauthSignIn)
.payload(OauthSignInPB {
map: map.clone(),
auth_type: AuthTypePB::Supabase,
auth_type: AuthenticatorPB::Supabase,
})
.async_send()
.await

View File

@ -4,7 +4,7 @@ use event_integration::{event_builder::EventBuilder, EventIntegrationTest};
use flowy_folder2::entities::WorkspaceSettingPB;
use flowy_folder2::event_map::FolderEvent::GetCurrentWorkspaceSetting;
use flowy_server::supabase::define::{USER_EMAIL, USER_UUID};
use flowy_user::entities::{AuthTypePB, OauthSignInPB, UserProfilePB};
use flowy_user::entities::{AuthenticatorPB, OauthSignInPB, UserProfilePB};
use flowy_user::event_map::UserEvent::*;
use crate::util::*;
@ -21,7 +21,7 @@ async fn initial_workspace_test() {
);
let payload = OauthSignInPB {
map,
auth_type: AuthTypePB::Supabase,
auth_type: AuthenticatorPB::Supabase,
};
let _ = EventBuilder::new(test.clone())

View File

@ -23,7 +23,7 @@ use flowy_server::supabase::api::*;
use flowy_server::{AppFlowyEncryption, EncryptionImpl};
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
use flowy_server_config::supabase_config::SupabaseConfiguration;
use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB};
use flowy_user::entities::{AuthenticatorPB, UpdateUserProfilePayloadPB};
use flowy_user::errors::FlowyError;
use flowy_user::event_map::UserCloudServiceProvider;
use flowy_user::event_map::UserEvent::*;
@ -43,7 +43,7 @@ impl FlowySupabaseTest {
pub async fn new() -> Option<Self> {
let _ = get_supabase_config()?;
let test = EventIntegrationTest::new().await;
test.set_auth_type(AuthTypePB::Supabase);
test.set_auth_type(AuthenticatorPB::Supabase);
test
.server_provider
.set_authenticator(Authenticator::Supabase);
@ -210,7 +210,7 @@ impl AFCloudTest {
pub async fn new() -> Option<Self> {
let _ = get_af_cloud_config()?;
let test = EventIntegrationTest::new().await;
test.set_auth_type(AuthTypePB::AFCloud);
test.set_auth_type(AuthenticatorPB::AppFlowyCloud);
test
.server_provider
.set_authenticator(Authenticator::AppFlowyCloud);

View File

@ -22,25 +22,25 @@ pub(crate) const SERVER_PROVIDER_TYPE_KEY: &str = "server_provider_type";
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum ServerType {
pub enum Server {
/// Local server provider.
/// Offline mode, no user authentication and the data is stored locally.
Local = 0,
/// AppFlowy Cloud server provider.
/// The [AppFlowy-Server](https://github.com/AppFlowy-IO/AppFlowy-Cloud) is still a work in
/// progress.
AFCloud = 1,
AppFlowyCloud = 1,
/// Supabase server provider.
/// It uses supabase postgresql database to store data and user authentication.
Supabase = 2,
}
impl Display for ServerType {
impl Display for Server {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ServerType::Local => write!(f, "Local"),
ServerType::AFCloud => write!(f, "AppFlowyCloud"),
ServerType::Supabase => write!(f, "Supabase"),
Server::Local => write!(f, "Local"),
Server::AppFlowyCloud => write!(f, "AppFlowyCloud"),
Server::Supabase => write!(f, "Supabase"),
}
}
}
@ -51,8 +51,8 @@ impl Display for ServerType {
/// Each server implements the [AppFlowyServer] trait, which provides the [UserCloudService], etc.
pub struct ServerProvider {
config: AppFlowyCoreConfig,
server_type: RwLock<ServerType>,
providers: RwLock<HashMap<ServerType, Arc<dyn AppFlowyServer>>>,
server: RwLock<Server>,
providers: RwLock<HashMap<Server, Arc<dyn AppFlowyServer>>>,
pub(crate) encryption: RwLock<Arc<dyn AppFlowyEncryption>>,
pub(crate) store_preferences: Weak<StorePreferences>,
pub(crate) enable_sync: RwLock<bool>,
@ -62,13 +62,13 @@ pub struct ServerProvider {
impl ServerProvider {
pub fn new(
config: AppFlowyCoreConfig,
server_type: ServerType,
server: Server,
store_preferences: Weak<StorePreferences>,
) -> Self {
let encryption = EncryptionImpl::new(None);
Self {
config,
server_type: RwLock::new(server_type),
server: RwLock::new(server),
providers: RwLock::new(HashMap::new()),
enable_sync: RwLock::new(true),
encryption: RwLock::new(Arc::new(encryption)),
@ -77,37 +77,34 @@ impl ServerProvider {
}
}
pub fn get_server_type(&self) -> ServerType {
self.server_type.read().clone()
pub fn get_server_type(&self) -> Server {
self.server.read().clone()
}
pub fn set_server_type(&self, server_type: ServerType) {
let old_server_type = self.server_type.read().clone();
pub fn set_server_type(&self, server_type: Server) {
let old_server_type = self.server.read().clone();
if server_type != old_server_type {
self.providers.write().remove(&old_server_type);
}
*self.server_type.write() = server_type;
*self.server.write() = server_type;
}
/// Returns a [AppFlowyServer] trait implementation base on the provider_type.
pub(crate) fn get_server(
&self,
server_type: &ServerType,
) -> FlowyResult<Arc<dyn AppFlowyServer>> {
pub(crate) fn get_server(&self, server_type: &Server) -> FlowyResult<Arc<dyn AppFlowyServer>> {
if let Some(provider) = self.providers.read().get(server_type) {
return Ok(provider.clone());
}
let server = match server_type {
ServerType::Local => {
Server::Local => {
let local_db = Arc::new(LocalServerDBImpl {
storage_path: self.config.storage_path.clone(),
});
let server = Arc::new(LocalServer::new(local_db));
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
},
ServerType::AFCloud => {
Server::AppFlowyCloud => {
let config = AFCloudConfiguration::from_env()?;
let server = Arc::new(AppFlowyCloudServer::new(
config,
@ -117,7 +114,7 @@ impl ServerProvider {
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
},
ServerType::Supabase => {
Server::Supabase => {
let config = SupabaseConfiguration::from_env()?;
let uid = self.uid.clone();
tracing::trace!("🔑Supabase config: {:?}", config);
@ -140,36 +137,35 @@ impl ServerProvider {
}
}
impl From<Authenticator> for ServerType {
impl From<Authenticator> for Server {
fn from(auth_provider: Authenticator) -> Self {
match auth_provider {
Authenticator::Local => ServerType::Local,
Authenticator::AppFlowyCloud => ServerType::AFCloud,
Authenticator::Supabase => ServerType::Supabase,
Authenticator::Local => Server::Local,
Authenticator::AppFlowyCloud => Server::AppFlowyCloud,
Authenticator::Supabase => Server::Supabase,
}
}
}
impl From<ServerType> for Authenticator {
fn from(ty: ServerType) -> Self {
impl From<Server> for Authenticator {
fn from(ty: Server) -> Self {
match ty {
ServerType::Local => Authenticator::Local,
ServerType::AFCloud => Authenticator::AppFlowyCloud,
ServerType::Supabase => Authenticator::Supabase,
Server::Local => Authenticator::Local,
Server::AppFlowyCloud => Authenticator::AppFlowyCloud,
Server::Supabase => Authenticator::Supabase,
}
}
}
impl From<&Authenticator> for ServerType {
impl From<&Authenticator> for Server {
fn from(auth_provider: &Authenticator) -> Self {
Self::from(auth_provider.clone())
}
}
pub fn current_server_type(store_preferences: &Arc<StorePreferences>) -> ServerType {
match store_preferences.get_object::<ServerType>(SERVER_PROVIDER_TYPE_KEY) {
None => ServerType::Local,
Some(provider_type) => provider_type,
}
pub fn current_server_type(store_preferences: &Arc<StorePreferences>) -> Server {
store_preferences
.get_object::<Server>(SERVER_PROVIDER_TYPE_KEY)
.unwrap_or(Server::Local)
}
struct LocalServerDBImpl {

View File

@ -30,7 +30,7 @@ use flowy_user_deps::cloud::UserCloudService;
use flowy_user_deps::entities::{Authenticator, UserTokenState};
use lib_infra::future::{to_fut, Fut, FutureResult};
use crate::integrate::server::{ServerProvider, ServerType, SERVER_PROVIDER_TYPE_KEY};
use crate::integrate::server::{Server, ServerProvider, SERVER_PROVIDER_TYPE_KEY};
impl FileStorageService for ServerProvider {
fn create_object(&self, object: StorageObject) -> FutureResult<String, FlowyError> {
@ -91,12 +91,12 @@ impl UserCloudServiceProvider for ServerProvider {
/// When user login, the provider type is set by the [Authenticator] and save to disk for next use.
///
/// Each [Authenticator] has a corresponding [ServerType]. The [ServerType] is used
/// to create a new [AppFlowyServer] if it doesn't exist. Once the [ServerType] is set,
/// Each [Authenticator] has a corresponding [Server]. The [Server] is used
/// to create a new [AppFlowyServer] if it doesn't exist. Once the [Server] is set,
/// it will be used when user open the app again.
///
fn set_authenticator(&self, authenticator: Authenticator) {
let server_type: ServerType = authenticator.into();
let server_type: Server = authenticator.into();
self.set_server_type(server_type.clone());
match self.store_preferences.upgrade() {
@ -117,7 +117,7 @@ impl UserCloudServiceProvider for ServerProvider {
Authenticator::from(server_type)
}
/// Returns the [UserCloudService] base on the current [ServerType].
/// Returns the [UserCloudService] base on the current [Server].
/// Creates a new [AppFlowyServer] if it doesn't exist.
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError> {
let server_type = self.get_server_type();
@ -127,11 +127,11 @@ impl UserCloudServiceProvider for ServerProvider {
fn service_url(&self) -> String {
match self.get_server_type() {
ServerType::Local => "".to_string(),
ServerType::AFCloud => AFCloudConfiguration::from_env()
Server::Local => "".to_string(),
Server::AppFlowyCloud => AFCloudConfiguration::from_env()
.map(|config| config.base_url)
.unwrap_or_default(),
ServerType::Supabase => SupabaseConfiguration::from_env()
Server::Supabase => SupabaseConfiguration::from_env()
.map(|config| config.url)
.unwrap_or_default(),
}
@ -325,7 +325,7 @@ impl CollabStorageProvider for ServerProvider {
collab_object,
local_collab,
} => {
if let Ok(server) = self.get_server(&ServerType::AFCloud) {
if let Ok(server) = self.get_server(&Server::AppFlowyCloud) {
to_fut(async move {
let mut plugins: Vec<Arc<dyn CollabPlugin>> = vec![];
match server.collab_ws_channel(&collab_object.object_id).await {
@ -373,7 +373,7 @@ impl CollabStorageProvider for ServerProvider {
} => {
let mut plugins: Vec<Arc<dyn CollabPlugin>> = vec![];
if let Some(remote_collab_storage) = self
.get_server(&ServerType::Supabase)
.get_server(&Server::Supabase)
.ok()
.and_then(|provider| provider.collab_storage(&collab_object))
{

View File

@ -26,7 +26,7 @@ use crate::deps_resolve::collab_backup::RocksdbBackupImpl;
use crate::deps_resolve::*;
use crate::integrate::collab_interact::CollabInteractImpl;
use crate::integrate::log::init_log;
use crate::integrate::server::{current_server_type, ServerProvider, ServerType};
use crate::integrate::server::{current_server_type, Server, ServerProvider};
use crate::integrate::user::UserStatusCallbackImpl;
pub mod config;
@ -232,12 +232,12 @@ fn init_user_manager(
)
}
impl From<ServerType> for CollabDataSource {
fn from(server_type: ServerType) -> Self {
impl From<Server> for CollabDataSource {
fn from(server_type: Server) -> Self {
match server_type {
ServerType::Local => CollabDataSource::Local,
ServerType::AFCloud => CollabDataSource::AppFlowyCloud,
ServerType::Supabase => CollabDataSource::Supabase,
Server::Local => CollabDataSource::Local,
Server::AppFlowyCloud => CollabDataSource::AppFlowyCloud,
Server::Supabase => CollabDataSource::Supabase,
}
}
}

View File

@ -5,7 +5,6 @@ use collab_document::blocks::DocumentData;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use tracing::trace;
use validator::ValidationError;
pub fn get_delta_for_block(block_id: &str, data: &DocumentData) -> Option<Vec<InsertDelta>> {

View File

@ -47,9 +47,6 @@ pub struct FolderManager {
pub cloud_service: Arc<dyn FolderCloudService>,
}
unsafe impl Send for FolderManager {}
unsafe impl Sync for FolderManager {}
impl FolderManager {
pub async fn new(
user: Arc<dyn FolderUser>,
@ -1012,8 +1009,8 @@ impl FolderManager {
/// Return the views that belong to the workspace. The views are filtered by the trash.
pub(crate) fn get_workspace_view_pbs(_workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
let trash_ids = folder
.get_all_trash()
let items = folder.get_all_trash();
let trash_ids = items
.into_iter()
.map(|trash| trash.id)
.collect::<Vec<String>>();

View File

@ -37,10 +37,10 @@ impl FolderManager {
let collab_db = self.user.collab_db(uid)?;
let (view_tx, view_rx) = tokio::sync::broadcast::channel(100);
let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100);
let (section_change_tx, section_change_rx) = tokio::sync::broadcast::channel(100);
let folder_notifier = FolderNotify {
view_change_tx: view_tx,
trash_change_tx: trash_tx,
section_change_tx,
};
let folder = match initial_data {
@ -99,7 +99,7 @@ impl FolderManager {
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder);
subscribe_folder_snapshot_state_changed(workspace_id, &weak_mutex_folder);
subscribe_folder_trash_changed(trash_rx, &weak_mutex_folder);
subscribe_folder_trash_changed(section_change_rx, &weak_mutex_folder);
subscribe_folder_view_changed(view_rx, &weak_mutex_folder);
Ok(())
}

View File

@ -3,7 +3,8 @@ use std::sync::{Arc, Weak};
use collab::core::collab_state::SyncState;
use collab_folder::{
Folder, TrashChange, TrashChangeReceiver, View, ViewChange, ViewChangeReceiver,
Folder, SectionChange, SectionChangeReceiver, TrashSectionChange, View, ViewChange,
ViewChangeReceiver,
};
use tokio_stream::wrappers::WatchStream;
use tokio_stream::StreamExt;
@ -102,7 +103,7 @@ pub(crate) fn subscribe_folder_sync_state_changed(
/// Listen on the [TrashChange]s and notify the frontend some views were changed.
pub(crate) fn subscribe_folder_trash_changed(
mut rx: TrashChangeReceiver,
mut rx: SectionChangeReceiver,
weak_mutex_folder: &Weak<MutexFolder>,
) {
let weak_mutex_folder = weak_mutex_folder.clone();
@ -111,25 +112,29 @@ pub(crate) fn subscribe_folder_trash_changed(
if let Some(folder) = weak_mutex_folder.upgrade() {
let mut unique_ids = HashSet::new();
tracing::trace!("Did receive trash change: {:?}", value);
let ids = match value {
TrashChange::DidCreateTrash { ids } => ids,
TrashChange::DidDeleteTrash { ids } => ids,
};
if let Some(folder) = folder.lock().as_ref() {
let views = folder.views.get_views(&ids);
for view in views {
unique_ids.insert(view.parent_view_id.clone());
}
match value {
SectionChange::Trash(change) => {
let ids = match change {
TrashSectionChange::TrashItemAdded { ids } => ids,
TrashSectionChange::TrashItemRemoved { ids } => ids,
};
if let Some(folder) = folder.lock().as_ref() {
let views = folder.views.get_views(&ids);
for view in views {
unique_ids.insert(view.parent_view_id.clone());
}
let repeated_trash: RepeatedTrashPB = folder.get_all_trash().into();
send_notification("trash", FolderNotification::DidUpdateTrash)
.payload(repeated_trash)
.send();
let repeated_trash: RepeatedTrashPB = folder.get_all_trash().into();
send_notification("trash", FolderNotification::DidUpdateTrash)
.payload(repeated_trash)
.send();
}
let parent_view_ids = unique_ids.into_iter().collect();
notify_parent_view_did_change(folder.clone(), parent_view_ids);
},
}
let parent_view_ids = unique_ids.into_iter().collect();
notify_parent_view_did_change(folder.clone(), parent_view_ids);
}
}
});

View File

@ -54,6 +54,7 @@ impl DefaultFolderBuilder {
views: FlattedViews::flatten_views(views),
favorites: Default::default(),
recent: Default::default(),
trash: Default::default(),
}
}
}

View File

@ -1,6 +1,6 @@
use anyhow::Error;
use client_api::entity::QueryCollabResult::{Failed, Success};
use client_api::entity::{BatchQueryCollab, BatchQueryCollabParams, QueryCollabParams};
use client_api::entity::{QueryCollab, QueryCollabParams};
use client_api::error::ErrorCode::RecordNotFound;
use collab::core::collab_plugin::EncodedCollabV1;
use collab_entity::CollabType;
@ -31,8 +31,10 @@ where
FutureResult::new(async move {
let params = QueryCollabParams {
workspace_id,
object_id,
collab_type,
inner: QueryCollab {
object_id,
collab_type,
},
};
match try_get_client?.get_collab(params).await {
Ok(data) => Ok(vec![data.doc_state.to_vec()]),
@ -57,15 +59,13 @@ where
let try_get_client = self.0.try_get_client();
FutureResult::new(async move {
let client = try_get_client?;
let params = BatchQueryCollabParams(
object_ids
.into_iter()
.map(|object_id| BatchQueryCollab {
object_id,
collab_type: object_ty.clone(),
})
.collect(),
);
let params = object_ids
.into_iter()
.map(|object_id| QueryCollab {
object_id,
collab_type: object_ty.clone(),
})
.collect();
let results = client.batch_get_collab(&workspace_id, params).await?;
Ok(
results

View File

@ -1,5 +1,5 @@
use anyhow::Error;
use client_api::entity::QueryCollabParams;
use client_api::entity::{QueryCollab, QueryCollabParams};
use collab::core::origin::CollabOrigin;
use collab_document::document::Document;
use collab_entity::CollabType;
@ -27,8 +27,10 @@ where
FutureResult::new(async move {
let params = QueryCollabParams {
workspace_id,
object_id: document_id.to_string(),
collab_type: CollabType::Document,
inner: QueryCollab {
object_id: document_id.to_string(),
collab_type: CollabType::Document,
},
};
let data = try_get_client?
.get_collab(params)
@ -60,8 +62,10 @@ where
FutureResult::new(async move {
let params = QueryCollabParams {
workspace_id,
object_id: document_id.clone(),
collab_type: CollabType::Document,
inner: QueryCollab {
object_id: document_id.clone(),
collab_type: CollabType::Document,
},
};
let doc_state = try_get_client?
.get_collab(params)

View File

@ -1,5 +1,5 @@
use anyhow::{anyhow, Error};
use client_api::entity::QueryCollabParams;
use client_api::entity::{QueryCollab, QueryCollabParams};
use collab::core::origin::CollabOrigin;
use collab_entity::CollabType;
@ -60,9 +60,11 @@ where
let try_get_client = self.0.try_get_client();
FutureResult::new(async move {
let params = QueryCollabParams {
object_id: workspace_id.clone(),
workspace_id: workspace_id.clone(),
collab_type: CollabType::Folder,
inner: QueryCollab {
object_id: workspace_id.clone(),
collab_type: CollabType::Folder,
},
};
let doc_state = try_get_client?
.get_collab(params)
@ -98,9 +100,11 @@ where
let try_get_client = self.0.try_get_client();
FutureResult::new(async move {
let params = QueryCollabParams {
object_id: workspace_id.clone(),
workspace_id,
collab_type: CollabType::Folder,
workspace_id: workspace_id.clone(),
inner: QueryCollab {
object_id: workspace_id,
collab_type: CollabType::Folder,
},
};
let doc_state = try_get_client?
.get_collab(params)

View File

@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::{anyhow, Error};
use client_api::entity::workspace_dto::{CreateWorkspaceMember, WorkspaceMemberChangeset};
use client_api::entity::{AFRole, AFWorkspace, AuthProvider, InsertCollabParams};
use client_api::entity::{AFRole, AFWorkspace, AuthProvider, CollabParams, CreateCollabParams};
use collab_entity::CollabObject;
use parking_lot::RwLock;
@ -231,16 +231,20 @@ where
&self,
collab_object: &CollabObject,
data: Vec<u8>,
override_if_exist: bool,
) -> FutureResult<(), Error> {
let try_get_client = self.server.try_get_client();
let collab_object = collab_object.clone();
FutureResult::new(async move {
let client = try_get_client?;
let params = InsertCollabParams::new(
collab_object.object_id.clone(),
collab_object.collab_type.clone(),
data,
let params = CreateCollabParams::new(
collab_object.workspace_id.clone(),
CollabParams {
object_id: collab_object.object_id.clone(),
encoded_collab_v1: data,
collab_type: collab_object.collab_type.clone(),
override_if_exist,
},
);
client.create_collab(params).await?;
Ok(())

View File

@ -141,6 +141,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
&self,
_collab_object: &CollabObject,
_data: Vec<u8>,
_override_if_exist: bool,
) -> FutureResult<(), Error> {
FutureResult::new(async { Ok(()) })
}

View File

@ -98,12 +98,10 @@ where
// Query the user profile and workspaces
tracing::debug!("user uuid: {}", params.uuid);
let user_profile = get_user_profile(
postgrest.clone(),
GetUserProfileParams::Uuid(params.uuid.clone()),
)
.await?
.unwrap();
let user_profile =
get_user_profile(postgrest.clone(), GetUserProfileParams::Uuid(params.uuid))
.await?
.unwrap();
let user_workspaces = get_user_workspaces(postgrest.clone(), user_profile.uid).await?;
let latest_workspace = user_workspaces
.iter()
@ -137,7 +135,7 @@ where
FutureResult::new(async move {
let postgrest = try_get_postgrest?;
let params = oauth_params_from_box_any(params)?;
let uuid = params.uuid.clone();
let uuid = params.uuid;
let response = get_user_profile(postgrest.clone(), GetUserProfileParams::Uuid(uuid))
.await?
.unwrap();
@ -311,7 +309,8 @@ where
fn create_collab_object(
&self,
collab_object: &CollabObject,
update: Vec<u8>,
data: Vec<u8>,
_override_if_exist: bool,
) -> FutureResult<(), Error> {
let try_get_postgrest = self.server.try_get_weak_postgrest();
let cloned_collab_object = collab_object.clone();
@ -319,7 +318,7 @@ where
af_spawn(async move {
tx.send(
async move {
CreateCollabAction::new(cloned_collab_object, try_get_postgrest?, update)
CreateCollabAction::new(cloned_collab_object, try_get_postgrest?, data)
.run()
.await?;
Ok(())

View File

@ -141,6 +141,7 @@ pub trait UserCloudService: Send + Sync + 'static {
&self,
collab_object: &CollabObject,
data: Vec<u8>,
override_if_exist: bool,
) -> FutureResult<(), Error>;
}

View File

@ -17,6 +17,7 @@ use parking_lot::{Mutex, RwLock};
use collab_integrate::{PersistenceError, RocksCollabDB, YrsDocAction};
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_folder_deps::cloud::gen_view_id;
use flowy_user_deps::entities::Authenticator;
use crate::migrations::MigrationUser;
@ -27,6 +28,7 @@ pub fn migration_anon_user_on_sign_up(
old_collab_db: &Arc<RocksCollabDB>,
new_user: &MigrationUser,
new_collab_db: &Arc<RocksCollabDB>,
authenticator: &Authenticator,
) -> FlowyResult<()> {
new_collab_db
.with_write_txn(|new_collab_w_txn| {
@ -72,6 +74,7 @@ pub fn migration_anon_user_on_sign_up(
&old_collab_r_txn,
new_user,
new_collab_w_txn,
authenticator,
)?;
// Migrate other collab objects
@ -191,6 +194,7 @@ fn migrate_workspace_folder<'a, 'b, W>(
old_collab_r_txn: &'b W,
new_user: &MigrationUser,
new_collab_w_txn: &'a W,
_authenticator: &Authenticator,
) -> Result<(), PersistenceError>
where
'a: 'b,
@ -206,9 +210,9 @@ where
old_folder_collab.with_origin_transact_mut(|txn| {
old_collab_r_txn.load_doc_with_txn(old_uid, old_workspace_id, txn)
})?;
let oid_user_id = UserId::from(old_uid);
let old_user_id = UserId::from(old_uid);
let old_folder = Folder::open(
oid_user_id,
old_user_id.clone(),
Arc::new(MutexCollab::from_collab(old_folder_collab)),
None,
)
@ -219,6 +223,41 @@ where
"Can't migrate the folder data"
)))?;
if let Some(old_fav_map) = folder_data.favorites.remove(&old_user_id) {
let fav_map = old_fav_map
.into_iter()
.map(|mut item| {
let new_view_id = old_to_new_id_map.get_new_id(&item.id);
item.id = new_view_id;
item
})
.collect();
folder_data.favorites.insert(UserId::from(new_uid), fav_map);
}
if let Some(old_trash_map) = folder_data.trash.remove(&old_user_id) {
let trash_map = old_trash_map
.into_iter()
.map(|mut item| {
let new_view_id = old_to_new_id_map.get_new_id(&item.id);
item.id = new_view_id;
item
})
.collect();
folder_data.trash.insert(UserId::from(new_uid), trash_map);
}
if let Some(old_recent_map) = folder_data.recent.remove(&old_user_id) {
let recent_map = old_recent_map
.into_iter()
.map(|mut item| {
let new_view_id = old_to_new_id_map.get_new_id(&item.id);
item.id = new_view_id;
item
})
.collect();
folder_data.recent.insert(UserId::from(new_uid), recent_map);
}
old_to_new_id_map
.0
.insert(old_workspace_id.to_string(), new_workspace_id.to_string());

View File

@ -109,7 +109,7 @@ fn sync_view(
encode_v1.len()
);
user_service
.create_collab_object(&collab_object, encode_v1)
.create_collab_object(&collab_object, encode_v1, false)
.await?;
},
ViewLayout::Grid | ViewLayout::Board | ViewLayout::Calendar => {
@ -121,7 +121,7 @@ fn sync_view(
database_encode_v1.len()
);
user_service
.create_collab_object(&collab_object, database_encode_v1)
.create_collab_object(&collab_object, database_encode_v1, false)
.await?;
// sync database's row
@ -145,7 +145,7 @@ fn sync_view(
);
let _ = user_service
.create_collab_object(&database_row_collab_object, database_row_encode_v1)
.create_collab_object(&database_row_collab_object, database_row_encode_v1, false)
.await;
let database_row_document = CollabObject::new(
@ -165,7 +165,7 @@ fn sync_view(
document_encode_v1.len()
);
let _ = user_service
.create_collab_object(&database_row_document, document_encode_v1)
.create_collab_object(&database_row_document, document_encode_v1, false)
.await;
}
}
@ -271,7 +271,7 @@ async fn sync_folder(
encode_v1.len()
);
if let Err(err) = user_service
.create_collab_object(&collab_object, encode_v1)
.create_collab_object(&collab_object, encode_v1, true)
.await
{
tracing::error!("🔴sync folder failed: {:?}", err);
@ -316,7 +316,7 @@ async fn sync_database_views(
if let Ok((records, encode_v1)) = result {
if let Ok(encode_v1) = encode_v1 {
let _ = user_service
.create_collab_object(&collab_object, encode_v1)
.create_collab_object(&collab_object, encode_v1, false)
.await;
}

View File

@ -109,7 +109,7 @@ fn sync_view(
doc_state.len()
);
user_service
.create_collab_object(&collab_object, doc_state)
.create_collab_object(&collab_object, doc_state, false)
.await?;
},
ViewLayout::Grid | ViewLayout::Board | ViewLayout::Calendar => {
@ -121,7 +121,7 @@ fn sync_view(
database_doc_state.len()
);
user_service
.create_collab_object(&collab_object, database_doc_state)
.create_collab_object(&collab_object, database_doc_state, false)
.await?;
// sync database's row
@ -145,7 +145,7 @@ fn sync_view(
);
let _ = user_service
.create_collab_object(&database_row_collab_object, database_row_doc_state)
.create_collab_object(&database_row_collab_object, database_row_doc_state, false)
.await;
let database_row_document = CollabObject::new(
@ -165,7 +165,7 @@ fn sync_view(
document_doc_state.len()
);
let _ = user_service
.create_collab_object(&database_row_document, document_doc_state)
.create_collab_object(&database_row_document, document_doc_state, false)
.await;
}
}
@ -281,7 +281,7 @@ async fn sync_folder(
update.len()
);
if let Err(err) = user_service
.create_collab_object(&collab_object, update.to_vec())
.create_collab_object(&collab_object, update.to_vec(), false)
.await
{
tracing::error!("🔴sync folder failed: {:?}", err);
@ -325,7 +325,7 @@ async fn sync_database_views(
if let Ok((records, doc_state)) = result {
let _ = user_service
.create_collab_object(&collab_object, doc_state.to_vec())
.create_collab_object(&collab_object, doc_state.to_vec(), false)
.await;
records.into_iter().map(Arc::new).collect()
} else {

View File

@ -19,7 +19,7 @@ pub struct SignInPayloadPB {
pub name: String,
#[pb(index = 4)]
pub auth_type: AuthTypePB,
pub auth_type: AuthenticatorPB,
#[pb(index = 5)]
pub device_id: String,
@ -53,7 +53,7 @@ pub struct SignUpPayloadPB {
pub password: String,
#[pb(index = 4)]
pub auth_type: AuthTypePB,
pub auth_type: AuthenticatorPB,
#[pb(index = 5)]
pub device_id: String,
@ -88,7 +88,7 @@ pub struct OauthSignInPB {
pub map: HashMap<String, String>,
#[pb(index = 2)]
pub auth_type: AuthTypePB,
pub auth_type: AuthenticatorPB,
}
#[derive(ProtoBuf, Default)]
@ -97,7 +97,7 @@ pub struct SignInUrlPayloadPB {
pub email: String,
#[pb(index = 2)]
pub auth_type: AuthTypePB,
pub auth_type: AuthenticatorPB,
}
#[derive(ProtoBuf, Default)]
@ -173,13 +173,13 @@ pub struct OauthProviderDataPB {
}
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
pub enum AuthTypePB {
pub enum AuthenticatorPB {
Local = 0,
Supabase = 1,
AFCloud = 2,
AppFlowyCloud = 2,
}
impl Default for AuthTypePB {
impl Default for AuthenticatorPB {
fn default() -> Self {
Self::Local
}
@ -232,7 +232,7 @@ impl From<UserCredentialsPB> for UserCredentials {
#[derive(Default, ProtoBuf)]
pub struct UserStatePB {
#[pb(index = 1)]
pub auth_type: AuthTypePB,
pub auth_type: AuthenticatorPB,
}
#[derive(ProtoBuf, Debug, Default, Clone)]

View File

@ -7,7 +7,7 @@ use flowy_user_deps::entities::*;
use crate::entities::parser::{UserEmail, UserIcon, UserName, UserOpenaiKey, UserPassword};
use crate::entities::required_not_empty_str;
use crate::entities::AuthTypePB;
use crate::entities::AuthenticatorPB;
use crate::errors::ErrorCode;
use super::parser::UserStabilityAIKey;
@ -45,7 +45,7 @@ pub struct UserProfilePB {
pub openai_key: String,
#[pb(index = 7)]
pub auth_type: AuthTypePB,
pub authenticator: AuthenticatorPB,
#[pb(index = 8)]
pub encryption_sign: String,
@ -85,7 +85,7 @@ impl std::convert::From<UserProfile> for UserProfilePB {
token: user_profile.token,
icon_url: user_profile.icon_url,
openai_key: user_profile.openai_key,
auth_type: user_profile.authenticator.into(),
authenticator: user_profile.authenticator.into(),
encryption_sign,
encryption_type: encryption_ty,
workspace_id: user_profile.workspace_id,

View File

@ -114,7 +114,7 @@ impl std::default::Default for LocaleSettingsPB {
}
}
#[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone)]
#[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone, Default)]
pub struct DocumentSettingsPB {
#[pb(index = 1, one_of)]
pub cursor_color: Option<String>,
@ -123,15 +123,6 @@ pub struct DocumentSettingsPB {
pub selection_color: Option<String>,
}
impl std::default::Default for DocumentSettingsPB {
fn default() -> Self {
Self {
cursor_color: None,
selection_color: None,
}
}
}
pub const APPEARANCE_DEFAULT_THEME: &str = "Default";
pub const APPEARANCE_DEFAULT_FONT: &str = "Poppins";
pub const APPEARANCE_DEFAULT_MONOSPACE_FONT: &str = "SF Mono";

View File

@ -35,6 +35,7 @@ use crate::migrations::document_empty_content::HistoricalEmptyDocumentMigration;
use crate::migrations::migration::{UserDataMigration, UserLocalDataMigration};
use crate::migrations::session_migration::migrate_session_with_user_uuid;
use crate::migrations::workspace_and_favorite_v1::FavoriteV1AndWorkspaceArrayMigration;
use crate::migrations::workspace_trash_v1::WorkspaceTrashMapToSectionMigration;
use crate::migrations::MigrationUser;
use crate::services::cloud_config::get_cloud_config;
use crate::services::collab_interact::{CollabInteract, DefaultCollabInteract};
@ -198,16 +199,18 @@ impl UserManager {
let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?);
if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() {
event!(tracing::Level::DEBUG, "Listen token state change");
let user_uid = user.uid;
let user_token = user.token.clone();
af_spawn(async move {
while let Some(token_state) = token_state_rx.next().await {
debug!("Token state changed: {:?}", token_state);
match token_state {
UserTokenState::Refresh { token } => {
// Only save the token if the token is different from the current token
if token != user.token {
if token != user_token {
if let Some(pool) = weak_pool.upgrade() {
// Save the new token
if let Err(err) = save_user_token(user.uid, pool, token) {
if let Err(err) = save_user_token(user_uid, pool, token) {
error!("Save user token failed: {}", err);
}
}
@ -232,9 +235,10 @@ impl UserManager {
let migrations: Vec<Box<dyn UserDataMigration>> = vec![
Box::new(HistoricalEmptyDocumentMigration),
Box::new(FavoriteV1AndWorkspaceArrayMigration),
Box::new(WorkspaceTrashMapToSectionMigration),
];
match UserLocalDataMigration::new(session.clone(), collab_db, sqlite_pool)
.run(migrations, &current_authenticator)
.run(migrations, &user.authenticator)
{
Ok(applied_migrations) => {
if !applied_migrations.is_empty() {
@ -786,7 +790,13 @@ impl UserManager {
) -> Result<(), FlowyError> {
let old_collab_db = self.database.get_collab_db(old_user.session.user_id)?;
let new_collab_db = self.database.get_collab_db(new_user.session.user_id)?;
migration_anon_user_on_sign_up(old_user, &old_collab_db, new_user, &new_collab_db)?;
migration_anon_user_on_sign_up(
old_user,
&old_collab_db,
new_user,
&new_collab_db,
authenticator,
)?;
match authenticator {
Authenticator::Supabase => {

View File

@ -1,11 +1,13 @@
use crate::services::entities::Session;
use flowy_user_deps::entities::UserProfile;
use crate::services::entities::Session;
pub mod document_empty_content;
pub mod migration;
pub mod session_migration;
mod util;
pub mod workspace_and_favorite_v1;
pub mod workspace_trash_v1;
#[derive(Clone, Debug)]
pub struct MigrationUser {

View File

@ -15,23 +15,21 @@ pub fn migrate_session_with_user_uuid(
session: &Arc<parking_lot::RwLock<Option<Session>>>,
store_preferences: &Arc<StorePreferences>,
) {
if !store_preferences.get_bool(MIGRATION_USER_NO_USER_UUID) {
if store_preferences
if !store_preferences.get_bool(MIGRATION_USER_NO_USER_UUID)
&& store_preferences
.set_bool(MIGRATION_USER_NO_USER_UUID, true)
.is_ok()
{
if let Some(mut value) = store_preferences.get_object::<Value>(&user_config.session_cache_key)
{
if value.get("user_uuid").is_none() {
value.as_object_mut().map(|map| {
map.insert("user_uuid".to_string(), json!(Uuid::new_v4()));
});
{
if let Some(mut value) = store_preferences.get_object::<Value>(&user_config.session_cache_key) {
if value.get("user_uuid").is_none() {
if let Some(map) = value.as_object_mut() {
map.insert("user_uuid".to_string(), json!(Uuid::new_v4()));
}
}
if let Ok(new_session) = serde_json::from_value::<Session>(value) {
*session.write() = Some(new_session.clone());
let _ = store_preferences.set_object(&user_config.session_cache_key, &new_session);
}
if let Ok(new_session) = serde_json::from_value::<Session>(value) {
*session.write() = Some(new_session.clone());
let _ = store_preferences.set_object(&user_config.session_cache_key, &new_session);
}
}
}

View File

@ -0,0 +1,56 @@
use std::sync::Arc;
use collab_folder::Folder;
use tracing::instrument;
use collab_integrate::{RocksCollabDB, YrsDocAction};
use flowy_error::{internal_error, FlowyResult};
use flowy_user_deps::entities::Authenticator;
use crate::migrations::migration::UserDataMigration;
use crate::migrations::util::load_collab;
use crate::services::entities::Session;
/// 1. Migrate the workspace: { trash: [view_id] } to { trash: { uid: [view_id] } }
pub struct WorkspaceTrashMapToSectionMigration;
impl UserDataMigration for WorkspaceTrashMapToSectionMigration {
fn name(&self) -> &str {
"workspace_trash_map_to_section_migration"
}
#[instrument(name = "WorkspaceTrashMapToSectionMigration", skip_all, err)]
fn run(
&self,
session: &Session,
collab_db: &Arc<RocksCollabDB>,
_authenticator: &Authenticator,
) -> FlowyResult<()> {
let write_txn = collab_db.write_txn();
if let Ok(collab) = load_collab(session.user_id, &write_txn, &session.user_workspace.id) {
let folder = Folder::open(session.user_id, collab, None)?;
let trash_ids = folder
.get_trash_v1()
.into_iter()
.map(|fav| fav.id)
.collect::<Vec<String>>();
if !trash_ids.is_empty() {
folder.add_trash(trash_ids);
}
let encode = folder.encode_collab_v1();
write_txn
.flush_doc_with(
session.user_id,
&session.user_workspace.id,
&encode.doc_state,
&encode.state_vector,
)
.map_err(internal_error)?;
}
write_txn.commit_transaction().map_err(internal_error)?;
Ok(())
}
}

View File

@ -11,7 +11,7 @@ use uuid::Uuid;
use flowy_user_deps::entities::{AuthResponse, UserProfile, UserWorkspace};
use flowy_user_deps::entities::{Authenticator, UserAuthResponse};
use crate::entities::AuthTypePB;
use crate::entities::AuthenticatorPB;
use crate::migrations::MigrationUser;
#[derive(Debug, Clone, Serialize)]
@ -99,7 +99,7 @@ where
fn from(value: &T) -> Self {
Self {
user_id: value.user_id(),
user_uuid: value.user_uuid().clone(),
user_uuid: *value.user_uuid(),
user_workspace: value.latest_workspace().clone(),
}
}
@ -114,22 +114,22 @@ impl std::convert::From<Session> for String {
}
}
impl From<AuthTypePB> for Authenticator {
fn from(pb: AuthTypePB) -> Self {
impl From<AuthenticatorPB> for Authenticator {
fn from(pb: AuthenticatorPB) -> Self {
match pb {
AuthTypePB::Supabase => Authenticator::Supabase,
AuthTypePB::Local => Authenticator::Local,
AuthTypePB::AFCloud => Authenticator::AppFlowyCloud,
AuthenticatorPB::Supabase => Authenticator::Supabase,
AuthenticatorPB::Local => Authenticator::Local,
AuthenticatorPB::AppFlowyCloud => Authenticator::AppFlowyCloud,
}
}
}
impl From<Authenticator> for AuthTypePB {
impl From<Authenticator> for AuthenticatorPB {
fn from(auth_type: Authenticator) -> Self {
match auth_type {
Authenticator::Supabase => AuthTypePB::Supabase,
Authenticator::Local => AuthTypePB::Local,
Authenticator::AppFlowyCloud => AuthTypePB::AFCloud,
Authenticator::Supabase => AuthenticatorPB::Supabase,
Authenticator::Local => AuthenticatorPB::Local,
Authenticator::AppFlowyCloud => AuthenticatorPB::AppFlowyCloud,
}
}
}

View File

@ -6,7 +6,7 @@ use tracing::subscriber::set_global_default;
use tracing_appender::{non_blocking::WorkerGuard, rolling::RollingFileAppender};
use tracing_bunyan_formatter::JsonStorageLayer;
use tracing_subscriber::fmt::format::Writer;
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter};
use crate::layer::FlowyFormattingLayer;
@ -37,22 +37,25 @@ impl Builder {
self
}
pub fn build(self) -> std::result::Result<(), String> {
pub fn build(self) -> Result<(), String> {
let env_filter = EnvFilter::new(self.env_filter);
let std_out_layer = fmt::layer().with_writer(std::io::stdout).pretty();
let (non_blocking, guard) = tracing_appender::non_blocking(self.file_appender);
let file_layer = FlowyFormattingLayer::new(non_blocking);
let subscriber = tracing_subscriber::fmt()
.with_timer(CustomTime)
.with_ansi(true)
.with_target(false)
.with_max_level(tracing::Level::TRACE)
.with_thread_ids(false)
.with_writer(std::io::stderr)
.pretty()
.with_env_filter(env_filter)
.finish()
.with(JsonStorageLayer)
.with(FlowyFormattingLayer::new(non_blocking));
.with(file_layer)
.with(std_out_layer);
set_global_default(subscriber).map_err(|e| format!("{:?}", e))?;

View File

@ -1,11 +1,11 @@
# If you want to test a single file with single case, you can try this command:
# RUST_LOG="debug" flutter test -j, --concurrency=1 'path to the file' --name 'test case name'
# RUST_LOG="debug" flutter test -d macOS -j, 'path to the file' --name 'test case name'
[tasks.flutter_test]
description = "Run flutter test with single case in single file. Input: cargo make flutter_test 'path to the file' --name 'test case name'"
script = '''
cd appflowy_flutter
RUST_LOG="debug" flutter test -j, --concurrency=1 "${@}"
flutter test -j, --concurrency=1 "${@}"
'''
script_runner = "@shell"