From 2fca01a405d8433d09fe5753c77cfdde4b084486 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 27 Jul 2021 12:54:46 +0700 Subject: [PATCH] Init login feature add data layer --- .../atuthentitcation_datasource.dart | 5 ++ .../authentication_datasource_impl.dart | 22 ++++++++ .../model/converter/user_id_converter.dart | 14 +++++ .../data/model/request/account_request.dart | 17 ++++++ .../data/model/response/user_response.dart | 46 +++++++++++++++ .../login/data/network/login_api.dart | 29 ++++++++++ .../authentication_repository_impl.dart | 14 +++++ .../credential_repository_impl.dart | 56 +++++++++++++++++++ .../login/data/utils/login_constant.dart | 5 ++ 9 files changed, 208 insertions(+) create mode 100644 lib/features/login/data/datasource/atuthentitcation_datasource.dart create mode 100644 lib/features/login/data/datasource_impl/authentication_datasource_impl.dart create mode 100644 lib/features/login/data/model/converter/user_id_converter.dart create mode 100644 lib/features/login/data/model/request/account_request.dart create mode 100644 lib/features/login/data/model/response/user_response.dart create mode 100644 lib/features/login/data/network/login_api.dart create mode 100644 lib/features/login/data/repository/authentication_repository_impl.dart create mode 100644 lib/features/login/data/repository/credential_repository_impl.dart create mode 100644 lib/features/login/data/utils/login_constant.dart diff --git a/lib/features/login/data/datasource/atuthentitcation_datasource.dart b/lib/features/login/data/datasource/atuthentitcation_datasource.dart new file mode 100644 index 000000000..ff2092bae --- /dev/null +++ b/lib/features/login/data/datasource/atuthentitcation_datasource.dart @@ -0,0 +1,5 @@ +import 'package:model/model.dart'; + +abstract class AuthenticationDataSource { + Future authenticationUser(Uri baseUrl, UserName userName, Password password); +} \ No newline at end of file diff --git a/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart b/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart new file mode 100644 index 000000000..9b0235c0d --- /dev/null +++ b/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart @@ -0,0 +1,22 @@ +import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/login/data/datasource/atuthentitcation_datasource.dart'; +import 'package:tmail_ui_user/features/login/data/model/request/account_request.dart'; +import 'package:tmail_ui_user/features/login/data/model/response/user_response.dart'; +import 'package:tmail_ui_user/features/login/data/network/login_api.dart'; + +class AuthenticationDataSourceImpl extends AuthenticationDataSource { + + final LoginAPI loginAPI; + + AuthenticationDataSourceImpl(this.loginAPI); + + @override + Future authenticationUser(Uri baseUrl, UserName userName, Password password) { + return Future.sync(() async { + final userResponse = await loginAPI.authenticationUser(baseUrl, AccountRequest(userName, password)); + return userResponse.toUser(); + }).catchError((error) { + throw error; + }); + } +} \ No newline at end of file diff --git a/lib/features/login/data/model/converter/user_id_converter.dart b/lib/features/login/data/model/converter/user_id_converter.dart new file mode 100644 index 000000000..7ead95f0e --- /dev/null +++ b/lib/features/login/data/model/converter/user_id_converter.dart @@ -0,0 +1,14 @@ +import 'dart:convert'; + +import 'package:json_annotation/json_annotation.dart'; +import 'package:model/model.dart'; + +class UserIdConverter implements JsonConverter { + const UserIdConverter(); + + @override + UserId fromJson(String json) => UserId(json); + + @override + String toJson(UserId object) => jsonEncode(object.id); +} diff --git a/lib/features/login/data/model/request/account_request.dart b/lib/features/login/data/model/request/account_request.dart new file mode 100644 index 000000000..5b24e8da1 --- /dev/null +++ b/lib/features/login/data/model/request/account_request.dart @@ -0,0 +1,17 @@ +import 'package:equatable/equatable.dart'; +import 'package:model/model.dart'; + +class AccountRequest with EquatableMixin { + final UserName userName; + final Password password; + + AccountRequest(this.userName, this.password); + + Map toJson() => { + 'username': userName.userName, + 'password': password.value, + }; + + @override + List get props => [userName, password]; +} \ No newline at end of file diff --git a/lib/features/login/data/model/response/user_response.dart b/lib/features/login/data/model/response/user_response.dart new file mode 100644 index 000000000..c9c8e02d5 --- /dev/null +++ b/lib/features/login/data/model/response/user_response.dart @@ -0,0 +1,46 @@ +import 'package:core/data/constants/constant.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/login/data/model/converter/user_id_converter.dart'; + +part 'user_response.g.dart'; + +@UserIdConverter() +@JsonSerializable() +class UserResponse with EquatableMixin { + + @JsonKey(name: Constant.userId) + final UserId userId; + @JsonKey(name: Constant.firstName) + final String firstName; + @JsonKey(name: Constant.lastName) + final String lastName; + + UserResponse( + this.userId, + this.firstName, + this.lastName + ); + + factory UserResponse.fromJson(Map json) => _$UserResponseFromJson(json); + + Map toJson() => _$UserResponseToJson(this); + + @override + List get props => [ + userId, + firstName, + lastName, + ]; +} + +extension UserResponseExtension on UserResponse { + User toUser() { + return User( + userId, + firstName, + lastName, + ); + } +} \ No newline at end of file diff --git a/lib/features/login/data/network/login_api.dart b/lib/features/login/data/network/login_api.dart new file mode 100644 index 000000000..526888fe2 --- /dev/null +++ b/lib/features/login/data/network/login_api.dart @@ -0,0 +1,29 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:core/core.dart'; +import 'package:dio/dio.dart'; +import 'package:tmail_ui_user/features/login/data/model/request/account_request.dart'; +import 'package:tmail_ui_user/features/login/data/model/response/user_response.dart'; + +class LoginAPI { + final DioClient _dioClient; + + LoginAPI(this._dioClient); + + Future authenticationUser(Uri baseUrl, AccountRequest accountRequest) async { + final basicAuth = 'Basic ' + base64Encode(utf8.encode('${accountRequest.userName.userName}:${accountRequest.password.value}')); + final resultJson = await _dioClient.post( + Endpoint.authentication.generateAuthenticationUrl(baseUrl), + options: Options(headers: _buildHeaderRequestParam(basicAuth)), + data: accountRequest.toJson()); + return UserResponse.fromJson(resultJson); + } + + Map _buildHeaderRequestParam(String authorizationHeader) { + final headerParam = _dioClient.getHeaders(); + headerParam[HttpHeaders.authorizationHeader] = authorizationHeader; + return headerParam; + } +} \ No newline at end of file diff --git a/lib/features/login/data/repository/authentication_repository_impl.dart b/lib/features/login/data/repository/authentication_repository_impl.dart new file mode 100644 index 000000000..36eebd08b --- /dev/null +++ b/lib/features/login/data/repository/authentication_repository_impl.dart @@ -0,0 +1,14 @@ +import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/login/data/datasource/atuthentitcation_datasource.dart'; +import 'package:tmail_ui_user/features/login/domain/repository/authentication_repository.dart'; + +class AuthenticationRepositoryImpl extends AuthenticationRepository { + final AuthenticationDataSource loginDataSource; + + AuthenticationRepositoryImpl(this.loginDataSource); + + @override + Future authenticationUser(Uri baseUrl, UserName userName, Password password) { + return Future.value(User(UserId(userName.userName), "Alice", "Alice")); + } +} \ No newline at end of file diff --git a/lib/features/login/data/repository/credential_repository_impl.dart b/lib/features/login/data/repository/credential_repository_impl.dart new file mode 100644 index 000000000..5466436a4 --- /dev/null +++ b/lib/features/login/data/repository/credential_repository_impl.dart @@ -0,0 +1,56 @@ +import 'package:model/model.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:tmail_ui_user/features/login/data/utils/login_constant.dart'; +import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; + +class CredentialRepositoryImpl extends CredentialRepository { + + final SharedPreferences sharedPreferences; + + CredentialRepositoryImpl(this.sharedPreferences); + + @override + Future getBaseUrl() async { + return Uri.parse(sharedPreferences.getString(LoginConstant.keyBaseUrl) ?? ''); + } + + @override + Future saveBaseUrl(Uri baseUrl) async { + await sharedPreferences.setString(LoginConstant.keyBaseUrl, baseUrl.origin); + } + + @override + Future removeBaseUrl() async { + await sharedPreferences.remove(LoginConstant.keyBaseUrl); + } + + @override + Future getPassword() async { + return Password(sharedPreferences.getString(LoginConstant.keyPassword) ?? ''); + } + + @override + Future removePassword() async { + await sharedPreferences.remove(LoginConstant.keyPassword); + } + + @override + Future savePassword(Password password) async { + await sharedPreferences.setString(LoginConstant.keyPassword, password.value); + } + + @override + Future getUserName() async { + return UserName(sharedPreferences.getString(LoginConstant.keyUserName) ?? ''); + } + + @override + Future removeUserName() async { + await sharedPreferences.remove(LoginConstant.keyUserName); + } + + @override + Future saveUserName(UserName userName) async { + await sharedPreferences.setString(LoginConstant.keyUserName, userName.userName); + } +} \ No newline at end of file diff --git a/lib/features/login/data/utils/login_constant.dart b/lib/features/login/data/utils/login_constant.dart new file mode 100644 index 000000000..ac9eb86ae --- /dev/null +++ b/lib/features/login/data/utils/login_constant.dart @@ -0,0 +1,5 @@ +class LoginConstant { + static const keyBaseUrl = 'KEY_BASE_URL'; + static const keyUserName = 'KEY_USER_NAME'; + static const keyPassword = 'KEY_PASSWORD'; +} \ No newline at end of file