payment quotation v2 + payment orchestration v2 draft
This commit is contained in:
@@ -6,7 +6,7 @@ import 'package:pshared/api/requests/login_data.dart';
|
||||
import 'package:pshared/api/responses/account.dart';
|
||||
import 'package:pshared/api/responses/login.dart';
|
||||
import 'package:pshared/api/responses/login_pending.dart';
|
||||
import 'package:pshared/config/web.dart';
|
||||
import 'package:pshared/config/constants.dart';
|
||||
import 'package:pshared/data/mapper/account/account.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/models/auth/login_outcome.dart';
|
||||
@@ -31,21 +31,33 @@ class AuthorizationService {
|
||||
final deviceId = await DeviceIdManager.getDeviceId();
|
||||
final response = await httpr.getPOSTResponse(
|
||||
service,
|
||||
'/login',
|
||||
LoginRequest(login: login, deviceId: deviceId, clientId: Constants.clientId).toJson(),
|
||||
'/login',
|
||||
LoginRequest(
|
||||
login: login,
|
||||
deviceId: deviceId,
|
||||
clientId: Constants.clientId,
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
if (response.containsKey('refreshToken')) {
|
||||
return LoginOutcome.completed((await completeLogin(response)).account.toDomain());
|
||||
return LoginOutcome.completed(
|
||||
(await completeLogin(response)).account.toDomain(),
|
||||
);
|
||||
}
|
||||
if (response.containsKey('pendingToken')) {
|
||||
final pending = PendingLogin.fromResponse(
|
||||
PendingLoginResponse.fromJson(response),
|
||||
session: SessionIdentifier(clientId: Constants.clientId, deviceId: deviceId),
|
||||
session: SessionIdentifier(
|
||||
clientId: Constants.clientId,
|
||||
deviceId: deviceId,
|
||||
),
|
||||
);
|
||||
return LoginOutcome.pending(pending);
|
||||
}
|
||||
throw AuthenticationFailedException('Unexpected login response', Exception(response.toString()));
|
||||
throw AuthenticationFailedException(
|
||||
'Unexpected login response',
|
||||
Exception(response.toString()),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _updateAccessToken(AccountResponse response) async {
|
||||
@@ -57,13 +69,16 @@ class AuthorizationService {
|
||||
return AuthorizationStorage.updateRefreshToken(response.refreshToken);
|
||||
}
|
||||
|
||||
static Future<LoginResponse> _completeLogin(Map<String, dynamic> response) async {
|
||||
static Future<LoginResponse> _completeLogin(
|
||||
Map<String, dynamic> response,
|
||||
) async {
|
||||
final LoginResponse lr = LoginResponse.fromJson(response);
|
||||
await _updateTokens(lr);
|
||||
return lr;
|
||||
}
|
||||
|
||||
static Future<LoginResponse> completeLogin(Map<String, dynamic> response) => _completeLogin(response);
|
||||
static Future<LoginResponse> completeLogin(Map<String, dynamic> response) =>
|
||||
_completeLogin(response);
|
||||
|
||||
static Future<Account> restore() async {
|
||||
return (await TokenService.refreshAccessToken()).account.toDomain();
|
||||
@@ -74,82 +89,123 @@ class AuthorizationService {
|
||||
}
|
||||
|
||||
// Original AuthorizationService methods - keeping the interface unchanged
|
||||
static Future<Map<String, dynamic>> getGETResponse(String service, String url) async {
|
||||
static Future<Map<String, dynamic>> getGETResponse(
|
||||
String service,
|
||||
String url,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
return httpr.getGETResponse(service, url, authToken: token);
|
||||
}
|
||||
|
||||
static Future<httpr.BinaryResponse> getGETBinaryResponse(String service, String url) async {
|
||||
static Future<httpr.BinaryResponse> getGETBinaryResponse(
|
||||
String service,
|
||||
String url,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
return httpr.getBinaryGETResponse(service, url, authToken: token);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> getPOSTResponse(String service, String url, Map<String, dynamic> body) async {
|
||||
static Future<Map<String, dynamic>> getPOSTResponse(
|
||||
String service,
|
||||
String url,
|
||||
Map<String, dynamic> body,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
return httpr.getPOSTResponse(service, url, body, authToken: token);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> getPUTResponse(String service, String url, Map<String, dynamic> body) async {
|
||||
static Future<Map<String, dynamic>> getPUTResponse(
|
||||
String service,
|
||||
String url,
|
||||
Map<String, dynamic> body,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
return httpr.getPUTResponse(service, url, body, authToken: token);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> getPATCHResponse(String service, String url, Map<String, dynamic> body) async {
|
||||
static Future<Map<String, dynamic>> getPATCHResponse(
|
||||
String service,
|
||||
String url,
|
||||
Map<String, dynamic> body,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
return httpr.getPATCHResponse(service, url, body, authToken: token);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> getDELETEResponse(String service, String url, Map<String, dynamic> body) async {
|
||||
static Future<Map<String, dynamic>> getDELETEResponse(
|
||||
String service,
|
||||
String url,
|
||||
Map<String, dynamic> body,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
return httpr.getDELETEResponse(service, url, body, authToken: token);
|
||||
}
|
||||
|
||||
static Future<String> getFileUploadResponseAuth(String service, String url, String fileName, String fileType, String mediaType, List<int> bytes) async {
|
||||
static Future<String> getFileUploadResponseAuth(
|
||||
String service,
|
||||
String url,
|
||||
String fileName,
|
||||
String fileType,
|
||||
String mediaType,
|
||||
List<int> bytes,
|
||||
) async {
|
||||
final token = await TokenService.getAccessTokenSafe();
|
||||
final res = await httpr.getFileUploadResponse(service, url, fileName, fileType, mediaType, bytes, authToken: token);
|
||||
final res = await httpr.getFileUploadResponse(
|
||||
service,
|
||||
url,
|
||||
fileName,
|
||||
fileType,
|
||||
mediaType,
|
||||
bytes,
|
||||
authToken: token,
|
||||
);
|
||||
if (res == null) {
|
||||
throw Exception('Upload failed');
|
||||
}
|
||||
return res.url;
|
||||
}
|
||||
|
||||
static Future<bool> isAuthorizationStored() async => AuthorizationStorage.isAuthorizationStored();
|
||||
static Future<bool> isAuthorizationStored() async =>
|
||||
AuthorizationStorage.isAuthorizationStored();
|
||||
|
||||
/// Execute an operation with automatic token management and retry logic
|
||||
static Future<T> executeWithAuth<T>(
|
||||
Future<T> Function() operation,
|
||||
String description, {
|
||||
int? maxRetries,
|
||||
}) async => AuthCircuitBreaker.execute(() async => RetryHelper.withExponentialBackoff(
|
||||
operation,
|
||||
maxRetries: maxRetries ?? 3,
|
||||
initialDelay: Duration(milliseconds: 100),
|
||||
maxDelay: Duration(seconds: 5),
|
||||
shouldRetry: (error) => RetryHelper.isRetryableError(error),
|
||||
));
|
||||
|
||||
}) async => AuthCircuitBreaker.execute(
|
||||
() async => RetryHelper.withExponentialBackoff(
|
||||
operation,
|
||||
maxRetries: maxRetries ?? 3,
|
||||
initialDelay: Duration(milliseconds: 100),
|
||||
maxDelay: Duration(seconds: 5),
|
||||
shouldRetry: (error) => RetryHelper.isRetryableError(error),
|
||||
),
|
||||
);
|
||||
|
||||
/// Handle 401 unauthorized errors with automatic token recovery
|
||||
static Future<T> handleUnauthorized<T>(
|
||||
Future<T> Function() operation,
|
||||
String description,
|
||||
) async {
|
||||
_logger.warning('Handling unauthorized error with token recovery: $description');
|
||||
|
||||
return executeWithAuth(
|
||||
() async {
|
||||
try {
|
||||
// Attempt token recovery first
|
||||
await TokenService.handleUnauthorized();
|
||||
|
||||
// Retry the original operation
|
||||
return await operation();
|
||||
} catch (e) {
|
||||
_logger.severe('Token recovery failed', e);
|
||||
throw AuthenticationFailedException('Token recovery failed', toException(e));
|
||||
}
|
||||
},
|
||||
'unauthorized recovery: $description',
|
||||
_logger.warning(
|
||||
'Handling unauthorized error with token recovery: $description',
|
||||
);
|
||||
|
||||
return executeWithAuth(() async {
|
||||
try {
|
||||
// Attempt token recovery first
|
||||
await TokenService.handleUnauthorized();
|
||||
|
||||
// Retry the original operation
|
||||
return await operation();
|
||||
} catch (e) {
|
||||
_logger.severe('Token recovery failed', e);
|
||||
throw AuthenticationFailedException(
|
||||
'Token recovery failed',
|
||||
toException(e),
|
||||
);
|
||||
}
|
||||
}, 'unauthorized recovery: $description');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user