fix: Return the binds migration interface

Turns out, there are still servers that didn't perform the binds migration. The can't perform it anymore because email changed the id. I'm getting back the option to perform the binds migration, with some fallback defaults.
pull/467/head
Inex Code 2024-02-23 19:50:28 +03:00
parent 490e5f92f3
commit a9a7b04ad5
8 changed files with 103 additions and 60 deletions

View File

@ -60,17 +60,18 @@ mixin VolumeApi on GraphQLApiMap {
Future<GenericResult<String?>> migrateToBinds( Future<GenericResult<String?>> migrateToBinds(
final Map<String, String> serviceToDisk, final Map<String, String> serviceToDisk,
final String fallbackDrive,
) async { ) async {
GenericResult<String?>? mutation; GenericResult<String?>? mutation;
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
final input = Input$MigrateToBindsInput( final input = Input$MigrateToBindsInput(
bitwardenBlockDevice: serviceToDisk['bitwarden']!, bitwardenBlockDevice: serviceToDisk['bitwarden'] ?? fallbackDrive,
emailBlockDevice: serviceToDisk['mailserver']!, emailBlockDevice: serviceToDisk['email'] ?? fallbackDrive,
giteaBlockDevice: serviceToDisk['gitea']!, giteaBlockDevice: serviceToDisk['gitea'] ?? fallbackDrive,
nextcloudBlockDevice: serviceToDisk['nextcloud']!, nextcloudBlockDevice: serviceToDisk['nextcloud'] ?? fallbackDrive,
pleromaBlockDevice: serviceToDisk['pleroma']!, pleromaBlockDevice: serviceToDisk['pleroma'] ?? fallbackDrive,
); );
final variables = Variables$Mutation$MigrateToBinds(input: input); final variables = Variables$Mutation$MigrateToBinds(input: input);
final migrateMutation = final migrateMutation =

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:bloc_concurrency/bloc_concurrency.dart'; import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart'; import 'package:selfprivacy/logic/models/json/server_job.dart';
@ -68,6 +69,25 @@ class ServerJobsBloc extends Bloc<ServerJobsEvent, ServerJobsState> {
await getIt<ApiConnectionRepository>().removeAllFinishedServerJobs(); await getIt<ApiConnectionRepository>().removeAllFinishedServerJobs();
} }
Future<void> migrateToBinds(final Map<String, String> serviceToDisk) async {
final fallbackDrive = getIt<ApiConnectionRepository>()
.apiData
.volumes
.data
?.where((final drive) => drive.root)
.first
.name ??
'sda1';
final result = await getIt<ApiConnectionRepository>()
.api
.migrateToBinds(serviceToDisk, fallbackDrive);
if (result.data == null) {
getIt<NavigationService>()
.showSnackBar(result.message!, behavior: SnackBarBehavior.floating);
return;
}
}
@override @override
void onChange(final Change<ServerJobsState> change) { void onChange(final Change<ServerJobsState> change) {
super.onChange(change); super.onChange(change);

View File

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class SectionTitle extends StatelessWidget {
const SectionTitle({
required this.title,
super.key,
});
final String title;
@override
Widget build(final BuildContext context) => Padding(
padding: const EdgeInsets.all(16),
child: Text(
title,
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
);
}

View File

@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/ui/components/list_tiles/section_title.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/utils/breakpoints.dart'; import 'package:selfprivacy/utils/breakpoints.dart';
import 'package:selfprivacy/utils/platform_adapter.dart'; import 'package:selfprivacy/utils/platform_adapter.dart';
@ -220,26 +221,6 @@ class AboutApplicationPage extends StatelessWidget {
} }
} }
class SectionTitle extends StatelessWidget {
const SectionTitle({
required this.title,
super.key,
});
final String title;
@override
Widget build(final BuildContext context) => Padding(
padding: const EdgeInsets.all(16),
child: Text(
title,
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
);
}
class LinkListTile extends StatelessWidget { class LinkListTile extends StatelessWidget {
const LinkListTile({ const LinkListTile({
required this.title, required this.title,

View File

@ -3,8 +3,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/tls_options.dart'; import 'package:selfprivacy/logic/api_maps/tls_options.dart';
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart'; import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/ui/components/list_tiles/section_title.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/router/router.dart';
@RoutePage() @RoutePage()
class DeveloperSettingsPage extends StatefulWidget { class DeveloperSettingsPage extends StatefulWidget {
@ -23,15 +27,7 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
heroTitle: 'developer_settings.title'.tr(), heroTitle: 'developer_settings.title'.tr(),
heroSubtitle: 'developer_settings.subtitle'.tr(), heroSubtitle: 'developer_settings.subtitle'.tr(),
children: [ children: [
Padding( SectionTitle(title: 'developer_settings.server_setup'.tr()),
padding: const EdgeInsets.all(16),
child: Text(
'developer_settings.server_setup'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
SwitchListTile( SwitchListTile(
title: Text('developer_settings.use_staging_acme'.tr()), title: Text('developer_settings.use_staging_acme'.tr()),
subtitle: subtitle:
@ -59,15 +55,7 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
() => TlsOptions.allowCustomSshKeyDuringSetup = value, () => TlsOptions.allowCustomSshKeyDuringSetup = value,
), ),
), ),
Padding( SectionTitle(title: 'developer_settings.routing'.tr()),
padding: const EdgeInsets.all(16),
child: Text(
'developer_settings.routing'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
ListTile( ListTile(
title: Text('developer_settings.reset_onboarding'.tr()), title: Text('developer_settings.reset_onboarding'.tr()),
subtitle: subtitle:
@ -78,15 +66,32 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
.read<AppSettingsCubit>() .read<AppSettingsCubit>()
.turnOffOnboarding(isOnboardingShowing: true), .turnOffOnboarding(isOnboardingShowing: true),
), ),
Padding( ListTile(
padding: const EdgeInsets.all(16), title: Text('storage.start_migration_button'.tr()),
child: Text( subtitle: Text('storage.data_migration_notice'.tr()),
'developer_settings.cubit_statuses'.tr(), enabled:
style: Theme.of(context).textTheme.labelLarge!.copyWith( !context.watch<AppSettingsCubit>().state.isOnboardingShowing,
color: Theme.of(context).colorScheme.secondary, onTap: () => context.pushRoute(
), ServicesMigrationRoute(
diskStatus: context.read<VolumesBloc>().state.diskStatus,
services: context
.read<ServicesBloc>()
.state
.services
.where(
(final service) =>
service.id == 'bitwarden' ||
service.id == 'gitea' ||
service.id == 'pleroma' ||
service.id == 'email' ||
service.id == 'nextcloud',
)
.toList(),
isMigration: true,
),
), ),
), ),
SectionTitle(title: 'developer_settings.cubit_statuses'.tr()),
ListTile( ListTile(
title: const Text('ApiConnectionRepository status'), title: const Text('ApiConnectionRepository status'),
subtitle: Text( subtitle: Text(

View File

@ -18,11 +18,13 @@ class ServicesMigrationPage extends StatefulWidget {
const ServicesMigrationPage({ const ServicesMigrationPage({
required this.services, required this.services,
required this.diskStatus, required this.diskStatus,
required this.isMigration,
super.key, super.key,
}); });
final DiskStatus diskStatus; final DiskStatus diskStatus;
final List<Service> services; final List<Service> services;
final bool isMigration;
@override @override
State<ServicesMigrationPage> createState() => _ServicesMigrationPageState(); State<ServicesMigrationPage> createState() => _ServicesMigrationPageState();
@ -169,18 +171,24 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (isVolumePicked) if (widget.isMigration || (!widget.isMigration && isVolumePicked))
BrandButton.filled( BrandButton.filled(
child: Text('storage.start_migration_button'.tr()), child: Text('storage.start_migration_button'.tr()),
onPressed: () { onPressed: () {
for (final service in widget.services) { if (widget.isMigration) {
if (serviceToDisk[service.id] != null) { context.read<ServerJobsBloc>().migrateToBinds(
context.read<ServicesBloc>().add( serviceToDisk,
ServiceMove( );
service, } else {
serviceToDisk[service.id]!, for (final service in widget.services) {
), if (serviceToDisk[service.id] != null) {
); context.read<ServicesBloc>().add(
ServiceMove(
service,
serviceToDisk[service.id]!,
),
);
}
} }
} }
context.router.popUntilRoot(); context.router.popUntilRoot();

View File

@ -114,6 +114,7 @@ class _ServicePageState extends State<ServicePage> {
ServicesMigrationRoute( ServicesMigrationRoute(
services: [service], services: [service],
diskStatus: context.read<VolumesBloc>().state.diskStatus, diskStatus: context.read<VolumesBloc>().state.diskStatus,
isMigration: false,
), ),
), ),
leading: const Icon(Icons.drive_file_move_outlined), leading: const Icon(Icons.drive_file_move_outlined),

View File

@ -159,6 +159,7 @@ abstract class _$RootRouter extends RootStackRouter {
child: ServicesMigrationPage( child: ServicesMigrationPage(
services: args.services, services: args.services,
diskStatus: args.diskStatus, diskStatus: args.diskStatus,
isMigration: args.isMigration,
key: args.key, key: args.key,
), ),
); );
@ -575,6 +576,7 @@ class ServicesMigrationRoute extends PageRouteInfo<ServicesMigrationRouteArgs> {
ServicesMigrationRoute({ ServicesMigrationRoute({
required List<Service> services, required List<Service> services,
required DiskStatus diskStatus, required DiskStatus diskStatus,
required bool isMigration,
Key? key, Key? key,
List<PageRouteInfo>? children, List<PageRouteInfo>? children,
}) : super( }) : super(
@ -582,6 +584,7 @@ class ServicesMigrationRoute extends PageRouteInfo<ServicesMigrationRouteArgs> {
args: ServicesMigrationRouteArgs( args: ServicesMigrationRouteArgs(
services: services, services: services,
diskStatus: diskStatus, diskStatus: diskStatus,
isMigration: isMigration,
key: key, key: key,
), ),
initialChildren: children, initialChildren: children,
@ -597,6 +600,7 @@ class ServicesMigrationRouteArgs {
const ServicesMigrationRouteArgs({ const ServicesMigrationRouteArgs({
required this.services, required this.services,
required this.diskStatus, required this.diskStatus,
required this.isMigration,
this.key, this.key,
}); });
@ -604,11 +608,13 @@ class ServicesMigrationRouteArgs {
final DiskStatus diskStatus; final DiskStatus diskStatus;
final bool isMigration;
final Key? key; final Key? key;
@override @override
String toString() { String toString() {
return 'ServicesMigrationRouteArgs{services: $services, diskStatus: $diskStatus, key: $key}'; return 'ServicesMigrationRouteArgs{services: $services, diskStatus: $diskStatus, isMigration: $isMigration, key: $key}';
} }
} }