91 lines
2.6 KiB
Dart
91 lines
2.6 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import '../../config/api_config.dart';
|
|
import '../../models/user_profile.dart';
|
|
import '../../services/auth_service.dart';
|
|
import 'profile_api_exception.dart';
|
|
|
|
/// HTTP client for Postgres-backed profile API.
|
|
class UserProfileRemoteStore {
|
|
UserProfileRemoteStore({http.Client? client}) : _client = client ?? http.Client();
|
|
|
|
final http.Client _client;
|
|
|
|
Future<UserProfile?> fetchProfile() async {
|
|
final String? token = await AuthService.instance.getIdToken();
|
|
if (token == null) {
|
|
return null;
|
|
}
|
|
|
|
final http.Response response = await _client.get(
|
|
Uri.parse('$apiBaseUrl/v1/me/profile'),
|
|
headers: _authHeaders(token),
|
|
);
|
|
|
|
if (response.statusCode == 404) {
|
|
return null;
|
|
}
|
|
if (response.statusCode != 200) {
|
|
throw ProfileApiException(response.statusCode, response.body);
|
|
}
|
|
|
|
return _profileFromApi(
|
|
jsonDecode(response.body) as Map<String, dynamic>,
|
|
);
|
|
}
|
|
|
|
Future<UserProfile> pushProfile(UserProfile profile) async {
|
|
final String? token = await AuthService.instance.getIdToken();
|
|
if (token == null) {
|
|
throw StateError('Not signed in');
|
|
}
|
|
|
|
final http.Response response = await _client.put(
|
|
Uri.parse('$apiBaseUrl/v1/me/profile'),
|
|
headers: _authHeaders(token),
|
|
body: jsonEncode(profile.toApiJson()),
|
|
);
|
|
|
|
if (response.statusCode == 409) {
|
|
final Map<String, dynamic> body =
|
|
jsonDecode(response.body) as Map<String, dynamic>;
|
|
throw ProfileConflictException(
|
|
_profileFromApi(body['profile'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
if (response.statusCode != 200) {
|
|
throw ProfileApiException(response.statusCode, response.body);
|
|
}
|
|
|
|
return _profileFromApi(
|
|
jsonDecode(response.body) as Map<String, dynamic>,
|
|
);
|
|
}
|
|
|
|
Map<String, String> _authHeaders(String token) {
|
|
return <String, String>{
|
|
'Authorization': 'Bearer $token',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
};
|
|
}
|
|
|
|
UserProfile _profileFromApi(Map<String, dynamic> json) {
|
|
return UserProfile(
|
|
firebaseUid: json['firebaseUid'] as String,
|
|
email: json['email'] as String?,
|
|
displayName: json['displayName'] as String?,
|
|
photoUrl: json['photoUrl'] as String?,
|
|
locale: json['locale'] as String? ?? 'en',
|
|
timezone: json['timezone'] as String?,
|
|
onboardingCompleted: json['onboardingCompleted'] as bool? ?? false,
|
|
revision: (json['revision'] as num).toInt(),
|
|
updatedAt: DateTime.parse(json['updatedAt'] as String).toUtc(),
|
|
lastSyncedAt: DateTime.now().toUtc(),
|
|
dirty: false,
|
|
);
|
|
}
|
|
}
|