LCOV - code coverage report
Current view: top level - lib/network - apptive_grid_client.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 95 97 97.9 %
Date: 2021-09-29 11:41:23 Functions: 0 0 -

          Line data    Source code
       1             : part of apptive_grid_network;
       2             : 
       3             : /// Api Client to communicate with the ApptiveGrid Backend
       4             : class ApptiveGridClient {
       5             :   /// Creates an ApiClient
       6           2 :   ApptiveGridClient({
       7             :     this.options = const ApptiveGridOptions(),
       8           2 :   })  : _client = http.Client(),
       9           2 :         _authenticator = ApptiveGridAuthenticator(options: options);
      10             : 
      11             :   /// Creates an Api Client on the Basis of a [http.Client]
      12             :   ///
      13             :   /// this should only be used for testing in order to pass in a Mocked [http.Client]
      14           1 :   @visibleForTesting
      15             :   ApptiveGridClient.fromClient(
      16             :     http.Client httpClient, {
      17             :     this.options = const ApptiveGridOptions(),
      18             :     ApptiveGridAuthenticator? authenticator,
      19             :   })  : _client = httpClient,
      20             :         _authenticator = authenticator ??
      21           1 :             ApptiveGridAuthenticator(options: options, httpClient: httpClient);
      22             : 
      23             :   /// Configuraptions
      24             :   ApptiveGridOptions options;
      25             : 
      26             :   final ApptiveGridAuthenticator _authenticator;
      27             : 
      28             :   final http.Client _client;
      29             : 
      30             :   /// Close the connection on the httpClient
      31           2 :   void dispose() {
      32           4 :     _client.close();
      33           4 :     _authenticator.dispose();
      34             :   }
      35             : 
      36             :   /// Headers that are used for multiple Calls
      37           1 :   @visibleForTesting
      38           1 :   Map<String, String> get headers => (<String, String?>{
      39           2 :         HttpHeaders.authorizationHeader: _authenticator.header,
      40             :         HttpHeaders.contentTypeHeader: ContentType.json,
      41           2 :       }..removeWhere((key, value) => value == null))
      42           3 :           .map((key, value) => MapEntry(key, value!));
      43             : 
      44             :   /// Loads a [FormData] represented by [formUri]
      45             :   ///
      46             :   /// Based on [formUri] this might require Authentication
      47             :   /// throws [Response] if the request fails
      48           1 :   Future<FormData> loadForm({
      49             :     required FormUri formUri,
      50             :   }) async {
      51           1 :     if (formUri.needsAuthorization) {
      52           3 :       await _authenticator.checkAuthentication();
      53             :     }
      54           6 :     final url = Uri.parse('${options.environment.url}${formUri.uriString}');
      55           4 :     final response = await _client.get(url, headers: headers);
      56           2 :     if (response.statusCode >= 400) {
      57             :       throw response;
      58             :     }
      59           3 :     return FormData.fromJson(json.decode(response.body));
      60             :   }
      61             : 
      62             :   /// Performs a [FormAction] using [formData]
      63             :   ///
      64             :   /// if this returns a [http.Response] with a [http.Response.statusCode] >= 400 it means that the Item was saved in [options.cache]
      65             :   /// throws [Response] if the request fails
      66           1 :   Future<http.Response> performAction(
      67             :     FormAction action,
      68             :     FormData formData, {
      69             :     bool saveToPendingItems = true,
      70             :   }) async {
      71           1 :     final actionItem = ActionItem(action: action, data: formData);
      72           6 :     final uri = Uri.parse('${options.environment.url}${action.uri}');
      73           2 :     final request = http.Request(action.method, uri);
      74           3 :     request.body = jsonEncode(formData.toRequestObject());
      75             : 
      76             :     // ignore: prefer_function_declarations_over_variables
      77           1 :     final handleError = (error) async {
      78             :       // TODO: Filter out Errors that happened because the Input was not correct
      79             :       // in that case don't save the Action and throw the error
      80           2 :       if (saveToPendingItems && options.cache != null) {
      81           4 :         await options.cache!.addPendingActionItem(actionItem);
      82           1 :         if (error is http.Response) {
      83             :           return error;
      84             :         } else {
      85           2 :           return http.Response(error.toString(), 400);
      86             :         }
      87             :       }
      88             :       throw error;
      89             :     };
      90             :     late http.Response response;
      91           3 :     request.headers.addAll(headers);
      92             :     try {
      93           3 :       final streamResponse = await _client.send(request);
      94           2 :       response = await http.Response.fromStream(streamResponse);
      95             :     } catch (e) {
      96             :       // Catch all Exception for compatibility Reasons between Web and non Web Apps
      97             :       return handleError(e);
      98             :     }
      99             : 
     100           2 :     if (response.statusCode >= 400) {
     101           0 :       return handleError(response);
     102             :     }
     103             :     // Action was performed successfully. Remove it from pending Actions
     104           4 :     await options.cache?.removePendingActionItem(actionItem);
     105           0 :     return response;
     106             :   }
     107             : 
     108             :   /// Loads a [Grid] represented by [gridUri]
     109             :   ///
     110             :   /// Requires Authorization
     111             :   /// throws [Response] if the request fails
     112           1 :   Future<Grid> loadGrid({
     113             :     required GridUri gridUri,
     114             :   }) async {
     115           3 :     await _authenticator.checkAuthentication();
     116           6 :     final url = Uri.parse('${options.environment.url}${gridUri.uriString}');
     117           4 :     final response = await _client.get(url, headers: headers);
     118           2 :     if (response.statusCode >= 400) {
     119             :       throw response;
     120             :     }
     121           3 :     return Grid.fromJson(json.decode(response.body));
     122             :   }
     123             : 
     124             :   /// Get the [User] that is authenticated
     125             :   ///
     126             :   /// Requires Authorization
     127             :   /// throws [Response] if the request fails
     128           1 :   Future<User> getMe() async {
     129           3 :     await _authenticator.checkAuthentication();
     130             : 
     131           5 :     final url = Uri.parse('${options.environment.url}/api/users/me');
     132           4 :     final response = await _client.get(url, headers: headers);
     133           2 :     if (response.statusCode >= 400) {
     134             :       throw response;
     135             :     }
     136           3 :     return User.fromJson(json.decode(response.body));
     137             :   }
     138             : 
     139             :   /// Get the [Space] represented by [spaceUri]
     140             :   ///
     141             :   /// Requires Authorization
     142             :   /// throws [Response] if the request fails
     143           1 :   Future<Space> getSpace({
     144             :     required SpaceUri spaceUri,
     145             :   }) async {
     146           3 :     await _authenticator.checkAuthentication();
     147             : 
     148           6 :     final url = Uri.parse('${options.environment.url}${spaceUri.uriString}');
     149           4 :     final response = await _client.get(url, headers: headers);
     150           2 :     if (response.statusCode >= 400) {
     151             :       throw response;
     152             :     }
     153           3 :     return Space.fromJson(json.decode(response.body));
     154             :   }
     155             : 
     156             :   /// Get all [FormUri]s that are contained in a [Grid] represented by [gridUri]
     157             :   ///
     158             :   /// Requires Authorization
     159             :   /// throws [Response] if the request fails
     160           1 :   Future<List<FormUri>> getForms({
     161             :     required GridUri gridUri,
     162             :   }) async {
     163           3 :     await _authenticator.checkAuthentication();
     164             : 
     165             :     final url =
     166           6 :         Uri.parse('${options.environment.url}${gridUri.uriString}/forms');
     167           4 :     final response = await _client.get(url, headers: headers);
     168           2 :     if (response.statusCode >= 400) {
     169             :       throw response;
     170             :     }
     171           2 :     return (json.decode(response.body) as List)
     172           3 :         .map((e) => FormUri.fromUri(e))
     173           1 :         .toList();
     174             :   }
     175             : 
     176             :   /// Get all [GridViewUri]s that are contained in a [Grid] represented by [gridUri]
     177             :   ///
     178             :   /// Requires Authorization
     179             :   /// throws [Response] if the request fails
     180           1 :   Future<List<GridViewUri>> getGridViews({
     181             :     required GridUri gridUri,
     182             :   }) async {
     183           3 :     await _authenticator.checkAuthentication();
     184             : 
     185             :     final url =
     186           6 :         Uri.parse('${options.environment.url}${gridUri.uriString}/views');
     187           4 :     final response = await _client.get(url, headers: headers);
     188           2 :     if (response.statusCode >= 400) {
     189             :       throw response;
     190             :     }
     191           2 :     return (json.decode(response.body) as List)
     192           3 :         .map((e) => GridViewUri.fromUri(e))
     193           1 :         .toList();
     194             :   }
     195             : 
     196             :   /// Creates and returns a [FormUri] filled with the Data represented by [entityUri]
     197             :   ///
     198             :   /// Requires Authorization
     199             :   /// throws [Response] if the request fails
     200           1 :   Future<FormUri> getEditLink({
     201             :     required EntityUri entityUri,
     202             :     required String formId,
     203             :   }) async {
     204           3 :     await _authenticator.checkAuthentication();
     205             : 
     206             :     final url =
     207           6 :         Uri.parse('${options.environment.url}${entityUri.uriString}/EditLink');
     208             : 
     209           3 :     final response = await _client.post(
     210             :       url,
     211           1 :       headers: headers,
     212           2 :       body: jsonEncode({
     213             :         'formId': formId,
     214             :       }),
     215             :     );
     216             : 
     217           2 :     if (response.statusCode >= 400) {
     218             :       throw response;
     219             :     }
     220             : 
     221           4 :     return FormUri.fromUri((json.decode(response.body) as Map)['uri']);
     222             :   }
     223             : 
     224             :   /// Authenticate the User
     225             :   ///
     226             :   /// This will open a Webpage for the User Auth
     227           1 :   Future<Credential?> authenticate() {
     228           2 :     return _authenticator.authenticate();
     229             :   }
     230             : 
     231             :   /// Logs out the user
     232           1 :   Future<void> logout() {
     233           2 :     return _authenticator.logout();
     234             :   }
     235             : 
     236             :   /// Checks if the User is currently authenticated
     237           3 :   bool get isAuthenticated => _authenticator.isAuthenticated;
     238             : 
     239             :   /// Updates the Environment for the client and handle necessary changes in the Authenticator
     240           1 :   Future<void> updateEnvironment(ApptiveGridEnvironment environment) async {
     241           3 :     final currentRealm = options.environment.authRealm;
     242             : 
     243           2 :     if (currentRealm != environment.authRealm) {
     244           3 :       await _authenticator.logout();
     245             :     }
     246             : 
     247           3 :     options = options.copyWith(environment: environment);
     248           3 :     _authenticator.options = options;
     249             :   }
     250             : 
     251             :   /// Tries to send pending [ActionItem]s that are stored in [options.cache]
     252           2 :   Future sendPendingActions() async {
     253           8 :     final pendingActions = await options.cache?.getPendingActionItems() ?? [];
     254             : 
     255           3 :     for (final action in pendingActions) {
     256             :       try {
     257           2 :         await performAction(
     258           1 :           action.action,
     259           1 :           action.data,
     260             :           saveToPendingItems: false, // don't resubmit this to pending items
     261             :         );
     262           1 :       } on http.Response catch (_) {
     263             :         // Was not able to submit this action
     264             :       }
     265             :     }
     266             :   }
     267             : }

Generated by: LCOV version 1.15