This commit is contained in:
2025-10-28 00:09:46 +07:00
parent 9ebe7c2919
commit de49f564b1
110 changed files with 15392 additions and 3996 deletions

View File

@@ -0,0 +1,12 @@
/// Barrel file for auth domain layer exports
///
/// Provides clean imports for domain layer components
// Entities
export 'entities/user_entity.dart';
// Repositories
export 'repositories/auth_repository.dart';
// Use cases
export 'usecases/login_usecase.dart';

View File

@@ -0,0 +1,48 @@
import 'package:equatable/equatable.dart';
/// User entity representing authenticated user in the domain layer
///
/// This is a pure domain model with no external dependencies
class UserEntity extends Equatable {
/// Unique user identifier
final String userId;
/// Username
final String username;
/// Access token for API authentication
final String accessToken;
/// Refresh token for renewing access token
final String? refreshToken;
const UserEntity({
required this.userId,
required this.username,
required this.accessToken,
this.refreshToken,
});
/// Create a copy with modified fields
UserEntity copyWith({
String? userId,
String? username,
String? accessToken,
String? refreshToken,
}) {
return UserEntity(
userId: userId ?? this.userId,
username: username ?? this.username,
accessToken: accessToken ?? this.accessToken,
refreshToken: refreshToken ?? this.refreshToken,
);
}
@override
List<Object?> get props => [userId, username, accessToken, refreshToken];
@override
String toString() {
return 'UserEntity(userId: $userId, username: $username, hasRefreshToken: ${refreshToken != null})';
}
}

View File

@@ -0,0 +1,46 @@
import 'package:dartz/dartz.dart';
import '../../../../core/errors/failures.dart';
import '../../data/models/login_request_model.dart';
import '../entities/user_entity.dart';
/// Abstract repository interface for authentication operations
///
/// This defines the contract that the data layer must implement.
/// Returns Either<Failure, Success> for proper error handling.
abstract class AuthRepository {
/// Login with username and password
///
/// Returns [Right(UserEntity)] on success
/// Returns [Left(Failure)] on error
Future<Either<Failure, UserEntity>> login(LoginRequestModel request);
/// Logout current user
///
/// Returns [Right(void)] on success
/// Returns [Left(Failure)] on error
Future<Either<Failure, void>> logout();
/// Refresh access token
///
/// Returns [Right(UserEntity)] with new tokens on success
/// Returns [Left(Failure)] on error
Future<Either<Failure, UserEntity>> refreshToken(String refreshToken);
/// Check if user is authenticated
///
/// Returns true if valid access token exists
Future<bool> isAuthenticated();
/// Get current user from local storage
///
/// Returns [Right(UserEntity)] if user data exists
/// Returns [Left(Failure)] if no user data found
Future<Either<Failure, UserEntity>> getCurrentUser();
/// Clear authentication data (logout locally)
///
/// Returns [Right(void)] on success
/// Returns [Left(Failure)] on error
Future<Either<Failure, void>> clearAuthData();
}

View File

@@ -0,0 +1,126 @@
import 'package:dartz/dartz.dart';
import '../../../../core/errors/failures.dart';
import '../../data/models/login_request_model.dart';
import '../entities/user_entity.dart';
import '../repositories/auth_repository.dart';
/// Use case for user login
///
/// Encapsulates the business logic for authentication
/// Validates input, calls repository, and handles the response
class LoginUseCase {
final AuthRepository repository;
LoginUseCase(this.repository);
/// Execute login operation
///
/// [request] - Login credentials (username and password)
///
/// Returns [Right(UserEntity)] on successful login
/// Returns [Left(Failure)] on error:
/// - [ValidationFailure] if credentials are invalid
/// - [AuthenticationFailure] if login fails
/// - [NetworkFailure] if network error occurs
Future<Either<Failure, UserEntity>> call(LoginRequestModel request) async {
// Validate input
final validationError = _validateInput(request);
if (validationError != null) {
return Left(validationError);
}
// Call repository to perform login
return await repository.login(request);
}
/// Validate login request input
///
/// Returns [ValidationFailure] if validation fails, null otherwise
ValidationFailure? _validateInput(LoginRequestModel request) {
// Validate username
if (request.username.trim().isEmpty) {
return const ValidationFailure('Username is required');
}
if (request.username.length < 3) {
return const ValidationFailure('Username must be at least 3 characters');
}
// Validate password
if (request.password.isEmpty) {
return const ValidationFailure('Password is required');
}
if (request.password.length < 6) {
return const ValidationFailure('Password must be at least 6 characters');
}
return null;
}
}
/// Use case for user logout
class LogoutUseCase {
final AuthRepository repository;
LogoutUseCase(this.repository);
/// Execute logout operation
///
/// Returns [Right(void)] on successful logout
/// Returns [Left(Failure)] on error
Future<Either<Failure, void>> call() async {
return await repository.logout();
}
}
/// Use case for checking authentication status
class CheckAuthStatusUseCase {
final AuthRepository repository;
CheckAuthStatusUseCase(this.repository);
/// Check if user is authenticated
///
/// Returns true if user has valid access token
Future<bool> call() async {
return await repository.isAuthenticated();
}
}
/// Use case for getting current user
class GetCurrentUserUseCase {
final AuthRepository repository;
GetCurrentUserUseCase(this.repository);
/// Get current authenticated user
///
/// Returns [Right(UserEntity)] if user is authenticated
/// Returns [Left(Failure)] if no user found or error occurs
Future<Either<Failure, UserEntity>> call() async {
return await repository.getCurrentUser();
}
}
/// Use case for refreshing access token
class RefreshTokenUseCase {
final AuthRepository repository;
RefreshTokenUseCase(this.repository);
/// Refresh access token using refresh token
///
/// [refreshToken] - The refresh token
///
/// Returns [Right(UserEntity)] with new tokens on success
/// Returns [Left(Failure)] on error
Future<Either<Failure, UserEntity>> call(String refreshToken) async {
if (refreshToken.isEmpty) {
return const Left(ValidationFailure('Refresh token is required'));
}
return await repository.refreshToken(refreshToken);
}
}