add auth register

This commit is contained in:
Phuoc Nguyen
2025-11-07 15:55:02 +07:00
parent ce7396f729
commit 9e55983d82
16 changed files with 2376 additions and 110 deletions

View File

@@ -0,0 +1,245 @@
/// Authentication Remote Data Source
///
/// Handles all authentication-related API calls.
library;
import 'package:dio/dio.dart';
import 'package:worker/core/errors/exceptions.dart';
import 'package:worker/features/auth/data/models/auth_session_model.dart';
import 'package:worker/features/auth/domain/entities/city.dart';
import 'package:worker/features/auth/domain/entities/customer_group.dart';
/// Authentication Remote Data Source
///
/// Provides methods for:
/// - Getting session (CSRF token and SID)
/// - Fetching cities for registration
/// - Fetching customer groups (roles) for registration
/// - User registration
class AuthRemoteDataSource {
final Dio _dio;
AuthRemoteDataSource(this._dio);
/// Get Session
///
/// Fetches session data including SID and CSRF token.
/// This should be called before making authenticated requests.
///
/// API: POST /api/method/dbiz_common.dbiz_common.api.auth.get_session
Future<GetSessionResponse> getSession() async {
try {
final response = await _dio.post<Map<String, dynamic>>(
'/api/method/dbiz_common.dbiz_common.api.auth.get_session',
data: '',
);
if (response.statusCode == 200 && response.data != null) {
return GetSessionResponse.fromJson(response.data!);
} else {
throw ServerException(
'Failed to get session: ${response.statusCode}',
);
}
} on DioException catch (e) {
if (e.response?.statusCode == 401) {
throw const UnauthorizedException();
} else if (e.response?.statusCode == 404) {
throw NotFoundException('Session endpoint not found');
} else {
throw NetworkException(
e.message ?? 'Failed to get session',
);
}
} catch (e) {
throw ServerException('Unexpected error: $e');
}
}
/// Get Cities
///
/// Fetches list of cities/provinces for address selection.
/// Requires authenticated session (CSRF token and Cookie).
///
/// API: POST /api/method/frappe.client.get_list
/// DocType: City
Future<List<City>> getCities({
required String csrfToken,
required String sid,
}) async {
try {
final response = await _dio.post<Map<String, dynamic>>(
'/api/method/frappe.client.get_list',
data: {
'doctype': 'City',
'fields': ['city_name', 'name', 'code'],
'limit_page_length': 0,
},
options: Options(
headers: {
'X-Frappe-Csrf-Token': csrfToken,
'Cookie': 'sid=$sid',
},
),
);
if (response.statusCode == 200 && response.data != null) {
final message = response.data!['message'];
if (message is List) {
return message
.map((json) => City.fromJson(json as Map<String, dynamic>))
.toList();
} else {
throw ServerException('Invalid response format for cities');
}
} else {
throw ServerException(
'Failed to get cities: ${response.statusCode}',
);
}
} on DioException catch (e) {
if (e.response?.statusCode == 401) {
throw const UnauthorizedException();
} else if (e.response?.statusCode == 404) {
throw NotFoundException('Cities endpoint not found');
} else {
throw NetworkException(
e.message ?? 'Failed to get cities',
);
}
} catch (e) {
throw ServerException('Unexpected error: $e');
}
}
/// Get Customer Groups (Roles)
///
/// Fetches list of customer groups for user role selection.
/// Requires authenticated session (CSRF token and Cookie).
///
/// API: POST /api/method/frappe.client.get_list
/// DocType: Customer Group
Future<List<CustomerGroup>> getCustomerGroups({
required String csrfToken,
required String sid,
}) async {
try {
final response = await _dio.post<Map<String, dynamic>>(
'/api/method/frappe.client.get_list',
data: {
'doctype': 'Customer Group',
'fields': ['customer_group_name', 'name', 'value'],
'filters': {
'is_group': 0,
'is_active': 1,
'customer': 1,
},
'limit_page_length': 0,
},
options: Options(
headers: {
'X-Frappe-Csrf-Token': csrfToken,
'Cookie': 'sid=$sid',
},
),
);
if (response.statusCode == 200 && response.data != null) {
final message = response.data!['message'];
if (message is List) {
return message
.map((json) =>
CustomerGroup.fromJson(json as Map<String, dynamic>))
.toList();
} else {
throw ServerException('Invalid response format for customer groups');
}
} else {
throw ServerException(
'Failed to get customer groups: ${response.statusCode}',
);
}
} on DioException catch (e) {
if (e.response?.statusCode == 401) {
throw const UnauthorizedException();
} else if (e.response?.statusCode == 404) {
throw NotFoundException('Customer groups endpoint not found');
} else {
throw NetworkException(
e.message ?? 'Failed to get customer groups',
);
}
} catch (e) {
throw ServerException('Unexpected error: $e');
}
}
/// Register User
///
/// Registers a new user with the provided information.
/// Requires authenticated session (CSRF token and Cookie).
///
/// API: POST /api/method/building_material.building_material.api.user.register
Future<Map<String, dynamic>> register({
required String csrfToken,
required String sid,
required String fullName,
required String phone,
required String email,
required String customerGroupCode,
required String cityCode,
String? companyName,
String? taxCode,
String? idCardFrontBase64,
String? idCardBackBase64,
List<String>? certificatesBase64,
}) async {
try {
final response = await _dio.post<Map<String, dynamic>>(
'/api/method/building_material.building_material.api.user.register',
data: {
'full_name': fullName,
'phone': phone,
'email': email,
'customer_group_code': customerGroupCode,
'city_code': cityCode,
'company_name': companyName,
'tax_code': taxCode,
'id_card_front_base64': idCardFrontBase64,
'id_card_back_base64': idCardBackBase64,
'certificates_base64': certificatesBase64 ?? [],
},
options: Options(
headers: {
'X-Frappe-Csrf-Token': csrfToken,
'Cookie': 'sid=$sid',
},
),
);
if (response.statusCode == 200 && response.data != null) {
return response.data!;
} else {
throw ServerException(
'Failed to register: ${response.statusCode}',
);
}
} on DioException catch (e) {
if (e.response?.statusCode == 401) {
throw const UnauthorizedException();
} else if (e.response?.statusCode == 400) {
throw ValidationException(
e.response?.data?['message'] as String? ?? 'Validation error',
);
} else if (e.response?.statusCode == 404) {
throw NotFoundException('Register endpoint not found');
} else {
throw NetworkException(
e.message ?? 'Failed to register',
);
}
} catch (e) {
throw ServerException('Unexpected error: $e');
}
}
}