From bd8faf876088f32668422b5efcb575f59bf15808 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Fri, 28 Jul 2023 20:42:41 -0300 Subject: [PATCH 1/5] feat: Replace general entity naming on UI with specifics. - Pass actual provider namings to .tr functions as arguments - Remove hardcoded namings where known - Get rid of general mentions of 'DNS Provider' or 'Server Provider' where confusing --- assets/translations/az.json | 12 +++----- assets/translations/be.json | 14 ++++------ assets/translations/cs.json | 14 ++++------ assets/translations/de.json | 14 ++++------ assets/translations/en.json | 19 ++++++------- assets/translations/pl.json | 12 +++----- assets/translations/ru.json | 14 ++++------ assets/translations/sk.json | 12 +++----- assets/translations/uk.json | 12 +++----- .../digital_ocean/digital_ocean_api.dart | 1 - .../server_providers/hetzner/hetzner_api.dart | 1 - .../server_detailed_info_repository.dart | 28 +++++++++++++++---- .../server_installation_cubit.dart | 20 +++++++++++-- lib/logic/models/hive/server_details.dart | 15 ++++------ lib/logic/models/hive/server_domain.dart | 7 +++++ .../server_providers/digital_ocean.dart | 4 +-- .../providers/server_providers/hetzner.dart | 4 +-- .../server_storage/extending_volume.dart | 12 +++----- .../recovery_confirm_backblaze.dart | 6 ++-- .../recovering/recovery_confirm_dns.dart | 14 +++++++--- .../recovery_server_provider_connected.dart | 17 ++++++++--- 21 files changed, 132 insertions(+), 120 deletions(-) diff --git a/assets/translations/az.json b/assets/translations/az.json index a49dd1ff..81d678c7 100644 --- a/assets/translations/az.json +++ b/assets/translations/az.json @@ -355,9 +355,9 @@ "fallback_select_provider_console": "Hostinq konsoluna giriş.", "authorization_failed": "Bu açarla daxil olmaq alınmadı", "fallback_select_provider_console_hint": "Məsələn: Hetzner.", - "server_provider_connected": "Server provayderinizə qoşulur", - "server_provider_connected_description": "Əlaqə quruldu. {} girişi ilə nişanınızı daxil edin:", - "server_provider_connected_placeholder": "Server provayderi nişanı", + "provider_connected": "{} qoşulur", + "provider_connected_description": "Əlaqə quruldu. {} girişi ilə nişanınızı daxil edin:", + "provider_connected_placeholder": "{} nişanı", "confirm_server": "Serveri təsdiqləyin", "confirm_server_description": "Server tapdım! Onun olduğunu təsdiq edin:", "confirm_server_accept": "Bəli, odur", @@ -368,11 +368,7 @@ "domain_not_available_on_token": "Daxil edilmiş işarənin tələb olunan domenə girişi yoxdur.", "modal_confirmation_dns_valid": "Əks DNS düzgündür", "modal_confirmation_dns_invalid": "Əks DNS fərqli domenə işarə edir", - "modal_confirmation_ip_valid": "IP DNS qeydində göstərilənə uyğun gəlir", - "confirm_cloudflare": "Cloudflare-ə qoşulur", - "confirm_cloudflare_description": "{} hüququ olan Cloudflare tokenini daxil edin:", - "confirm_backblaze": "Backblaze-ə qoşulur", - "confirm_backblaze_description": "Ehtiyat saxlama hüququ olan Backblaze tokenini daxil edin:" + "modal_confirmation_ip_valid": "IP DNS qeydində göstərilənə uyğun gəlir" }, "devices": { "main_screen": { diff --git a/assets/translations/be.json b/assets/translations/be.json index f6eff55c..3a5e84a8 100644 --- a/assets/translations/be.json +++ b/assets/translations/be.json @@ -97,8 +97,8 @@ "fallback_select_root_ssh": "Каранёвы доступ да сервера праз SSH.", "authorization_failed": "Не ўдалося ўвайсці з гэтым ключом", "fallback_select_provider_console_hint": "Напрыклад, Hetzner.", - "server_provider_connected": "Падлучэнне да вашага сервернага правайдэра", - "server_provider_connected_placeholder": "Токен сервернага правайдэра", + "provider_connected": "Падлучэнне да вашага {}", + "provider_connected_placeholder": "Токен {}", "confirm_server": "Пацвердзіце сервер", "confirm_server_description": "Знайшлі сервер! Пацьвердзіце, што гэта ён:", "confirm_server_accept": "Да, гэта ён", @@ -109,16 +109,12 @@ "modal_confirmation_dns_valid": "Зваротны DNS карэктны", "modal_confirmation_dns_invalid": "Зваротны DNS паказвае на іншы дамен", "modal_confirmation_ip_invalid": "IP не супадае з паказаным у DNS запісу", - "confirm_backblaze": "Падключэнне да Backblaze", - "confirm_backblaze_description": "Увядзіце токен Backblaze, які мае правы на сховішча рэзервовых копій:", "fallback_select_provider_console": "Доступ да кансолі хостынгу.", - "server_provider_connected_description": "Сувязь устаноўлена. Увядзіце свой токен з доступам да {}:", + "provider_connected_description": "Сувязь устаноўлена. Увядзіце свой токен з доступам да {}:", "choose_server": "Выберыце сервер", "no_servers": "На вашым акаўнце няма даступных сэрвэраў.", "modal_confirmation_description": "Падлучэнне да няправільнага сервера можа прывесці да дэструктыўных наступстваў.", - "modal_confirmation_ip_valid": "IP супадае з паказаным у DNS запісу", - "confirm_cloudflare": "Падключэнне да DNS Правайдэра", - "confirm_cloudflare_description": "Увядзіце токен DNS Правайдэра, які мае правы на {}:" + "modal_confirmation_ip_valid": "IP супадае з паказаным у DNS запісу" }, "devices": { "main_screen": { @@ -514,4 +510,4 @@ "support": { "title": "Падтрымка SelfPrivacy" } -} +} \ No newline at end of file diff --git a/assets/translations/cs.json b/assets/translations/cs.json index 22b82f52..818cd320 100644 --- a/assets/translations/cs.json +++ b/assets/translations/cs.json @@ -369,9 +369,9 @@ "fallback_select_root_ssh": "Kořenový přístup SSH k serveru.", "fallback_select_provider_console": "Přístup ke konzole serveru mého prodiveru.", "authorization_failed": "Nelze se přihlásit pomocí tohoto klíče", - "server_provider_connected": "Připojení k poskytovateli serveru", - "server_provider_connected_description": "Komunikace navázána. Zadejte svůj token s přístupem k {}:", - "server_provider_connected_placeholder": "Token poskytovatele serveru", + "provider_connected": "Připojení k poskytovateli {}", + "provider_connected_description": "Komunikace navázána. Zadejte svůj token s přístupem k {}:", + "provider_connected_placeholder": "Token {}", "confirm_server": "Potvrzení serveru", "confirm_server_accept": "Ano! To je ono", "confirm_server_decline": "Výběr jiného serveru", @@ -383,17 +383,13 @@ "modal_confirmation_dns_valid": "Reverzní DNS je platný", "modal_confirmation_dns_invalid": "Reverzní DNS ukazuje na jinou doménu", "modal_confirmation_ip_invalid": "IP není stejná jako v záznamu DNS", - "confirm_cloudflare": "Připojení k poskytovateli DNS", - "confirm_cloudflare_description": "Zadejte token DNS poskytovatele, který má práva k {}:", - "confirm_backblaze": "Připojení k službě Backblaze", "generic_error": "Operace se nezdařila, zkuste to prosím znovu.", "domain_recovery_description": "Zadejte doménu serveru, ke které chcete získat přístup:", "method_device_description": "Otevřete aplikaci v jiném zařízení a přejděte na stránku zařízení. Stisknutím tlačítka \"Přidat zařízení\" získáte token.", "fallback_select_provider_console_hint": "Například: Hetzner.", "confirm_server_description": "Našel jsem váš server! Potvrďte, že je to ten správný:", "domain_not_available_on_token": "Vybraná doména není na tomto tokenu k dispozici.", - "modal_confirmation_ip_valid": "IP je stejná jako v záznamu DNS", - "confirm_backblaze_description": "Zadejte token Backblaze s přístupem k úložišti záloh:" + "modal_confirmation_ip_valid": "IP je stejná jako v záznamu DNS" }, "devices": { "main_screen": { @@ -514,4 +510,4 @@ "ignore_tls": "Nekontrolujte certifikáty TLS", "ignore_tls_description": "Aplikace nebude při připojování k serveru ověřovat certifikáty TLS." } -} +} \ No newline at end of file diff --git a/assets/translations/de.json b/assets/translations/de.json index 105b5f2f..9b8b1093 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -411,12 +411,9 @@ "domain_recovery_description": "Geben Sie eine Serverdomäne ein, für die Sie Zugriff erhalten möchten:", "method_device_description": "Öffnen Sie die Anwendung auf einem anderen Gerät und gehen Sie dann zur Geräteseite. Drücken Sie auf „Gerät hinzufügen“, um Ihren Token zu erhalten.", "fallback_select_token_copy": "Kopie des Authentifizierungstokens von einer anderen Version der Anwendung.", - "server_provider_connected_description": "Kommunikation hergestellt. Eingabe Ihres Tokens Token mit Zugriff auf {}:", + "provider_connected_description": "Kommunikation hergestellt. Eingabe Ihres Tokens Token mit Zugriff auf {}:", "choose_server_description": "Wir konnten nicht herausfinden, mit welchem Server Sie sich verbinden möchten.", "modal_confirmation_dns_invalid": "Reverse DNS zeigt auf eine andere Domain", - "confirm_cloudflare_description": "Geben Sie das DNS-Token des Anbieters ein, der Rechte für {} hat:", - "confirm_backblaze": "Mit Backblaze verbinden", - "confirm_backblaze_description": "Geben Sie ein Backblaze-Token mit Zugriff auf den Sicherungsspeicher ein:", "generic_error": "Vorgang fehlgeschlagen, bitte versuchen Sie es erneut.", "recovery_main_header": "Verbindung zu einem vorhandenen Server herstellen", "domain_recover_placeholder": "Ihre Domain", @@ -434,8 +431,8 @@ "fallback_select_provider_console": "Zugang zur Serverkonsole meines Providers.", "authorization_failed": "Anmeldung mit diesem Schlüssel nicht möglich", "fallback_select_provider_console_hint": "Zum Beispiel: Hetzner.", - "server_provider_connected": "Verbinden Sie sich mit Ihrem Serveranbieter", - "server_provider_connected_placeholder": "Token des Serveranbieters", + "provider_connected": "Verbinden Sie sich mit Ihrem {}", + "provider_connected_placeholder": "Token des {}", "confirm_server": "Server bestätigen", "confirm_server_description": "Server gefunden! Bestätigen Sie, dass es das Richtige ist:", "confirm_server_accept": "Ja! Das ist es", @@ -447,8 +444,7 @@ "modal_confirmation_description": "Wenn Sie sich mit einem falschen Server verbinden, können Sie alle Ihre Daten verlieren.", "modal_confirmation_dns_valid": "Reverse DNS ist gültig", "modal_confirmation_ip_valid": "Die IP ist die gleiche wie im DNS-Eintrag", - "modal_confirmation_ip_invalid": "Die IP ist nicht dieselbe wie im DNS-Eintrag", - "confirm_cloudflare": "Verbindung zu einem DNS-Anbieter herstellen" + "modal_confirmation_ip_invalid": "Die IP ist nicht dieselbe wie im DNS-Eintrag" }, "recovery_key": { "key_connection_error": "Es konnte keine Verbindung zum Server hergestellt werden.", @@ -514,4 +510,4 @@ "ignore_tls": "Überprüfen Sie keine TLS-Zertifikate", "ignore_tls_description": "Die Anwendung validiert TLS-Zertifikate nicht, wenn sie eine Verbindung zum Server herstellt." } -} +} \ No newline at end of file diff --git a/assets/translations/en.json b/assets/translations/en.json index f66df742..51c47263 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -124,7 +124,8 @@ "disk": "Disk local", "monthly_cost": "Monthly cost", "location": "Location", - "provider": "Provider", + "server_provider": "Server Provider", + "dns_provider": "DNS Provider", "core_count": { "one": "{} core", "two": "{} cores", @@ -218,7 +219,7 @@ "extend_volume_button": "Extend volume", "extending_volume_title": "Extending volume", "extending_volume_description": "Resizing volume will allow you to store more data on your server without extending the server itself. Volume can only be extended: shrinking is not possible.", - "extending_volume_price_info": "Price includes VAT and is estimated from pricing data provided by Hetzner. Server will be rebooted after resizing.", + "extending_volume_price_info": "Price includes VAT and is estimated from pricing data provided by your server provider. Server will be rebooted after resizing.", "extending_volume_error": "Couldn't initialize volume extending.", "size": "Size", "data_migration_title": "Data migration", @@ -404,9 +405,9 @@ "fallback_select_provider_console": "Access to the server console of my provider.", "authorization_failed": "Couldn't log in with this key", "fallback_select_provider_console_hint": "For example: Hetzner.", - "server_provider_connected": "Connect to your Server Provider", - "server_provider_connected_description": "Communication established. Enter you token with access to {}:", - "server_provider_connected_placeholder": "Server Provider token", + "provider_connected": "Connect to {}", + "provider_connected_description": "Enter your token with access to {}:", + "provider_connected_placeholder": "{} token", "confirm_server": "Confirm server", "confirm_server_description": "Found your server! Confirm it is the right one:", "confirm_server_accept": "Yes! That's it", @@ -420,11 +421,7 @@ "modal_confirmation_dns_valid": "Reverse DNS is valid", "modal_confirmation_dns_invalid": "Reverse DNS points to another domain", "modal_confirmation_ip_valid": "IP is the same as in DNS record", - "modal_confirmation_ip_invalid": "IP is not the same as in DNS record", - "confirm_cloudflare": "Connect to your DNS Provider", - "confirm_cloudflare_description": "Enter a token of your DNS Provider with access to {}:", - "confirm_backblaze": "Connect to Backblaze", - "confirm_backblaze_description": "Enter a Backblaze token with access to backup storage:" + "modal_confirmation_ip_invalid": "IP is not the same as in DNS record" }, "devices": { "main_screen": { @@ -542,4 +539,4 @@ "reset_onboarding_description": "Reset onboarding switch to show onboarding screen again", "cubit_statuses": "Cubit loading statuses" } -} +} \ No newline at end of file diff --git a/assets/translations/pl.json b/assets/translations/pl.json index 93bdb733..0f0acdb0 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -433,7 +433,6 @@ "recovering": { "confirm_server_decline": "Wybierz inny serwer", "domain_not_available_on_token": "Wprowadzony token nie ma dostępu do żądanej domeny.", - "confirm_cloudflare_description": "Wprowadź token DNS dostawcy, który ma uprawnienia do {}:", "method_recovery_input_description": "Wprowadź swój token odzyskiwania", "fallback_select_provider_console": "Dostęp do konsoli serwera mojego dostawcy.", "confirm_server_description": "Znalazłem twój serwer! Potwierdź, że jest to właściwe:", @@ -461,17 +460,14 @@ "modal_confirmation_dns_invalid": "Odwrócony DNS wskazuje na inną domenę", "modal_confirmation_ip_valid": "IP jest takie samo jak w rekordzie DNS", "modal_confirmation_ip_invalid": "IP nie jest zgodne z tym w rekordzie DNS", - "confirm_cloudflare": "Łączenie z dostawcą DNS", - "confirm_backblaze": "Podłączanie do Backblaze", - "confirm_backblaze_description": "Wpisz token Backblaze, który ma prawa do magazynu kopii zapasowych:", "fallback_select_description": "Które z nich posiadasz? Wybierz pierwszą, która pasuje:", "fallback_select_token_copy": "Kopia tokena autoryzacyjnego z innej wersji aplikacji.", "fallback_select_root_ssh": "Dostęp Root do serwera poprzez SSH.", "authorization_failed": "Nie udało się zalogować za pomocą tego klucza", "fallback_select_provider_console_hint": "Na przykład: Hetzner.", - "server_provider_connected": "Połączenie z dostawcą serwera", - "server_provider_connected_description": "Połączenie ustanowione. Podaj swój token z dostępem do {}:", - "server_provider_connected_placeholder": "Token dostawcy serwera" + "provider_connected": "Połączenie z dostawcą {}", + "provider_connected_description": "Połączenie ustanowione. Podaj swój token z dostępem do {}:", + "provider_connected_placeholder": "{} Token " }, "devices": { "main_screen": { @@ -513,4 +509,4 @@ "cubit_statuses": "Aktualny stan qubitów ładujących", "ignore_tls": "Używane podczas konfigurowania nowego serwera." } -} +} \ No newline at end of file diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 738bceea..fdc276cd 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -214,7 +214,7 @@ "extend_volume_button": "Расширить хранилище", "extending_volume_title": "Расширение хранилища", "extending_volume_description": "Изменение размера хранилища позволит вам держать больше данных на вашем сервере без расширения самого сервера. Объем можно только увеличить: уменьшить нельзя.", - "extending_volume_price_info": "Цена включает НДС и рассчитана на основе данных о ценах, предоставленных Hetzner. Сервер будет перезагружен во время процесса.", + "extending_volume_price_info": "Цена включает НДС и рассчитана на основе данных о ценах, предоставленных вашим провайдером. Сервер будет перезагружен во время процесса.", "extending_volume_error": "Не удалось начать расширение хранилища.", "size": "Размер", "data_migration_title": "Миграция данных", @@ -414,13 +414,9 @@ "modal_confirmation_dns_invalid": "Обратный DNS указывает на другой домен", "modal_confirmation_ip_valid": "IP совпадает с указанным в DNS записи", "modal_confirmation_ip_invalid": "IP не совпадает с указанным в DNS записи", - "confirm_cloudflare": "Подключение к DNS Провайдеру", - "confirm_cloudflare_description": "Введите токен DNS Провайдера, который имеет права на {}:", - "confirm_backblaze_description": "Введите токен Backblaze, который имеет права на хранилище резервных копий:", - "confirm_backblaze": "Подключение к Backblaze", - "server_provider_connected": "Подключение к вашему серверному провайдеру", - "server_provider_connected_description": "Связь установлена. Введите свой токен с доступом к {}:", - "server_provider_connected_placeholder": "Токен серверного провайдера" + "provider_connected": "Подключение к вашему {}", + "provider_connected_description": "Связь установлена. Введите свой токен с доступом к {}:", + "provider_connected_placeholder": "{} Токен" }, "devices": { "main_screen": { @@ -538,4 +534,4 @@ "ignore_tls_description": "Приложение не будет проверять сертификаты TLS при подключении к серверу.", "ignore_tls": "Не проверять сертификаты TLS" } -} +} \ No newline at end of file diff --git a/assets/translations/sk.json b/assets/translations/sk.json index 9573ccae..c45523d4 100644 --- a/assets/translations/sk.json +++ b/assets/translations/sk.json @@ -388,11 +388,10 @@ "recovery_main_header": "Pripojiť sa k existujúcemu serveru", "method_select_other_device": "Mám prístup na inom zariadení", "method_device_description": "Otvorte aplikáciu na inom zariadení a otvorte obrazovku správy zariadenia. Kliknutím na „Pridať zariadenie“ získate autorizačný token.", - "server_provider_connected": "Pripojiť sa k poskytovateľovi servera", + "provider_connected": "Pripojiť sa k poskytovateľovi {}", "choose_server": "Vyberte si svoj server", "domain_not_available_on_token": "Vybraná doména nie je na tomto tokene dostupná.", "modal_confirmation_ip_valid": "IP je rovnaká ako v DNS zázname", - "confirm_backblaze_description": "Zadajte token Backblaze, ktorý má práva na úložisko záloh:", "generic_error": "Operácia zlyhala, skúste to znova.", "domain_recovery_description": "Zadajte doménu servera, pre ktorú chcete získať prístup:", "domain_recover_placeholder": "Vaša doména", @@ -410,8 +409,8 @@ "fallback_select_provider_console": "Prístup ku konzole servera môjho poskytovateľa.", "authorization_failed": "Pomocou tohto kľúča sa nepodarilo prihlásiť", "fallback_select_provider_console_hint": "Napríklad Hetzner.", - "server_provider_connected_description": "Spojenie bolo nadviazané. Zadajte svoj token s prístupom k {}:", - "server_provider_connected_placeholder": "Token poskytovateľa servera", + "provider_connected_description": "Spojenie bolo nadviazané. Zadajte svoj token s prístupom k {}:", + "provider_connected_placeholder": "{} Token", "confirm_server": "Potvrďte server", "confirm_server_description": "Našiel sa server! Potvrďte, že je to on:", "confirm_server_accept": "Áno, to je on", @@ -422,10 +421,7 @@ "modal_confirmation_description": "Ak sa pripojíte k nesprávnemu serveru, môžete stratiť všetky svoje údaje.", "modal_confirmation_dns_valid": "Reverzný DNS je platný", "modal_confirmation_dns_invalid": "Reverzné DNS ukazuje na inú doménu", - "modal_confirmation_ip_invalid": "IP nie je rovnaká ako v DNS zázname", - "confirm_cloudflare": "Pripojenie k službe CloudFlare", - "confirm_cloudflare_description": "Zadajte token Cloudflare, ktorý má práva na {}:", - "confirm_backblaze": "Pripojenie ku Backblaze" + "modal_confirmation_ip_invalid": "IP nie je rovnaká ako v DNS zázname" }, "devices": { "add_new_device_screen": { diff --git a/assets/translations/uk.json b/assets/translations/uk.json index 7a80b0dd..0d5726bf 100644 --- a/assets/translations/uk.json +++ b/assets/translations/uk.json @@ -171,9 +171,9 @@ "fallback_select_provider_console": "Доступ до серверної консолі мого продiвера.", "authorization_failed": "Не можу авторизуватись за цим ключем", "fallback_select_provider_console_hint": "Наприклад: Hetzner.", - "server_provider_connected": "Підключіться до провайдера сервера", - "server_provider_connected_description": "Зв'язок встановлений. Введіть свій токен з доступом до {}:", - "server_provider_connected_placeholder": "Токен провайдера сервера", + "provider_connected": "Підключіться до {}", + "provider_connected_description": "Зв'язок встановлений. Введіть свій токен з доступом до {}:", + "provider_connected_placeholder": "{} Токен", "confirm_server": "Підтвердити сервер", "confirm_server_description": "Знайдено ваш сервер! Підтвердіть, що він правильний:", "confirm_server_accept": "Так! Це воно", @@ -187,11 +187,7 @@ "modal_confirmation_dns_valid": "Зворотна DNS дійсна", "modal_confirmation_dns_invalid": "Зворотна DNS вказує на інший домен", "modal_confirmation_ip_valid": "IP той же, що і в записі DNS", - "modal_confirmation_ip_invalid": "IP не такий, як в DNS-записі", - "confirm_cloudflare": "Підключення до CloudFlare", - "confirm_cloudflare_description": "Введіть токен CloudFlare з доступом до {}:", - "confirm_backblaze": "Підкючитися до Backblaze", - "confirm_backblaze_description": "Введіть токен Backblaze із доступом до сховища резервних копій:" + "modal_confirmation_ip_invalid": "IP не такий, як в DNS-записі" }, "resource_chart": { "month": "Місяць", diff --git a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart index cebb568c..6a886e75 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart @@ -46,7 +46,6 @@ class DigitalOceanApi extends RestApiMap { @override String get rootAddress => 'https://api.digitalocean.com/v2'; String get infectProviderName => 'digitalocean'; - String get displayProviderName => 'Digital Ocean'; Future> getServers() async { List servers = []; diff --git a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart index 7fbf3dac..afb061d1 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart @@ -46,7 +46,6 @@ class HetznerApi extends RestApiMap { @override String get rootAddress => 'https://api.hetzner.cloud/v1'; String get infectProviderName => 'hetzner'; - String get displayProviderName => 'Hetzner'; Future>> getServers() async { List servers = []; 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 3bad75eb..0d2d80e3 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 @@ -9,20 +9,38 @@ class ServerDetailsRepository { ServerApi server = ServerApi(); Future load() async { - final serverProviderApi = ProvidersController.currentServerProvider; final settings = await server.getSystemSettings(); - final serverId = getIt().serverDetails!.id; - final metadata = await serverProviderApi?.getMetadata(serverId); - return ServerDetailsRepositoryDto( autoUpgradeSettings: settings.autoUpgradeSettings, - metadata: metadata!.data, + metadata: await metadata, serverTimezone: TimeZoneSettings.fromString( settings.timezone, ), ); } + Future> get metadata async { + List data = []; + + final serverProviderApi = ProvidersController.currentServerProvider; + final dnsProviderApi = ProvidersController.currentDnsProvider; + if (serverProviderApi != null && dnsProviderApi != null) { + final serverId = getIt().serverDetails?.id ?? 0; + final metadataResult = await serverProviderApi.getMetadata(serverId); + metadataResult.data.add( + ServerMetadataEntity( + trId: 'server.dns_provider', + value: dnsProviderApi.type.displayName, + type: MetadataType.other, + ), + ); + + data = metadataResult.data; + } + + return data; + } + Future setAutoUpgradeSettings( final AutoUpgradeSettings settings, ) async { diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index c669cf75..25fa4c01 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -532,13 +532,29 @@ class ServerInstallationCubit extends Cubit { .showSnackBar('recovering.generic_error'.tr()); return; } - await repository.saveServerDetails(serverDetails); + final newServerDetails = ServerHostingDetails( + provider: serverProvider, + apiToken: serverDetails.apiToken, + createTime: serverDetails.createTime, + id: serverDetails.id, + ip4: serverDetails.ip4, + volume: serverDetails.volume, + startTime: serverDetails.startTime, + ); + final newServerDomain = ServerDomain( + domainName: serverDomain.domainName, + zoneId: serverDomain.zoneId, + provider: dnsProvider, + ); + await repository.saveServerDetails(newServerDetails); await repository.saveDnsProviderType(dnsProvider); + await repository.saveDomain(newServerDomain); setServerProviderType(serverProvider); setDnsProviderType(dnsProvider); emit( dataState.copyWith( - serverDetails: serverDetails, + serverDetails: newServerDetails, + serverDomain: newServerDomain, currentStep: RecoveryStep.serverProviderToken, ), ); diff --git a/lib/logic/models/hive/server_details.dart b/lib/logic/models/hive/server_details.dart index e746dd75..0e9d825a 100644 --- a/lib/logic/models/hive/server_details.dart +++ b/lib/logic/models/hive/server_details.dart @@ -96,14 +96,9 @@ enum ServerProviderType { } } - String get displayName { - switch (this) { - case ServerProviderType.hetzner: - return 'Hetzner Cloud'; - case ServerProviderType.digitalOcean: - return 'Digital Ocean'; - default: - return 'Unknown'; - } - } + String get displayName => switch (this) { + digitalOcean => 'Digital Ocean', + hetzner => 'Hetzner Cloud', + unknown => 'Unknown', + }; } diff --git a/lib/logic/models/hive/server_domain.dart b/lib/logic/models/hive/server_domain.dart index bd755bbc..5eb20bd8 100644 --- a/lib/logic/models/hive/server_domain.dart +++ b/lib/logic/models/hive/server_domain.dart @@ -54,4 +54,11 @@ enum DnsProviderType { desec => 'DESEC', unknown => 'UNKNOWN', }; + + String get displayName => switch (this) { + digitalOcean => 'Digital Ocean DNS', + cloudflare => 'Cloudflare', + desec => 'deSEC', + unknown => 'Unknown', + }; } diff --git a/lib/logic/providers/server_providers/digital_ocean.dart b/lib/logic/providers/server_providers/digital_ocean.dart index da246b18..945977fb 100644 --- a/lib/logic/providers/server_providers/digital_ocean.dart +++ b/lib/logic/providers/server_providers/digital_ocean.dart @@ -748,8 +748,8 @@ class DigitalOceanServerProvider extends ServerProvider { ), ServerMetadataEntity( type: MetadataType.other, - trId: 'server.provider', - value: _adapter.api().displayProviderName, + trId: 'server.server_provider', + value: type.displayName, ), ]; } catch (e) { diff --git a/lib/logic/providers/server_providers/hetzner.dart b/lib/logic/providers/server_providers/hetzner.dart index ec15801e..857c5a6e 100644 --- a/lib/logic/providers/server_providers/hetzner.dart +++ b/lib/logic/providers/server_providers/hetzner.dart @@ -752,8 +752,8 @@ class HetznerServerProvider extends ServerProvider { ), ServerMetadataEntity( type: MetadataType.other, - trId: 'server.provider', - value: _adapter.api().displayProviderName, + trId: 'server.server_provider', + value: type.displayName, ), ]; } catch (e) { diff --git a/lib/ui/pages/server_storage/extending_volume.dart b/lib/ui/pages/server_storage/extending_volume.dart index 39872494..004995a0 100644 --- a/lib/ui/pages/server_storage/extending_volume.dart +++ b/lib/ui/pages/server_storage/extending_volume.dart @@ -7,6 +7,7 @@ import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart' import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/ui/components/buttons/brand_button.dart'; +import 'package:selfprivacy/ui/components/info_box/info_box.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/logic/models/disk_status.dart'; @@ -165,16 +166,11 @@ class _ExtendingVolumePageState extends State { height: 1.0, ), const SizedBox(height: 16), - const Align( - alignment: Alignment.centerLeft, - child: Icon( - Icons.info_outlined, - size: 24, - ), + InfoBox( + text: 'storage.extending_volume_price_info'.tr(), + isWarning: false, ), const SizedBox(height: 16), - Text('storage.extending_volume_price_info'.tr()), - const SizedBox(height: 16), ], ); }, diff --git a/lib/ui/pages/setup/recovering/recovery_confirm_backblaze.dart b/lib/ui/pages/setup/recovering/recovery_confirm_backblaze.dart index f7216a74..a4d04aae 100644 --- a/lib/ui/pages/setup/recovering/recovery_confirm_backblaze.dart +++ b/lib/ui/pages/setup/recovering/recovery_confirm_backblaze.dart @@ -23,8 +23,10 @@ class RecoveryConfirmBackblaze extends StatelessWidget { context.watch().state; return BrandHeroScreen( - heroTitle: 'recovering.confirm_backblaze'.tr(), - heroSubtitle: 'recovering.confirm_backblaze_description'.tr(), + heroTitle: 'recovering.provider_connected'.tr(args: ['Backblaze']), + heroSubtitle: 'recovering.provider_connected_description'.tr( + args: ['Backblaze'], + ), hasBackButton: true, ignoreBreakpoints: true, hasSupportDrawer: true, diff --git a/lib/ui/pages/setup/recovering/recovery_confirm_dns.dart b/lib/ui/pages/setup/recovering/recovery_confirm_dns.dart index 9dcad056..02a2afeb 100644 --- a/lib/ui/pages/setup/recovering/recovery_confirm_dns.dart +++ b/lib/ui/pages/setup/recovering/recovery_confirm_dns.dart @@ -21,10 +21,14 @@ class RecoveryConfirmDns extends StatelessWidget { builder: (final BuildContext context) { final FormCubitState formCubitState = context.watch().state; - + final String providerDisplayName = + appConfig.state.serverDomain?.provider.displayName ?? + 'DNS Provider'; return BrandHeroScreen( - heroTitle: 'recovering.confirm_cloudflare'.tr(), - heroSubtitle: 'recovering.confirm_cloudflare_description'.tr( + heroTitle: 'recovering.provider_connected'.tr( + args: [providerDisplayName], + ), + heroSubtitle: 'recovering.provider_connected_description'.tr( args: [appConfig.state.serverDomain?.domainName ?? 'your domain'], ), hasBackButton: true, @@ -38,7 +42,9 @@ class RecoveryConfirmDns extends StatelessWidget { formFieldCubit: context.read().apiKey, decoration: InputDecoration( border: const OutlineInputBorder(), - labelText: 'initializing.cloudflare_api_token'.tr(), + labelText: 'recovering.provider_connected_placeholder'.tr( + args: [providerDisplayName], + ), ), ), const SizedBox(height: 16), diff --git a/lib/ui/pages/setup/recovering/recovery_server_provider_connected.dart b/lib/ui/pages/setup/recovering/recovery_server_provider_connected.dart index 82c29ba2..86a1bf44 100644 --- a/lib/ui/pages/setup/recovering/recovery_server_provider_connected.dart +++ b/lib/ui/pages/setup/recovering/recovery_server_provider_connected.dart @@ -20,8 +20,13 @@ class RecoveryServerProviderConnected extends StatelessWidget { ServerProviderFormCubit(appConfig), child: Builder( builder: (final BuildContext context) => BrandHeroScreen( - heroTitle: 'recovering.server_provider_connected'.tr(), - heroSubtitle: 'recovering.server_provider_connected_description'.tr( + heroTitle: 'recovering.provider_connected'.tr( + args: [ + appConfig.state.serverDetails?.provider.displayName ?? + 'Server Provider' + ], + ), + heroSubtitle: 'recovering.provider_connected_description'.tr( args: [appConfig.state.serverDomain?.domainName ?? 'your domain'], ), hasBackButton: true, @@ -36,8 +41,12 @@ class RecoveryServerProviderConnected extends StatelessWidget { formFieldCubit: context.read().apiKey, decoration: InputDecoration( border: const OutlineInputBorder(), - labelText: - 'recovering.server_provider_connected_placeholder'.tr(), + labelText: 'recovering.provider_connected_placeholder'.tr( + args: [ + appConfig.state.serverDetails?.provider.displayName ?? + 'Server Provider' + ], + ), ), ), const SizedBox(height: 16), From b2c67c80bd580436aba476258999414f7081681f Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 31 Jul 2023 23:40:25 -0300 Subject: [PATCH 2/5] refactor: Implement Cloudflare objects to avoid usage of dynamic blobs - Get rid of ZoneId term outside of Cloudflare --- .../cloudflare/cloudflare_api.dart | 80 +++------- .../initializing/domain_setup_cubit.dart | 18 +-- .../server_installation_cubit.dart | 10 +- .../server_installation_repository.dart | 18 ++- lib/logic/models/hive/server_domain.dart | 7 +- lib/logic/models/hive/server_domain.g.dart | 5 +- .../models/json/cloudflare_dns_info.dart | 86 +++++++++++ .../models/json/cloudflare_dns_info.g.dart | 42 +++++ .../providers/dns_providers/cloudflare.dart | 144 +++++++++++++++--- lib/logic/providers/dns_providers/desec.dart | 7 - .../dns_providers/digital_ocean_dns.dart | 7 - .../providers/dns_providers/dns_provider.dart | 8 - 12 files changed, 296 insertions(+), 136 deletions(-) create mode 100644 lib/logic/models/json/cloudflare_dns_info.dart create mode 100644 lib/logic/models/json/cloudflare_dns_info.g.dart diff --git a/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart b/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart index ae015d9d..0ba88ee3 100644 --- a/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart +++ b/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart @@ -4,8 +4,7 @@ import 'package:dio/dio.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; -import 'package:selfprivacy/logic/models/hive/server_domain.dart'; -import 'package:selfprivacy/logic/models/json/dns_records.dart'; +import 'package:selfprivacy/logic/models/json/cloudflare_dns_info.dart'; class CloudflareApi extends RestApiMap { CloudflareApi({ @@ -92,9 +91,9 @@ class CloudflareApi extends RestApiMap { ); } - Future> getDomains() async { + Future>> getZones() async { final String url = '$rootAddress/zones'; - List domains = []; + List domains = []; late final Response? response; final Dio client = await getClient(); @@ -103,7 +102,11 @@ class CloudflareApi extends RestApiMap { url, queryParameters: {'per_page': 50}, ); - domains = response.data['result']; + domains = response.data['result']! + .map( + (final json) => CloudflareZone.fromJson(json), + ) + .toList(); } catch (e) { print(e); return GenericResult( @@ -125,18 +128,17 @@ class CloudflareApi extends RestApiMap { } Future> createMultipleDnsRecords({ - required final ServerDomain domain, - required final List records, + required final String zoneId, + required final List records, }) async { - final String domainZoneId = domain.zoneId; final List allCreateFutures = []; final Dio client = await getClient(); try { - for (final DnsRecord record in records) { + for (final CloudflareDnsRecord record in records) { allCreateFutures.add( client.post( - '/zones/$domainZoneId/dns_records', + '/zones/$zoneId/dns_records', data: record.toJson(), ), ); @@ -160,11 +162,10 @@ class CloudflareApi extends RestApiMap { } Future> removeSimilarRecords({ - required final ServerDomain domain, - required final List records, + required final String zoneId, + required final List records, }) async { - final String domainZoneId = domain.zoneId; - final String url = '/zones/$domainZoneId/dns_records'; + final String url = '/zones/$zoneId/dns_records'; final Dio client = await getClient(); try { @@ -172,7 +173,7 @@ class CloudflareApi extends RestApiMap { for (final record in records) { allDeleteFutures.add( - client.delete('$url/${record["id"]}'), + client.delete('$url/${record.id}'), ); } await Future.wait(allDeleteFutures); @@ -190,26 +191,21 @@ class CloudflareApi extends RestApiMap { return GenericResult(success: true, data: null); } - Future> getDnsRecords({ - required final ServerDomain domain, + Future>> getDnsRecords({ + required final String zoneId, }) async { Response response; - final String domainName = domain.domainName; - final String domainZoneId = domain.zoneId; - final List allRecords = []; - - final String url = '/zones/$domainZoneId/dns_records'; + List allRecords = []; + final String url = '/zones/$zoneId/dns_records'; final Dio client = await getClient(); try { response = await client.get(url); - final List records = response.data['result'] ?? []; - - for (final record in records) { - if (record['zone_name'] == domainName) { - allRecords.add(record); - } - } + allRecords = response.data['result']! + .map( + (final json) => CloudflareDnsRecord.fromJson(json), + ) + .toList(); } catch (e) { print(e); return GenericResult( @@ -223,30 +219,4 @@ class CloudflareApi extends RestApiMap { return GenericResult(data: allRecords, success: true); } - - Future>> getZones(final String domain) async { - List zones = []; - - late final Response? response; - final Dio client = await getClient(); - try { - response = await client.get( - '/zones', - queryParameters: {'name': domain}, - ); - zones = response.data['result']; - } catch (e) { - print(e); - GenericResult( - success: false, - data: zones, - code: response?.statusCode, - message: response?.statusMessage, - ); - } finally { - close(client); - } - - return GenericResult(success: true, data: zones); - } } diff --git a/lib/logic/cubit/forms/setup/initializing/domain_setup_cubit.dart b/lib/logic/cubit/forms/setup/initializing/domain_setup_cubit.dart index 8c66deb7..f4597439 100644 --- a/lib/logic/cubit/forms/setup/initializing/domain_setup_cubit.dart +++ b/lib/logic/cubit/forms/setup/initializing/domain_setup_cubit.dart @@ -25,23 +25,17 @@ class DomainSetupCubit extends Cubit { Future saveDomain() async { assert(state is Loaded, 'wrong state'); final String domainName = (state as Loaded).domain; - emit(Loading(LoadingTypes.saving)); final dnsProvider = ProvidersController.currentDnsProvider!; - final GenericResult zoneIdResult = - await dnsProvider.getZoneId(domainName); - if (zoneIdResult.success || zoneIdResult.data != null) { - final ServerDomain domain = ServerDomain( - domainName: domainName, - zoneId: zoneIdResult.data!, - provider: dnsProvider.type, - ); + final ServerDomain domain = ServerDomain( + domainName: domainName, + provider: dnsProvider.type, + ); - serverInstallationCubit.setDomain(domain); - emit(DomainSet()); - } + serverInstallationCubit.setDomain(domain); + emit(DomainSet()); } } diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index c669cf75..f29f70c5 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -467,7 +467,6 @@ class ServerInstallationCubit extends Cubit { final ServerDomain serverDomain = ServerDomain( domainName: domain, provider: DnsProviderType.unknown, - zoneId: '', ); final ServerRecoveryCapabilities recoveryCapabilities = await repository.getRecoveryCapabilities(serverDomain); @@ -681,9 +680,9 @@ class ServerInstallationCubit extends Cubit { if (serverDomain == null) { return; } - final String? zoneId = - await repository.getDomainId(token, serverDomain.domainName); - if (zoneId == null) { + final isTokenValid = + await repository.validateDnsToken(token, serverDomain.domainName); + if (!isTokenValid) { getIt() .showSnackBar('recovering.domain_not_available_on_token'.tr()); return; @@ -695,16 +694,13 @@ class ServerInstallationCubit extends Cubit { await repository.saveDomain( ServerDomain( domainName: serverDomain.domainName, - zoneId: zoneId, provider: dnsProviderType, ), ); - // await repository.setDnsApiToken(token); emit( dataState.copyWith( serverDomain: ServerDomain( domainName: serverDomain.domainName, - zoneId: zoneId, provider: dnsProviderType, ), dnsApiToken: token, diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index dd3388c6..1518d7ac 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -193,17 +193,23 @@ class ServerInstallationRepository { return server; } - Future getDomainId(final String token, final String domain) async { + Future validateDnsToken( + final String token, + final String domain, + ) async { final result = await ProvidersController.currentDnsProvider!.tryInitApiByToken(token); if (!result.success) { - return null; + return false; } await setDnsApiToken(token); - return (await ProvidersController.currentDnsProvider!.getZoneId( - domain, - )) - .data; + final domainResult = + await ProvidersController.currentDnsProvider!.domainList(); + if (!domainResult.success || domainResult.data.isEmpty) { + return false; + } + + return domain == domainResult.data[0]; } Future> isDnsAddressesMatch( diff --git a/lib/logic/models/hive/server_domain.dart b/lib/logic/models/hive/server_domain.dart index bd755bbc..4415ab20 100644 --- a/lib/logic/models/hive/server_domain.dart +++ b/lib/logic/models/hive/server_domain.dart @@ -7,21 +7,16 @@ part 'server_domain.g.dart'; class ServerDomain { ServerDomain({ required this.domainName, - required this.zoneId, required this.provider, }); @HiveField(0) final String domainName; - @HiveField(1) - final String zoneId; + // @HiveField(1) @HiveField(2, defaultValue: DnsProviderType.cloudflare) final DnsProviderType provider; - - @override - String toString() => '$domainName: $zoneId'; } @HiveType(typeId: 100) diff --git a/lib/logic/models/hive/server_domain.g.dart b/lib/logic/models/hive/server_domain.g.dart index 303407bc..2557ec43 100644 --- a/lib/logic/models/hive/server_domain.g.dart +++ b/lib/logic/models/hive/server_domain.g.dart @@ -18,7 +18,6 @@ class ServerDomainAdapter extends TypeAdapter { }; return ServerDomain( domainName: fields[0] as String, - zoneId: fields[1] as String, provider: fields[2] == null ? DnsProviderType.cloudflare : fields[2] as DnsProviderType, @@ -28,11 +27,9 @@ class ServerDomainAdapter extends TypeAdapter { @override void write(BinaryWriter writer, ServerDomain obj) { writer - ..writeByte(3) + ..writeByte(2) ..writeByte(0) ..write(obj.domainName) - ..writeByte(1) - ..write(obj.zoneId) ..writeByte(2) ..write(obj.provider); } diff --git a/lib/logic/models/json/cloudflare_dns_info.dart b/lib/logic/models/json/cloudflare_dns_info.dart new file mode 100644 index 00000000..3cd11bcd --- /dev/null +++ b/lib/logic/models/json/cloudflare_dns_info.dart @@ -0,0 +1,86 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'cloudflare_dns_info.g.dart'; + +/// https://developers.cloudflare.com/api/operations/zones-get +@JsonSerializable() +class CloudflareZone { + CloudflareZone({ + required this.id, + required this.name, + }); + + /// Zone identifier + /// + /// `<= 32 characters` + /// + /// Example: 023e105f4ecef8ad9ca31a8372d0c353 + final String id; + + /// The domain name + /// + /// `<= 253 characters` + /// + /// Example: example.com + final String name; + + static CloudflareZone fromJson(final Map json) => + _$CloudflareZoneFromJson(json); +} + +/// https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-list-dns-records +@JsonSerializable() +class CloudflareDnsRecord { + CloudflareDnsRecord({ + required this.type, + required this.name, + required this.content, + required this.zoneName, + this.ttl = 3600, + this.priority = 10, + this.id, + }); + + /// Record identifier + /// + /// `<= 32 characters` + /// Example: 023e105f4ecef8ad9ca31a8372d0c353 + final String? id; + + /// Record type. + /// + /// Example: A + final String type; + + /// DNS record name (or @ for the zone apex) in Punycode. + /// + /// `<= 255 characters` + /// + /// Example: example.com + final String? name; + + /// Valid DNS Record string content. + /// + /// Example: A valid IPv4 address "198.51.100.4" + final String? content; + + /// The domain of the record. + /// + /// Example: example.com + @JsonKey(name: 'zone_name') + final String zoneName; + + /// Time To Live (TTL) of the DNS record in seconds. Setting to 1 means 'automatic'. + /// + /// Value must be between 60 and 86400, with the minimum reduced to 30 for Enterprise zones. + final int ttl; + + /// Required for MX, SRV and URI records; unused by other record types. Records with lower priorities are preferred. + /// + /// `>= 0 <= 65535` + final int priority; + + static CloudflareDnsRecord fromJson(final Map json) => + _$CloudflareDnsRecordFromJson(json); + Map toJson() => _$CloudflareDnsRecordToJson(this); +} diff --git a/lib/logic/models/json/cloudflare_dns_info.g.dart b/lib/logic/models/json/cloudflare_dns_info.g.dart new file mode 100644 index 00000000..d02fc2d2 --- /dev/null +++ b/lib/logic/models/json/cloudflare_dns_info.g.dart @@ -0,0 +1,42 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'cloudflare_dns_info.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CloudflareZone _$CloudflareZoneFromJson(Map json) => + CloudflareZone( + id: json['id'] as String, + name: json['name'] as String, + ); + +Map _$CloudflareZoneToJson(CloudflareZone instance) => + { + 'id': instance.id, + 'name': instance.name, + }; + +CloudflareDnsRecord _$CloudflareDnsRecordFromJson(Map json) => + CloudflareDnsRecord( + type: json['type'] as String, + name: json['name'] as String?, + content: json['content'] as String?, + zoneName: json['zone_name'] as String, + ttl: json['ttl'] as int? ?? 3600, + priority: json['priority'] as int? ?? 10, + id: json['id'] as String?, + ); + +Map _$CloudflareDnsRecordToJson( + CloudflareDnsRecord instance) => + { + 'id': instance.id, + 'type': instance.type, + 'name': instance.name, + 'content': instance.content, + 'zone_name': instance.zoneName, + 'ttl': instance.ttl, + 'priority': instance.priority, + }; diff --git a/lib/logic/providers/dns_providers/cloudflare.dart b/lib/logic/providers/dns_providers/cloudflare.dart index 83d665b3..596c03ab 100644 --- a/lib/logic/providers/dns_providers/cloudflare.dart +++ b/lib/logic/providers/dns_providers/cloudflare.dart @@ -1,12 +1,16 @@ import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; +import 'package:selfprivacy/logic/models/json/cloudflare_dns_info.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart'; class ApiAdapter { - ApiAdapter({final bool isWithToken = true}) - : _api = CloudflareApi( + ApiAdapter({ + final bool isWithToken = true, + this.cachedDomain = '', + this.cachedZoneId = '', + }) : _api = CloudflareApi( isWithToken: isWithToken, ); @@ -17,6 +21,8 @@ class ApiAdapter { ); final CloudflareApi _api; + final String cachedZoneId; + final String cachedDomain; } class CloudflareDnsProvider extends DnsProvider { @@ -47,7 +53,7 @@ class CloudflareDnsProvider extends DnsProvider { @override Future>> domainList() async { List domains = []; - final result = await _adapter.api().getDomains(); + final result = await _adapter.api().getZones(); if (result.data.isEmpty || !result.success) { return GenericResult( success: result.success, @@ -59,10 +65,18 @@ class CloudflareDnsProvider extends DnsProvider { domains = result.data .map( - (final el) => el['name'] as String, + (final el) => el.name, ) .toList(); + /// TODO: Remove when domain selection for more than one domain on account is implemented, move cachedZoneId writing to domain saving method + _adapter = ApiAdapter( + isWithToken: true, + cachedDomain: result.data[0].name, + cachedZoneId: result.data[0].id, + ); + print('cachedZoneId saved for the first time!!!'); + return GenericResult( success: true, data: domains, @@ -73,11 +87,27 @@ class CloudflareDnsProvider extends DnsProvider { Future> createDomainRecords({ required final ServerDomain domain, final String? ip4, - }) { + }) async { + final syncZoneIdResult = await syncZoneId(domain.domainName); + if (!syncZoneIdResult.success) { + return syncZoneIdResult; + } + final records = getProjectDnsRecords(domain.domainName, ip4); return _adapter.api().createMultipleDnsRecords( - domain: domain, - records: records, + zoneId: _adapter.cachedZoneId, + records: records + .map( + (final rec) => CloudflareDnsRecord( + content: rec.content, + name: rec.name, + type: rec.type, + zoneName: domain.domainName, + id: null, + ttl: rec.ttl, + ), + ) + .toList(), ); } @@ -86,7 +116,13 @@ class CloudflareDnsProvider extends DnsProvider { required final ServerDomain domain, final String? ip4, }) async { - final result = await _adapter.api().getDnsRecords(domain: domain); + final syncZoneIdResult = await syncZoneId(domain.domainName); + if (!syncZoneIdResult.success) { + return syncZoneIdResult; + } + + final result = + await _adapter.api().getDnsRecords(zoneId: _adapter.cachedZoneId); if (result.data.isEmpty || !result.success) { return GenericResult( success: result.success, @@ -97,7 +133,7 @@ class CloudflareDnsProvider extends DnsProvider { } return _adapter.api().removeSimilarRecords( - domain: domain, + zoneId: _adapter.cachedZoneId, records: result.data, ); } @@ -106,8 +142,19 @@ class CloudflareDnsProvider extends DnsProvider { Future>> getDnsRecords({ required final ServerDomain domain, }) async { + final syncZoneIdResult = await syncZoneId(domain.domainName); + if (!syncZoneIdResult.success) { + return GenericResult( + success: syncZoneIdResult.success, + data: [], + code: syncZoneIdResult.code, + message: syncZoneIdResult.message, + ); + } + final List records = []; - final result = await _adapter.api().getDnsRecords(domain: domain); + final result = + await _adapter.api().getDnsRecords(zoneId: _adapter.cachedZoneId); if (result.data.isEmpty || !result.success) { return GenericResult( success: result.success, @@ -120,11 +167,10 @@ class CloudflareDnsProvider extends DnsProvider { for (final rawRecord in result.data) { records.add( DnsRecord( - name: rawRecord['name'], - type: rawRecord['type'], - content: rawRecord['content'], - ttl: rawRecord['ttl'], - proxied: rawRecord['proxied'], + name: rawRecord.name, + type: rawRecord.type, + content: rawRecord.content, + ttl: rawRecord.ttl, ), ); } @@ -139,11 +185,26 @@ class CloudflareDnsProvider extends DnsProvider { Future> setDnsRecord( final DnsRecord record, final ServerDomain domain, - ) async => - _adapter.api().createMultipleDnsRecords( - domain: domain, - records: [record], - ); + ) async { + final syncZoneIdResult = await syncZoneId(domain.domainName); + if (!syncZoneIdResult.success) { + return syncZoneIdResult; + } + + return _adapter.api().createMultipleDnsRecords( + zoneId: _adapter.cachedZoneId, + records: [ + CloudflareDnsRecord( + content: record.content, + id: null, + name: record.name, + type: record.type, + zoneName: domain.domainName, + ttl: record.ttl, + ), + ], + ); + } @override Future>> validateDnsRecords( @@ -336,10 +397,41 @@ class CloudflareDnsProvider extends DnsProvider { ]; } - @override + Future> syncZoneId(final String domain) async { + if (domain == _adapter.cachedDomain && _adapter.cachedZoneId.isNotEmpty) { + return GenericResult( + success: true, + data: null, + ); + } + + print('syncZoneId!!!'); + + final getZoneIdResult = await getZoneId(domain); + if (!getZoneIdResult.success || getZoneIdResult.data == null) { + return GenericResult( + success: false, + data: null, + code: getZoneIdResult.code, + message: getZoneIdResult.message, + ); + } + + _adapter = ApiAdapter( + isWithToken: true, + cachedDomain: domain, + cachedZoneId: getZoneIdResult.data!, + ); + + return GenericResult( + success: true, + data: null, + ); + } + Future> getZoneId(final String domain) async { String? id; - final result = await _adapter.api().getZones(domain); + final result = await _adapter.api().getZones(); if (result.data.isEmpty || !result.success) { return GenericResult( success: result.success, @@ -349,8 +441,12 @@ class CloudflareDnsProvider extends DnsProvider { ); } - id = result.data[0]['id']; + for (final availableDomain in result.data) { + if (availableDomain.name == domain) { + id = availableDomain.id; + } + } - return GenericResult(success: true, data: id); + return GenericResult(success: id != null, data: id); } } diff --git a/lib/logic/providers/dns_providers/desec.dart b/lib/logic/providers/dns_providers/desec.dart index e20d82bf..a5e3e8d7 100644 --- a/lib/logic/providers/dns_providers/desec.dart +++ b/lib/logic/providers/dns_providers/desec.dart @@ -408,11 +408,4 @@ class DesecDnsProvider extends DnsProvider { ), ]; } - - @override - Future> getZoneId(final String domain) async => - GenericResult( - data: domain, - success: true, - ); } diff --git a/lib/logic/providers/dns_providers/digital_ocean_dns.dart b/lib/logic/providers/dns_providers/digital_ocean_dns.dart index 7397f41c..4fac4b65 100644 --- a/lib/logic/providers/dns_providers/digital_ocean_dns.dart +++ b/lib/logic/providers/dns_providers/digital_ocean_dns.dart @@ -369,11 +369,4 @@ class DigitalOceanDnsProvider extends DnsProvider { ), ]; } - - @override - Future> getZoneId(final String domain) async => - GenericResult( - data: domain, - success: true, - ); } diff --git a/lib/logic/providers/dns_providers/dns_provider.dart b/lib/logic/providers/dns_providers/dns_provider.dart index 28517a83..647e84ea 100644 --- a/lib/logic/providers/dns_providers/dns_provider.dart +++ b/lib/logic/providers/dns_providers/dns_provider.dart @@ -73,12 +73,4 @@ abstract class DnsProvider { final String? ip4, final String? dkimPublicKey, ); - - /// Tries to access zone of requested domain. - /// - /// If a DNS provider doesn't support zones, - /// will return domain without any changes. - /// - /// If success, returns an initializing string of zone id. - Future> getZoneId(final String domain); } From bd9a383d38e794e56c9154bf75fda5ebabfece4f Mon Sep 17 00:00:00 2001 From: NaiJi Date: Wed, 2 Aug 2023 16:08:26 -0300 Subject: [PATCH 3/5] chore: Remove debug prints --- lib/logic/providers/dns_providers/cloudflare.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/logic/providers/dns_providers/cloudflare.dart b/lib/logic/providers/dns_providers/cloudflare.dart index 596c03ab..4a8062f1 100644 --- a/lib/logic/providers/dns_providers/cloudflare.dart +++ b/lib/logic/providers/dns_providers/cloudflare.dart @@ -75,7 +75,6 @@ class CloudflareDnsProvider extends DnsProvider { cachedDomain: result.data[0].name, cachedZoneId: result.data[0].id, ); - print('cachedZoneId saved for the first time!!!'); return GenericResult( success: true, @@ -405,8 +404,6 @@ class CloudflareDnsProvider extends DnsProvider { ); } - print('syncZoneId!!!'); - final getZoneIdResult = await getZoneId(domain); if (!getZoneIdResult.success || getZoneIdResult.data == null) { return GenericResult( From 4b1c85c4a8c6ee5eedf4708b63aefc30fd935294 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Sun, 6 Aug 2023 20:32:05 -0300 Subject: [PATCH 4/5] chore: Add missing trailing commas to encryption key modal page --- .../backups/copy_encryption_key_modal.dart | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/lib/ui/pages/backups/copy_encryption_key_modal.dart b/lib/ui/pages/backups/copy_encryption_key_modal.dart index aff629f7..42bc1ba9 100644 --- a/lib/ui/pages/backups/copy_encryption_key_modal.dart +++ b/lib/ui/pages/backups/copy_encryption_key_modal.dart @@ -52,57 +52,59 @@ class _CopyEncryptionKeyModalState extends State { ), const SizedBox(height: 8), Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: Theme.of(context).colorScheme.surfaceVariant, - ), - padding: const EdgeInsets.all(16), - child: Stack( - children: [ - SelectableText( - encryptionKey, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Theme.of(context).colorScheme.surfaceVariant, + ), + padding: const EdgeInsets.all(16), + child: Stack( + children: [ + SelectableText( + encryptionKey, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + Positioned.fill( + child: InkWell( + onTap: () { + setState( + () { + isKeyVisible = !isKeyVisible; + }, + ); + }, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 200), + opacity: isKeyVisible ? 0 : 1, + child: Container( + color: Theme.of(context).colorScheme.surfaceVariant, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.visibility_outlined), + const SizedBox(width: 8), + Text( + 'backup.backups_encryption_key_show'.tr(), + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + color: Theme.of(context) + .colorScheme + .onSurfaceVariant, + ), + ), + ], ), - ), - Positioned.fill( - child: InkWell( - onTap: () { - setState( - () { - isKeyVisible = !isKeyVisible; - }, - ); - }, - child: AnimatedOpacity( - duration: const Duration(milliseconds: 200), - opacity: isKeyVisible ? 0 : 1, - child: Container( - color: Theme.of(context).colorScheme.surfaceVariant, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.visibility_outlined), - const SizedBox(width: 8), - Text( - 'backup.backups_encryption_key_show'.tr(), - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith( - color: Theme.of(context) - .colorScheme - .onSurfaceVariant, - ), - ), - ], - )), ), ), ), - ], - )), + ), + ], + ), + ), const SizedBox(height: 8), FilledButton.icon( onPressed: () { From 719a5a7274a78e832a91f705de8907cd29cb32c2 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 7 Aug 2023 04:08:54 -0300 Subject: [PATCH 5/5] fix(hetzner): Normalize CPU usage percentage by cached amount of cores --- .../providers/server_providers/hetzner.dart | 52 +++++++++++++++++-- .../server_details/charts/cpu_chart.dart | 6 +-- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/lib/logic/providers/server_providers/hetzner.dart b/lib/logic/providers/server_providers/hetzner.dart index ec15801e..fb32dc12 100644 --- a/lib/logic/providers/server_providers/hetzner.dart +++ b/lib/logic/providers/server_providers/hetzner.dart @@ -46,6 +46,7 @@ class HetznerServerProvider extends ServerProvider { ApiAdapter _adapter; final Currency currency = Currency.fromType(CurrencyType.eur); + int? cachedCoreAmount; @override ServerProviderType get type => ServerProviderType.hetzner; @@ -287,6 +288,8 @@ class HetznerServerProvider extends ServerProvider { provider: ServerProviderType.hetzner, ); + cachedCoreAmount = serverResult.data!.serverType.cores; + final createDnsResult = await _adapter.api().createReverseDns( serverId: serverDetails.id, ip4: serverDetails.ip4, @@ -775,7 +778,7 @@ class HetznerServerProvider extends ServerProvider { ) async { ServerMetrics? metrics; - List serializeTimeSeries( + List serializeTimeNetworkSeries( final Map json, final String type, ) { @@ -785,6 +788,47 @@ class HetznerServerProvider extends ServerProvider { .toList(); } + if (cachedCoreAmount == null) { + final serversResult = await _adapter.api().getServers(); + if (serversResult.data.isEmpty || !serversResult.success) { + return GenericResult( + success: false, + data: metrics, + code: serversResult.code, + message: serversResult.message, + ); + } + + for (final server in serversResult.data) { + if (server.id == serverId) { + cachedCoreAmount = server.serverType.cores; + } + } + + if (cachedCoreAmount == null) { + return GenericResult( + success: false, + data: metrics, + message: "Couldn't find active server to cache core amount", + ); + } + } + + List serializeTimeCpuSeries( + final Map json, + final String type, + ) { + final List list = json['time_series'][type]['values']; + return list + .map( + (final el) => TimeSeriesData( + el[0], + double.parse(el[1]) / cachedCoreAmount!, + ), + ) + .toList(); + } + final cpuResult = await _adapter.api().getMetrics( serverId, start, @@ -818,15 +862,15 @@ class HetznerServerProvider extends ServerProvider { } metrics = ServerMetrics( - cpu: serializeTimeSeries( + cpu: serializeTimeCpuSeries( cpuResult.data, 'cpu', ), - bandwidthIn: serializeTimeSeries( + bandwidthIn: serializeTimeNetworkSeries( netResult.data, 'network.0.bandwidth.in', ), - bandwidthOut: serializeTimeSeries( + bandwidthOut: serializeTimeNetworkSeries( netResult.data, 'network.0.bandwidth.out', ), diff --git a/lib/ui/pages/server_details/charts/cpu_chart.dart b/lib/ui/pages/server_details/charts/cpu_chart.dart index 2ec349a0..a11361d4 100644 --- a/lib/ui/pages/server_details/charts/cpu_chart.dart +++ b/lib/ui/pages/server_details/charts/cpu_chart.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:selfprivacy/logic/common_enum/common_enum.dart'; @@ -85,9 +83,7 @@ class CpuChart extends StatelessWidget { ], minY: 0, // Maximal value of data by 100 step - maxY: - ((data.map((final e) => e.value).reduce(max) - 1) / 100).ceil() * - 100.0, + maxY: 100, minX: 0, titlesData: FlTitlesData( topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),