Implement server settings page functionality

pull/116/head
NaiJi ✨ 2022-09-15 02:31:25 +03:00
parent 12d4cd23ec
commit dc72b6d1b2
18 changed files with 234 additions and 171 deletions

View File

@ -107,7 +107,8 @@
"allow_autoupgrade_hint": "Allow automatic packages upgrades on server",
"reboot_after_upgrade": "Reboot after upgrade",
"reboot_after_upgrade_hint": "Reboot without prompt after applying changes on server",
"server_timezone": "Server timezone"
"server_timezone": "Server timezone",
"select_timezone": "Select timezone"
}
},
"domain": {

View File

@ -107,7 +107,8 @@
"allow_autoupgrade_hint": "Разрешить автоматичесую установку обновлений на сервер",
"reboot_after_upgrade": "Перезагружать после обновлений",
"reboot_after_upgrade_hint": "Автоматически перезагружать сервер после применения обновлений",
"server_timezone": "Часовой пояс сервера"
"server_timezone": "Часовой пояс сервера",
"select_timezone": "Выберите часовой пояс"
}
},
"domain": {

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/logic/cubit/devices/devices_cubit.dart';
import 'package:selfprivacy/logic/cubit/recovery_key/recovery_key_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';

View File

@ -14,7 +14,6 @@ query SystemSettings {
ssh {
enable
passwordAuthentication
rootSshKeys
}
timezone
}

View File

@ -336,12 +336,6 @@ const documentNodeQuerySystemSettings = DocumentNode(definitions: [
arguments: [],
directives: [],
selectionSet: null),
FieldNode(
name: NameNode(value: 'rootSshKeys'),
alias: null,
arguments: [],
directives: [],
selectionSet: null),
FieldNode(
name: NameNode(value: '__typename'),
alias: null,
@ -810,7 +804,6 @@ class Query$SystemSettings$system$settings$ssh {
Query$SystemSettings$system$settings$ssh(
{required this.enable,
required this.passwordAuthentication,
required this.rootSshKeys,
required this.$__typename});
@override
@ -822,8 +815,6 @@ class Query$SystemSettings$system$settings$ssh {
final bool passwordAuthentication;
final List<String> rootSshKeys;
@JsonKey(name: '__typename')
final String $__typename;
@ -832,14 +823,8 @@ class Query$SystemSettings$system$settings$ssh {
int get hashCode {
final l$enable = enable;
final l$passwordAuthentication = passwordAuthentication;
final l$rootSshKeys = rootSshKeys;
final l$$__typename = $__typename;
return Object.hashAll([
l$enable,
l$passwordAuthentication,
Object.hashAll(l$rootSshKeys.map((v) => v)),
l$$__typename
]);
return Object.hashAll([l$enable, l$passwordAuthentication, l$$__typename]);
}
@override
@ -853,15 +838,6 @@ class Query$SystemSettings$system$settings$ssh {
final l$passwordAuthentication = passwordAuthentication;
final lOther$passwordAuthentication = other.passwordAuthentication;
if (l$passwordAuthentication != lOther$passwordAuthentication) return false;
final l$rootSshKeys = rootSshKeys;
final lOther$rootSshKeys = other.rootSshKeys;
if (l$rootSshKeys.length != lOther$rootSshKeys.length) return false;
for (int i = 0; i < l$rootSshKeys.length; i++) {
final l$rootSshKeys$entry = l$rootSshKeys[i];
final lOther$rootSshKeys$entry = lOther$rootSshKeys[i];
if (l$rootSshKeys$entry != lOther$rootSshKeys$entry) return false;
}
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) return false;
@ -886,11 +862,7 @@ abstract class CopyWith$Query$SystemSettings$system$settings$ssh<TRes> {
factory CopyWith$Query$SystemSettings$system$settings$ssh.stub(TRes res) =
_CopyWithStubImpl$Query$SystemSettings$system$settings$ssh;
TRes call(
{bool? enable,
bool? passwordAuthentication,
List<String>? rootSshKeys,
String? $__typename});
TRes call({bool? enable, bool? passwordAuthentication, String? $__typename});
}
class _CopyWithImpl$Query$SystemSettings$system$settings$ssh<TRes>
@ -907,7 +879,6 @@ class _CopyWithImpl$Query$SystemSettings$system$settings$ssh<TRes>
TRes call(
{Object? enable = _undefined,
Object? passwordAuthentication = _undefined,
Object? rootSshKeys = _undefined,
Object? $__typename = _undefined}) =>
_then(Query$SystemSettings$system$settings$ssh(
enable: enable == _undefined || enable == null
@ -917,9 +888,6 @@ class _CopyWithImpl$Query$SystemSettings$system$settings$ssh<TRes>
passwordAuthentication == null
? _instance.passwordAuthentication
: (passwordAuthentication as bool),
rootSshKeys: rootSshKeys == _undefined || rootSshKeys == null
? _instance.rootSshKeys
: (rootSshKeys as List<String>),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String)));
@ -931,11 +899,7 @@ class _CopyWithStubImpl$Query$SystemSettings$system$settings$ssh<TRes>
TRes _res;
call(
{bool? enable,
bool? passwordAuthentication,
List<String>? rootSshKeys,
String? $__typename}) =>
call({bool? enable, bool? passwordAuthentication, String? $__typename}) =>
_res;
}

View File

@ -98,9 +98,6 @@ Query$SystemSettings$system$settings$ssh
Query$SystemSettings$system$settings$ssh(
enable: json['enable'] as bool,
passwordAuthentication: json['passwordAuthentication'] as bool,
rootSshKeys: (json['rootSshKeys'] as List<dynamic>)
.map((e) => e as String)
.toList(),
$__typename: json['__typename'] as String,
);
@ -109,7 +106,6 @@ Map<String, dynamic> _$Query$SystemSettings$system$settings$sshToJson(
<String, dynamic>{
'enable': instance.enable,
'passwordAuthentication': instance.passwordAuthentication,
'rootSshKeys': instance.rootSshKeys,
'__typename': instance.$__typename,
};

View File

@ -7,11 +7,14 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_api.graphq
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/users.graphql.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/json/api_token.dart';
import 'package:selfprivacy/logic/models/json/server_disk_volume.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/logic/models/ssh_settings.dart';
import 'package:selfprivacy/logic/models/system_settings.dart';
part 'jobs_api.dart';
part 'server_actions_api.dart';
@ -128,14 +131,13 @@ class ServerApi extends ApiMap
}
Future<void> setAutoUpgradeSettings(
final bool allowReboot,
final bool enableAutoUpgrade,
final AutoUpgradeSettings settings,
) async {
try {
final GraphQLClient client = await getClient();
final input = Input$AutoUpgradeSettingsInput(
allowReboot: allowReboot,
enableAutoUpgrade: enableAutoUpgrade,
allowReboot: settings.allowReboot,
enableAutoUpgrade: settings.enable,
);
final variables = Variables$Mutation$ChangeAutoUpgradeSettings(
settings: input,
@ -148,4 +150,47 @@ class ServerApi extends ApiMap
print(e);
}
}
Future<void> setTimezone(final String timezone) async {
try {
final GraphQLClient client = await getClient();
final variables = Variables$Mutation$ChangeTimezone(
timezone: timezone,
);
final mutation = Options$Mutation$ChangeTimezone(
variables: variables,
);
await client.mutate$ChangeTimezone(mutation);
} catch (e) {
print(e);
}
}
Future<SystemSettings> getSystemSettings() async {
QueryResult<Query$SystemSettings> response;
SystemSettings settings = SystemSettings(
autoUpgradeSettings: AutoUpgradeSettings(
allowReboot: false,
enable: false,
),
sshSettings: SshSettings(
enable: false,
passwordAuthentication: false,
),
timezone: 'Unknown',
);
try {
final GraphQLClient client = await getClient();
response = await client.query$SystemSettings();
if (response.hasException) {
print(response.exception.toString());
}
settings = SystemSettings.fromGraphQL(response.parsedData!.system);
} catch (e) {
print(e);
}
return settings;
}
}

View File

@ -10,7 +10,6 @@ import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/json/api_token.dart';
import 'package:selfprivacy/logic/models/json/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/json/backup.dart';
import 'package:selfprivacy/logic/models/json/device_token.dart';
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
@ -565,43 +564,6 @@ class ServerApi extends ApiMap {
return result;
}
Future<AutoUpgradeSettings> getAutoUpgradeSettings() async {
Response response;
AutoUpgradeSettings settings = const AutoUpgradeSettings(
enable: false,
allowReboot: false,
);
final Dio client = await getClient();
try {
response = await client.get('/system/configuration/autoUpgrade');
if (response.data != null) {
settings = AutoUpgradeSettings.fromJson(response.data);
}
} on DioError catch (e) {
print(e.message);
} finally {
close(client);
}
return settings;
}
Future<void> updateAutoUpgradeSettings(
final AutoUpgradeSettings settings,
) async {
final Dio client = await getClient();
try {
await client.put(
'/system/configuration/autoUpgrade',
data: settings.toJson(),
);
} on DioError catch (e) {
print(e.message);
} finally {
close(client);
}
}
Future<TimeZoneSettings> getServerTimezone() async {
TimeZoneSettings settings = TimeZoneSettings();
final Dio client = await getClient();

View File

@ -2,7 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_repository.dart';
import 'package:selfprivacy/logic/models/json/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/json/hetzner_server_info.dart';
import 'package:selfprivacy/logic/models/timezone_settings.dart';

View File

@ -1,6 +1,6 @@
import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/server.dart';
import 'package:selfprivacy/logic/models/json/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/json/hetzner_server_info.dart';
import 'package:selfprivacy/logic/models/timezone_settings.dart';
@ -8,11 +8,30 @@ class ServerDetailsRepository {
HetznerApi hetzner = HetznerApi();
ServerApi server = ServerApi();
Future<ServerDetailsRepositoryDto> load() async => ServerDetailsRepositoryDto(
autoUpgradeSettings: await server.getAutoUpgradeSettings(),
hetznerServerInfo: await hetzner.getInfo(),
serverTimezone: await server.getServerTimezone(),
);
Future<ServerDetailsRepositoryDto> load() async {
final settings = await server.getSystemSettings();
return ServerDetailsRepositoryDto(
autoUpgradeSettings: settings.autoUpgradeSettings,
hetznerServerInfo: await hetzner.getInfo(),
serverTimezone: TimeZoneSettings.fromString(
settings.timezone,
),
);
}
Future<void> setAutoUpgradeSettings(
final AutoUpgradeSettings settings,
) async {
await server.setAutoUpgradeSettings(settings);
}
Future<void> setTimezone(
final String timezone,
) async {
if (timezone.isNotEmpty) {
await server.setTimezone(timezone);
}
}
}
class ServerDetailsRepositoryDto {

View File

@ -0,0 +1,18 @@
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart';
class AutoUpgradeSettings {
AutoUpgradeSettings({
required this.enable,
required this.allowReboot,
});
AutoUpgradeSettings.fromGraphQL(
final Query$SystemSettings$system$settings$autoUpgrade autoUpgrade,
) : this(
enable: autoUpgrade.enable,
allowReboot: autoUpgrade.allowReboot,
);
final bool enable;
final bool allowReboot;
}

View File

@ -1,22 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
part 'auto_upgrade_settings.g.dart';
@JsonSerializable(createToJson: true)
class AutoUpgradeSettings extends Equatable {
factory AutoUpgradeSettings.fromJson(final Map<String, dynamic> json) =>
_$AutoUpgradeSettingsFromJson(json);
const AutoUpgradeSettings({
required this.enable,
required this.allowReboot,
});
final bool enable;
final bool allowReboot;
@override
List<Object?> get props => [enable, allowReboot];
Map<String, dynamic> toJson() => _$AutoUpgradeSettingsToJson(this);
}

View File

@ -1,20 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'auto_upgrade_settings.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
AutoUpgradeSettings _$AutoUpgradeSettingsFromJson(Map<String, dynamic> json) =>
AutoUpgradeSettings(
enable: json['enable'] as bool,
allowReboot: json['allowReboot'] as bool,
);
Map<String, dynamic> _$AutoUpgradeSettingsToJson(
AutoUpgradeSettings instance) =>
<String, dynamic>{
'enable': instance.enable,
'allowReboot': instance.allowReboot,
};

View File

@ -0,0 +1,17 @@
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart';
class SshSettings {
SshSettings({
required this.enable,
required this.passwordAuthentication,
});
SshSettings.fromGraphQL(final Query$SystemSettings$system$settings$ssh ssh)
: this(
enable: ssh.enable,
passwordAuthentication: ssh.passwordAuthentication,
);
final bool enable;
final bool passwordAuthentication;
}

View File

@ -0,0 +1,26 @@
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/ssh_settings.dart';
class SystemSettings {
SystemSettings({
required this.sshSettings,
required this.autoUpgradeSettings,
required this.timezone,
});
SystemSettings.fromGraphQL(final Query$SystemSettings$system system)
: this(
sshSettings: SshSettings.fromGraphQL(
system.settings.ssh,
),
autoUpgradeSettings: AutoUpgradeSettings.fromGraphQL(
system.settings.autoUpgrade,
),
timezone: system.settings.timezone,
);
final SshSettings sshSettings;
final AutoUpgradeSettings autoUpgradeSettings;
final String timezone;
}

View File

@ -7,6 +7,7 @@ import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/hetzner_metrics/hetzner_metrics_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/state_types.dart';
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';

View File

@ -1,12 +1,18 @@
part of 'server_details_screen.dart';
class _ServerSettings extends StatelessWidget {
const _ServerSettings({
required this.tabController,
});
class _ServerSettings extends StatefulWidget {
const _ServerSettings({required this.tabController});
final TabController tabController;
@override
State<_ServerSettings> createState() => _ServerSettingsState();
}
class _ServerSettingsState extends State<_ServerSettings> {
bool? allowAutoUpgrade;
bool? rebootAfterUpgrade;
@override
Widget build(final BuildContext context) {
final serverDetailsState = context.watch<ServerDetailsCubit>().state;
@ -15,6 +21,11 @@ class _ServerSettings extends StatelessWidget {
} else if (serverDetailsState is! Loaded) {
return BrandLoader.horizontal();
}
if (allowAutoUpgrade == null || rebootAfterUpgrade == null) {
allowAutoUpgrade = serverDetailsState.autoUpgradeSettings.enable;
rebootAfterUpgrade = serverDetailsState.autoUpgradeSettings.allowReboot;
}
return ListView(
padding: paddingH15V0,
children: [
@ -27,7 +38,7 @@ class _ServerSettings extends StatelessWidget {
children: [
IconButton(
icon: const Icon(BrandIcons.arrowLeft),
onPressed: () => tabController.animateTo(0),
onPressed: () => widget.tabController.animateTo(0),
),
const SizedBox(width: 10),
BrandText.h4('basis.settings'.tr()),
@ -35,8 +46,21 @@ class _ServerSettings extends StatelessWidget {
),
),
SwitcherBlock(
onChange: (final _) {},
isActive: serverDetailsState.autoUpgradeSettings.enable,
onChange: (final switched) {
context
.read<ServerDetailsCubit>()
.repository
.setAutoUpgradeSettings(
AutoUpgradeSettings(
enable: switched,
allowReboot: rebootAfterUpgrade ?? false,
),
);
setState(() {
allowAutoUpgrade = switched;
});
},
isActive: allowAutoUpgrade ?? false,
child: _TextColumn(
title: 'providers.server.settings.allow_autoupgrade'.tr(),
value: 'providers.server.settings.allow_autoupgrade_hint'.tr(),
@ -44,8 +68,23 @@ class _ServerSettings extends StatelessWidget {
),
const Divider(height: 0),
SwitcherBlock(
onChange: (final _) {},
isActive: serverDetailsState.autoUpgradeSettings.allowReboot,
onChange: (final switched) {
context
.read<ServerDetailsCubit>()
.repository
.setAutoUpgradeSettings(
AutoUpgradeSettings(
enable: allowAutoUpgrade ?? false,
allowReboot: switched,
),
);
setState(
() {
rebootAfterUpgrade = switched;
},
);
},
isActive: rebootAfterUpgrade ?? false,
child: _TextColumn(
title: 'providers.server.settings.reboot_after_upgrade'.tr(),
value: 'providers.server.settings.reboot_after_upgrade_hint'.tr(),
@ -54,7 +93,11 @@ class _ServerSettings extends StatelessWidget {
const Divider(height: 0),
_Button(
onTap: () {
Navigator.of(context).push(materialRoute(const SelectTimezone()));
Navigator.of(context).push(
materialRoute(
const SelectTimezone(),
),
);
},
child: _TextColumn(
title: 'providers.server.settings.server_timezone'.tr(),
@ -89,12 +132,10 @@ class _TextColumn extends StatelessWidget {
const _TextColumn({
required this.title,
required this.value,
this.hasWarning = false,
});
final String title;
final String value;
final bool hasWarning;
@override
Widget build(final BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -47,10 +47,10 @@ class _SelectTimezoneState extends State<SelectTimezone> {
@override
Widget build(final BuildContext context) => Scaffold(
appBar: const PreferredSize(
preferredSize: Size.fromHeight(52),
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'select timezone',
title: 'providers.server.settings.select_timezone'.tr(),
hasBackButton: true,
),
),
@ -76,7 +76,7 @@ class _SelectTimezoneState extends State<SelectTimezone> {
return MapEntry(
key,
Container(
height: 60,
height: 75,
padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: const BoxDecoration(
border: Border(
@ -85,24 +85,38 @@ class _SelectTimezoneState extends State<SelectTimezone> {
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
BrandText.body1(
timezoneName,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
child: InkWell(
onTap: () {
context
.read<ServerDetailsCubit>()
.repository
.setTimezone(
timezoneName,
);
Navigator.of(context).pop();
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
BrandText.body1(
timezoneName,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
BrandText.small(
'GMT ${duration.toDayHourMinuteFormat()} ${area.isNotEmpty ? '($area)' : ''}',
style: const TextStyle(
fontSize: 13,
),
),
],
),
BrandText.small(
'GMT ${duration.toDayHourMinuteFormat()} ${area.isNotEmpty ? '($area)' : ''}',
style: const TextStyle(
fontSize: 13,
),
),
],
),
),
),
);