diff --git a/assets/translations/en.json b/assets/translations/en.json index dd6e2ca3..4cc240b9 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -110,6 +110,7 @@ "disk": "Disk local", "monthly_cost": "Monthly cost", "location": "Location", + "provider": "Provider", "core_count": { "one": "{} core", "two": "{} cores", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 71f5c0ef..49c08079 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -110,6 +110,7 @@ "disk": "Диск", "monthly_cost": "Ежемесячная стоимость", "location": "Размещение", + "provider": "Провайдер", "core_count": { "one": "{} ядро", "two": "{} ядра", diff --git a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart index a951daa0..c216d4c5 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart @@ -2,18 +2,20 @@ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/volume_provider.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider.dart'; import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; -import 'package:selfprivacy/logic/models/json/hetzner_server_info.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/logic/models/server_basic_info.dart'; +import 'package:selfprivacy/logic/models/server_metadata.dart'; import 'package:selfprivacy/logic/models/server_provider_location.dart'; import 'package:selfprivacy/logic/models/server_type.dart'; +import 'package:selfprivacy/utils/extensions/string_extensions.dart'; import 'package:selfprivacy/utils/password_generator.dart'; class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { @@ -313,8 +315,6 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { base64.encode(utf8.encode(rootUser.password ?? 'PASS')); final String formattedHostname = getHostnameFromDomain(domainName); - - // TODO: change to 'master' change to 'master' change to 'master' const String infectBranch = 'providers/digital-ocean'; final String userdataString = @@ -474,14 +474,59 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { return metrics; } - Future getInfo() async { - final ServerHostingDetails? hetznerServer = - getIt().serverDetails; - final Dio client = await getClient(); - final Response response = await client.get('/servers/${hetznerServer!.id}'); - close(client); + @override + Future> getMetadata(final int serverId) async { + List metadata = []; - return HetznerServerInfo.fromJson(response.data!['server']); + final Dio client = await getClient(); + try { + final Response response = await client.get('/droplets/$serverId'); + final droplet = response.data!['droplet']; + metadata = [ + ServerMetadataEntity( + type: MetadataType.id, + name: 'server.server_id'.tr(), + value: droplet['id'].toString(), + ), + ServerMetadataEntity( + type: MetadataType.status, + name: 'server.status'.tr(), + value: droplet['status'].toString().capitalize(), + ), + ServerMetadataEntity( + type: MetadataType.cpu, + name: 'server.cpu'.tr(), + value: 'server.core_count'.plural(droplet['vcpus']), + ), + ServerMetadataEntity( + type: MetadataType.ram, + name: 'server.ram'.tr(), + value: "${droplet['memory'].toString()} MB", + ), + ServerMetadataEntity( + type: MetadataType.cost, + name: 'server.monthly_cost'.tr(), + value: droplet['size']['price_monthly'].toString(), + ), + ServerMetadataEntity( + type: MetadataType.location, + name: 'server.location'.tr(), + value: + '${droplet['region']['name']} ${getEmojiFlag(droplet['region']['slug'].toString()) ?? ''}', + ), + ServerMetadataEntity( + type: MetadataType.other, + name: 'server.provider'.tr(), + value: 'Digital Ocean', + ), + ]; + } catch (e) { + print(e); + } finally { + close(client); + } + + return metadata; } @override diff --git a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart index 13fb2cde..922c309c 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/volume_provider.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider.dart'; @@ -12,8 +13,10 @@ import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/logic/models/server_basic_info.dart'; +import 'package:selfprivacy/logic/models/server_metadata.dart'; import 'package:selfprivacy/logic/models/server_provider_location.dart'; import 'package:selfprivacy/logic/models/server_type.dart'; +import 'package:selfprivacy/utils/extensions/string_extensions.dart'; import 'package:selfprivacy/utils/password_generator.dart'; class HetznerApi extends ServerProviderApi with VolumeProviderApi { @@ -513,14 +516,59 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { return metrics; } - Future getInfo() async { - final ServerHostingDetails? hetznerServer = - getIt().serverDetails; - final Dio client = await getClient(); - final Response response = await client.get('/servers/${hetznerServer!.id}'); - close(client); + @override + Future> getMetadata(final int serverId) async { + List metadata = []; - return HetznerServerInfo.fromJson(response.data!['server']); + final Dio client = await getClient(); + try { + final Response response = await client.get('/servers/$serverId'); + final hetznerInfo = HetznerServerInfo.fromJson(response.data!['server']); + metadata = [ + ServerMetadataEntity( + type: MetadataType.id, + name: 'server.server_id'.tr(), + value: hetznerInfo.id.toString(), + ), + ServerMetadataEntity( + type: MetadataType.status, + name: 'server.status'.tr(), + value: hetznerInfo.status.toString().split('.')[1].capitalize(), + ), + ServerMetadataEntity( + type: MetadataType.cpu, + name: 'server.cpu'.tr(), + value: 'server.core_count'.plural(hetznerInfo.serverType.cores), + ), + ServerMetadataEntity( + type: MetadataType.ram, + name: 'server.ram'.tr(), + value: '${hetznerInfo.serverType.memory.toString()} GB', + ), + ServerMetadataEntity( + type: MetadataType.cost, + name: 'server.monthly_cost'.tr(), + value: hetznerInfo.serverType.prices[1].monthly.toStringAsFixed(2), + ), + ServerMetadataEntity( + type: MetadataType.location, + name: 'server.location'.tr(), + value: + '${hetznerInfo.location.city}, ${hetznerInfo.location.country}', + ), + ServerMetadataEntity( + type: MetadataType.other, + name: 'server.provider'.tr(), + value: 'Hetzner', + ), + ]; + } catch (e) { + print(e); + } finally { + close(client); + } + + return metadata; } @override diff --git a/lib/logic/api_maps/rest_maps/server_providers/server_provider.dart b/lib/logic/api_maps/rest_maps/server_providers/server_provider.dart index b04ae1e0..9e0b57bf 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/server_provider.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/server_provider.dart @@ -3,6 +3,7 @@ import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/logic/models/server_basic_info.dart'; +import 'package:selfprivacy/logic/models/server_metadata.dart'; import 'package:selfprivacy/logic/models/server_provider_location.dart'; import 'package:selfprivacy/logic/models/server_type.dart'; @@ -39,6 +40,7 @@ abstract class ServerProviderApi extends ApiMap { Future isApiTokenValid(final String token); ProviderApiTokenValidation getApiTokenValidation(); + Future> getMetadata(final int serverId); abstract final String infectProviderName; } diff --git a/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart b/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart index a3af96e8..b6a39733 100644 --- a/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart +++ b/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart @@ -2,7 +2,7 @@ import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_repository.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/server_metadata.dart'; import 'package:selfprivacy/logic/models/timezone_settings.dart'; part 'server_detailed_info_state.dart'; @@ -22,7 +22,7 @@ class ServerDetailsCubit final ServerDetailsRepositoryDto data = await repository.load(); emit( Loaded( - serverInfo: data.hetznerServerInfo, + metadata: data.metadata, autoUpgradeSettings: data.autoUpgradeSettings, serverTimezone: data.serverTimezone, checkTime: DateTime.now(), diff --git a/lib/logic/cubit/server_detailed_info/server_detailed_info_repository.dart b/lib/logic/cubit/server_detailed_info/server_detailed_info_repository.dart index bfa3991f..fcc0c5d8 100644 --- a/lib/logic/cubit/server_detailed_info/server_detailed_info_repository.dart +++ b/lib/logic/cubit/server_detailed_info/server_detailed_info_repository.dart @@ -1,22 +1,42 @@ import 'package:selfprivacy/config/get_it_config.dart'; -import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server.dart'; +import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_creator.dart'; +import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_settings.dart'; +import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider_factory.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/hive/server_details.dart'; +import 'package:selfprivacy/logic/models/server_metadata.dart'; import 'package:selfprivacy/logic/models/timezone_settings.dart'; class ServerDetailsRepository { - HetznerApi hetzner = HetznerApi( - /// TODO: Hetzner hardcode (???) - region: getIt().serverLocation, - ); ServerApi server = ServerApi(); + ServerProviderApiFactory? serverProviderApiFactory; + + void _buildServerProviderFactory() { + final ServerProvider? providerType = getIt().serverProvider; + final String? location = getIt().serverLocation; + serverProviderApiFactory = ApiFactoryCreator.createServerProviderApiFactory( + ServerProviderApiFactorySettings( + provider: providerType ?? ServerProvider.unknown, + location: location, + ), + ); + } Future load() async { + if (serverProviderApiFactory == null) { + _buildServerProviderFactory(); + } + final settings = await server.getSystemSettings(); + final serverId = getIt().serverDetails!.id; + final metadata = await serverProviderApiFactory! + .getServerProvider() + .getMetadata(serverId); + return ServerDetailsRepositoryDto( autoUpgradeSettings: settings.autoUpgradeSettings, - hetznerServerInfo: await hetzner.getInfo(), + metadata: metadata, serverTimezone: TimeZoneSettings.fromString( settings.timezone, ), @@ -40,13 +60,11 @@ class ServerDetailsRepository { class ServerDetailsRepositoryDto { ServerDetailsRepositoryDto({ - required this.hetznerServerInfo, + required this.metadata, required this.serverTimezone, required this.autoUpgradeSettings, }); - final HetznerServerInfo hetznerServerInfo; - + final List metadata; final TimeZoneSettings serverTimezone; - final AutoUpgradeSettings autoUpgradeSettings; } diff --git a/lib/logic/cubit/server_detailed_info/server_detailed_info_state.dart b/lib/logic/cubit/server_detailed_info/server_detailed_info_state.dart index ea5f4864..64f4d91d 100644 --- a/lib/logic/cubit/server_detailed_info/server_detailed_info_state.dart +++ b/lib/logic/cubit/server_detailed_info/server_detailed_info_state.dart @@ -17,21 +17,19 @@ class Loading extends ServerDetailsState {} class Loaded extends ServerDetailsState { const Loaded({ - required this.serverInfo, + required this.metadata, required this.serverTimezone, required this.autoUpgradeSettings, required this.checkTime, }); - final HetznerServerInfo serverInfo; - + final List metadata; final TimeZoneSettings serverTimezone; - final AutoUpgradeSettings autoUpgradeSettings; final DateTime checkTime; @override List get props => [ - serverInfo, + metadata, serverTimezone, autoUpgradeSettings, checkTime, diff --git a/lib/logic/models/server_metadata.dart b/lib/logic/models/server_metadata.dart new file mode 100644 index 00000000..1a08abc0 --- /dev/null +++ b/lib/logic/models/server_metadata.dart @@ -0,0 +1,21 @@ +enum MetadataType { + id, + status, + cpu, + ram, + cost, + location, + + other, +} + +class ServerMetadataEntity { + ServerMetadataEntity({ + required this.name, + required this.value, + this.type = MetadataType.other, + }); + final MetadataType type; + final String name; + final String value; +} diff --git a/lib/ui/pages/server_details/server_details_screen.dart b/lib/ui/pages/server_details/server_details_screen.dart index e0d82b6d..acf19583 100644 --- a/lib/ui/pages/server_details/server_details_screen.dart +++ b/lib/ui/pages/server_details/server_details_screen.dart @@ -10,6 +10,7 @@ import 'package:selfprivacy/logic/cubit/server_installation/server_installation_ import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart'; import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart'; import 'package:selfprivacy/logic/models/job.dart'; +import 'package:selfprivacy/logic/models/server_metadata.dart'; import 'package:selfprivacy/ui/components/brand_button/segmented_buttons.dart'; import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart'; import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; diff --git a/lib/ui/pages/server_details/text_details.dart b/lib/ui/pages/server_details/text_details.dart index e9b3c0f7..2c06375f 100644 --- a/lib/ui/pages/server_details/text_details.dart +++ b/lib/ui/pages/server_details/text_details.dart @@ -1,6 +1,16 @@ part of 'server_details_screen.dart'; class _TextDetails extends StatelessWidget { + final Map metadataToIcon = const { + MetadataType.id: Icons.numbers_outlined, + MetadataType.status: Icons.mode_standby_outlined, + MetadataType.cpu: Icons.memory_outlined, + MetadataType.ram: Icons.memory_outlined, + MetadataType.cost: Icons.euro_outlined, + MetadataType.location: Icons.location_on_outlined, + MetadataType.other: Icons.info_outlined, + }; + @override Widget build(final BuildContext context) { final details = context.watch().state; @@ -10,7 +20,6 @@ class _TextDetails extends StatelessWidget { } else if (details is ServerDetailsNotReady) { return _TempMessage(message: 'basis.no_data'.tr()); } else if (details is Loaded) { - final data = details.serverInfo; return FilledCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -24,37 +33,15 @@ class _TextDetails extends StatelessWidget { ), ), ), - ListTileOnSurfaceVariant( - leadingIcon: Icons.numbers_outlined, - title: data.id.toString(), - subtitle: 'server.server_id'.tr(), - ), - ListTileOnSurfaceVariant( - leadingIcon: Icons.mode_standby_outlined, - title: data.status.toString().split('.')[1].capitalize(), - subtitle: 'server.status'.tr(), - ), - ListTileOnSurfaceVariant( - leadingIcon: Icons.memory_outlined, - title: 'server.core_count'.plural(data.serverType.cores), - subtitle: 'server.cpu'.tr(), - ), - ListTileOnSurfaceVariant( - leadingIcon: Icons.memory_outlined, - title: '${data.serverType.memory.toString()} GB', - subtitle: 'server.ram'.tr(), - ), - ListTileOnSurfaceVariant( - leadingIcon: Icons.euro_outlined, - title: data.serverType.prices[1].monthly.toStringAsFixed(2), - subtitle: 'server.monthly_cost'.tr(), - ), - // Server location - ListTileOnSurfaceVariant( - leadingIcon: Icons.location_on_outlined, - title: '${data.location.city}, ${data.location.country}', - subtitle: 'server.location'.tr(), - ), + ...details.metadata + .map( + (final metadata) => ListTileOnSurfaceVariant( + leadingIcon: metadataToIcon[metadata.type], + title: metadata.name, + subtitle: metadata.value, + ), + ) + .toList(), ], ), );