mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
tests: AppFlowy Cloud integration test (#4015)
* chore: save cloud ofnig * chore: fix .a link warnings * chore: add cloud test runner * refactor: test folder * ci: add test * ci: add test * ci: fix * ci: fix
This commit is contained in:
121
.github/workflows/flutter_ci.yaml
vendored
121
.github/workflows/flutter_ci.yaml
vendored
@ -119,7 +119,8 @@ jobs:
|
|||||||
run: flutter analyze .
|
run: flutter analyze .
|
||||||
|
|
||||||
- name: Compress appflowy_flutter
|
- name: Compress appflowy_flutter
|
||||||
run: tar -czf appflowy_flutter.tar.gz frontend/appflowy_flutter
|
run: |
|
||||||
|
tar -czf appflowy_flutter.tar.gz frontend/appflowy_flutter
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
@ -297,17 +298,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ${{ github.run_id }}-${{ matrix.os }}
|
name: ${{ github.run_id }}-${{ matrix.os }}
|
||||||
|
|
||||||
- name: Uncompress appflowy_flutter
|
- name: Uncompressed appflowy_flutter
|
||||||
run: tar -xf appflowy_flutter.tar.gz
|
run: tar -xf appflowy_flutter.tar.gz
|
||||||
|
|
||||||
# - name: Create .env.cloud.test file in flowy-server
|
|
||||||
# working-directory: frontend/appflowy_flutter
|
|
||||||
# run: |
|
|
||||||
# touch .env.cloud.test
|
|
||||||
# echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.cloud.test
|
|
||||||
# echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.cloud.test
|
|
||||||
# echo APPFLOWY_CLOUD_URL=${{ secrets.APPFLOWY_CLOUD_URL }} >> .env.cloud.test
|
|
||||||
|
|
||||||
- name: Run flutter pub get
|
- name: Run flutter pub get
|
||||||
working-directory: frontend
|
working-directory: frontend
|
||||||
run: cargo make pub_get
|
run: cargo make pub_get
|
||||||
@ -327,19 +320,101 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
cloud_integration_test:
|
||||||
uses: Wandalen/wretry.action@v1.0.36
|
needs: [prepare]
|
||||||
|
# if: github.event_name != 'pull_request'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
flutter_profile: development-linux-x86_64
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout appflowy cloud code
|
||||||
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
action: codecov/codecov-action@v3
|
repository: AppFlowy-IO/AppFlowy-Cloud
|
||||||
with: |
|
path: AppFlowy-Cloud
|
||||||
name: appflowy
|
depth: 1
|
||||||
flags: appflowy_flutter_integrateion_test
|
|
||||||
fail_ci_if_error: true
|
|
||||||
verbose: true
|
- name: Prepare appflowy cloud env
|
||||||
os: ${{ matrix.os }}
|
working-directory: AppFlowy-Cloud
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
run: |
|
||||||
attempt_limit: 20
|
# log level
|
||||||
attempt_delay: 10000
|
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: Checkout source code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install flutter
|
||||||
|
id: flutter
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: "stable"
|
||||||
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
|
|
||||||
|
- uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
|
||||||
|
|
||||||
|
- name: Install prerequisites
|
||||||
|
working-directory: frontend
|
||||||
|
run: |
|
||||||
|
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
|
||||||
|
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Enable Flutter Desktop
|
||||||
|
run: |
|
||||||
|
flutter config --enable-linux-desktop
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ github.run_id }}-${{ matrix.os }}
|
||||||
|
|
||||||
|
- name: Uncompressed appflowy_flutter
|
||||||
|
run: |
|
||||||
|
tar -xf appflowy_flutter.tar.gz
|
||||||
|
ls -al
|
||||||
|
|
||||||
|
- name: Enable localhost env
|
||||||
|
working-directory: frontend/appflowy_flutter
|
||||||
|
run: |
|
||||||
|
echo 'APPFLOWY_CLOUD_URL=http://localhost' >> .env
|
||||||
|
dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
|
||||||
|
|
||||||
|
- name: Run flutter pub get
|
||||||
|
working-directory: frontend
|
||||||
|
run: cargo make pub_get
|
||||||
|
|
||||||
|
- name: Run Flutter integration tests
|
||||||
|
working-directory: frontend/appflowy_flutter
|
||||||
|
run: |
|
||||||
|
export DISPLAY=:99
|
||||||
|
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
||||||
|
sudo apt-get install network-manager
|
||||||
|
flutter test integration_test/cloud_runner.dart -d Linux --coverage
|
||||||
|
shell: bash
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: [prepare]
|
needs: [prepare]
|
||||||
@ -411,7 +486,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ${{ github.run_id }}-${{ matrix.os }}
|
name: ${{ github.run_id }}-${{ matrix.os }}
|
||||||
|
|
||||||
- name: Uncompress appflowy_flutter
|
- name: Uncompressed appflowy_flutter
|
||||||
run: tar -xf appflowy_flutter.tar.gz
|
run: tar -xf appflowy_flutter.tar.gz
|
||||||
|
|
||||||
- name: Build flutter product
|
- name: Build flutter product
|
||||||
|
@ -28,6 +28,7 @@ LIB_NAME = "dart_ffi"
|
|||||||
CURRENT_APP_VERSION = "0.3.8"
|
CURRENT_APP_VERSION = "0.3.8"
|
||||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
|
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
|
||||||
PRODUCT_NAME = "AppFlowy"
|
PRODUCT_NAME = "AppFlowy"
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = "11.0"
|
||||||
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
|
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
|
||||||
# If you update the macOS's CRATE_TYPE, don't forget to update the
|
# If you update the macOS's CRATE_TYPE, don't forget to update the
|
||||||
# appflowy_backend.podspec
|
# appflowy_backend.podspec
|
||||||
|
1
frontend/appflowy_flutter/dev.env
Normal file
1
frontend/appflowy_flutter/dev.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
APPFLOWY_CLOUD_URL=
|
@ -4,6 +4,7 @@ import 'package:appflowy/workspace/presentation/settings/widgets/settings_appear
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/util.dart';
|
import 'util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -0,0 +1,123 @@
|
|||||||
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
|
import 'package:appflowy/generated/locale_keys.g.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:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import '../util/mock/mock_file_picker.dart';
|
||||||
|
import '../util/util.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group('appflowy cloud auth', () {
|
||||||
|
testWidgets('sign in', (tester) async {
|
||||||
|
await tester.initializeAppFlowy(
|
||||||
|
cloudType: AuthenticatorType.appflowyCloud,
|
||||||
|
);
|
||||||
|
await tester.tapGoogleLoginInButton();
|
||||||
|
tester.expectToSeeHomePage();
|
||||||
|
});
|
||||||
|
|
||||||
|
// testWidgets('sign out', (tester) async {
|
||||||
|
// await tester.initializeAppFlowy(
|
||||||
|
// cloudType: AuthenticatorType.appflowyCloud,
|
||||||
|
// );
|
||||||
|
// await tester.tapGoogleLoginInButton();
|
||||||
|
|
||||||
|
// // Open the setting page and sign out
|
||||||
|
// await tester.openSettings();
|
||||||
|
// await tester.openSettingsPage(SettingsPage.user);
|
||||||
|
// await tester.tapButton(find.byType(SettingLogoutButton));
|
||||||
|
|
||||||
|
// tester.expectToSeeText(LocaleKeys.button_ok.tr());
|
||||||
|
// await tester.tapButtonWithName(LocaleKeys.button_ok.tr());
|
||||||
|
|
||||||
|
// // Go to the sign in page again
|
||||||
|
// await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||||
|
// tester.expectToSeeGoogleLoginButton();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// testWidgets('sign in as annoymous', (tester) async {
|
||||||
|
// await tester.initializeAppFlowy(
|
||||||
|
// cloudType: AuthenticatorType.appflowyCloud,
|
||||||
|
// );
|
||||||
|
// await tester.tapSignInAsGuest();
|
||||||
|
|
||||||
|
// // should not see the sync setting page when sign in as annoymous
|
||||||
|
// await tester.openSettings();
|
||||||
|
// await tester.openSettingsPage(SettingsPage.user);
|
||||||
|
// tester.expectToSeeGoogleLoginButton();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// testWidgets('enable sync', (tester) async {
|
||||||
|
// await tester.initializeAppFlowy(
|
||||||
|
// cloudType: AuthenticatorType.appflowyCloud,
|
||||||
|
// );
|
||||||
|
// await tester.tapGoogleLoginInButton();
|
||||||
|
|
||||||
|
// // Open the setting page and sign out
|
||||||
|
// await tester.openSettings();
|
||||||
|
// await tester.openSettingsPage(SettingsPage.cloud);
|
||||||
|
|
||||||
|
// // the switch should be on by default
|
||||||
|
// tester.assertAppFlowyCloudEnableSyncSwitchValue(true);
|
||||||
|
// await tester.toggleEnableSync(AppFlowyCloudEnableSync);
|
||||||
|
|
||||||
|
// // the switch should be off
|
||||||
|
// tester.assertAppFlowyCloudEnableSyncSwitchValue(false);
|
||||||
|
|
||||||
|
// // the switch should be on after toggling
|
||||||
|
// await tester.toggleEnableSync(AppFlowyCloudEnableSync);
|
||||||
|
// tester.assertAppFlowyCloudEnableSyncSwitchValue(true);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// testWidgets('custom folder sign in', (tester) async {
|
||||||
|
// const userA = 'UserA';
|
||||||
|
// final initialPath = p.join(userA, appFlowyDataFolder);
|
||||||
|
// final context = await tester.initializeAppFlowy(
|
||||||
|
// cloudType: AuthenticatorType.appflowyCloud,
|
||||||
|
// pathExtension: initialPath,
|
||||||
|
// );
|
||||||
|
// // remove the last extension
|
||||||
|
// final rootPath = context.applicationDataDirectory.replaceFirst(
|
||||||
|
// initialPath,
|
||||||
|
// '',
|
||||||
|
// );
|
||||||
|
// await tester.tapGoogleLoginInButton();
|
||||||
|
|
||||||
|
// // Open the setting page and sign out
|
||||||
|
// await tester.openSettings();
|
||||||
|
// await tester.openSettingsPage(SettingsPage.user);
|
||||||
|
// await tester.enterUserName(userA);
|
||||||
|
|
||||||
|
// await tester.openSettingsPage(SettingsPage.files);
|
||||||
|
// await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// // mock the file_picker result
|
||||||
|
// await mockGetDirectoryPath(
|
||||||
|
// p.join(rootPath, "random_folder"),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // after selecting the folder, an annoymous user should be signed in
|
||||||
|
// await tester.tapCustomLocationButton();
|
||||||
|
// tester.expectToSeeHomePage();
|
||||||
|
// await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// // Login as userA in custom folder
|
||||||
|
// await tester.openSettings();
|
||||||
|
// await tester.openSettingsPage(SettingsPage.user);
|
||||||
|
// await tester.tapGoogleLoginInButton();
|
||||||
|
|
||||||
|
// await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||||
|
// tester.expectToSeeHomePage();
|
||||||
|
// // UserA should be displayed
|
||||||
|
// tester.expectToSeeUserName(userA);
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:appflowy/env/cloud_env.dart';
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.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:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
@ -10,15 +11,15 @@ import '../util/util.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('auth', () {
|
group('supabase auth', () {
|
||||||
testWidgets('sign in with supabase', (tester) async {
|
testWidgets('sign in with supabase', (tester) async {
|
||||||
await tester.initializeAppFlowy(cloudType: CloudType.supabase);
|
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
|
||||||
await tester.tapGoogleLoginInButton();
|
await tester.tapGoogleLoginInButton();
|
||||||
tester.expectToSeeHomePage();
|
tester.expectToSeeHomePage();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('sign out with supabase', (tester) async {
|
testWidgets('sign out with supabase', (tester) async {
|
||||||
await tester.initializeAppFlowy(cloudType: CloudType.supabase);
|
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
|
||||||
await tester.tapGoogleLoginInButton();
|
await tester.tapGoogleLoginInButton();
|
||||||
|
|
||||||
// Open the setting page and sign out
|
// Open the setting page and sign out
|
||||||
@ -35,7 +36,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('sign in as annoymous', (tester) async {
|
testWidgets('sign in as annoymous', (tester) async {
|
||||||
await tester.initializeAppFlowy(cloudType: CloudType.supabase);
|
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
|
||||||
await tester.tapSignInAsGuest();
|
await tester.tapSignInAsGuest();
|
||||||
|
|
||||||
// should not see the sync setting page when sign in as annoymous
|
// should not see the sync setting page when sign in as annoymous
|
||||||
@ -65,7 +66,7 @@ void main() {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
testWidgets('enable sync', (tester) async {
|
testWidgets('enable sync', (tester) async {
|
||||||
await tester.initializeAppFlowy(cloudType: CloudType.supabase);
|
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
|
||||||
await tester.tapGoogleLoginInButton();
|
await tester.tapGoogleLoginInButton();
|
||||||
|
|
||||||
// Open the setting page and sign out
|
// Open the setting page and sign out
|
||||||
@ -73,15 +74,15 @@ void main() {
|
|||||||
await tester.openSettingsPage(SettingsPage.cloud);
|
await tester.openSettingsPage(SettingsPage.cloud);
|
||||||
|
|
||||||
// the switch should be on by default
|
// the switch should be on by default
|
||||||
tester.assertEnableSyncSwitchValue(true);
|
tester.assertSupabaseEnableSyncSwitchValue(true);
|
||||||
await tester.toggleEnableSync();
|
await tester.toggleEnableSync(SupabaseEnableSync);
|
||||||
|
|
||||||
// the switch should be off
|
// the switch should be off
|
||||||
tester.assertEnableSyncSwitchValue(false);
|
tester.assertSupabaseEnableSyncSwitchValue(false);
|
||||||
|
|
||||||
// the switch should be on after toggling
|
// the switch should be on after toggling
|
||||||
await tester.toggleEnableSync();
|
await tester.toggleEnableSync(SupabaseEnableSync);
|
||||||
tester.assertEnableSyncSwitchValue(true);
|
tester.assertSupabaseEnableSyncSwitchValue(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
13
frontend/appflowy_flutter/integration_test/cloud_runner.dart
Normal file
13
frontend/appflowy_flutter/integration_test/cloud_runner.dart
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
|
import 'auth/appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
|
||||||
|
import 'empty_test.dart' as first_test;
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
// This test must be run first, otherwise the CI will fail.
|
||||||
|
first_test.main();
|
||||||
|
|
||||||
|
appflowy_cloud_auth_test.main();
|
||||||
|
}
|
@ -3,8 +3,8 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pbenum.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -4,8 +4,8 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -4,8 +4,8 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pbenum.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -6,8 +6,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -4,7 +4,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -7,9 +7,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/emoji.dart';
|
import '../util/emoji.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -2,8 +2,8 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -3,8 +3,8 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -2,7 +2,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -2,7 +2,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -3,8 +3,8 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import '../util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
import '../util/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
@ -2,17 +2,18 @@ import 'package:integration_test/integration_test.dart';
|
|||||||
|
|
||||||
import 'appearance_settings_test.dart' as appearance_test_runner;
|
import 'appearance_settings_test.dart' as appearance_test_runner;
|
||||||
import 'board/board_test_runner.dart' as board_test_runner;
|
import 'board/board_test_runner.dart' as board_test_runner;
|
||||||
import 'database_calendar_test.dart' as database_calendar_test;
|
import 'database/database_calendar_test.dart' as database_calendar_test;
|
||||||
import 'database_cell_test.dart' as database_cell_test;
|
import 'database/database_cell_test.dart' as database_cell_test;
|
||||||
import 'database_field_settings_test.dart' as database_field_settings_test;
|
import 'database/database_field_settings_test.dart'
|
||||||
import 'database_field_test.dart' as database_field_test;
|
as database_field_settings_test;
|
||||||
import 'database_filter_test.dart' as database_filter_test;
|
import 'database/database_field_test.dart' as database_field_test;
|
||||||
import 'database_row_page_test.dart' as database_row_page_test;
|
import 'database/database_filter_test.dart' as database_filter_test;
|
||||||
import 'database_row_test.dart' as database_row_test;
|
import 'database/database_row_page_test.dart' as database_row_page_test;
|
||||||
import 'database_setting_test.dart' as database_setting_test;
|
import 'database/database_row_test.dart' as database_row_test;
|
||||||
import 'database_share_test.dart' as database_share_test;
|
import 'database/database_setting_test.dart' as database_setting_test;
|
||||||
import 'database_sort_test.dart' as database_sort_test;
|
import 'database/database_share_test.dart' as database_share_test;
|
||||||
import 'database_view_test.dart' as database_view_test;
|
import 'database/database_sort_test.dart' as database_sort_test;
|
||||||
|
import 'database/database_view_test.dart' as database_view_test;
|
||||||
import 'document/document_test_runner.dart' as document_test_runner;
|
import 'document/document_test_runner.dart' as document_test_runner;
|
||||||
import 'empty_test.dart' as first_test;
|
import 'empty_test.dart' as first_test;
|
||||||
import 'hotkeys_test.dart' as hotkeys_test;
|
import 'hotkeys_test.dart' as hotkeys_test;
|
||||||
@ -75,8 +76,6 @@ Future<void> main() async {
|
|||||||
// User settings
|
// User settings
|
||||||
settings_test_runner.main();
|
settings_test_runner.main();
|
||||||
|
|
||||||
// supabase_auth_test_runner.main();
|
|
||||||
|
|
||||||
// board_test.main();
|
// board_test.main();
|
||||||
// empty_document_test.main();
|
// empty_document_test.main();
|
||||||
// smart_menu_test.main();
|
// smart_menu_test.main();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.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/setting_supabase_cloud.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
@ -34,7 +35,7 @@ extension AppFlowyAuthTest on WidgetTester {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertEnableSyncSwitchValue(bool value) {
|
void assertSupabaseEnableSyncSwitchValue(bool value) {
|
||||||
assertSwitchValue(
|
assertSwitchValue(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
of: find.byType(SupabaseEnableSync),
|
of: find.byType(SupabaseEnableSync),
|
||||||
@ -44,6 +45,16 @@ extension AppFlowyAuthTest on WidgetTester {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assertAppFlowyCloudEnableSyncSwitchValue(bool value) {
|
||||||
|
assertSwitchValue(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(AppFlowyCloudEnableSync),
|
||||||
|
matching: find.byWidgetPredicate((widget) => widget is Switch),
|
||||||
|
),
|
||||||
|
value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> toggleEnableEncrypt() async {
|
Future<void> toggleEnableEncrypt() async {
|
||||||
final finder = find.descendant(
|
final finder = find.descendant(
|
||||||
of: find.byType(EnableEncrypt),
|
of: find.byType(EnableEncrypt),
|
||||||
@ -53,9 +64,9 @@ extension AppFlowyAuthTest on WidgetTester {
|
|||||||
await tapButton(finder);
|
await tapButton(finder);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleEnableSync() async {
|
Future<void> toggleEnableSync(Type syncButton) async {
|
||||||
final finder = find.descendant(
|
final finder = find.descendant(
|
||||||
of: find.byType(SupabaseEnableSync),
|
of: find.byType(syncButton),
|
||||||
matching: find.byWidgetPredicate((widget) => widget is Switch),
|
matching: find.byWidgetPredicate((widget) => widget is Switch),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ extension AppFlowyTestBase on WidgetTester {
|
|||||||
// use to append after the application data directory
|
// use to append after the application data directory
|
||||||
String? pathExtension,
|
String? pathExtension,
|
||||||
Size windowsSize = const Size(1600, 1200),
|
Size windowsSize = const Size(1600, 1200),
|
||||||
CloudType? cloudType,
|
AuthenticatorType? cloudType,
|
||||||
}) async {
|
}) async {
|
||||||
binding.setSurfaceSize(windowsSize);
|
binding.setSurfaceSize(windowsSize);
|
||||||
|
|
||||||
@ -45,16 +45,32 @@ extension AppFlowyTestBase on WidgetTester {
|
|||||||
await FlowyRunner.run(
|
await FlowyRunner.run(
|
||||||
FlowyApp(),
|
FlowyApp(),
|
||||||
IntegrationMode.integrationTest,
|
IntegrationMode.integrationTest,
|
||||||
didInitGetIt: Future(
|
rustEnvsBuilder: () {
|
||||||
|
final rustEnvs = <String, String>{};
|
||||||
|
if (cloudType != null) {
|
||||||
|
switch (cloudType) {
|
||||||
|
case AuthenticatorType.local:
|
||||||
|
break;
|
||||||
|
case AuthenticatorType.supabase:
|
||||||
|
break;
|
||||||
|
case AuthenticatorType.appflowyCloud:
|
||||||
|
rustEnvs["GOTRUE_ADMIN_EMAIL"] = "admin@example.com";
|
||||||
|
rustEnvs["GOTRUE_ADMIN_PASSWORD"] = "password";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rustEnvs;
|
||||||
|
},
|
||||||
|
didInitGetItCallback: Future(
|
||||||
() async {
|
() async {
|
||||||
if (cloudType != null) {
|
if (cloudType != null) {
|
||||||
switch (cloudType) {
|
switch (cloudType) {
|
||||||
case CloudType.local:
|
case AuthenticatorType.local:
|
||||||
break;
|
break;
|
||||||
case CloudType.supabase:
|
case AuthenticatorType.supabase:
|
||||||
await useSupabaseCloud();
|
await useSupabaseCloud();
|
||||||
break;
|
break;
|
||||||
case CloudType.appflowyCloud:
|
case AuthenticatorType.appflowyCloud:
|
||||||
await useAppFlowyCloud();
|
await useAppFlowyCloud();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -227,7 +243,7 @@ extension AppFlowyFinderTestBase on CommonFinders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> useSupabaseCloud() async {
|
Future<void> useSupabaseCloud() async {
|
||||||
await setCloudType(CloudType.supabase);
|
await setAuthenticatorType(AuthenticatorType.supabase);
|
||||||
await setSupbaseServer(
|
await setSupbaseServer(
|
||||||
Some(TestEnv.supabaseUrl),
|
Some(TestEnv.supabaseUrl),
|
||||||
Some(TestEnv.supabaseAnonKey),
|
Some(TestEnv.supabaseAnonKey),
|
||||||
@ -235,6 +251,6 @@ Future<void> useSupabaseCloud() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> useAppFlowyCloud() async {
|
Future<void> useAppFlowyCloud() async {
|
||||||
await setCloudType(CloudType.appflowyCloud);
|
await setAuthenticatorType(AuthenticatorType.appflowyCloud);
|
||||||
await setAppFlowyCloudUrl(Some(TestEnv.afCloudUrl));
|
await setAppFlowyCloudUrl(Some(TestEnv.afCloudUrl));
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,24 @@ part 'backend_env.g.dart';
|
|||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class AppFlowyConfiguration {
|
class AppFlowyConfiguration {
|
||||||
|
final String root;
|
||||||
final String custom_app_path;
|
final String custom_app_path;
|
||||||
final String origin_app_path;
|
final String origin_app_path;
|
||||||
final String device_id;
|
final String device_id;
|
||||||
final int cloud_type;
|
final int authenticator_type;
|
||||||
final SupabaseConfiguration supabase_config;
|
final SupabaseConfiguration supabase_config;
|
||||||
final AppFlowyCloudConfiguration appflowy_cloud_config;
|
final AppFlowyCloudConfiguration appflowy_cloud_config;
|
||||||
|
final Map<String, String> envs;
|
||||||
|
|
||||||
AppFlowyConfiguration({
|
AppFlowyConfiguration({
|
||||||
|
required this.root,
|
||||||
required this.custom_app_path,
|
required this.custom_app_path,
|
||||||
required this.origin_app_path,
|
required this.origin_app_path,
|
||||||
required this.device_id,
|
required this.device_id,
|
||||||
required this.cloud_type,
|
required this.authenticator_type,
|
||||||
required this.supabase_config,
|
required this.supabase_config,
|
||||||
required this.appflowy_cloud_config,
|
required this.appflowy_cloud_config,
|
||||||
|
required this.envs,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory AppFlowyConfiguration.fromJson(Map<String, dynamic> json) =>
|
factory AppFlowyConfiguration.fromJson(Map<String, dynamic> json) =>
|
||||||
|
127
frontend/appflowy_flutter/lib/env/cloud_env.dart
vendored
127
frontend/appflowy_flutter/lib/env/cloud_env.dart
vendored
@ -1,6 +1,7 @@
|
|||||||
import 'package:appflowy/core/config/kv.dart';
|
import 'package:appflowy/core/config/kv.dart';
|
||||||
import 'package:appflowy/core/config/kv_keys.dart';
|
import 'package:appflowy/core/config/kv_keys.dart';
|
||||||
import 'package:appflowy/env/backend_env.dart';
|
import 'package:appflowy/env/backend_env.dart';
|
||||||
|
import 'package:appflowy/env/env.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
@ -9,22 +10,22 @@ import 'package:dartz/dartz.dart';
|
|||||||
///
|
///
|
||||||
/// This method updates the cloud type setting in the key-value storage
|
/// This method updates the cloud type setting in the key-value storage
|
||||||
/// using the [KeyValueStorage] service. The cloud type is identified
|
/// using the [KeyValueStorage] service. The cloud type is identified
|
||||||
/// by the [CloudType] enum.
|
/// by the [AuthenticatorType] enum.
|
||||||
///
|
///
|
||||||
/// [ty] - The type of cloud to be set. It must be one of the values from
|
/// [ty] - The type of cloud to be set. It must be one of the values from
|
||||||
/// [CloudType] enum. The corresponding integer value of the enum is stored:
|
/// [AuthenticatorType] enum. The corresponding integer value of the enum is stored:
|
||||||
/// - `CloudType.local` is stored as "0".
|
/// - `CloudType.local` is stored as "0".
|
||||||
/// - `CloudType.supabase` is stored as "1".
|
/// - `CloudType.supabase` is stored as "1".
|
||||||
/// - `CloudType.appflowyCloud` is stored as "2".
|
/// - `CloudType.appflowyCloud` is stored as "2".
|
||||||
Future<void> setCloudType(CloudType ty) async {
|
Future<void> setAuthenticatorType(AuthenticatorType ty) async {
|
||||||
switch (ty) {
|
switch (ty) {
|
||||||
case CloudType.local:
|
case AuthenticatorType.local:
|
||||||
getIt<KeyValueStorage>().set(KVKeys.kCloudType, 0.toString());
|
getIt<KeyValueStorage>().set(KVKeys.kCloudType, 0.toString());
|
||||||
break;
|
break;
|
||||||
case CloudType.supabase:
|
case AuthenticatorType.supabase:
|
||||||
getIt<KeyValueStorage>().set(KVKeys.kCloudType, 1.toString());
|
getIt<KeyValueStorage>().set(KVKeys.kCloudType, 1.toString());
|
||||||
break;
|
break;
|
||||||
case CloudType.appflowyCloud:
|
case AuthenticatorType.appflowyCloud:
|
||||||
getIt<KeyValueStorage>().set(KVKeys.kCloudType, 2.toString());
|
getIt<KeyValueStorage>().set(KVKeys.kCloudType, 2.toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -34,25 +35,25 @@ Future<void> setCloudType(CloudType ty) async {
|
|||||||
///
|
///
|
||||||
/// This method fetches the cloud type setting from the key-value storage
|
/// This method fetches the cloud type setting from the key-value storage
|
||||||
/// using the [KeyValueStorage] service and returns the corresponding
|
/// using the [KeyValueStorage] service and returns the corresponding
|
||||||
/// [CloudType] enum value.
|
/// [AuthenticatorType] enum value.
|
||||||
///
|
///
|
||||||
/// Returns:
|
/// Returns:
|
||||||
/// A Future that resolves to a [CloudType] enum value representing the
|
/// A Future that resolves to a [AuthenticatorType] enum value representing the
|
||||||
/// currently set cloud type. The default return value is `CloudType.local`
|
/// currently set cloud type. The default return value is `CloudType.local`
|
||||||
/// if no valid setting is found.
|
/// if no valid setting is found.
|
||||||
///
|
///
|
||||||
Future<CloudType> getCloudType() async {
|
Future<AuthenticatorType> getAuthenticatorType() async {
|
||||||
final value = await getIt<KeyValueStorage>().get(KVKeys.kCloudType);
|
final value = await getIt<KeyValueStorage>().get(KVKeys.kCloudType);
|
||||||
return value.fold(() => CloudType.local, (s) {
|
return value.fold(() => AuthenticatorType.local, (s) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case "0":
|
case "0":
|
||||||
return CloudType.local;
|
return AuthenticatorType.local;
|
||||||
case "1":
|
case "1":
|
||||||
return CloudType.supabase;
|
return AuthenticatorType.supabase;
|
||||||
case "2":
|
case "2":
|
||||||
return CloudType.appflowyCloud;
|
return AuthenticatorType.appflowyCloud;
|
||||||
default:
|
default:
|
||||||
return CloudType.local;
|
return AuthenticatorType.local;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -70,17 +71,15 @@ Future<CloudType> getCloudType() async {
|
|||||||
/// Returns `false` otherwise.
|
/// Returns `false` otherwise.
|
||||||
bool get isAuthEnabled {
|
bool get isAuthEnabled {
|
||||||
// Only enable supabase in release and develop mode.
|
// Only enable supabase in release and develop mode.
|
||||||
if (integrationMode().isRelease || integrationMode().isDevelop) {
|
if (integrationMode().isRelease ||
|
||||||
|
integrationMode().isDevelop ||
|
||||||
|
integrationMode().isIntegrationTest) {
|
||||||
final env = getIt<AppFlowyCloudSharedEnv>();
|
final env = getIt<AppFlowyCloudSharedEnv>();
|
||||||
if (env.cloudType == CloudType.local) {
|
if (env.authenticatorType == AuthenticatorType.supabase) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.cloudType == CloudType.supabase) {
|
|
||||||
return env.supabaseConfig.isValid;
|
return env.supabaseConfig.isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.cloudType == CloudType.appflowyCloud) {
|
if (env.authenticatorType == AuthenticatorType.appflowyCloud) {
|
||||||
return env.appflowyCloudConfig.isValid;
|
return env.appflowyCloudConfig.isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +100,10 @@ bool get isAuthEnabled {
|
|||||||
/// is `CloudType.supabase`. Otherwise, it returns `false`.
|
/// is `CloudType.supabase`. Otherwise, it returns `false`.
|
||||||
bool get isSupabaseEnabled {
|
bool get isSupabaseEnabled {
|
||||||
// Only enable supabase in release and develop mode.
|
// Only enable supabase in release and develop mode.
|
||||||
if (integrationMode().isRelease || integrationMode().isDevelop) {
|
if (integrationMode().isRelease ||
|
||||||
return currentCloudType() == CloudType.supabase;
|
integrationMode().isDevelop ||
|
||||||
|
integrationMode().isIntegrationTest) {
|
||||||
|
return currentCloudType() == AuthenticatorType.supabase;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -119,26 +120,28 @@ bool get isSupabaseEnabled {
|
|||||||
/// cloud type is `CloudType.appflowyCloud`. Otherwise, it returns `false`.
|
/// cloud type is `CloudType.appflowyCloud`. Otherwise, it returns `false`.
|
||||||
bool get isAppFlowyCloudEnabled {
|
bool get isAppFlowyCloudEnabled {
|
||||||
// Only enable appflowy cloud in release and develop mode.
|
// Only enable appflowy cloud in release and develop mode.
|
||||||
if (integrationMode().isRelease || integrationMode().isDevelop) {
|
if (integrationMode().isRelease ||
|
||||||
return currentCloudType() == CloudType.appflowyCloud;
|
integrationMode().isDevelop ||
|
||||||
|
integrationMode().isIntegrationTest) {
|
||||||
|
return currentCloudType() == AuthenticatorType.appflowyCloud;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CloudType {
|
enum AuthenticatorType {
|
||||||
local,
|
local,
|
||||||
supabase,
|
supabase,
|
||||||
appflowyCloud;
|
appflowyCloud;
|
||||||
|
|
||||||
bool get isEnabled => this != CloudType.local;
|
bool get isEnabled => this != AuthenticatorType.local;
|
||||||
int get value {
|
int get value {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case CloudType.local:
|
case AuthenticatorType.local:
|
||||||
return 0;
|
return 0;
|
||||||
case CloudType.supabase:
|
case AuthenticatorType.supabase:
|
||||||
return 1;
|
return 1;
|
||||||
case CloudType.appflowyCloud:
|
case AuthenticatorType.appflowyCloud:
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,19 +149,19 @@ enum CloudType {
|
|||||||
static fromValue(int value) {
|
static fromValue(int value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 0:
|
case 0:
|
||||||
return CloudType.local;
|
return AuthenticatorType.local;
|
||||||
case 1:
|
case 1:
|
||||||
return CloudType.supabase;
|
return AuthenticatorType.supabase;
|
||||||
case 2:
|
case 2:
|
||||||
return CloudType.appflowyCloud;
|
return AuthenticatorType.appflowyCloud;
|
||||||
default:
|
default:
|
||||||
return CloudType.local;
|
return AuthenticatorType.local;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CloudType currentCloudType() {
|
AuthenticatorType currentCloudType() {
|
||||||
return getIt<AppFlowyCloudSharedEnv>().cloudType;
|
return getIt<AppFlowyCloudSharedEnv>().authenticatorType;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setAppFlowyCloudUrl(Option<String> url) async {
|
Future<void> setAppFlowyCloudUrl(Option<String> url) async {
|
||||||
@ -170,22 +173,52 @@ Future<void> setAppFlowyCloudUrl(Option<String> url) async {
|
|||||||
|
|
||||||
/// Use getIt<AppFlowyCloudSharedEnv>() to get the shared environment.
|
/// Use getIt<AppFlowyCloudSharedEnv>() to get the shared environment.
|
||||||
class AppFlowyCloudSharedEnv {
|
class AppFlowyCloudSharedEnv {
|
||||||
final CloudType cloudType;
|
final AuthenticatorType _authenticatorType;
|
||||||
final AppFlowyCloudConfiguration appflowyCloudConfig;
|
final AppFlowyCloudConfiguration appflowyCloudConfig;
|
||||||
final SupabaseConfiguration supabaseConfig;
|
final SupabaseConfiguration supabaseConfig;
|
||||||
|
|
||||||
AppFlowyCloudSharedEnv({
|
AppFlowyCloudSharedEnv({
|
||||||
required this.cloudType,
|
required AuthenticatorType authenticatorType,
|
||||||
required this.appflowyCloudConfig,
|
required this.appflowyCloudConfig,
|
||||||
required this.supabaseConfig,
|
required this.supabaseConfig,
|
||||||
});
|
}) : _authenticatorType = authenticatorType;
|
||||||
|
|
||||||
|
AuthenticatorType get authenticatorType => _authenticatorType;
|
||||||
|
|
||||||
|
static Future<AppFlowyCloudSharedEnv> fromEnv() async {
|
||||||
|
if (Env.enableCustomCloud) {
|
||||||
|
// Use the custom cloud configuration.
|
||||||
|
final cloudType = await getAuthenticatorType();
|
||||||
|
final appflowyCloudConfig = await getAppFlowyCloudConfig();
|
||||||
|
final supabaseCloudConfig = await getSupabaseCloudConfig();
|
||||||
|
|
||||||
|
return AppFlowyCloudSharedEnv(
|
||||||
|
authenticatorType: cloudType,
|
||||||
|
appflowyCloudConfig: appflowyCloudConfig,
|
||||||
|
supabaseConfig: supabaseCloudConfig,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final appflowyCloudConfig = AppFlowyCloudConfiguration(
|
||||||
|
base_url: Env.afCloudUrl,
|
||||||
|
ws_base_url: await _getAppFlowyCloudWSUrl(Env.afCloudUrl),
|
||||||
|
gotrue_url: await _getAppFlowyCloudGotrueUrl(Env.afCloudUrl),
|
||||||
|
);
|
||||||
|
|
||||||
|
return AppFlowyCloudSharedEnv(
|
||||||
|
authenticatorType: AuthenticatorType.fromValue(Env.authenticatorType),
|
||||||
|
appflowyCloudConfig: appflowyCloudConfig,
|
||||||
|
supabaseConfig: SupabaseConfiguration.defaultConfig(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<AppFlowyCloudConfiguration> getAppFlowyCloudConfig() async {
|
Future<AppFlowyCloudConfiguration> getAppFlowyCloudConfig() async {
|
||||||
|
final baseURL = await getAppFlowyCloudUrl();
|
||||||
return AppFlowyCloudConfiguration(
|
return AppFlowyCloudConfiguration(
|
||||||
base_url: await getAppFlowyCloudUrl(),
|
base_url: baseURL,
|
||||||
ws_base_url: await _getAppFlowyCloudWSUrl(),
|
ws_base_url: await _getAppFlowyCloudWSUrl(baseURL),
|
||||||
gotrue_url: await _getAppFlowyCloudGotrueUrl(),
|
gotrue_url: await _getAppFlowyCloudGotrueUrl(baseURL),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,10 +231,9 @@ Future<String> getAppFlowyCloudUrl() async {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _getAppFlowyCloudWSUrl() async {
|
Future<String> _getAppFlowyCloudWSUrl(String baseURL) async {
|
||||||
try {
|
try {
|
||||||
final serverUrl = await getAppFlowyCloudUrl();
|
final uri = Uri.parse(baseURL);
|
||||||
final uri = Uri.parse(serverUrl);
|
|
||||||
|
|
||||||
// Construct the WebSocket URL directly from the parsed URI.
|
// Construct the WebSocket URL directly from the parsed URI.
|
||||||
final wsScheme = uri.isScheme('HTTPS') ? 'wss' : 'ws';
|
final wsScheme = uri.isScheme('HTTPS') ? 'wss' : 'ws';
|
||||||
@ -214,9 +246,8 @@ Future<String> _getAppFlowyCloudWSUrl() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _getAppFlowyCloudGotrueUrl() async {
|
Future<String> _getAppFlowyCloudGotrueUrl(String baseURL) async {
|
||||||
final serverUrl = await getAppFlowyCloudUrl();
|
return "$baseURL/gotrue";
|
||||||
return "$serverUrl/gotrue";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setSupbaseServer(
|
Future<void> setSupbaseServer(
|
||||||
|
28
frontend/appflowy_flutter/lib/env/env.dart
vendored
Normal file
28
frontend/appflowy_flutter/lib/env/env.dart
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// lib/env/env.dart
|
||||||
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
|
import 'package:envied/envied.dart';
|
||||||
|
|
||||||
|
part 'env.g.dart';
|
||||||
|
|
||||||
|
@Envied(path: '.env')
|
||||||
|
abstract class Env {
|
||||||
|
static bool get enableCustomCloud {
|
||||||
|
return Env.authenticatorType == AuthenticatorType.appflowyCloud.value &&
|
||||||
|
_Env.afCloudUrl.isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnviedField(
|
||||||
|
obfuscate: false,
|
||||||
|
varName: 'AUTHENTICATOR_TYPE',
|
||||||
|
defaultValue: 2,
|
||||||
|
)
|
||||||
|
static const int authenticatorType = _Env.authenticatorType;
|
||||||
|
|
||||||
|
/// AppFlowy Cloud Configuration
|
||||||
|
@EnviedField(
|
||||||
|
obfuscate: false,
|
||||||
|
varName: 'APPFLOWY_CLOUD_URL',
|
||||||
|
defaultValue: '',
|
||||||
|
)
|
||||||
|
static const String afCloudUrl = _Env.afCloudUrl;
|
||||||
|
}
|
@ -9,6 +9,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/stability_
|
|||||||
import 'package:appflowy/plugins/trash/application/prelude.dart';
|
import 'package:appflowy/plugins/trash/application/prelude.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/user/application/auth/af_cloud_auth_service.dart';
|
import 'package:appflowy/user/application/auth/af_cloud_auth_service.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/application/auth/auth_service.dart';
|
||||||
import 'package:appflowy/user/application/auth/supabase_auth_service.dart';
|
import 'package:appflowy/user/application/auth/supabase_auth_service.dart';
|
||||||
import 'package:appflowy/user/application/auth/supabase_mock_auth_service.dart';
|
import 'package:appflowy/user/application/auth/supabase_mock_auth_service.dart';
|
||||||
@ -57,16 +58,8 @@ class DependencyResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _resolveCloudDeps(GetIt getIt) async {
|
Future<void> _resolveCloudDeps(GetIt getIt) async {
|
||||||
final cloudType = await getCloudType();
|
final env = await AppFlowyCloudSharedEnv.fromEnv();
|
||||||
final appflowyCloudConfig = await getAppFlowyCloudConfig();
|
getIt.registerFactory<AppFlowyCloudSharedEnv>(() => env);
|
||||||
final supabaseCloudConfig = await getSupabaseCloudConfig();
|
|
||||||
getIt.registerFactory<AppFlowyCloudSharedEnv>(() {
|
|
||||||
return AppFlowyCloudSharedEnv(
|
|
||||||
cloudType: cloudType,
|
|
||||||
appflowyCloudConfig: appflowyCloudConfig,
|
|
||||||
supabaseConfig: supabaseCloudConfig,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _resolveCommonService(
|
void _resolveCommonService(
|
||||||
@ -130,22 +123,27 @@ void _resolveCommonService(
|
|||||||
|
|
||||||
void _resolveUserDeps(GetIt getIt, IntegrationMode mode) {
|
void _resolveUserDeps(GetIt getIt, IntegrationMode mode) {
|
||||||
switch (currentCloudType()) {
|
switch (currentCloudType()) {
|
||||||
case CloudType.local:
|
case AuthenticatorType.local:
|
||||||
getIt.registerFactory<AuthService>(
|
getIt.registerFactory<AuthService>(
|
||||||
() => BackendAuthService(
|
() => BackendAuthService(
|
||||||
AuthTypePB.Local,
|
AuthTypePB.Local,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case CloudType.supabase:
|
case AuthenticatorType.supabase:
|
||||||
if (mode.isIntegrationTest) {
|
if (mode.isIntegrationTest) {
|
||||||
getIt.registerFactory<AuthService>(() => MockAuthService());
|
getIt.registerFactory<AuthService>(() => SupabaseMockAuthService());
|
||||||
} else {
|
} else {
|
||||||
getIt.registerFactory<AuthService>(() => SupabaseAuthService());
|
getIt.registerFactory<AuthService>(() => SupabaseAuthService());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CloudType.appflowyCloud:
|
case AuthenticatorType.appflowyCloud:
|
||||||
getIt.registerFactory<AuthService>(() => AFCloudAuthService());
|
if (mode.isIntegrationTest) {
|
||||||
|
getIt
|
||||||
|
.registerFactory<AuthService>(() => AppFlowyCloudMockAuthService());
|
||||||
|
} else {
|
||||||
|
getIt.registerFactory<AuthService>(() => AppFlowyCloudAuthService());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ class FlowyApp implements EntryPoint {
|
|||||||
@override
|
@override
|
||||||
Widget create(LaunchConfiguration config) {
|
Widget create(LaunchConfiguration config) {
|
||||||
return SplashScreen(
|
return SplashScreen(
|
||||||
autoRegister: config.autoRegistrationSupported,
|
isAnon: config.isAnon,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
class LaunchConfiguration {
|
class LaunchConfiguration {
|
||||||
const LaunchConfiguration({
|
const LaunchConfiguration({
|
||||||
this.autoRegistrationSupported = false,
|
this.isAnon = false,
|
||||||
|
required this.rustEnvs,
|
||||||
});
|
});
|
||||||
|
|
||||||
// APP will automatically register after launching.
|
// APP will automatically register after launching.
|
||||||
final bool autoRegistrationSupported;
|
final bool isAnon;
|
||||||
|
//
|
||||||
|
final Map<String, String> rustEnvs;
|
||||||
}
|
}
|
||||||
|
@ -36,21 +36,35 @@ Future<void> runAppFlowy() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlowyRunner {
|
class FlowyRunner {
|
||||||
|
static var currentMode = integrationMode();
|
||||||
|
|
||||||
static Future<FlowyRunnerContext> run(
|
static Future<FlowyRunnerContext> run(
|
||||||
EntryPoint f,
|
EntryPoint f,
|
||||||
IntegrationMode mode, {
|
IntegrationMode mode, {
|
||||||
Future? didInitGetIt,
|
// This callback is triggered after the initialization of 'getIt',
|
||||||
LaunchConfiguration config = const LaunchConfiguration(
|
// which is used for dependency injection throughout the app.
|
||||||
autoRegistrationSupported: false,
|
// If your functionality depends on 'getIt', ensure to register
|
||||||
),
|
// your callback here to execute any necessary actions post-initialization.
|
||||||
|
Future? didInitGetItCallback,
|
||||||
|
// Passing the envs to the backend
|
||||||
|
Map<String, String> Function()? rustEnvsBuilder,
|
||||||
|
// Indicate whether the app is running in anonymous mode.
|
||||||
|
// Note: when the app is running in anonymous mode, the user no need to
|
||||||
|
// sign in, and the app will only save the data in the local storage.
|
||||||
|
bool isAnon = false,
|
||||||
}) async {
|
}) async {
|
||||||
|
currentMode = mode;
|
||||||
// Clear all the states in case of rebuilding.
|
// Clear all the states in case of rebuilding.
|
||||||
await getIt.reset();
|
await getIt.reset();
|
||||||
|
|
||||||
|
final config = LaunchConfiguration(
|
||||||
|
isAnon: isAnon,
|
||||||
|
rustEnvs: rustEnvsBuilder?.call() ?? {},
|
||||||
|
);
|
||||||
|
|
||||||
// Specify the env
|
// Specify the env
|
||||||
await initGetIt(getIt, mode, f, config);
|
await initGetIt(getIt, mode, f, config);
|
||||||
|
await didInitGetItCallback;
|
||||||
await didInitGetIt;
|
|
||||||
|
|
||||||
final applicationDataDirectory =
|
final applicationDataDirectory =
|
||||||
await getIt<ApplicationDataStorage>().getPath().then(
|
await getIt<ApplicationDataStorage>().getPath().then(
|
||||||
|
@ -23,15 +23,18 @@ class InitRustSDKTask extends LaunchTask {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> initialize(LaunchContext context) async {
|
Future<void> initialize(LaunchContext context) async {
|
||||||
|
final root = await getApplicationSupportDirectory();
|
||||||
final applicationPath = await appFlowyApplicationDataDirectory();
|
final applicationPath = await appFlowyApplicationDataDirectory();
|
||||||
final dir = customApplicationPath ?? applicationPath;
|
final dir = customApplicationPath ?? applicationPath;
|
||||||
final deviceId = await getDeviceId();
|
final deviceId = await getDeviceId();
|
||||||
|
|
||||||
// Pass the environment variables to the Rust SDK
|
// Pass the environment variables to the Rust SDK
|
||||||
final env = _getAppFlowyConfiguration(
|
final env = _makeAppFlowyConfiguration(
|
||||||
|
root.path,
|
||||||
dir.path,
|
dir.path,
|
||||||
applicationPath.path,
|
applicationPath.path,
|
||||||
deviceId,
|
deviceId,
|
||||||
|
rustEnvs: context.config.rustEnvs,
|
||||||
);
|
);
|
||||||
await context.getIt<FlowySDK>().init(jsonEncode(env.toJson()));
|
await context.getIt<FlowySDK>().init(jsonEncode(env.toJson()));
|
||||||
}
|
}
|
||||||
@ -40,19 +43,23 @@ class InitRustSDKTask extends LaunchTask {
|
|||||||
Future<void> dispose() async {}
|
Future<void> dispose() async {}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppFlowyConfiguration _getAppFlowyConfiguration(
|
AppFlowyConfiguration _makeAppFlowyConfiguration(
|
||||||
|
String root,
|
||||||
String customAppPath,
|
String customAppPath,
|
||||||
String originAppPath,
|
String originAppPath,
|
||||||
String deviceId,
|
String deviceId, {
|
||||||
) {
|
required Map<String, String> rustEnvs,
|
||||||
|
}) {
|
||||||
final env = getIt<AppFlowyCloudSharedEnv>();
|
final env = getIt<AppFlowyCloudSharedEnv>();
|
||||||
return AppFlowyConfiguration(
|
return AppFlowyConfiguration(
|
||||||
|
root: root,
|
||||||
custom_app_path: customAppPath,
|
custom_app_path: customAppPath,
|
||||||
origin_app_path: originAppPath,
|
origin_app_path: originAppPath,
|
||||||
device_id: deviceId,
|
device_id: deviceId,
|
||||||
cloud_type: env.cloudType.value,
|
authenticator_type: env.authenticatorType.value,
|
||||||
supabase_config: env.supabaseConfig,
|
supabase_config: env.supabaseConfig,
|
||||||
appflowy_cloud_config: env.appflowyCloudConfig,
|
appflowy_cloud_config: env.appflowyCloudConfig,
|
||||||
|
envs: rustEnvs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@ import 'package:url_launcher/url_launcher.dart';
|
|||||||
import 'auth_error.dart';
|
import 'auth_error.dart';
|
||||||
import 'device_id.dart';
|
import 'device_id.dart';
|
||||||
|
|
||||||
class AFCloudAuthService implements AuthService {
|
class AppFlowyCloudAuthService implements AuthService {
|
||||||
final _appLinks = AppLinks();
|
final _appLinks = AppLinks();
|
||||||
StreamSubscription<Uri?>? _deeplinkSubscription;
|
StreamSubscription<Uri?>? _deeplinkSubscription;
|
||||||
|
|
||||||
AFCloudAuthService();
|
AppFlowyCloudAuthService();
|
||||||
|
|
||||||
final BackendAuthService _backendAuthService = BackendAuthService(
|
final BackendAuthService _backendAuthService = BackendAuthService(
|
||||||
AuthTypePB.AFCloud,
|
AuthTypePB.AFCloud,
|
||||||
@ -35,7 +35,7 @@ class AFCloudAuthService implements AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Either<FlowyError, UserProfilePB>> signIn({
|
Future<Either<FlowyError, UserProfilePB>> signInWithEmailPassword({
|
||||||
required String email,
|
required String email,
|
||||||
required String password,
|
required String password,
|
||||||
Map<String, String> params = const {},
|
Map<String, String> params = const {},
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:appflowy/user/application/auth/backend_auth_service.dart';
|
||||||
|
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||||
|
import 'package:appflowy/user/application/auth/device_id.dart';
|
||||||
|
import 'package:appflowy/user/application/user_service.dart';
|
||||||
|
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:flowy_infra/uuid.dart';
|
||||||
|
|
||||||
|
/// Only used for testing.
|
||||||
|
class AppFlowyCloudMockAuthService implements AuthService {
|
||||||
|
// Use same email for all tests.
|
||||||
|
static String currentUserEmail = "";
|
||||||
|
|
||||||
|
AppFlowyCloudMockAuthService() {
|
||||||
|
if (currentUserEmail.isEmpty) {
|
||||||
|
currentUserEmail = "${uuid()}@appflowy.io";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final BackendAuthService _appFlowyAuthService =
|
||||||
|
BackendAuthService(AuthTypePB.Supabase);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<FlowyError, UserProfilePB>> signUp({
|
||||||
|
required String name,
|
||||||
|
required String email,
|
||||||
|
required String password,
|
||||||
|
Map<String, String> params = const {},
|
||||||
|
}) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<FlowyError, UserProfilePB>> signInWithEmailPassword({
|
||||||
|
required String email,
|
||||||
|
required String password,
|
||||||
|
Map<String, String> params = const {},
|
||||||
|
}) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<FlowyError, UserProfilePB>> signUpWithOAuth({
|
||||||
|
required String platform,
|
||||||
|
Map<String, String> params = const {},
|
||||||
|
}) async {
|
||||||
|
final payload = SignInUrlPayloadPB.create()
|
||||||
|
..authType = AuthTypePB.AFCloud
|
||||||
|
// don't use nanoid here, the gotrue server will transform the email
|
||||||
|
..email = currentUserEmail;
|
||||||
|
|
||||||
|
final deviceId = await getDeviceId();
|
||||||
|
final getSignInURLResult = await UserEventGenerateSignInURL(payload).send();
|
||||||
|
|
||||||
|
return getSignInURLResult.fold(
|
||||||
|
(urlPB) async {
|
||||||
|
final payload = OauthSignInPB(
|
||||||
|
authType: AuthTypePB.AFCloud,
|
||||||
|
map: {
|
||||||
|
AuthServiceMapKeys.signInURL: urlPB.signInUrl,
|
||||||
|
AuthServiceMapKeys.deviceId: deviceId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return await UserEventOauthSignIn(payload)
|
||||||
|
.send()
|
||||||
|
.then((value) => value.swap());
|
||||||
|
},
|
||||||
|
(r) => left(r),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> signOut() async {
|
||||||
|
await _appFlowyAuthService.signOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<FlowyError, UserProfilePB>> signUpAsGuest({
|
||||||
|
Map<String, String> params = const {},
|
||||||
|
}) async {
|
||||||
|
return _appFlowyAuthService.signUpAsGuest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<FlowyError, UserProfilePB>> signInWithMagicLink({
|
||||||
|
required String email,
|
||||||
|
Map<String, String> params = const {},
|
||||||
|
}) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<FlowyError, UserProfilePB>> getUser() async {
|
||||||
|
return UserBackendService.getCurrentUserProfile();
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ abstract class AuthService {
|
|||||||
///
|
///
|
||||||
/// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError].
|
/// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError].
|
||||||
|
|
||||||
Future<Either<FlowyError, UserProfilePB>> signIn({
|
Future<Either<FlowyError, UserProfilePB>> signInWithEmailPassword({
|
||||||
required String email,
|
required String email,
|
||||||
required String password,
|
required String password,
|
||||||
Map<String, String> params,
|
Map<String, String> params,
|
||||||
|
@ -19,7 +19,7 @@ class BackendAuthService implements AuthService {
|
|||||||
BackendAuthService(this.authType);
|
BackendAuthService(this.authType);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Either<FlowyError, UserProfilePB>> signIn({
|
Future<Either<FlowyError, UserProfilePB>> signInWithEmailPassword({
|
||||||
required String email,
|
required String email,
|
||||||
required String password,
|
required String password,
|
||||||
Map<String, String> params = const {},
|
Map<String, String> params = const {},
|
||||||
@ -29,7 +29,7 @@ class BackendAuthService implements AuthService {
|
|||||||
..password = password
|
..password = password
|
||||||
..authType = authType
|
..authType = authType
|
||||||
..deviceId = await getDeviceId();
|
..deviceId = await getDeviceId();
|
||||||
final response = UserEventSignIn(request).send();
|
final response = UserEventSignInWithEmailPassword(request).send();
|
||||||
return response.then((value) => value.swap());
|
return response.then((value) => value.swap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class SupabaseAuthService implements AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Either<FlowyError, UserProfilePB>> signIn({
|
Future<Either<FlowyError, UserProfilePB>> signInWithEmailPassword({
|
||||||
required String email,
|
required String email,
|
||||||
required String password,
|
required String password,
|
||||||
Map<String, String> params = const {},
|
Map<String, String> params = const {},
|
||||||
@ -68,7 +68,7 @@ class SupabaseAuthService implements AuthService {
|
|||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
return Left(AuthError.supabaseSignInError);
|
return Left(AuthError.supabaseSignInError);
|
||||||
}
|
}
|
||||||
return _backendAuthService.signIn(
|
return _backendAuthService.signInWithEmailPassword(
|
||||||
email: email,
|
email: email,
|
||||||
password: password,
|
password: password,
|
||||||
params: {
|
params: {
|
||||||
|
@ -13,8 +13,8 @@ import 'package:supabase_flutter/supabase_flutter.dart';
|
|||||||
import 'auth_error.dart';
|
import 'auth_error.dart';
|
||||||
|
|
||||||
/// Only used for testing.
|
/// Only used for testing.
|
||||||
class MockAuthService implements AuthService {
|
class SupabaseMockAuthService implements AuthService {
|
||||||
MockAuthService();
|
SupabaseMockAuthService();
|
||||||
static OauthSignInPB? signInPayload;
|
static OauthSignInPB? signInPayload;
|
||||||
|
|
||||||
SupabaseClient get _client => Supabase.instance.client;
|
SupabaseClient get _client => Supabase.instance.client;
|
||||||
@ -34,7 +34,7 @@ class MockAuthService implements AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Either<FlowyError, UserProfilePB>> signIn({
|
Future<Either<FlowyError, UserProfilePB>> signInWithEmailPassword({
|
||||||
required String email,
|
required String email,
|
||||||
required String password,
|
required String password,
|
||||||
Map<String, String> params = const {},
|
Map<String, String> params = const {},
|
||||||
|
@ -59,7 +59,7 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
|
|||||||
SignInState state,
|
SignInState state,
|
||||||
Emitter<SignInState> emit,
|
Emitter<SignInState> emit,
|
||||||
) async {
|
) async {
|
||||||
final result = await authService.signIn(
|
final result = await authService.signInWithEmailPassword(
|
||||||
email: state.email ?? '',
|
email: state.email ?? '',
|
||||||
password: state.password ?? '',
|
password: state.password ?? '',
|
||||||
);
|
);
|
||||||
|
@ -20,10 +20,15 @@ void handleOpenWorkspaceError(BuildContext context, FlowyError error) {
|
|||||||
error.msg,
|
error.msg,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case ErrorCode.HttpError:
|
||||||
|
showSnapBar(
|
||||||
|
context,
|
||||||
|
error.toString(),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
showSnapBar(
|
showSnapBar(
|
||||||
context,
|
context,
|
||||||
error.msg,
|
error.toString(),
|
||||||
onClosed: () {
|
onClosed: () {
|
||||||
getIt<AuthService>().signOut();
|
getIt<AuthService>().signOut();
|
||||||
runAppFlowy();
|
runAppFlowy();
|
||||||
|
@ -2,7 +2,6 @@ import 'package:appflowy/core/frameless_window.dart';
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/startup/entry_point.dart';
|
import 'package:appflowy/startup/entry_point.dart';
|
||||||
import 'package:appflowy/startup/launch_configuration.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||||
import 'package:appflowy/user/application/historical_user_bloc.dart';
|
import 'package:appflowy/user/application/historical_user_bloc.dart';
|
||||||
@ -66,6 +65,13 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
// if (Env.enableCustomCloud) ...[
|
||||||
|
// const VSpace(10),
|
||||||
|
// const SizedBox(
|
||||||
|
// width: 340,
|
||||||
|
// child: _SetupYourServer(),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
const VSpace(32),
|
const VSpace(32),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: size.width * 0.7,
|
width: size.width * 0.7,
|
||||||
@ -98,9 +104,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
|||||||
await FlowyRunner.run(
|
await FlowyRunner.run(
|
||||||
FlowyApp(),
|
FlowyApp(),
|
||||||
integrationMode(),
|
integrationMode(),
|
||||||
config: const LaunchConfiguration(
|
isAnon: true,
|
||||||
autoRegistrationSupported: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,10 +283,33 @@ class GoButton extends StatelessWidget {
|
|||||||
? LocaleKeys.letsGoButtonText.tr()
|
? LocaleKeys.letsGoButtonText.tr()
|
||||||
: LocaleKeys.signIn_continueAnonymousUser.tr();
|
: LocaleKeys.signIn_continueAnonymousUser.tr();
|
||||||
|
|
||||||
final textWidget = FlowyText.medium(
|
final textWidget = Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: FlowyText.medium(
|
||||||
text,
|
text,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Tooltip(
|
||||||
|
// message: LocaleKeys.settings_menu_configServerGuide.tr(),
|
||||||
|
// child: Container(
|
||||||
|
// width: 30.0,
|
||||||
|
// decoration: const BoxDecoration(
|
||||||
|
// shape: BoxShape.circle,
|
||||||
|
// ),
|
||||||
|
// child: Center(
|
||||||
|
// child: Icon(
|
||||||
|
// Icons.help,
|
||||||
|
// color: Colors.white,
|
||||||
|
// weight: 2,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
@ -18,16 +18,14 @@ class SplashScreen extends StatelessWidget {
|
|||||||
/// Root Page of the app.
|
/// Root Page of the app.
|
||||||
const SplashScreen({
|
const SplashScreen({
|
||||||
super.key,
|
super.key,
|
||||||
required this.autoRegister,
|
required this.isAnon,
|
||||||
});
|
});
|
||||||
|
|
||||||
final bool autoRegister;
|
final bool isAnon;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (!autoRegister) {
|
if (isAnon) {
|
||||||
return _buildChild(context);
|
|
||||||
} else {
|
|
||||||
return FutureBuilder<void>(
|
return FutureBuilder<void>(
|
||||||
future: _registerIfNeeded(),
|
future: _registerIfNeeded(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
@ -37,6 +35,8 @@ class SplashScreen extends StatelessWidget {
|
|||||||
return _buildChild(context);
|
return _buildChild(context);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return _buildChild(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,13 +5,13 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||||||
part 'cloud_setting_bloc.freezed.dart';
|
part 'cloud_setting_bloc.freezed.dart';
|
||||||
|
|
||||||
class CloudSettingBloc extends Bloc<CloudSettingEvent, CloudSettingState> {
|
class CloudSettingBloc extends Bloc<CloudSettingEvent, CloudSettingState> {
|
||||||
CloudSettingBloc(CloudType cloudType)
|
CloudSettingBloc(AuthenticatorType cloudType)
|
||||||
: super(CloudSettingState.initial(cloudType)) {
|
: super(CloudSettingState.initial(cloudType)) {
|
||||||
on<CloudSettingEvent>((event, emit) async {
|
on<CloudSettingEvent>((event, emit) async {
|
||||||
await event.when(
|
await event.when(
|
||||||
initial: () async {},
|
initial: () async {},
|
||||||
updateCloudType: (CloudType newCloudType) async {
|
updateCloudType: (AuthenticatorType newCloudType) async {
|
||||||
await setCloudType(newCloudType);
|
await setAuthenticatorType(newCloudType);
|
||||||
emit(state.copyWith(cloudType: newCloudType));
|
emit(state.copyWith(cloudType: newCloudType));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -22,17 +22,19 @@ class CloudSettingBloc extends Bloc<CloudSettingEvent, CloudSettingState> {
|
|||||||
@freezed
|
@freezed
|
||||||
class CloudSettingEvent with _$CloudSettingEvent {
|
class CloudSettingEvent with _$CloudSettingEvent {
|
||||||
const factory CloudSettingEvent.initial() = _Initial;
|
const factory CloudSettingEvent.initial() = _Initial;
|
||||||
const factory CloudSettingEvent.updateCloudType(CloudType newCloudType) =
|
const factory CloudSettingEvent.updateCloudType(
|
||||||
_UpdateCloudType;
|
AuthenticatorType newCloudType,
|
||||||
|
) = _UpdateCloudType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class CloudSettingState with _$CloudSettingState {
|
class CloudSettingState with _$CloudSettingState {
|
||||||
const factory CloudSettingState({
|
const factory CloudSettingState({
|
||||||
required CloudType cloudType,
|
required AuthenticatorType cloudType,
|
||||||
}) = _CloudSettingState;
|
}) = _CloudSettingState;
|
||||||
|
|
||||||
factory CloudSettingState.initial(CloudType cloudType) => CloudSettingState(
|
factory CloudSettingState.initial(AuthenticatorType cloudType) =>
|
||||||
|
CloudSettingState(
|
||||||
cloudType: cloudType,
|
cloudType: cloudType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy/env/env.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/appflowy_cloud_setting_bloc.dart';
|
import 'package:appflowy/workspace/application/settings/appflowy_cloud_setting_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/appflowy_cloud_urls_bloc.dart';
|
import 'package:appflowy/workspace/application/settings/appflowy_cloud_urls_bloc.dart';
|
||||||
@ -50,7 +51,16 @@ class SettingAppFlowyCloudView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const AppFlowyCloudEnableSync(),
|
const AppFlowyCloudEnableSync(),
|
||||||
const VSpace(40),
|
const VSpace(40),
|
||||||
|
if (Env.enableCustomCloud)
|
||||||
AppFlowyCloudURLs(didUpdateUrls: () => didResetServerUrl()),
|
AppFlowyCloudURLs(didUpdateUrls: () => didResetServerUrl()),
|
||||||
|
if (!Env.enableCustomCloud)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
FlowyText(LocaleKeys.settings_menu_cloudServerType.tr()),
|
||||||
|
const Spacer(),
|
||||||
|
const FlowyText(Env.afCloudUrl),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:appflowy/env/cloud_env.dart';
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
|
import 'package:appflowy/env/env.dart';
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/cloud_setting_bloc.dart';
|
import 'package:appflowy/workspace/application/settings/cloud_setting_bloc.dart';
|
||||||
@ -19,8 +20,9 @@ class SettingCloud extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: getCloudType(),
|
future: getAuthenticatorType(),
|
||||||
builder: (BuildContext context, AsyncSnapshot<CloudType> snapshot) {
|
builder:
|
||||||
|
(BuildContext context, AsyncSnapshot<AuthenticatorType> snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
final cloudType = snapshot.data!;
|
final cloudType = snapshot.data!;
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
@ -29,6 +31,7 @@ class SettingCloud extends StatelessWidget {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
|
if (Env.enableCustomCloud)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -37,8 +40,8 @@ class SettingCloud extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message:
|
message: LocaleKeys.settings_menu_cloudServerTypeTip
|
||||||
LocaleKeys.settings_menu_cloudServerTypeTip.tr(),
|
.tr(),
|
||||||
child: CloudTypeSwitcher(
|
child: CloudTypeSwitcher(
|
||||||
cloudType: state.cloudType,
|
cloudType: state.cloudType,
|
||||||
onSelected: (newCloudType) {
|
onSelected: (newCloudType) {
|
||||||
@ -67,15 +70,15 @@ class SettingCloud extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _viewFromCloudType(CloudType cloudType) {
|
Widget _viewFromCloudType(AuthenticatorType cloudType) {
|
||||||
switch (cloudType) {
|
switch (cloudType) {
|
||||||
case CloudType.local:
|
case AuthenticatorType.local:
|
||||||
return SettingLocalCloud(didResetServerUrl: didResetServerUrl);
|
return SettingLocalCloud(didResetServerUrl: didResetServerUrl);
|
||||||
case CloudType.supabase:
|
case AuthenticatorType.supabase:
|
||||||
return SettingSupabaseCloudView(
|
return SettingSupabaseCloudView(
|
||||||
didResetServerUrl: didResetServerUrl,
|
didResetServerUrl: didResetServerUrl,
|
||||||
);
|
);
|
||||||
case CloudType.appflowyCloud:
|
case AuthenticatorType.appflowyCloud:
|
||||||
return SettingAppFlowyCloudView(
|
return SettingAppFlowyCloudView(
|
||||||
didResetServerUrl: didResetServerUrl,
|
didResetServerUrl: didResetServerUrl,
|
||||||
);
|
);
|
||||||
@ -84,8 +87,8 @@ class SettingCloud extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CloudTypeSwitcher extends StatelessWidget {
|
class CloudTypeSwitcher extends StatelessWidget {
|
||||||
final CloudType cloudType;
|
final AuthenticatorType cloudType;
|
||||||
final Function(CloudType) onSelected;
|
final Function(AuthenticatorType) onSelected;
|
||||||
const CloudTypeSwitcher({
|
const CloudTypeSwitcher({
|
||||||
required this.cloudType,
|
required this.cloudType,
|
||||||
required this.onSelected,
|
required this.onSelected,
|
||||||
@ -108,12 +111,12 @@ class CloudTypeSwitcher extends StatelessWidget {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return CloudTypeItem(
|
return CloudTypeItem(
|
||||||
cloudType: CloudType.values[index],
|
cloudType: AuthenticatorType.values[index],
|
||||||
currentCloudtype: cloudType,
|
currentCloudtype: cloudType,
|
||||||
onSelected: onSelected,
|
onSelected: onSelected,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
itemCount: CloudType.values.length,
|
itemCount: AuthenticatorType.values.length,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -121,9 +124,9 @@ class CloudTypeSwitcher extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CloudTypeItem extends StatelessWidget {
|
class CloudTypeItem extends StatelessWidget {
|
||||||
final CloudType cloudType;
|
final AuthenticatorType cloudType;
|
||||||
final CloudType currentCloudtype;
|
final AuthenticatorType currentCloudtype;
|
||||||
final Function(CloudType) onSelected;
|
final Function(AuthenticatorType) onSelected;
|
||||||
|
|
||||||
const CloudTypeItem({
|
const CloudTypeItem({
|
||||||
required this.cloudType,
|
required this.cloudType,
|
||||||
@ -154,13 +157,13 @@ class CloudTypeItem extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String titleFromCloudType(CloudType cloudType) {
|
String titleFromCloudType(AuthenticatorType cloudType) {
|
||||||
switch (cloudType) {
|
switch (cloudType) {
|
||||||
case CloudType.local:
|
case AuthenticatorType.local:
|
||||||
return LocaleKeys.settings_menu_cloudLocal.tr();
|
return LocaleKeys.settings_menu_cloudLocal.tr();
|
||||||
case CloudType.supabase:
|
case AuthenticatorType.supabase:
|
||||||
return LocaleKeys.settings_menu_cloudSupabase.tr();
|
return LocaleKeys.settings_menu_cloudSupabase.tr();
|
||||||
case CloudType.appflowyCloud:
|
case AuthenticatorType.appflowyCloud:
|
||||||
return LocaleKeys.settings_menu_cloudAppFlowy.tr();
|
return LocaleKeys.settings_menu_cloudAppFlowy.tr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ import 'package:styled_widget/styled_widget.dart';
|
|||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import '../../../../generated/locale_keys.g.dart';
|
import '../../../../generated/locale_keys.g.dart';
|
||||||
import '../../../../startup/launch_configuration.dart';
|
|
||||||
import '../../../../startup/startup.dart';
|
import '../../../../startup/startup.dart';
|
||||||
import '../../../../startup/tasks/prelude.dart';
|
import '../../../../startup/tasks/prelude.dart';
|
||||||
|
|
||||||
@ -210,10 +209,8 @@ class _ChangeStoragePathButtonState extends State<_ChangeStoragePathButton> {
|
|||||||
await context.read<SettingsLocationCubit>().setCustomPath(path);
|
await context.read<SettingsLocationCubit>().setCustomPath(path);
|
||||||
await FlowyRunner.run(
|
await FlowyRunner.run(
|
||||||
FlowyApp(),
|
FlowyApp(),
|
||||||
integrationMode(),
|
FlowyRunner.currentMode,
|
||||||
config: const LaunchConfiguration(
|
isAnon: true,
|
||||||
autoRegistrationSupported: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@ -288,10 +285,8 @@ class _RecoverDefaultStorageButtonState
|
|||||||
.resetDataStoragePathToApplicationDefault();
|
.resetDataStoragePathToApplicationDefault();
|
||||||
await FlowyRunner.run(
|
await FlowyRunner.run(
|
||||||
FlowyApp(),
|
FlowyApp(),
|
||||||
integrationMode(),
|
FlowyRunner.currentMode,
|
||||||
config: const LaunchConfiguration(
|
isAnon: true,
|
||||||
autoRegistrationSupported: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
platform :osx, '10.11'
|
platform :osx, '10.13'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
@ -17,7 +17,7 @@ A new flutter plugin project.
|
|||||||
s.public_header_files = 'Classes/**/*.h'
|
s.public_header_files = 'Classes/**/*.h'
|
||||||
s.dependency 'FlutterMacOS'
|
s.dependency 'FlutterMacOS'
|
||||||
|
|
||||||
s.platform = :osx, '10.11'
|
s.platform = :osx, '10.13'
|
||||||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
||||||
s.swift_version = '5.0'
|
s.swift_version = '5.0'
|
||||||
s.static_framework = true
|
s.static_framework = true
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
platform :osx, '10.11'
|
platform :osx, '10.13'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
@ -15,7 +15,8 @@ void showSnapBar(BuildContext context, String title, {VoidCallback? onClosed}) {
|
|||||||
},
|
},
|
||||||
child: FlowyText.medium(
|
child: FlowyText.medium(
|
||||||
title,
|
title,
|
||||||
fontSize: 16,
|
fontSize: 12,
|
||||||
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
|
@ -16,7 +16,7 @@ A new flutter plugin project.
|
|||||||
s.source_files = 'Classes/**/*'
|
s.source_files = 'Classes/**/*'
|
||||||
s.dependency 'FlutterMacOS'
|
s.dependency 'FlutterMacOS'
|
||||||
|
|
||||||
s.platform = :osx, '10.11'
|
s.platform = :osx, '10.13'
|
||||||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
||||||
s.swift_version = '5.0'
|
s.swift_version = '5.0'
|
||||||
end
|
end
|
||||||
|
@ -271,12 +271,12 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: connectivity_plus
|
name: connectivity_plus
|
||||||
sha256: b502a681ba415272ecc41400bd04fe543ed1a62632137dc84d25a91e7746f55f
|
sha256: "224a77051d52a11fbad53dd57827594d3bd24f945af28bd70bab376d68d437f0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.1"
|
version: "5.0.2"
|
||||||
connectivity_plus_platform_interface:
|
connectivity_plus_platform_interface:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: connectivity_plus_platform_interface
|
name: connectivity_plus_platform_interface
|
||||||
sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a
|
sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a
|
||||||
@ -1463,10 +1463,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
|
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.2.2"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1495,10 +1495,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
|
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.1"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -74,8 +74,7 @@ dependencies:
|
|||||||
package_info_plus: ^4.0.1
|
package_info_plus: ^4.0.1
|
||||||
url_launcher: ^6.1.11
|
url_launcher: ^6.1.11
|
||||||
clipboard: ^0.1.3
|
clipboard: ^0.1.3
|
||||||
connectivity_plus: ^5.0.1
|
connectivity_plus: ^5.0.2
|
||||||
connectivity_plus_platform_interface: ^1.2.4
|
|
||||||
easy_localization: ^3.0.2
|
easy_localization: ^3.0.2
|
||||||
textfield_tags: ^2.0.2
|
textfield_tags: ^2.0.2
|
||||||
device_info_plus: ^9.0.1
|
device_info_plus: ^9.0.1
|
||||||
@ -91,7 +90,7 @@ dependencies:
|
|||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
collection: ^1.17.1
|
collection: ^1.17.1
|
||||||
bloc: ^8.1.2
|
bloc: ^8.1.2
|
||||||
shared_preferences: ^2.1.1
|
shared_preferences: ^2.2.2
|
||||||
google_fonts: ^4.0.5
|
google_fonts: ^4.0.5
|
||||||
percent_indicator: ^4.2.3
|
percent_indicator: ^4.2.3
|
||||||
calendar_view:
|
calendar_view:
|
||||||
|
36
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
36
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -138,7 +138,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "app-error"
|
name = "app-error"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -785,7 +785,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-api"
|
name = "client-api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -1326,7 +1326,7 @@ dependencies = [
|
|||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa 1.0.6",
|
"itoa 1.0.6",
|
||||||
"phf 0.11.2",
|
"phf 0.8.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1472,7 +1472,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "database-entity"
|
name = "database-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2830,7 +2830,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gotrue"
|
name = "gotrue"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -2846,7 +2846,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gotrue-entity"
|
name = "gotrue-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -3267,7 +3267,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "infra"
|
name = "infra"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -4363,7 +4363,6 @@ version = "0.11.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros 0.11.2",
|
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4455,19 +4454,6 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_macros"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
|
||||||
dependencies = [
|
|
||||||
"phf_generator 0.11.2",
|
|
||||||
"phf_shared 0.11.2",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.29",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -4709,7 +4695,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"heck 0.4.1",
|
"heck 0.4.1",
|
||||||
"itertools 0.11.0",
|
"itertools 0.10.5",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -4730,7 +4716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.11.0",
|
"itertools 0.10.5",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.29",
|
"syn 2.0.29",
|
||||||
@ -5025,7 +5011,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "realtime-entity"
|
name = "realtime-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -5778,7 +5764,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "shared_entity"
|
name = "shared_entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
|
@ -57,7 +57,7 @@ custom-protocol = ["tauri/custom-protocol"]
|
|||||||
# Run the script:
|
# Run the script:
|
||||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b578c83cc912255e48dea9e33a203a069ce7d0c5" }
|
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5090711272dbc503912544375307365c174bb804" }
|
||||||
# Please use the following script to update collab.
|
# Please use the following script to update collab.
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
#
|
#
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
UserEventGetUserProfile,
|
UserEventGetUserProfile,
|
||||||
UserEventGetUserSetting,
|
UserEventGetUserSetting,
|
||||||
UserEventSetAppearanceSetting,
|
UserEventSetAppearanceSetting,
|
||||||
UserEventSignIn,
|
UserEventSignInWithEmailPassword,
|
||||||
UserEventSignOut,
|
UserEventSignOut,
|
||||||
UserEventSignUp,
|
UserEventSignUp,
|
||||||
UserEventUpdateUserProfile,
|
UserEventUpdateUserProfile,
|
||||||
@ -99,7 +99,7 @@ export class AuthBackendService {
|
|||||||
signIn = (params: { email: string; password: string }) => {
|
signIn = (params: { email: string; password: string }) => {
|
||||||
const payload = SignInPayloadPB.fromObject({ email: params.email, password: params.password });
|
const payload = SignInPayloadPB.fromObject({ email: params.email, password: params.password });
|
||||||
|
|
||||||
return UserEventSignIn(payload);
|
return UserEventSignInWithEmailPassword(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
signUp = (params: { name: string; email: string; password: string }) => {
|
signUp = (params: { name: string; email: string; password: string }) => {
|
||||||
|
@ -290,6 +290,8 @@
|
|||||||
"enableEncryptPrompt": "Activate encryption to secure your data with this secret. Store it safely; once enabled, it can't be turned off. If lost, your data becomes irretrievable. Click to copy",
|
"enableEncryptPrompt": "Activate encryption to secure your data with this secret. Store it safely; once enabled, it can't be turned off. If lost, your data becomes irretrievable. Click to copy",
|
||||||
"inputEncryptPrompt": "Please enter your encryption secret for",
|
"inputEncryptPrompt": "Please enter your encryption secret for",
|
||||||
"clickToCopySecret": "Click to copy secret",
|
"clickToCopySecret": "Click to copy secret",
|
||||||
|
"configServerSetting": "Configurate your server settings",
|
||||||
|
"configServerGuide": "After selecting `Quick Start`, navigate to `Settings` and then \"Cloud Setting\" to configure your self-hosted server.",
|
||||||
"inputTextFieldHint": "Your secret",
|
"inputTextFieldHint": "Your secret",
|
||||||
"historicalUserList": "User login history",
|
"historicalUserList": "User login history",
|
||||||
"historicalUserListTooltip": "This list displays your anonymous accounts. You can click on an account to view its details. Anonymous accounts are created by clicking the 'Get Started' button",
|
"historicalUserListTooltip": "This list displays your anonymous accounts. You can click on an account to view its details. Anonymous accounts are created by clicking the 'Get Started' button",
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
[build]
|
|
||||||
rustflags = ["--cfg", "tokio_unstable"]
|
|
||||||
|
|
||||||
[target.x86_64-apple-darwin]
|
[target.x86_64-apple-darwin]
|
||||||
rustflags = ["-C", "target-cpu=native", "-C", "link-arg=-mmacosx-version-min=11.0"]
|
rustflags = ["-C", "target-cpu=native", "-C", "link-arg=-mmacosx-version-min=11.0"]
|
||||||
|
|
66
frontend/rust-lib/Cargo.lock
generated
66
frontend/rust-lib/Cargo.lock
generated
@ -124,7 +124,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "app-error"
|
name = "app-error"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -666,7 +666,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "client-api"
|
name = "client-api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -1150,7 +1150,7 @@ dependencies = [
|
|||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa",
|
"itoa",
|
||||||
"phf 0.11.2",
|
"phf 0.8.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1251,6 +1251,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
|
"serde_yaml",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@ -1277,7 +1278,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "database-entity"
|
name = "database-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2470,7 +2471,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gotrue"
|
name = "gotrue"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -2486,7 +2487,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gotrue-entity"
|
name = "gotrue-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -2847,7 +2848,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "infra"
|
name = "infra"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -3663,7 +3664,7 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros 0.8.0",
|
"phf_macros",
|
||||||
"phf_shared 0.8.0",
|
"phf_shared 0.8.0",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
]
|
]
|
||||||
@ -3683,7 +3684,6 @@ version = "0.11.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros 0.11.2",
|
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3751,19 +3751,6 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_macros"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
|
||||||
dependencies = [
|
|
||||||
"phf_generator 0.11.2",
|
|
||||||
"phf_shared 0.11.2",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.31",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -3967,7 +3954,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"heck 0.4.1",
|
"heck 0.4.1",
|
||||||
"itertools 0.11.0",
|
"itertools 0.10.5",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -3988,7 +3975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.11.0",
|
"itertools 0.10.5",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.31",
|
"syn 2.0.31",
|
||||||
@ -4327,7 +4314,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "realtime-entity"
|
name = "realtime-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -4868,9 +4855,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.188"
|
version = "1.0.193"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@ -4888,9 +4875,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.188"
|
version = "1.0.193"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -4931,6 +4918,19 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.9.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.0.0",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"unsafe-libyaml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_arc"
|
name = "servo_arc"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -4980,7 +4980,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "shared_entity"
|
name = "shared_entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b578c83cc912255e48dea9e33a203a069ce7d0c5#b578c83cc912255e48dea9e33a203a069ce7d0c5"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5090711272dbc503912544375307365c174bb804#5090711272dbc503912544375307365c174bb804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"app-error",
|
"app-error",
|
||||||
@ -5950,6 +5950,12 @@ dependencies = [
|
|||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -99,7 +99,7 @@ incremental = false
|
|||||||
# Run the script:
|
# Run the script:
|
||||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b578c83cc912255e48dea9e33a203a069ce7d0c5" }
|
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5090711272dbc503912544375307365c174bb804" }
|
||||||
# Please use the following script to update collab.
|
# Please use the following script to update collab.
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
#
|
#
|
||||||
|
@ -34,6 +34,7 @@ flowy-server = { workspace = true }
|
|||||||
flowy-server-config = { workspace = true}
|
flowy-server-config = { workspace = true}
|
||||||
collab-integrate = { workspace = true }
|
collab-integrate = { workspace = true }
|
||||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||||
|
serde_yaml = "0.9.27"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["dart", "rev-sqlite"]
|
default = ["dart", "rev-sqlite"]
|
||||||
|
54
frontend/rust-lib/dart-ffi/src/appflowy_yaml.rs
Normal file
54
frontend/rust-lib/dart-ffi/src/appflowy_yaml.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
|
pub struct AppFlowyYamlConfiguration {
|
||||||
|
cloud_config: Vec<AFCloudConfiguration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_appflowy_cloud_config(
|
||||||
|
root: impl AsRef<Path>,
|
||||||
|
new_config: &AFCloudConfiguration,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let file_path = root.as_ref().join("appflowy.yaml");
|
||||||
|
let mut config = read_yaml_file(&file_path).unwrap_or_default();
|
||||||
|
|
||||||
|
if !config
|
||||||
|
.cloud_config
|
||||||
|
.iter()
|
||||||
|
.any(|c| c.base_url == new_config.base_url)
|
||||||
|
{
|
||||||
|
config.cloud_config.push(new_config.clone());
|
||||||
|
write_yaml_file(&file_path, &config)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_yaml_file(
|
||||||
|
file_path: impl AsRef<Path>,
|
||||||
|
) -> Result<AppFlowyYamlConfiguration, Box<dyn std::error::Error>> {
|
||||||
|
let mut file = File::open(file_path)?;
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)?;
|
||||||
|
let config: AppFlowyYamlConfiguration = serde_yaml::from_str(&contents)?;
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_yaml_file(
|
||||||
|
file_path: impl AsRef<Path>,
|
||||||
|
config: &AppFlowyYamlConfiguration,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let yaml_string = serde_yaml::to_string(config)?;
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(file_path)?;
|
||||||
|
file.write_all(yaml_string.as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||||
@ -6,13 +8,17 @@ use flowy_server_config::AuthenticatorType;
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct AppFlowyDartConfiguration {
|
pub struct AppFlowyDartConfiguration {
|
||||||
|
/// The root path of the application
|
||||||
|
pub root: String,
|
||||||
/// This path will be used to store the user data
|
/// This path will be used to store the user data
|
||||||
pub custom_app_path: String,
|
pub custom_app_path: String,
|
||||||
pub origin_app_path: String,
|
pub origin_app_path: String,
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
pub cloud_type: AuthenticatorType,
|
pub authenticator_type: AuthenticatorType,
|
||||||
pub(crate) supabase_config: SupabaseConfiguration,
|
pub(crate) supabase_config: SupabaseConfiguration,
|
||||||
pub(crate) appflowy_cloud_config: AFCloudConfiguration,
|
pub(crate) appflowy_cloud_config: AFCloudConfiguration,
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) envs: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppFlowyDartConfiguration {
|
impl AppFlowyDartConfiguration {
|
||||||
@ -20,12 +26,13 @@ impl AppFlowyDartConfiguration {
|
|||||||
serde_json::from_str::<AppFlowyDartConfiguration>(s).unwrap()
|
serde_json::from_str::<AppFlowyDartConfiguration>(s).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the environment variable from the frontend application. The frontend will
|
pub fn write_env(&self) {
|
||||||
/// pass the environment variable as a json string after launching.
|
self.authenticator_type.write_env();
|
||||||
pub fn write_env_from(env_str: &str) {
|
self.appflowy_cloud_config.write_env();
|
||||||
let configuration = Self::from_str(env_str);
|
self.supabase_config.write_env();
|
||||||
configuration.cloud_type.write_env();
|
|
||||||
configuration.appflowy_cloud_config.write_env();
|
for (k, v) in self.envs.iter() {
|
||||||
configuration.supabase_config.write_env();
|
std::env::set_var(k, v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,11 @@ use tracing::{error, trace};
|
|||||||
use flowy_core::config::AppFlowyCoreConfig;
|
use flowy_core::config::AppFlowyCoreConfig;
|
||||||
use flowy_core::*;
|
use flowy_core::*;
|
||||||
use flowy_notification::{register_notification_sender, unregister_all_notification_sender};
|
use flowy_notification::{register_notification_sender, unregister_all_notification_sender};
|
||||||
|
use flowy_server_config::AuthenticatorType;
|
||||||
use lib_dispatch::prelude::ToBytes;
|
use lib_dispatch::prelude::ToBytes;
|
||||||
use lib_dispatch::prelude::*;
|
use lib_dispatch::prelude::*;
|
||||||
|
|
||||||
|
use crate::appflowy_yaml::save_appflowy_cloud_config;
|
||||||
use crate::env_serde::AppFlowyDartConfiguration;
|
use crate::env_serde::AppFlowyDartConfiguration;
|
||||||
use crate::notification::DartNotificationSender;
|
use crate::notification::DartNotificationSender;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -20,6 +22,7 @@ use crate::{
|
|||||||
model::{FFIRequest, FFIResponse},
|
model::{FFIRequest, FFIResponse},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod appflowy_yaml;
|
||||||
mod c;
|
mod c;
|
||||||
mod env_serde;
|
mod env_serde;
|
||||||
mod model;
|
mod model;
|
||||||
@ -53,10 +56,11 @@ pub extern "C" fn init_sdk(data: *mut c_char) -> i64 {
|
|||||||
let c_str = unsafe { CStr::from_ptr(data) };
|
let c_str = unsafe { CStr::from_ptr(data) };
|
||||||
let serde_str = c_str.to_str().unwrap();
|
let serde_str = c_str.to_str().unwrap();
|
||||||
let configuration = AppFlowyDartConfiguration::from_str(serde_str);
|
let configuration = AppFlowyDartConfiguration::from_str(serde_str);
|
||||||
|
configuration.write_env();
|
||||||
|
|
||||||
configuration.cloud_type.write_env();
|
if configuration.authenticator_type == AuthenticatorType::AppFlowyCloud {
|
||||||
configuration.appflowy_cloud_config.write_env();
|
let _ = save_appflowy_cloud_config(&configuration.root, &configuration.appflowy_cloud_config);
|
||||||
configuration.supabase_config.write_env();
|
}
|
||||||
|
|
||||||
let log_crates = vec!["flowy-ffi".to_string()];
|
let log_crates = vec!["flowy-ffi".to_string()];
|
||||||
let config = AppFlowyCoreConfig::new(
|
let config = AppFlowyCoreConfig::new(
|
||||||
@ -170,8 +174,6 @@ pub extern "C" fn backend_log(level: i64, data: *const c_char) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn set_env(data: *const c_char) {
|
pub extern "C" fn set_env(_data: *const c_char) {
|
||||||
let c_str = unsafe { CStr::from_ptr(data) };
|
// Deprecated
|
||||||
let serde_str = c_str.to_str().unwrap();
|
|
||||||
AppFlowyDartConfiguration::write_env_from(serde_str);
|
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ impl EventIntegrationTest {
|
|||||||
auth_type: AuthTypePB::AFCloud,
|
auth_type: AuthTypePB::AFCloud,
|
||||||
};
|
};
|
||||||
let sign_in_url = EventBuilder::new(self.clone())
|
let sign_in_url = EventBuilder::new(self.clone())
|
||||||
.event(GetSignInURL)
|
.event(GenerateSignInURL)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
|
@ -69,7 +69,7 @@ async fn sign_in_with_invalid_email() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EventBuilder::new(sdk)
|
EventBuilder::new(sdk)
|
||||||
.event(SignIn)
|
.event(SignInWithEmailPassword)
|
||||||
.payload(request)
|
.payload(request)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
@ -95,7 +95,7 @@ async fn sign_in_with_invalid_password() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert!(EventBuilder::new(sdk)
|
assert!(EventBuilder::new(sdk)
|
||||||
.event(SignIn)
|
.event(SignInWithEmailPassword)
|
||||||
.payload(request)
|
.payload(request)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
|
@ -77,6 +77,12 @@ impl UserCloudServiceProvider for ServerProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_network_reachable(&self, reachable: bool) {
|
||||||
|
if let Ok(server) = self.get_server(&self.get_server_type()) {
|
||||||
|
server.set_network_reachable(reachable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_encrypt_secret(&self, secret: String) {
|
fn set_encrypt_secret(&self, secret: String) {
|
||||||
tracing::info!("🔑Set encrypt secret");
|
tracing::info!("🔑Set encrypt secret");
|
||||||
self.encryption.write().set_secret(secret);
|
self.encryption.write().set_secret(secret);
|
||||||
|
@ -19,6 +19,7 @@ impl From<AppResponseError> for FlowyError {
|
|||||||
AppErrorCode::InvalidOAuthProvider => ErrorCode::InvalidAuthConfig,
|
AppErrorCode::InvalidOAuthProvider => ErrorCode::InvalidAuthConfig,
|
||||||
AppErrorCode::NotLoggedIn => ErrorCode::UserUnauthorized,
|
AppErrorCode::NotLoggedIn => ErrorCode::UserUnauthorized,
|
||||||
AppErrorCode::NotEnoughPermissions => ErrorCode::NotEnoughPermissions,
|
AppErrorCode::NotEnoughPermissions => ErrorCode::NotEnoughPermissions,
|
||||||
|
AppErrorCode::NetworkError => ErrorCode::HttpError,
|
||||||
_ => ErrorCode::Internal,
|
_ => ErrorCode::Internal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ pub mod supabase_config;
|
|||||||
|
|
||||||
pub const CLOUT_TYPE_STR: &str = "APPFLOWY_CLOUD_ENV_CLOUD_TYPE";
|
pub const CLOUT_TYPE_STR: &str = "APPFLOWY_CLOUD_ENV_CLOUD_TYPE";
|
||||||
|
|
||||||
#[derive(Deserialize_repr, Debug, Clone)]
|
#[derive(Deserialize_repr, Debug, Clone, PartialEq, Eq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum AuthenticatorType {
|
pub enum AuthenticatorType {
|
||||||
Local = 0,
|
Local = 0,
|
||||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use client_api::entity::workspace_dto::{CreateWorkspaceMember, WorkspaceMemberChangeset};
|
use client_api::entity::workspace_dto::{CreateWorkspaceMember, WorkspaceMemberChangeset};
|
||||||
use client_api::entity::{AFRole, AFWorkspace, InsertCollabParams, OAuthProvider};
|
use client_api::entity::{AFRole, AFWorkspace, AuthProvider, InsertCollabParams};
|
||||||
use collab_entity::CollabObject;
|
use collab_entity::CollabObject;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ impl<T> UserCloudService for AFCloudUserAuthServiceImpl<T>
|
|||||||
where
|
where
|
||||||
T: AFServer,
|
T: AFServer,
|
||||||
{
|
{
|
||||||
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, Error> {
|
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let params = oauth_params_from_box_any(params)?;
|
let params = oauth_params_from_box_any(params)?;
|
||||||
@ -48,7 +48,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Zack: Not sure if this is needed anymore since sign_up handles both cases
|
// Zack: Not sure if this is needed anymore since sign_up handles both cases
|
||||||
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, Error> {
|
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let client = try_get_client?;
|
let client = try_get_client?;
|
||||||
@ -58,12 +58,12 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), Error> {
|
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move { Ok(try_get_client?.sign_out().await?) })
|
FutureResult::new(async move { Ok(try_get_client?.sign_out().await?) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_sign_in_url_with_email(&self, email: &str) -> FutureResult<String, Error> {
|
fn generate_sign_in_url_with_email(&self, email: &str) -> FutureResult<String, FlowyError> {
|
||||||
let email = email.to_string();
|
let email = email.to_string();
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
@ -82,8 +82,7 @@ where
|
|||||||
client_api::Client::new(client.base_url(), client.ws_addr(), client.gotrue_url());
|
client_api::Client::new(client.base_url(), client.ws_addr(), client.gotrue_url());
|
||||||
admin_client
|
admin_client
|
||||||
.sign_in_password(&admin_email, &admin_password)
|
.sign_in_password(&admin_email, &admin_password)
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let action_link = admin_client.generate_sign_in_action_link(&email).await?;
|
let action_link = admin_client.generate_sign_in_action_link(&email).await?;
|
||||||
let sign_in_url = client.extract_sign_in_url(&action_link).await?;
|
let sign_in_url = client.extract_sign_in_url(&action_link).await?;
|
||||||
@ -91,8 +90,8 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_oauth_url_with_provider(&self, provider: &str) -> FutureResult<String, Error> {
|
fn generate_oauth_url_with_provider(&self, provider: &str) -> FutureResult<String, FlowyError> {
|
||||||
let provider = OAuthProvider::from(provider);
|
let provider = AuthProvider::from(provider);
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let provider = provider.ok_or(anyhow!("invalid provider"))?;
|
let provider = provider.ok_or(anyhow!("invalid provider"))?;
|
||||||
@ -107,7 +106,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
_credential: UserCredentials,
|
_credential: UserCredentials,
|
||||||
params: UpdateUserProfileParams,
|
params: UpdateUserProfileParams,
|
||||||
) -> FutureResult<(), Error> {
|
) -> FutureResult<(), FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let client = try_get_client?;
|
let client = try_get_client?;
|
||||||
@ -142,11 +141,11 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_workspace(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
fn get_all_workspace(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, FlowyError> {
|
||||||
let try_get_client = self.server.try_get_client();
|
let try_get_client = self.server.try_get_client();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let workspaces = try_get_client?.get_workspaces().await?;
|
let workspaces = try_get_client?.get_workspaces().await?;
|
||||||
Ok(to_user_workspaces(workspaces.0)?)
|
to_user_workspaces(workspaces.0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ pub struct AppFlowyCloudServer {
|
|||||||
pub(crate) config: AFCloudConfiguration,
|
pub(crate) config: AFCloudConfiguration,
|
||||||
pub(crate) client: Arc<AFCloudClient>,
|
pub(crate) client: Arc<AFCloudClient>,
|
||||||
enable_sync: Arc<AtomicBool>,
|
enable_sync: Arc<AtomicBool>,
|
||||||
|
network_reachable: Arc<AtomicBool>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
device_id: String,
|
device_id: String,
|
||||||
ws_client: Arc<WSClient>,
|
ws_client: Arc<WSClient>,
|
||||||
@ -47,6 +48,7 @@ impl AppFlowyCloudServer {
|
|||||||
let api_client = AFCloudClient::new(&config.base_url, &config.ws_base_url, &config.gotrue_url);
|
let api_client = AFCloudClient::new(&config.base_url, &config.ws_base_url, &config.gotrue_url);
|
||||||
let token_state_rx = api_client.subscribe_token_state();
|
let token_state_rx = api_client.subscribe_token_state();
|
||||||
let enable_sync = Arc::new(AtomicBool::new(enable_sync));
|
let enable_sync = Arc::new(AtomicBool::new(enable_sync));
|
||||||
|
let network_reachable = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
let ws_client = WSClient::new(WSClientConfig::default(), api_client.clone());
|
let ws_client = WSClient::new(WSClientConfig::default(), api_client.clone());
|
||||||
let ws_client = Arc::new(ws_client);
|
let ws_client = Arc::new(ws_client);
|
||||||
@ -63,6 +65,7 @@ impl AppFlowyCloudServer {
|
|||||||
config,
|
config,
|
||||||
client: api_client,
|
client: api_client,
|
||||||
enable_sync,
|
enable_sync,
|
||||||
|
network_reachable,
|
||||||
device_id,
|
device_id,
|
||||||
ws_client,
|
ws_client,
|
||||||
}
|
}
|
||||||
@ -117,8 +120,14 @@ impl AppFlowyServer for AppFlowyCloudServer {
|
|||||||
self.enable_sync.store(enable, Ordering::SeqCst);
|
self.enable_sync.store(enable, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_network_reachable(&self, reachable: bool) {
|
||||||
|
self.network_reachable.store(reachable, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
fn user_service(&self) -> Arc<dyn UserCloudService> {
|
fn user_service(&self) -> Arc<dyn UserCloudService> {
|
||||||
let server = AFServerImpl(self.get_client());
|
let server = AFServerImpl {
|
||||||
|
client: self.get_client(),
|
||||||
|
};
|
||||||
let mut user_change = self.ws_client.subscribe_user_changed();
|
let mut user_change = self.ws_client.subscribe_user_changed();
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel(1);
|
let (tx, rx) = tokio::sync::mpsc::channel(1);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
@ -139,17 +148,23 @@ impl AppFlowyServer for AppFlowyCloudServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn folder_service(&self) -> Arc<dyn FolderCloudService> {
|
fn folder_service(&self) -> Arc<dyn FolderCloudService> {
|
||||||
let server = AFServerImpl(self.get_client());
|
let server = AFServerImpl {
|
||||||
|
client: self.get_client(),
|
||||||
|
};
|
||||||
Arc::new(AFCloudFolderCloudServiceImpl(server))
|
Arc::new(AFCloudFolderCloudServiceImpl(server))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn database_service(&self) -> Arc<dyn DatabaseCloudService> {
|
fn database_service(&self) -> Arc<dyn DatabaseCloudService> {
|
||||||
let server = AFServerImpl(self.get_client());
|
let server = AFServerImpl {
|
||||||
|
client: self.get_client(),
|
||||||
|
};
|
||||||
Arc::new(AFCloudDatabaseCloudServiceImpl(server))
|
Arc::new(AFCloudDatabaseCloudServiceImpl(server))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
|
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
|
||||||
let server = AFServerImpl(self.get_client());
|
let server = AFServerImpl {
|
||||||
|
client: self.get_client(),
|
||||||
|
};
|
||||||
Arc::new(AFCloudDocumentCloudServiceImpl(server))
|
Arc::new(AFCloudDocumentCloudServiceImpl(server))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +199,9 @@ impl AppFlowyServer for AppFlowyCloudServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn file_storage(&self) -> Option<Arc<dyn FileStorageService>> {
|
fn file_storage(&self) -> Option<Arc<dyn FileStorageService>> {
|
||||||
let client = AFServerImpl(self.get_client());
|
let client = AFServerImpl {
|
||||||
|
client: self.get_client(),
|
||||||
|
};
|
||||||
Some(Arc::new(AFCloudFileStorageServiceImpl::new(client)))
|
Some(Arc::new(AFCloudFileStorageServiceImpl::new(client)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,15 +291,17 @@ pub trait AFServer: Send + Sync + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AFServerImpl(pub Option<Arc<AFCloudClient>>);
|
pub struct AFServerImpl {
|
||||||
|
client: Option<Arc<AFCloudClient>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl AFServer for AFServerImpl {
|
impl AFServer for AFServerImpl {
|
||||||
fn get_client(&self) -> Option<Arc<AFCloudClient>> {
|
fn get_client(&self) -> Option<Arc<AFCloudClient>> {
|
||||||
self.0.clone()
|
self.client.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_client(&self) -> Result<Arc<AFCloudClient>, Error> {
|
fn try_get_client(&self) -> Result<Arc<AFCloudClient>, Error> {
|
||||||
match self.0.clone() {
|
match self.client.clone() {
|
||||||
None => Err(
|
None => Err(
|
||||||
FlowyError::new(
|
FlowyError::new(
|
||||||
ErrorCode::DataSyncRequired,
|
ErrorCode::DataSyncRequired,
|
||||||
|
@ -26,7 +26,7 @@ pub(crate) struct LocalServerUserAuthServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UserCloudService for LocalServerUserAuthServiceImpl {
|
impl UserCloudService for LocalServerUserAuthServiceImpl {
|
||||||
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, Error> {
|
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError> {
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let params = params.unbox_or_error::<SignUpParams>()?;
|
let params = params.unbox_or_error::<SignUpParams>()?;
|
||||||
let uid = ID_GEN.lock().next_id();
|
let uid = ID_GEN.lock().next_id();
|
||||||
@ -52,7 +52,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, Error> {
|
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError> {
|
||||||
let db = self.db.clone();
|
let db = self.db.clone();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let params: SignInParams = params.unbox_or_error::<SignInParams>()?;
|
let params: SignInParams = params.unbox_or_error::<SignInParams>()?;
|
||||||
@ -76,27 +76,29 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), Error> {
|
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), FlowyError> {
|
||||||
FutureResult::new(async { Ok(()) })
|
FutureResult::new(async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_sign_in_url_with_email(&self, _email: &str) -> FutureResult<String, Error> {
|
fn generate_sign_in_url_with_email(&self, _email: &str) -> FutureResult<String, FlowyError> {
|
||||||
FutureResult::new(async {
|
FutureResult::new(async {
|
||||||
Err(anyhow::anyhow!(
|
Err(
|
||||||
"Can't generate callback url when using offline mode"
|
FlowyError::internal().with_context("Can't generate callback url when using offline mode"),
|
||||||
))
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, Error> {
|
fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, FlowyError> {
|
||||||
FutureResult::new(async { Err(anyhow::anyhow!("Can't oauth url when using offline mode")) })
|
FutureResult::new(async {
|
||||||
|
Err(FlowyError::internal().with_context("Can't oauth url when using offline mode"))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_user(
|
fn update_user(
|
||||||
&self,
|
&self,
|
||||||
_credential: UserCredentials,
|
_credential: UserCredentials,
|
||||||
_params: UpdateUserProfileParams,
|
_params: UpdateUserProfileParams,
|
||||||
) -> FutureResult<(), Error> {
|
) -> FutureResult<(), FlowyError> {
|
||||||
FutureResult::new(async { Ok(()) })
|
FutureResult::new(async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +122,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_workspace(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
fn get_all_workspace(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, FlowyError> {
|
||||||
FutureResult::new(async { Ok(vec![]) })
|
FutureResult::new(async { Ok(vec![]) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,12 @@ pub trait AppFlowyServer: Send + Sync + 'static {
|
|||||||
/// * `_enable` - A boolean to toggle the server synchronization.
|
/// * `_enable` - A boolean to toggle the server synchronization.
|
||||||
fn set_enable_sync(&self, _uid: i64, _enable: bool) {}
|
fn set_enable_sync(&self, _uid: i64, _enable: bool) {}
|
||||||
|
|
||||||
|
/// Sets the network reachability status.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `reachable`: A boolean indicating whether the network is reachable.
|
||||||
|
fn set_network_reachable(&self, _reachable: bool) {}
|
||||||
|
|
||||||
/// Provides access to cloud-based user management functionalities. This includes operations
|
/// Provides access to cloud-based user management functionalities. This includes operations
|
||||||
/// such as user registration, authentication, profile management, and handling of user workspaces.
|
/// such as user registration, authentication, profile management, and handling of user workspaces.
|
||||||
/// The interface also offers methods for managing collaborative objects, subscribing to user updates,
|
/// The interface also offers methods for managing collaborative objects, subscribing to user updates,
|
||||||
|
@ -64,7 +64,7 @@ impl<T> UserCloudService for SupabaseUserServiceImpl<T>
|
|||||||
where
|
where
|
||||||
T: SupabaseServerService,
|
T: SupabaseServerService,
|
||||||
{
|
{
|
||||||
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, Error> {
|
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError> {
|
||||||
let try_get_postgrest = self.server.try_get_postgrest();
|
let try_get_postgrest = self.server.try_get_postgrest();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let postgrest = try_get_postgrest?;
|
let postgrest = try_get_postgrest?;
|
||||||
@ -129,7 +129,7 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, Error> {
|
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError> {
|
||||||
let try_get_postgrest = self.server.try_get_postgrest();
|
let try_get_postgrest = self.server.try_get_postgrest();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let postgrest = try_get_postgrest?;
|
let postgrest = try_get_postgrest?;
|
||||||
@ -159,23 +159,19 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), Error> {
|
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), FlowyError> {
|
||||||
FutureResult::new(async { Ok(()) })
|
FutureResult::new(async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_sign_in_url_with_email(&self, _email: &str) -> FutureResult<String, Error> {
|
fn generate_sign_in_url_with_email(&self, _email: &str) -> FutureResult<String, FlowyError> {
|
||||||
FutureResult::new(async {
|
FutureResult::new(async {
|
||||||
Err(anyhow::anyhow!(
|
Err(FlowyError::internal().with_context("Can't generate callback url when using supabase"))
|
||||||
"Can't generate callback url when using supabase"
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, Error> {
|
fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, FlowyError> {
|
||||||
FutureResult::new(async {
|
FutureResult::new(async {
|
||||||
Err(anyhow::anyhow!(
|
Err(FlowyError::internal().with_context("Can't generate oauth url when using supabase"))
|
||||||
"Can't generate oauth url when using supabase"
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +179,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
_credential: UserCredentials,
|
_credential: UserCredentials,
|
||||||
params: UpdateUserProfileParams,
|
params: UpdateUserProfileParams,
|
||||||
) -> FutureResult<(), Error> {
|
) -> FutureResult<(), FlowyError> {
|
||||||
let try_get_postgrest = self.server.try_get_postgrest();
|
let try_get_postgrest = self.server.try_get_postgrest();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let postgrest = try_get_postgrest?;
|
let postgrest = try_get_postgrest?;
|
||||||
@ -226,7 +222,7 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_workspace(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
fn get_all_workspace(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, FlowyError> {
|
||||||
let try_get_postgrest = self.server.try_get_postgrest();
|
let try_get_postgrest = self.server.try_get_postgrest();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
let postgrest = try_get_postgrest?;
|
let postgrest = try_get_postgrest?;
|
||||||
|
@ -59,32 +59,32 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||||||
/// Sign up a new account.
|
/// Sign up a new account.
|
||||||
/// The type of the params is defined the this trait's implementation.
|
/// The type of the params is defined the this trait's implementation.
|
||||||
/// Use the `unbox_or_error` of the [BoxAny] to get the params.
|
/// Use the `unbox_or_error` of the [BoxAny] to get the params.
|
||||||
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, Error>;
|
fn sign_up(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError>;
|
||||||
|
|
||||||
/// Sign in an account
|
/// Sign in an account
|
||||||
/// The type of the params is defined the this trait's implementation.
|
/// The type of the params is defined the this trait's implementation.
|
||||||
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, Error>;
|
fn sign_in(&self, params: BoxAny) -> FutureResult<AuthResponse, FlowyError>;
|
||||||
|
|
||||||
/// Sign out an account
|
/// Sign out an account
|
||||||
fn sign_out(&self, token: Option<String>) -> FutureResult<(), Error>;
|
fn sign_out(&self, token: Option<String>) -> FutureResult<(), FlowyError>;
|
||||||
|
|
||||||
/// Generate a sign in url for the user with the given email
|
/// Generate a sign in url for the user with the given email
|
||||||
/// Currently, only use the admin client for testing
|
/// Currently, only use the admin client for testing
|
||||||
fn generate_sign_in_url_with_email(&self, email: &str) -> FutureResult<String, Error>;
|
fn generate_sign_in_url_with_email(&self, email: &str) -> FutureResult<String, FlowyError>;
|
||||||
|
|
||||||
/// When the user opens the OAuth URL, it redirects to the corresponding provider's OAuth web page.
|
/// When the user opens the OAuth URL, it redirects to the corresponding provider's OAuth web page.
|
||||||
/// After the user is authenticated, the browser will open a deep link to the AppFlowy app (iOS, macOS, etc.),
|
/// After the user is authenticated, the browser will open a deep link to the AppFlowy app (iOS, macOS, etc.),
|
||||||
/// which will call [Client::sign_in_with_url] to sign in.
|
/// which will call [Client::sign_in_with_url] to sign in.
|
||||||
///
|
///
|
||||||
/// For example, the OAuth URL on Google looks like `https://appflowy.io/authorize?provider=google`.
|
/// For example, the OAuth URL on Google looks like `https://appflowy.io/authorize?provider=google`.
|
||||||
fn generate_oauth_url_with_provider(&self, provider: &str) -> FutureResult<String, Error>;
|
fn generate_oauth_url_with_provider(&self, provider: &str) -> FutureResult<String, FlowyError>;
|
||||||
|
|
||||||
/// Using the user's token to update the user information
|
/// Using the user's token to update the user information
|
||||||
fn update_user(
|
fn update_user(
|
||||||
&self,
|
&self,
|
||||||
credential: UserCredentials,
|
credential: UserCredentials,
|
||||||
params: UpdateUserProfileParams,
|
params: UpdateUserProfileParams,
|
||||||
) -> FutureResult<(), Error>;
|
) -> FutureResult<(), FlowyError>;
|
||||||
|
|
||||||
/// Get the user information using the user's token or uid
|
/// Get the user information using the user's token or uid
|
||||||
/// return None if the user is not found
|
/// return None if the user is not found
|
||||||
@ -93,7 +93,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError>;
|
fn open_workspace(&self, workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError>;
|
||||||
|
|
||||||
/// Return the all the workspaces of the user
|
/// Return the all the workspaces of the user
|
||||||
fn get_all_workspace(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error>;
|
fn get_all_workspace(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, FlowyError>;
|
||||||
|
|
||||||
fn add_workspace_member(
|
fn add_workspace_member(
|
||||||
&self,
|
&self,
|
||||||
|
@ -180,7 +180,7 @@ impl EncryptionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_need_encrypt_secret(&self) -> bool {
|
pub fn require_encrypt_secret(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
EncryptionType::NoEncryption => false,
|
EncryptionType::NoEncryption => false,
|
||||||
EncryptionType::SelfEncryption(sign) => !sign.is_empty(),
|
EncryptionType::SelfEncryption(sign) => !sign.is_empty(),
|
||||||
|
@ -35,7 +35,7 @@ fn upgrade_store_preferences(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", name = "sign_in", skip(data, manager), fields(email = %data.email), err)]
|
#[tracing::instrument(level = "debug", name = "sign_in", skip(data, manager), fields(email = %data.email), err)]
|
||||||
pub async fn sign_in(
|
pub async fn sign_in_with_email_password_handler(
|
||||||
data: AFPluginData<SignInPayloadPB>,
|
data: AFPluginData<SignInPayloadPB>,
|
||||||
manager: AFPluginState<Weak<UserManager>>,
|
manager: AFPluginState<Weak<UserManager>>,
|
||||||
) -> DataResult<UserProfilePB, FlowyError> {
|
) -> DataResult<UserProfilePB, FlowyError> {
|
||||||
@ -43,10 +43,7 @@ pub async fn sign_in(
|
|||||||
let params: SignInParams = data.into_inner().try_into()?;
|
let params: SignInParams = data.into_inner().try_into()?;
|
||||||
let auth_type = params.auth_type.clone();
|
let auth_type = params.auth_type.clone();
|
||||||
|
|
||||||
let user_profile: UserProfilePB = manager
|
let user_profile: UserProfilePB = manager.sign_in(params, auth_type).await?.into();
|
||||||
.sign_in(BoxAny::new(params), auth_type)
|
|
||||||
.await?
|
|
||||||
.into();
|
|
||||||
data_result_ok(user_profile)
|
data_result_ok(user_profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +261,7 @@ pub async fn oauth_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||||
pub async fn get_sign_in_url_handler(
|
pub async fn gen_sign_in_url_handler(
|
||||||
data: AFPluginData<SignInUrlPayloadPB>,
|
data: AFPluginData<SignInUrlPayloadPB>,
|
||||||
manager: AFPluginState<Weak<UserManager>>,
|
manager: AFPluginState<Weak<UserManager>>,
|
||||||
) -> DataResult<SignInUrlPB, FlowyError> {
|
) -> DataResult<SignInUrlPB, FlowyError> {
|
||||||
@ -274,8 +271,7 @@ pub async fn get_sign_in_url_handler(
|
|||||||
let sign_in_url = manager
|
let sign_in_url = manager
|
||||||
.generate_sign_in_url_with_email(&auth_type, ¶ms.email)
|
.generate_sign_in_url_with_email(&auth_type, ¶ms.email)
|
||||||
.await?;
|
.await?;
|
||||||
let resp = SignInUrlPB { sign_in_url };
|
data_result_ok(SignInUrlPB { sign_in_url })
|
||||||
data_result_ok(resp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||||
@ -459,6 +455,7 @@ pub async fn update_network_state_handler(
|
|||||||
) -> Result<(), FlowyError> {
|
) -> Result<(), FlowyError> {
|
||||||
let manager = upgrade_manager(manager)?;
|
let manager = upgrade_manager(manager)?;
|
||||||
let reachable = data.into_inner().ty.is_reachable();
|
let reachable = data.into_inner().ty.is_reachable();
|
||||||
|
manager.cloud_services.set_network_reachable(reachable);
|
||||||
manager
|
manager
|
||||||
.user_status_callback
|
.user_status_callback
|
||||||
.read()
|
.read()
|
||||||
|
@ -25,7 +25,7 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
|||||||
.name("Flowy-User")
|
.name("Flowy-User")
|
||||||
.state(user_session)
|
.state(user_session)
|
||||||
.state(store_preferences)
|
.state(store_preferences)
|
||||||
.event(UserEvent::SignIn, sign_in)
|
.event(UserEvent::SignInWithEmailPassword, sign_in_with_email_password_handler)
|
||||||
.event(UserEvent::SignUp, sign_up)
|
.event(UserEvent::SignUp, sign_up)
|
||||||
.event(UserEvent::InitUser, init_user_handler)
|
.event(UserEvent::InitUser, init_user_handler)
|
||||||
.event(UserEvent::GetUserProfile, get_user_profile_handler)
|
.event(UserEvent::GetUserProfile, get_user_profile_handler)
|
||||||
@ -39,7 +39,7 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
|||||||
.event(UserEvent::SetEncryptionSecret, set_encrypt_secret_handler)
|
.event(UserEvent::SetEncryptionSecret, set_encrypt_secret_handler)
|
||||||
.event(UserEvent::CheckEncryptionSign, check_encrypt_secret_handler)
|
.event(UserEvent::CheckEncryptionSign, check_encrypt_secret_handler)
|
||||||
.event(UserEvent::OauthSignIn, oauth_handler)
|
.event(UserEvent::OauthSignIn, oauth_handler)
|
||||||
.event(UserEvent::GetSignInURL, get_sign_in_url_handler)
|
.event(UserEvent::GenerateSignInURL, gen_sign_in_url_handler)
|
||||||
.event(UserEvent::GetOauthURLWithProvider, sign_in_with_provider_handler)
|
.event(UserEvent::GetOauthURLWithProvider, sign_in_with_provider_handler)
|
||||||
.event(UserEvent::GetAllWorkspace, get_all_workspace_handler)
|
.event(UserEvent::GetAllWorkspace, get_all_workspace_handler)
|
||||||
.event(UserEvent::OpenWorkspace, open_workspace_handler)
|
.event(UserEvent::OpenWorkspace, open_workspace_handler)
|
||||||
@ -69,7 +69,7 @@ pub enum UserEvent {
|
|||||||
/// Only use when the [Authenticator] is Local or SelfHosted
|
/// Only use when the [Authenticator] is Local or SelfHosted
|
||||||
/// Logging into an account using a register email and password
|
/// Logging into an account using a register email and password
|
||||||
#[event(input = "SignInPayloadPB", output = "UserProfilePB")]
|
#[event(input = "SignInPayloadPB", output = "UserProfilePB")]
|
||||||
SignIn = 0,
|
SignInWithEmailPassword = 0,
|
||||||
|
|
||||||
/// Only use when the [Authenticator] is Local or SelfHosted
|
/// Only use when the [Authenticator] is Local or SelfHosted
|
||||||
/// Creating a new account
|
/// Creating a new account
|
||||||
@ -111,7 +111,7 @@ pub enum UserEvent {
|
|||||||
/// Get the OAuth callback url
|
/// Get the OAuth callback url
|
||||||
/// Only use when the [Authenticator] is AFCloud
|
/// Only use when the [Authenticator] is AFCloud
|
||||||
#[event(input = "SignInUrlPayloadPB", output = "SignInUrlPB")]
|
#[event(input = "SignInUrlPayloadPB", output = "SignInUrlPB")]
|
||||||
GetSignInURL = 11,
|
GenerateSignInURL = 11,
|
||||||
|
|
||||||
#[event(input = "OauthProviderPB", output = "OauthProviderDataPB")]
|
#[event(input = "OauthProviderPB", output = "OauthProviderDataPB")]
|
||||||
GetOauthURLWithProvider = 12,
|
GetOauthURLWithProvider = 12,
|
||||||
@ -234,55 +234,73 @@ pub trait UserStatusCallback: Send + Sync + 'static {
|
|||||||
fn did_update_network(&self, _reachable: bool) {}
|
fn did_update_network(&self, _reachable: bool) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The user cloud service provider.
|
/// `UserCloudServiceProvider` defines a set of methods for managing user cloud services,
|
||||||
/// The provider can be supabase, firebase, aws, or any other cloud service.
|
/// including token management, synchronization settings, network reachability, and authentication.
|
||||||
|
///
|
||||||
|
/// This trait is intended for implementation by providers that offer cloud-based services for users.
|
||||||
|
/// It includes methods for handling authentication tokens, enabling/disabling synchronization,
|
||||||
|
/// setting network reachability, managing encryption secrets, and accessing user-specific cloud services.
|
||||||
pub trait UserCloudServiceProvider: Send + Sync + 'static {
|
pub trait UserCloudServiceProvider: Send + Sync + 'static {
|
||||||
|
/// Sets the authentication token for the cloud service.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `token`: A string slice representing the authentication token.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// A `Result` which is `Ok` if the token is successfully set, or a `FlowyError` otherwise.
|
||||||
fn set_token(&self, token: &str) -> Result<(), FlowyError>;
|
fn set_token(&self, token: &str) -> Result<(), FlowyError>;
|
||||||
fn subscribe_token_state(&self) -> Option<WatchStream<UserTokenState>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// Subscribes to the state of the authentication token.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An `Option` containing a `WatchStream<UserTokenState>` if available, or `None` otherwise.
|
||||||
|
/// The stream allows the caller to watch for changes in the token state.
|
||||||
|
fn subscribe_token_state(&self) -> Option<WatchStream<UserTokenState>>;
|
||||||
|
|
||||||
|
/// Sets the synchronization state for a user.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `uid`: An i64 representing the user ID.
|
||||||
|
/// * `enable_sync`: A boolean indicating whether synchronization should be enabled or disabled.
|
||||||
fn set_enable_sync(&self, uid: i64, enable_sync: bool);
|
fn set_enable_sync(&self, uid: i64, enable_sync: bool);
|
||||||
|
|
||||||
|
/// Sets the network reachability status.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `reachable`: A boolean indicating whether the network is reachable.
|
||||||
|
fn set_network_reachable(&self, reachable: bool);
|
||||||
|
|
||||||
|
/// Sets the encryption secret for secure communication.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `secret`: A `String` representing the encryption secret.
|
||||||
fn set_encrypt_secret(&self, secret: String);
|
fn set_encrypt_secret(&self, secret: String);
|
||||||
|
|
||||||
|
/// Sets the authenticator used for authentication processes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `authenticator`: An `Authenticator` object.
|
||||||
fn set_authenticator(&self, authenticator: Authenticator);
|
fn set_authenticator(&self, authenticator: Authenticator);
|
||||||
|
|
||||||
|
/// Retrieves the current authenticator.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// The current `Authenticator` object.
|
||||||
fn get_authenticator(&self) -> Authenticator;
|
fn get_authenticator(&self) -> Authenticator;
|
||||||
|
|
||||||
|
/// Retrieves the user-specific cloud service.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// A `Result` containing an `Arc<dyn UserCloudService>` if successful, or a `FlowyError` otherwise.
|
||||||
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError>;
|
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError>;
|
||||||
|
|
||||||
|
/// Retrieves the service URL.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// A `String` representing the service URL.
|
||||||
fn service_url(&self) -> String;
|
fn service_url(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> UserCloudServiceProvider for Arc<T>
|
|
||||||
where
|
|
||||||
T: UserCloudServiceProvider,
|
|
||||||
{
|
|
||||||
fn set_token(&self, token: &str) -> Result<(), FlowyError> {
|
|
||||||
(**self).set_token(token)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_enable_sync(&self, uid: i64, enable_sync: bool) {
|
|
||||||
(**self).set_enable_sync(uid, enable_sync)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_encrypt_secret(&self, secret: String) {
|
|
||||||
(**self).set_encrypt_secret(secret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_authenticator(&self, authenticator: Authenticator) {
|
|
||||||
(**self).set_authenticator(authenticator)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_authenticator(&self) -> Authenticator {
|
|
||||||
(**self).get_authenticator()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError> {
|
|
||||||
(**self).get_user_service()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn service_url(&self) -> String {
|
|
||||||
(**self).service_url()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Acts as a placeholder [UserStatusCallback] for the user session, but does not perform any function
|
/// Acts as a placeholder [UserStatusCallback] for the user session, but does not perform any function
|
||||||
pub(crate) struct DefaultUserStatusCallback;
|
pub(crate) struct DefaultUserStatusCallback;
|
||||||
impl UserStatusCallback for DefaultUserStatusCallback {
|
impl UserStatusCallback for DefaultUserStatusCallback {
|
||||||
|
@ -291,14 +291,14 @@ impl UserManager {
|
|||||||
#[tracing::instrument(level = "debug", skip(self, params))]
|
#[tracing::instrument(level = "debug", skip(self, params))]
|
||||||
pub async fn sign_in(
|
pub async fn sign_in(
|
||||||
&self,
|
&self,
|
||||||
params: BoxAny,
|
params: SignInParams,
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
) -> Result<UserProfile, FlowyError> {
|
) -> Result<UserProfile, FlowyError> {
|
||||||
self.update_authenticator(&authenticator).await;
|
self.update_authenticator(&authenticator).await;
|
||||||
let response: AuthResponse = self
|
let response: AuthResponse = self
|
||||||
.cloud_services
|
.cloud_services
|
||||||
.get_user_service()?
|
.get_user_service()?
|
||||||
.sign_in(params)
|
.sign_in(BoxAny::new(params))
|
||||||
.await?;
|
.await?;
|
||||||
let session = Session::from(&response);
|
let session = Session::from(&response);
|
||||||
self.prepare_user(&session).await;
|
self.prepare_user(&session).await;
|
||||||
@ -362,7 +362,7 @@ impl UserManager {
|
|||||||
let auth_service = self.cloud_services.get_user_service()?;
|
let auth_service = self.cloud_services.get_user_service()?;
|
||||||
let response: AuthResponse = auth_service.sign_up(params).await?;
|
let response: AuthResponse = auth_service.sign_up(params).await?;
|
||||||
let user_profile = UserProfile::from((&response, &authenticator));
|
let user_profile = UserProfile::from((&response, &authenticator));
|
||||||
if user_profile.encryption_type.is_need_encrypt_secret() {
|
if user_profile.encryption_type.require_encrypt_secret() {
|
||||||
self
|
self
|
||||||
.resumable_sign_up
|
.resumable_sign_up
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -51,9 +51,7 @@ private = true
|
|||||||
script = [
|
script = [
|
||||||
"""
|
"""
|
||||||
cd rust-lib/
|
cd rust-lib/
|
||||||
rustup show
|
RUSTFLAGS="--cfg tokio_unstable" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||||
echo cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
|
||||||
cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
|
||||||
cd ../
|
cd ../
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
@ -64,8 +62,6 @@ private = true
|
|||||||
script = [
|
script = [
|
||||||
"""
|
"""
|
||||||
cd rust-lib/
|
cd rust-lib/
|
||||||
rustup show
|
|
||||||
echo RUSTFLAGS="-C target-cpu=native -C link-arg=-mmacosx-version-min=11.0" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
|
||||||
RUSTFLAGS="--cfg tokio_unstable" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
RUSTFLAGS="--cfg tokio_unstable" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||||
cd ../
|
cd ../
|
||||||
""",
|
""",
|
||||||
@ -106,6 +102,16 @@ script = [
|
|||||||
]
|
]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
|
|
||||||
|
[tasks.sdk-release-build.mac]
|
||||||
|
script = [
|
||||||
|
"""
|
||||||
|
cd rust-lib/
|
||||||
|
cargo build --profile ${CARGO_PROFILE} --${BUILD_FLAG} --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||||
|
cd ../
|
||||||
|
""",
|
||||||
|
]
|
||||||
|
script_runner = "@shell"
|
||||||
|
|
||||||
#
|
#
|
||||||
[tasks.post-desktop]
|
[tasks.post-desktop]
|
||||||
mac_alias = "post-desktop-macos"
|
mac_alias = "post-desktop-macos"
|
||||||
|
@ -33,7 +33,7 @@ dependencies = ["inner_build_test_backend"]
|
|||||||
description = "Run flutter unit tests"
|
description = "Run flutter unit tests"
|
||||||
script = '''
|
script = '''
|
||||||
cd appflowy_flutter
|
cd appflowy_flutter
|
||||||
flutter test --dart-define=RUST_LOG=${RUST_LOG} -j, --concurrency=1 --coverage
|
flutter test -j, --concurrency=1 --coverage
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[tasks.dart_unit_test_no_build]
|
[tasks.dart_unit_test_no_build]
|
||||||
@ -57,7 +57,7 @@ dependencies = ["copy-from-build-to-sandbox-folder"]
|
|||||||
description = "Run flutter unit tests"
|
description = "Run flutter unit tests"
|
||||||
script = '''
|
script = '''
|
||||||
cd appflowy_flutter
|
cd appflowy_flutter
|
||||||
flutter test --dart-define=RUST_LOG=${RUST_LOG} -j, --concurrency=1 --coverage
|
flutter test -j, --concurrency=1 --coverage
|
||||||
'''
|
'''
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
|
|
||||||
@ -259,6 +259,7 @@ run_task = { name = [
|
|||||||
|
|
||||||
|
|
||||||
[tasks.build_test_backend]
|
[tasks.build_test_backend]
|
||||||
|
env = { RUST_LOG = "trace" }
|
||||||
script = '''
|
script = '''
|
||||||
cargo make --profile test-macos-$(uname -m) inner_build_test_backend
|
cargo make --profile test-macos-$(uname -m) inner_build_test_backend
|
||||||
'''
|
'''
|
||||||
@ -292,6 +293,7 @@ windows_alias = "compile_test_backend_windows"
|
|||||||
linux_alias = "compile_test_backend_default"
|
linux_alias = "compile_test_backend_default"
|
||||||
|
|
||||||
[tasks.compile_test_backend_default]
|
[tasks.compile_test_backend_default]
|
||||||
|
env = { RUST_LOG = "trace" }
|
||||||
private = true
|
private = true
|
||||||
script = [
|
script = [
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user