diff --git a/front001/mosenioring/lib/src/core/config/app_config.dart b/front001/mosenioring/lib/src/core/config/app_config.dart index d42ff48..f208e86 100644 --- a/front001/mosenioring/lib/src/core/config/app_config.dart +++ b/front001/mosenioring/lib/src/core/config/app_config.dart @@ -11,6 +11,40 @@ class AppConfig { required this.keycloakRedirectUrl, }); + factory AppConfig.fromEnvironment() { + const apiBaseUrl = String.fromEnvironment('API_BASE_URL', defaultValue: ''); + const useLocalAuth = + bool.fromEnvironment('USE_LOCAL_AUTH', defaultValue: false); + const localTenantId = String.fromEnvironment( + 'LOCAL_TENANT_ID', + defaultValue: '11111111-1111-1111-1111-111111111111', + ); + const localRoles = + String.fromEnvironment('LOCAL_ROLES', defaultValue: 'CAREGIVER'); + const keycloakIssuer = + String.fromEnvironment('KEYCLOAK_ISSUER', defaultValue: ''); + const keycloakIssuerUri = + String.fromEnvironment('KEYCLOAK_ISSUER_URI', defaultValue: ''); + final resolvedIssuer = + keycloakIssuer.isNotEmpty ? keycloakIssuer : keycloakIssuerUri; + const keycloakClientId = + String.fromEnvironment('KEYCLOAK_CLIENT_ID', defaultValue: ''); + const keycloakRedirectUrl = String.fromEnvironment( + 'KEYCLOAK_REDIRECT_URL', + defaultValue: '', + ); + + return AppConfig( + apiBaseUrl: apiBaseUrl, + useLocalAuth: useLocalAuth, + localTenantId: localTenantId, + localRoles: localRoles, + keycloakIssuer: resolvedIssuer, + keycloakClientId: keycloakClientId, + keycloakRedirectUrl: keycloakRedirectUrl, + ); + } + final String apiBaseUrl; final bool useLocalAuth; final String localTenantId; diff --git a/front001/mosenioring/lib/src/di/providers.dart b/front001/mosenioring/lib/src/di/providers.dart index 428a919..bfe37e7 100644 --- a/front001/mosenioring/lib/src/di/providers.dart +++ b/front001/mosenioring/lib/src/di/providers.dart @@ -22,37 +22,7 @@ import '../features/telemetry/domain/token_provider.dart'; import '../features/telemetry/presentation/telemetry_controller.dart'; import '../features/telemetry/presentation/telemetry_state.dart'; -final appConfigProvider = Provider((ref) { - const apiBaseUrl = String.fromEnvironment('API_BASE_URL', defaultValue: ''); - const useLocalAuth = - bool.fromEnvironment('USE_LOCAL_AUTH', defaultValue: false); - const localTenantId = String.fromEnvironment( - 'LOCAL_TENANT_ID', - defaultValue: '11111111-1111-1111-1111-111111111111', - ); - const localRoles = - String.fromEnvironment('LOCAL_ROLES', defaultValue: 'CAREGIVER'); - const keycloakIssuer = String.fromEnvironment('KEYCLOAK_ISSUER', defaultValue: ''); - const keycloakIssuerUri = - String.fromEnvironment('KEYCLOAK_ISSUER_URI', defaultValue: ''); - final resolvedIssuer = - keycloakIssuer.isNotEmpty ? keycloakIssuer : keycloakIssuerUri; - const keycloakClientId = - String.fromEnvironment('KEYCLOAK_CLIENT_ID', defaultValue: ''); - const keycloakRedirectUrl = String.fromEnvironment( - 'KEYCLOAK_REDIRECT_URL', - defaultValue: '', - ); - return AppConfig( - apiBaseUrl: apiBaseUrl, - useLocalAuth: useLocalAuth, - localTenantId: localTenantId, - localRoles: localRoles, - keycloakIssuer: resolvedIssuer, - keycloakClientId: keycloakClientId, - keycloakRedirectUrl: keycloakRedirectUrl, - ); -}); +final appConfigProvider = Provider((ref) => AppConfig.fromEnvironment()); final secureStorageProvider = Provider((ref) { return const FlutterSecureStorage(); @@ -85,9 +55,11 @@ final dioProvider = Provider((ref) { if (config.useLocalAuth) { final session = await localDataSource.readLocalSession(); if (session != null) { - options.headers['X-Local-Email'] = session.email; - options.headers['X-Local-Roles'] = session.roles; - options.headers['X-Tenant-Id'] = session.tenantId; + options.headers.addAll({ + 'X-Local-Email': session.email, + 'X-Local-Roles': session.roles, + 'X-Tenant-Id': session.tenantId, + }); } } else { final token = await localDataSource.readToken(); @@ -98,21 +70,18 @@ final dioProvider = Provider((ref) { handler.next(options); }, onError: (error, handler) async { - if (config.useLocalAuth) { - handler.next(error); - return; - } final response = error.response; final requestOptions = error.requestOptions; - if (response?.statusCode != 401 || requestOptions.extra['retried'] == true) { - handler.next(error); - return; - } final refreshToken = (await localDataSource.readToken())?.refreshToken; - if (refreshToken == null || refreshToken.isEmpty) { - handler.next(error); - return; + + if (config.useLocalAuth || + response?.statusCode != 401 || + requestOptions.extra['retried'] == true || + refreshToken == null || + refreshToken.isEmpty) { + return handler.next(error); } + try { final newToken = await authRemoteDataSource.refreshToken(refreshToken: refreshToken); diff --git a/front001/mosenioring/lib/src/features/auth/data/auth_local_data_source.dart b/front001/mosenioring/lib/src/features/auth/data/auth_local_data_source.dart index 34254e3..0903729 100644 --- a/front001/mosenioring/lib/src/features/auth/data/auth_local_data_source.dart +++ b/front001/mosenioring/lib/src/features/auth/data/auth_local_data_source.dart @@ -40,9 +40,15 @@ class AuthLocalDataSource { } Future readLocalSession() async { - final email = await _storage.read(key: _localEmailKey); - final roles = await _storage.read(key: _localRolesKey); - final tenantId = await _storage.read(key: _localTenantKey); + final results = await Future.wait([ + _storage.read(key: _localEmailKey), + _storage.read(key: _localRolesKey), + _storage.read(key: _localTenantKey), + ]); + final email = results[0]; + final roles = results[1]; + final tenantId = results[2]; + if (email == null || tenantId == null) { return null; } @@ -54,11 +60,13 @@ class AuthLocalDataSource { } Future clear() async { - await _storage.delete(key: _accessTokenKey); - await _storage.delete(key: _refreshTokenKey); - await _storage.delete(key: _localEmailKey); - await _storage.delete(key: _localRolesKey); - await _storage.delete(key: _localTenantKey); + await Future.wait([ + _storage.delete(key: _accessTokenKey), + _storage.delete(key: _refreshTokenKey), + _storage.delete(key: _localEmailKey), + _storage.delete(key: _localRolesKey), + _storage.delete(key: _localTenantKey), + ]); } } diff --git a/front001/mosenioring/lib/src/features/auth/presentation/auth_controller.dart b/front001/mosenioring/lib/src/features/auth/presentation/auth_controller.dart index 8a4a62d..429a1e1 100644 --- a/front001/mosenioring/lib/src/features/auth/presentation/auth_controller.dart +++ b/front001/mosenioring/lib/src/features/auth/presentation/auth_controller.dart @@ -76,9 +76,8 @@ class AuthController extends Notifier { String _friendlyError(Object error) { final message = error.toString(); - if (message.startsWith('Exception: ')) { - return message.substring('Exception: '.length); - } - return message; + return message.startsWith('Exception: ') + ? message.substring('Exception: '.length) + : message; } } diff --git a/front001/mosenioring/lib/src/features/home/presentation/home_page.dart b/front001/mosenioring/lib/src/features/home/presentation/home_page.dart index ff3da87..72551fd 100644 --- a/front001/mosenioring/lib/src/features/home/presentation/home_page.dart +++ b/front001/mosenioring/lib/src/features/home/presentation/home_page.dart @@ -13,13 +13,9 @@ class HomePage extends ConsumerStatefulWidget { } class _HomePageState extends ConsumerState { - late final ProviderSubscription _telemetrySubscription; - @override - void initState() { - super.initState(); - _telemetrySubscription = - ref.listenManual(telemetryControllerProvider, (previous, next) { + Widget build(BuildContext context) { + ref.listen(telemetryControllerProvider, (previous, next) { if (previous?.lastOutcome == next.lastOutcome || next.lastOutcome == null || !mounted) { @@ -37,16 +33,7 @@ class _HomePageState extends ConsumerState { ); } }); - } - @override - void dispose() { - _telemetrySubscription.close(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final telemetryState = ref.watch(telemetryControllerProvider); diff --git a/front001/mosenioring/lib/src/features/telemetry/data/telemetry_service_impl.dart b/front001/mosenioring/lib/src/features/telemetry/data/telemetry_service_impl.dart index 829e094..0df75fd 100644 --- a/front001/mosenioring/lib/src/features/telemetry/data/telemetry_service_impl.dart +++ b/front001/mosenioring/lib/src/features/telemetry/data/telemetry_service_impl.dart @@ -28,17 +28,14 @@ class TelemetryServiceImpl implements TelemetryService { } try { - final payload = _payloadBuilder.build(); final response = await _remoteDataSource.sendTestTelemetry( accessToken: accessToken, - payload: payload, + payload: _payloadBuilder.build(), ); - if (response.statusCode == 200 || response.statusCode == 201) { - return; + if (response.statusCode != 200 && response.statusCode != 201) { + throw _failureFromStatus(response.statusCode); } - - throw _failureFromStatus(response.statusCode); } on HttpClientException catch (error) { throw _failureFromHttp(error); } on TelemetryFailure { @@ -53,19 +50,16 @@ class TelemetryServiceImpl implements TelemetryService { } TelemetryFailure _failureFromStatus(int statusCode) { - if (statusCode == 401 || statusCode == 403) { - return TelemetryFailure( - 'Not authorized', - type: TelemetryFailureType.unauthorized, - statusCode: statusCode, - debugMessage: 'Telemetry request unauthorized ($statusCode)', - ); - } + final isUnauthorized = statusCode == 401 || statusCode == 403; return TelemetryFailure( - 'Telemetry request failed', - type: TelemetryFailureType.server, + isUnauthorized ? 'Not authorized' : 'Telemetry request failed', + type: isUnauthorized + ? TelemetryFailureType.unauthorized + : TelemetryFailureType.server, statusCode: statusCode, - debugMessage: 'Telemetry request failed with status $statusCode', + debugMessage: isUnauthorized + ? 'Telemetry request unauthorized ($statusCode)' + : 'Telemetry request failed with status $statusCode', ); }