233 lines
6.8 KiB
Dart
233 lines
6.8 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http_parser/http_parser.dart';
|
|
import 'package:mime/mime.dart';
|
|
import '../config/api_config.dart';
|
|
|
|
class VanguardApi {
|
|
static Map<String, String> authHeaders(String token) => {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $token',
|
|
};
|
|
|
|
static Future<String> login({
|
|
required String username,
|
|
required String password,
|
|
}) async {
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/login');
|
|
|
|
final res = await http.post(
|
|
url,
|
|
headers: const {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: jsonEncode({
|
|
'username': username,
|
|
'password': password,
|
|
'device_name': ApiConfig.deviceName,
|
|
}),
|
|
);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception('Login failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
final data = jsonDecode(res.body) as Map<String, dynamic>;
|
|
final token = data['token'];
|
|
if (token == null || token.toString().isEmpty) {
|
|
throw Exception('Missing token in login response.');
|
|
}
|
|
return token.toString();
|
|
}
|
|
|
|
static Future<void> requestPasswordResetEmail({required String email}) async {
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/password/remind');
|
|
|
|
final res = await http.post(
|
|
url,
|
|
headers: const {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: jsonEncode({'email': email}),
|
|
);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception(
|
|
'Password remind failed (${res.statusCode}): ${res.body}',
|
|
);
|
|
}
|
|
}
|
|
|
|
// ---------- Your custom APIs ----------
|
|
|
|
static Future<Map<String, dynamic>> getUserSchools({
|
|
required String token,
|
|
}) async {
|
|
final url = Uri.parse('${ApiConfig.phpApiBase}/api_user_schools.php');
|
|
|
|
final res = await http.get(
|
|
url,
|
|
headers: {'Accept': 'application/json', 'Authorization': 'Bearer $token'},
|
|
);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception('User schools failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
final data = jsonDecode(res.body) as Map<String, dynamic>;
|
|
if (data['success'] != true) {
|
|
throw Exception(data['message'] ?? 'Unknown error (user schools).');
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static Future<Map<String, dynamic>> getMyLessons({
|
|
required String token,
|
|
required int schoolId,
|
|
required String month, // YYYY-MM
|
|
}) async {
|
|
final url = Uri.parse(
|
|
'${ApiConfig.phpApiBase}/api_my_lessons.php',
|
|
).replace(queryParameters: {'school_id': '$schoolId', 'month': month});
|
|
|
|
final res = await http.get(
|
|
url,
|
|
headers: {'Accept': 'application/json', 'Authorization': 'Bearer $token'},
|
|
);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception('My lessons failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
final data = jsonDecode(res.body) as Map<String, dynamic>;
|
|
if (data['success'] != true) {
|
|
throw Exception(data['message'] ?? 'Unknown error (my lessons).');
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static Future<void> logout({required String token}) async {
|
|
// Vanguard / Laravel: quasi sempre POST /logout con Bearer token (Sanctum)
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/logout');
|
|
|
|
final res = await http.post(url, headers: authHeaders(token));
|
|
|
|
// 200 o 204 ok. Alcuni backend rispondono 401 se token già scaduto:
|
|
// in app lo consideriamo comunque "logout riuscito".
|
|
if (res.statusCode == 200 ||
|
|
res.statusCode == 204 ||
|
|
res.statusCode == 401) {
|
|
return;
|
|
}
|
|
|
|
throw Exception('Logout failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
// ---------- Profilo (Vanguard native) ----------
|
|
|
|
/// GET /me — dati profilo. Ritorna il contenuto di "data".
|
|
static Future<Map<String, dynamic>> getMe({required String token}) async {
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/me');
|
|
|
|
final res = await http.get(url, headers: authHeaders(token));
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception('Get profile failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
final body = jsonDecode(res.body) as Map<String, dynamic>;
|
|
final data = body['data'];
|
|
if (data is! Map<String, dynamic>) {
|
|
throw Exception('Formato risposta /me non valido.');
|
|
}
|
|
return data;
|
|
}
|
|
|
|
/// PATCH /me/details — aggiorna nome e cognome.
|
|
static Future<Map<String, dynamic>> updateDetails({
|
|
required String token,
|
|
String? firstName,
|
|
String? lastName,
|
|
}) async {
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/me/details');
|
|
|
|
final payload = <String, dynamic>{};
|
|
if (firstName != null) payload['first_name'] = firstName;
|
|
if (lastName != null) payload['last_name'] = lastName;
|
|
|
|
final res = await http.patch(
|
|
url,
|
|
headers: authHeaders(token),
|
|
body: jsonEncode(payload),
|
|
);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception('Update details failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
final body = jsonDecode(res.body) as Map<String, dynamic>;
|
|
return (body['data'] as Map<String, dynamic>?) ?? {};
|
|
}
|
|
|
|
/// PATCH /me/details/auth — aggiorna la password (nuova + conferma).
|
|
static Future<void> updatePassword({
|
|
required String token,
|
|
required String password,
|
|
required String passwordConfirmation,
|
|
}) async {
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/me/details/auth');
|
|
|
|
final res = await http.patch(
|
|
url,
|
|
headers: authHeaders(token),
|
|
body: jsonEncode({
|
|
'password': password,
|
|
'password_confirmation': passwordConfirmation,
|
|
}),
|
|
);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception(
|
|
'Update password failed (${res.statusCode}): ${res.body}',
|
|
);
|
|
}
|
|
}
|
|
|
|
/// POST /me/avatar — upload avatar (multipart). Ritorna l'URL avatar aggiornato.
|
|
static Future<String?> uploadAvatar({
|
|
required String token,
|
|
required String filePath,
|
|
}) async {
|
|
final url = Uri.parse('${ApiConfig.laravelApiBase}/me/avatar');
|
|
|
|
final mimeType = lookupMimeType(filePath) ?? 'image/jpeg';
|
|
final parts = mimeType.split('/');
|
|
|
|
final request = http.MultipartRequest('POST', url)
|
|
..headers['Accept'] = 'application/json'
|
|
..headers['Authorization'] = 'Bearer $token'
|
|
..files.add(
|
|
await http.MultipartFile.fromPath(
|
|
'file',
|
|
filePath,
|
|
contentType: MediaType(parts[0], parts[1]),
|
|
),
|
|
);
|
|
|
|
final streamed = await request.send();
|
|
final res = await http.Response.fromStream(streamed);
|
|
|
|
if (res.statusCode != 200) {
|
|
throw Exception('Upload avatar failed (${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
final body = jsonDecode(res.body) as Map<String, dynamic>;
|
|
final data = body['data'] as Map<String, dynamic>?;
|
|
return data?['avatar']?.toString();
|
|
}
|
|
}
|