From e62e8bf916c4757330c25c1fa33074126b1e3891 Mon Sep 17 00:00:00 2001
From: NaiJi <naijiworld@protonmail.com>
Date: Mon, 28 Nov 2022 23:55:37 +0400
Subject: [PATCH] feat: Implement distinction for connection errors on dns
 provider page

Now user gets notified when connection error occurs
---
 .../dns_providers/cloudflare/cloudflare.dart  | 39 +++++++++++++------
 .../rest_maps/dns_providers/dns_provider.dart |  5 ++-
 .../initializing/dns_provider_form_cubit.dart | 11 ++++--
 .../server_installation_cubit.dart            | 22 ++++++++---
 4 files changed, 55 insertions(+), 22 deletions(-)

diff --git a/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare.dart b/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare.dart
index c79f0987..f4d786ca 100644
--- a/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare.dart
+++ b/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare.dart
@@ -46,33 +46,50 @@ class CloudflareApi extends DnsProviderApi {
   String rootAddress = 'https://api.cloudflare.com/client/v4';
 
   @override
-  Future<bool> isApiTokenValid(final String token) async {
+  Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
     bool isValid = false;
     Response? response;
+    String message = '';
     final Dio client = await getClient();
     try {
       response = await client.get(
         '/user/tokens/verify',
-        options: Options(headers: {'Authorization': 'Bearer $token'}),
+        options: Options(
+          followRedirects: false,
+          validateStatus: (final status) =>
+              status != null && (status >= 200 || status == 401),
+          headers: {'Authorization': 'Bearer $token'},
+        ),
       );
     } catch (e) {
       print(e);
       isValid = false;
+      message = e.toString();
     } finally {
       close(client);
     }
 
-    if (response != null) {
-      if (response.statusCode == HttpStatus.ok) {
-        isValid = true;
-      } else if (response.statusCode == HttpStatus.unauthorized) {
-        isValid = false;
-      } else {
-        throw Exception('code: ${response.statusCode}');
-      }
+    if (response == null) {
+      return APIGenericResult(
+        data: isValid,
+        success: false,
+        message: message,
+      );
     }
 
-    return isValid;
+    if (response.statusCode == HttpStatus.ok) {
+      isValid = true;
+    } else if (response.statusCode == HttpStatus.unauthorized) {
+      isValid = false;
+    } else {
+      throw Exception('code: ${response.statusCode}');
+    }
+
+    return APIGenericResult(
+      data: isValid,
+      success: true,
+      message: response.statusMessage,
+    );
   }
 
   @override
diff --git a/lib/logic/api_maps/rest_maps/dns_providers/dns_provider.dart b/lib/logic/api_maps/rest_maps/dns_providers/dns_provider.dart
index 3ff6222e..2c538251 100644
--- a/lib/logic/api_maps/rest_maps/dns_providers/dns_provider.dart
+++ b/lib/logic/api_maps/rest_maps/dns_providers/dns_provider.dart
@@ -1,7 +1,10 @@
+import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
 import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
 import 'package:selfprivacy/logic/models/hive/server_domain.dart';
 import 'package:selfprivacy/logic/models/json/dns_records.dart';
 
+export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
+
 class DomainNotFoundException implements Exception {
   DomainNotFoundException(this.message);
   final String message;
@@ -26,6 +29,6 @@ abstract class DnsProviderApi extends ApiMap {
   Future<String?> getZoneId(final String domain);
   Future<List<String>> domainList();
 
-  Future<bool> isApiTokenValid(final String token);
+  Future<APIGenericResult<bool>> isApiTokenValid(final String token);
   RegExp getApiTokenValidation();
 }
diff --git a/lib/logic/cubit/forms/setup/initializing/dns_provider_form_cubit.dart b/lib/logic/cubit/forms/setup/initializing/dns_provider_form_cubit.dart
index e50d7db3..553c3492 100644
--- a/lib/logic/cubit/forms/setup/initializing/dns_provider_form_cubit.dart
+++ b/lib/logic/cubit/forms/setup/initializing/dns_provider_form_cubit.dart
@@ -28,21 +28,24 @@ class DnsProviderFormCubit extends FormCubit {
 
   @override
   FutureOr<bool> asyncValidation() async {
-    late bool isKeyValid;
+    bool? isKeyValid;
 
     try {
       isKeyValid = await initializingCubit
           .isDnsProviderApiTokenValid(apiKey.state.value);
     } catch (e) {
       addError(e);
-      isKeyValid = false;
+    }
+
+    if (isKeyValid == null) {
+      apiKey.setError('');
+      return false;
     }
 
     if (!isKeyValid) {
       apiKey.setError('initializing.cloudflare_bad_key_error'.tr());
-      return false;
     }
 
-    return true;
+    return isKeyValid;
   }
 }
diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart
index ef23d18a..c63154c0 100644
--- a/lib/logic/cubit/server_installation/server_installation_cubit.dart
+++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart
@@ -98,7 +98,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
     return apiResponse.data;
   }
 
-  Future<bool> isDnsProviderApiTokenValid(
+  Future<bool?> isDnsProviderApiTokenValid(
     final String providerToken,
   ) async {
     if (ApiController.currentDnsProviderApiFactory == null) {
@@ -111,11 +111,21 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
       );
     }
 
-    return ApiController.currentDnsProviderApiFactory!
-        .getDnsProvider(
-          settings: const DnsProviderApiSettings(isWithToken: false),
-        )
-        .isApiTokenValid(providerToken);
+    final APIGenericResult<bool> apiResponse =
+        await ApiController.currentDnsProviderApiFactory!
+            .getDnsProvider(
+              settings: const DnsProviderApiSettings(isWithToken: false),
+            )
+            .isApiTokenValid(providerToken);
+
+    if (!apiResponse.success) {
+      getIt<NavigationService>().showSnackBar(
+        'initializing.could_not_connect'.tr(),
+      );
+      return null;
+    }
+
+    return apiResponse.data;
   }
 
   Future<List<ServerProviderLocation>> fetchAvailableLocations() async {